Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix error range for cvc-datatype-valid-1-2-1 #542

Merged
merged 1 commit into from
Aug 22, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import org.eclipse.lsp4j.Range;
import org.eclipse.lsp4xml.commons.BadLocationException;
import org.eclipse.lsp4xml.dom.DOMDocument;
import org.eclipse.lsp4xml.dom.DOMElement;
import org.eclipse.lsp4xml.dom.DOMNode;
import org.eclipse.lsp4xml.dom.NoNamespaceSchemaLocation;
import org.eclipse.lsp4xml.dom.SchemaLocation;
Expand All @@ -32,6 +33,7 @@
import org.eclipse.lsp4xml.extensions.contentmodel.participants.codeactions.cvc_type_3_1_1CodeAction;
import org.eclipse.lsp4xml.services.extensions.ICodeActionParticipant;
import org.eclipse.lsp4xml.services.extensions.diagnostics.IXMLErrorCode;
import org.eclipse.lsp4xml.utils.DOMUtils;
import org.eclipse.lsp4xml.utils.XMLPositionUtility;

/**
Expand Down Expand Up @@ -192,11 +194,26 @@ public static Range toLSPRange(XMLLocator location, XMLSchemaErrorCode code, Obj
case cvc_type_3_1_1:
return XMLPositionUtility.selectAllAttributes(offset, document);
case cvc_complex_type_2_1:
case cvc_type_3_1_3:
case cvc_elt_3_2_1:
return XMLPositionUtility.selectContent(offset, document);
case cvc_type_3_1_3:
case cvc_datatype_valid_1_2_1: {
String attrValue = getString(arguments[0]);
Range range = XMLPositionUtility.selectAttributeValueFromGivenValue(attrValue, offset, document);

if (range != null) {
return range;
}

DOMElement element = (DOMElement) document.findNodeAt(offset);

if (DOMUtils.containsTextOnly(element)) {
return XMLPositionUtility.selectTextTrimmed(offset, document);
} else {
return XMLPositionUtility.selectFirstChild(offset, document);
}
}
case cvc_enumeration_valid:
case cvc_datatype_valid_1_2_1:
case cvc_maxlength_valid:
case cvc_minlength_valid:
case cvc_maxExclusive_valid:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ private List<TextEdit> getRenameTextEdits(DOMDocument xmlDocument, DOMNode node,
}

/**
* Returns <code>DOMElement</code> associated with
* Returns <code>DOMElement</code> associated with
* <code>node</code>
*
* @param node node representing an element or attribute
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,4 +89,12 @@ public static boolean isDTD(String uri) {
return uri != null
&& (uri.endsWith(DTD_EXTENSION) || uri.endsWith(ENT_EXTENSION) || uri.endsWith(MOD_EXTENSION));
}

/**
* Returns true if element contains only DOMText and false otherwise.
* @return true if element contains only DOMText and false otherwise.
*/
public static boolean containsTextOnly(DOMElement element) {
return element.getChildNodes().getLength() == 1 && element.getFirstChild().isText();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,48 @@ public static int getOffsetAfterWhitespace(String text, int endOffset) {
return -1;
}

/**
* Returns the number of consecutive whitespace characters in front
* of text
* @param text String of interest
* @return the number of consecutive whitespace characters in front
* of text
*/
public static int getFrontWhitespaceLength(String text) {

if (StringUtils.isWhitespace(text)) {
return text.length();
}

int i = 0;
while (Character.isWhitespace(text.charAt(i))) {
i++;
}

return i;
}

/**
* Returns the number of consecutive whitespace characters from
* the end of text
* @param text String of interest
* @return the number of consecutive whitespace characters from
* the end of text
*/
public static int getTrailingWhitespaceLength(String text) {

if (StringUtils.isWhitespace(text)) {
return text.length();
}

int i = text.length() - 1;
while (Character.isWhitespace(text.charAt(i))) {
i--;
}

return text.length() - i - 1;
}

public static String cleanPathForWindows(String pathString) {
if (pathString.startsWith("/")) {
if (pathString.length() > 3) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -489,6 +489,43 @@ public static Location createLocation(DOMRange target) {
return new Location(targetDocument.getDocumentURI(), targetRange);
}

/**
* Returns the range covering the first child of the node located
* at offset.
*
* Returns null if node is not a DOMElement, or if a node does not
* exist at offset.
*
* @param offset
* @param document
* @return range covering the first child of the node located
* at offset
*/
public static Range selectFirstChild(int offset, DOMDocument document) {
DOMNode node = document.findNodeAt(offset);
if (node == null || !node.isElement()) {
return null;
}

DOMElement element = (DOMElement) node;
DOMNode child = element.getFirstChild();

if (child == null) {
return null;
}

int startOffset = child.getStart();
int endOffset = child.getEnd();

try {
Position startPosition = document.positionAt(startOffset);
Position endPosition = document.positionAt(endOffset);
return new Range(startPosition, endPosition);
} catch (BadLocationException e) {
return null;
}
}

public static Range selectContent(int offset, DOMDocument document) {
DOMNode node = document.findNodeAt(offset);
if (node != null) {
Expand All @@ -507,6 +544,59 @@ public static Range selectContent(int offset, DOMDocument document) {
return null;
}

/**
* Returns the range covering the trimmed text belonging to the node
* located at offset.
*
* This method assumes that the node located at offset only contains
* text.
*
* For example, if the node located at offset is:
*
* <a>
* hello
*
* </a>
*
* the returned range will cover only "hello".
*
* @param offset
* @param document
* @return range covering the trimmed text belonging to the node
* located at offset
*/
public static Range selectTextTrimmed(int offset, DOMDocument document) {
DOMNode node = document.findNodeAt(offset);
if (node == null || !node.isElement()) {
return null;
}

DOMElement element = (DOMElement) node;

if (DOMUtils.containsTextOnly(element)) {
DOMNode textNode = (DOMNode) element.getFirstChild();
String text = element.getFirstChild().getTextContent();

int startOffset = textNode.getStart();
int endOffset = textNode.getEnd();

if (!StringUtils.isWhitespace(text)) {
startOffset += StringUtils.getFrontWhitespaceLength(text);
endOffset -= StringUtils.getTrailingWhitespaceLength(text);
}

try {
Position startPosition = document.positionAt(startOffset);
Position endPosition = document.positionAt(endOffset);
return new Range(startPosition, endPosition);
} catch (BadLocationException e) {
return null;
}
}

return null;
}

public static Range selectDTDElementDeclAt(int offset, DOMDocument document) {
DOMNode node = document.findNodeAt(offset);
if (node != null && node.isDTDElementDecl()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,47 @@ public void cvc_datatype_valid_1_2_1OnText() throws Exception {
d(4, 10, 4, 22, XMLSchemaErrorCode.cvc_type_3_1_3));
}

@Test
public void cvc_datatype_valid_1_2_1_TextOnlyWithWhitespace() throws Exception {
String xml = "<a xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" \r\n" +
" xsi:noNamespaceSchemaLocation=\"src/test/resources/xsd/integerElement.xsd\">\r\n" +
"\r\n" +
" TEXT\r\n" +
"\r\n" +
"</a>";
testDiagnosticsFor(xml, d(3, 4, 3, 8, XMLSchemaErrorCode.cvc_datatype_valid_1_2_1),
d(3, 4, 3, 8, XMLSchemaErrorCode.cvc_type_3_1_3));
}

@Test
public void cvc_datatype_valid_1_2_1_OneElement() throws Exception {
String xml = "<a xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" \r\n" +
" xsi:noNamespaceSchemaLocation=\"src/test/resources/xsd/integerElement.xsd\">\r\n" +
"\r\n" +
" <b></b>\r\n" +
"\r\n" +
"</a>";

testDiagnosticsFor(xml, d(0, 1, 0, 2 , XMLSchemaErrorCode.cvc_type_3_1_2),
d(3, 4, 3, 11, XMLSchemaErrorCode.cvc_datatype_valid_1_2_1),
d(3, 4, 3, 11, XMLSchemaErrorCode.cvc_type_3_1_3));
}

@Test
public void cvc_datatype_valid_1_2_1_TwoElements() throws Exception {
String xml = "<a xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" \r\n" +
" xsi:noNamespaceSchemaLocation=\"src/test/resources/xsd/integerElement.xsd\">\r\n" +
"\r\n" +
" <b></b>\r\n" +
" <c></c>\r\n" +
"\r\n" +
"</a>";

testDiagnosticsFor(xml, d(0, 1, 0, 2 , XMLSchemaErrorCode.cvc_type_3_1_2),
d(3, 4, 3, 11, XMLSchemaErrorCode.cvc_datatype_valid_1_2_1),
d(3, 4, 3, 11, XMLSchemaErrorCode.cvc_type_3_1_3));
}

@Test
public void cvc_maxLength_validOnAttribute() throws Exception {
String xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n" + //
Expand Down
4 changes: 4 additions & 0 deletions org.eclipse.lsp4xml/src/test/resources/xsd/integerElement.xsd
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="a" type="xs:integer">
</xs:element>
</xs:schema>