Skip to content

Commit

Permalink
Improve DOM parser memory
Browse files Browse the repository at this point in the history
Signed-off-by: azerr <azerr@redhat.com>
  • Loading branch information
angelozerr committed Jun 1, 2022
1 parent 3ed3054 commit c0eec05
Show file tree
Hide file tree
Showing 10 changed files with 151 additions and 87 deletions.
125 changes: 84 additions & 41 deletions org.eclipse.lemminx/src/main/java/org/eclipse/lemminx/dom/DOMAttr.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,62 +25,89 @@
*/
public class DOMAttr extends DOMNode implements org.w3c.dom.Attr {

private final String name;
public static final String XMLNS_ATTR = "xmlns";
public static final String XMLNS_NO_DEFAULT_ATTR = "xmlns:";

private String name;

private final DOMNode nodeAttrName;
private final AttrName nodeAttrName;

private DOMNode nodeAttrValue;
private int delimiter;

private AttrValue nodeAttrValue;

private String quotelessValue;// Value without quotes

private String originalValue;// Exact value from document

private final DOMNode ownerElement;

private boolean hasDelimiter; // has '='
abstract class AttrNameOrValue implements DOMRange {

public static final String XMLNS_ATTR = "xmlns";
public static final String XMLNS_NO_DEFAULT_ATTR = "xmlns:";
private final int start;

class AttrNameOrValue extends DOMNode {
private final int end;

public AttrNameOrValue(int start, int end) {
super(start, end);
this.start = start;
this.end = end;
}

@Override
public String getNodeName() {
return null;
public int getStart() {
return start;
}

@Override
public short getNodeType() {
return -1;
public int getEnd() {
return end;
}

public DOMAttr getOwnerAttr() {
return DOMAttr.this;
}

@Override
public DOMNode getParentNode() {
return DOMAttr.this;
public DOMDocument getOwnerDocument() {
return getOwnerAttr().getOwnerDocument();
}

public String getContent() {
return getOwnerDocument().getText().substring(getStart(), getEnd());
}
}

class AttrName extends AttrNameOrValue {

public AttrName(int start, int end) {
super(start, end);
}
}

class AttrValue extends AttrNameOrValue {

public AttrValue(int start, int end) {
super(start, end);
}

@Override
public DOMDocument getOwnerDocument() {
return getOwnerAttr().getOwnerDocument();
public String getContent() {
if (getOwnerAttr().delimiter < getStart()) {
return super.getContent();
}
return null;
}
}

public DOMAttr(String name, DOMNode ownerElement) {
this(name, -1, -1, ownerElement);
this(name, NULL_VALUE, NULL_VALUE, ownerElement);
}

public DOMAttr(String name, int start, int end, DOMNode ownerElement) {
super(-1, -1);
super(NULL_VALUE, NULL_VALUE);
this.name = name;
this.nodeAttrName = start != -1 ? new AttrNameOrValue(start, end) : null;
this.delimiter = NULL_VALUE;
this.nodeAttrName = start != -1 ? new AttrName(start, end) : null;
this.ownerElement = ownerElement;
}

Expand Down Expand Up @@ -111,6 +138,9 @@ public String getNodeName() {
*/
@Override
public String getName() {
if (name == null && nodeAttrName != null) {
name = nodeAttrName.getContent();
}
return name;
}

Expand All @@ -121,6 +151,7 @@ public String getNodeValue() throws DOMException {

@Override
public String getLocalName() {
String name = getName();
int colonIndex = name.indexOf(":");
if (colonIndex > 0) {
return name.substring(colonIndex + 1);
Expand Down Expand Up @@ -148,6 +179,7 @@ public DOMDocument getOwnerDocument() {
*/
@Override
public String getValue() {
getOriginalValue();
return quotelessValue;
}

Expand Down Expand Up @@ -188,19 +220,19 @@ public boolean isId() {
*/
@Override
public void setValue(String value) throws DOMException {
setValue(value, -1, -1);
setValue(value, NULL_VALUE, NULL_VALUE);
}

public DOMNode getNodeAttrName() {
public DOMRange getNodeAttrName() {
return nodeAttrName;
}

public void setDelimiter(boolean hasDelimiter) {
this.hasDelimiter = hasDelimiter;
public void setDelimiter(int delimiter) {
this.delimiter = delimiter;
}

public boolean hasDelimiter() {
return this.hasDelimiter;
return delimiter != NULL_VALUE;
}

/**
Expand All @@ -211,23 +243,23 @@ public boolean hasDelimiter() {
* @return attribute value with quotations if it had them.
*/
public String getOriginalValue() {
if (originalValue == null && nodeAttrValue != null) {
originalValue = nodeAttrValue.getContent();
this.quotelessValue = StringUtils.convertToQuotelessValue(originalValue);
}
return originalValue;
}

public void setValue(String value, int start, int end) {
this.originalValue = value;
this.quotelessValue = StringUtils.convertToQuotelessValue(value);
this.nodeAttrValue = start != -1 ? new AttrNameOrValue(start, end) : null;
this.nodeAttrValue = start != -1 ? new AttrValue(start, end) : null;
}

public DOMNode getNodeAttrValue() {
public DOMRange getNodeAttrValue() {
return nodeAttrValue;
}

public void setNodeAttrValue(DOMNode nodeAttrValue) {
this.nodeAttrValue = nodeAttrValue;
}

public boolean valueContainsOffset(int offset) {
return nodeAttrValue != null && offset >= nodeAttrValue.getStart() && offset < nodeAttrValue.getEnd();
}
Expand Down Expand Up @@ -273,7 +305,7 @@ public String getNamespaceURI() {
* @return true if attribute name is a xmlns attribute and false otherwise.
*/
public boolean isXmlns() {
return isXmlns(name);
return isXmlns(getName());
}

public static boolean isXmlns(String attributeName) {
Expand All @@ -289,14 +321,15 @@ public static boolean isXmlns(String attributeName) {
* otherwise.
*/
public boolean isDefaultXmlns() {
return isDefaultXmlns(name);
return isDefaultXmlns(getName());
}

public static boolean isDefaultXmlns(String attributeName) {
return attributeName.equals(XMLNS_ATTR);
}

public String extractPrefixFromXmlns() {
String name = getName();
if (isDefaultXmlns()) {
return name.substring(XMLNS_ATTR.length(), name.length());
}
Expand All @@ -313,7 +346,8 @@ public String extractPrefixFromXmlns() {
*/
public String getPrefixIfMatchesURI(String uri) {
if (isXmlns()) {
if (quotelessValue != null && quotelessValue.equals(uri)) {
String value = getValue();
if (value != null && value.equals(uri)) {
if (isDefaultXmlns()) {
// xmlns="http://"
return null;
Expand All @@ -334,7 +368,7 @@ public String getPrefixIfMatchesURI(String uri) {
* otherwise.
*/
public boolean isNoDefaultXmlns() {
return isNoDefaultXmlns(name);
return isNoDefaultXmlns(getName());
}

public static boolean isNoDefaultXmlns(String attributeName) {
Expand Down Expand Up @@ -363,16 +397,23 @@ public boolean isIncluded(int offset) {

@Override
public int getStart() {
return nodeAttrName.start;
return nodeAttrName.getStart();
}

@Override
public int getEnd() {
return nodeAttrValue != null ? nodeAttrValue.end : nodeAttrName.end;
if (nodeAttrValue != null) {
return nodeAttrValue.getEnd();
}
if (hasDelimiter()) {
return delimiter + 1;
}
return nodeAttrName.getEnd();
}

@Override
public int hashCode() {
String name = getName();
final int prime = 31;
int result = 1;
result = prime * result + ((name == null) ? 0 : name.hashCode());
Expand All @@ -392,18 +433,20 @@ public boolean equals(Object obj) {
return false;
}
DOMAttr other = (DOMAttr) obj;
String name = getName();
if (name == null) {
if (other.name != null) {
if (other.getName() != null) {
return false;
}
} else if (!name.equals(other.name)) {
} else if (!name.equals(other.getName())) {
return false;
}
if (quotelessValue == null) {
if (other.quotelessValue != null) {
String value = getValue();
if (value == null) {
if (other.getValue() != null) {
return false;
}
} else if (!quotelessValue.equals(other.quotelessValue)) {
} else if (!value.equals(other.getValue())) {
return false;
}
return true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -410,7 +410,7 @@ public void setAttribute(String name, String value) {
attr = new DOMAttr(name, this);
setAttributeNode(attr);
}
attr.setValue(value, -1, -1);
attr.setValue(value);
}

public void setAttributeNode(DOMAttr attr) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,6 @@ public DOMDocument parse(TextDocument document, URIResolverExtensionManager reso
DOMNode lastClosed = curr;
DOMAttr attr = null;
int endTagOpenOffset = -1;
String pendingAttribute = null;
DOMNode tempWhitespaceContent = null;
boolean isInitialDeclaration = true; // A declaration can have multiple internal declarations
boolean previousTokenWasEndTagOpen = false;
Expand Down Expand Up @@ -226,9 +225,8 @@ public DOMDocument parse(TextDocument document, URIResolverExtensionManager reso
break;

case AttributeName: {
pendingAttribute = scanner.getTokenText();
attr = new DOMAttr(pendingAttribute, scanner.getTokenOffset(),
scanner.getTokenOffset() + pendingAttribute.length(), curr);
attr = new DOMAttr(null, scanner.getTokenOffset(),
scanner.getTokenEnd(), curr);
curr.setAttributeNode(attr);
curr.end = scanner.getTokenEnd();
break;
Expand All @@ -237,18 +235,15 @@ public DOMDocument parse(TextDocument document, URIResolverExtensionManager reso
case DelimiterAssign: {
if (attr != null) {
// Sets the value to the '=' position in case there is no AttributeValue
attr.setValue(null, scanner.getTokenOffset(), scanner.getTokenEnd());
attr.setDelimiter(true);
attr.setDelimiter(scanner.getTokenOffset());
}
break;
}

case AttributeValue: {
String value = scanner.getTokenText();
if (curr.hasAttributes() && attr != null) {
attr.setValue(value, scanner.getTokenOffset(), scanner.getTokenOffset() + value.length());
attr.setValue(null, scanner.getTokenOffset(), scanner.getTokenEnd());
}
pendingAttribute = null;
attr = null;
curr.end = scanner.getTokenEnd();
break;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ public SchemaLocation(DOMAttr attr) {
if (namespaceURI == null || locationHint == null) {
break;
}
DOMNode valNode = attr.getNodeAttrValue();
DOMRange valNode = attr.getNodeAttrValue();
// http://example.org/schema/root |root.xsd http://example.org/schema/bison bison.xsd
int start = valNode.getStart() + locPairMatcher.start(2) + 1;
// http://example.org/schema/root root.xsd| http://example.org/schema/bison bison.xsd
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ public static Range toLSPRange(XMLLocator location, XMLSyntaxErrorCode code, Obj
}
case QuoteRequiredInXMLDecl: {
String attrName = getString(arguments[0]);
return XMLPositionUtility.selectAttributeValueAt(attrName, offset, document);
return XMLPositionUtility.selectAttributeFromGivenNameAt(attrName, offset, document);
}
case EmptyPrefixedAttName: {
QName qName = (QName) arguments[0];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import org.eclipse.lemminx.dom.DOMDocument;
import org.eclipse.lemminx.dom.DOMElement;
import org.eclipse.lemminx.dom.DOMNode;
import org.eclipse.lemminx.dom.DOMRange;
import org.eclipse.lemminx.extensions.xsd.utils.XSDUtils;
import org.eclipse.lemminx.services.extensions.IRenameParticipant;
import org.eclipse.lemminx.services.extensions.IRenameRequest;
Expand Down Expand Up @@ -87,7 +88,7 @@ private List<Location> getReferenceLocations(DOMNode node) {
}

private List<TextEdit> renameAttributeValueTextEdits(DOMDocument document, DOMAttr attribute, String newText, List<Location> locations) {
DOMNode attrValue = attribute.getNodeAttrValue();
DOMRange attrValue = attribute.getNodeAttrValue();
List<TextEdit> textEdits = new ArrayList<>();

int valueStart = attrValue.getStart();
Expand Down
Loading

0 comments on commit c0eec05

Please sign in to comment.