diff --git a/plugins/org.eclipse.xtext/src/org/eclipse/xtext/linking/lazy/SyntheticLinkingSupport.java b/plugins/org.eclipse.xtext/src/org/eclipse/xtext/linking/lazy/SyntheticLinkingSupport.java index 5590f306a..90a294d25 100644 --- a/plugins/org.eclipse.xtext/src/org/eclipse/xtext/linking/lazy/SyntheticLinkingSupport.java +++ b/plugins/org.eclipse.xtext/src/org/eclipse/xtext/linking/lazy/SyntheticLinkingSupport.java @@ -7,23 +7,17 @@ *******************************************************************************/ package org.eclipse.xtext.linking.lazy; -import static java.util.Collections.*; - import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.EReference; +import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.xtext.XtextFactory; -import org.eclipse.xtext.nodemodel.BidiTreeIterable; -import org.eclipse.xtext.nodemodel.BidiTreeIterator; import org.eclipse.xtext.nodemodel.ICompositeNode; -import org.eclipse.xtext.nodemodel.ILeafNode; import org.eclipse.xtext.nodemodel.INode; -import org.eclipse.xtext.nodemodel.SyntaxErrorMessage; -import org.eclipse.xtext.nodemodel.util.NodeTreeIterator; -import org.eclipse.xtext.nodemodel.util.ReversedBidiTreeIterable; -import org.eclipse.xtext.util.ITextRegion; -import org.eclipse.xtext.util.ITextRegionWithLineInformation; -import org.eclipse.xtext.util.TextRegion; -import org.eclipse.xtext.util.TextRegionWithLineInformation; +import org.eclipse.xtext.nodemodel.impl.CompositeNode; +import org.eclipse.xtext.nodemodel.impl.LeafNode; +import org.eclipse.xtext.nodemodel.util.NodeModelUtils; +import org.eclipse.xtext.parser.IParseResult; +import org.eclipse.xtext.resource.XtextResource; import com.google.inject.Inject; @@ -39,179 +33,99 @@ public class SyntheticLinkingSupport { private LazyLinker lazyLinker; public void createAndSetProxy(EObject obj, EReference eRef, String crossRefString) { - lazyLinker.createAndSetProxy(obj, new SyntheticLinkingLeafNode(obj, crossRefString), eRef); + createAndSetProxy(obj, eRef, crossRefString, 0, 1); + } + + /** + * @since 2.10 + */ + public void createAndSetProxy(EObject obj, EReference eRef, String crossRefString, int offset, int length) { + INode crossReferenceNode = createCrossReferenceNode(obj, eRef, crossRefString, offset, length); + lazyLinker.createAndSetProxy(obj, crossReferenceNode, eRef); + } + + /** + * @since 2.10 + */ + protected INode createCrossReferenceNode(EObject obj, EReference eRef, String crossRefString, int offset, int length) { + CompositeNode parent = getParent(obj, eRef, crossRefString, offset, length); + EObject grammarElement = getGrammarElement(obj, eRef, crossRefString, offset, length); + return new SyntheticLinkingLeafNode(obj, crossRefString, offset, length, grammarElement, parent); + } + + /** + * @since 2.10 + */ + protected EObject getGrammarElement(EObject obj, EReference eRef, String crossRefString, int offset, int length) { + return XtextFactory.eINSTANCE.createKeyword(); + } + + /** + * @since 2.10 + */ + protected CompositeNode getParent(EObject obj, EReference eRef, String crossRefString, int offset, int length) { + ICompositeNode node = NodeModelUtils.getNode(obj); + if (node != null) { + ICompositeNode rootNode = node.getRootNode(); + if (rootNode instanceof CompositeNode) + return (CompositeNode) rootNode; + } + Resource resource = obj.eResource(); + if (resource instanceof XtextResource) { + IParseResult parseResult = ((XtextResource) resource).getParseResult(); + if (parseResult != null) { + ICompositeNode rootNode = parseResult.getRootNode(); + if (rootNode instanceof CompositeNode) + return (CompositeNode) rootNode; + } + } + return null; } } -class SyntheticLinkingLeafNode implements ILeafNode, BidiTreeIterable { - - private final static int OFFSET = 0; - private final static int LENGTH = 1; - private final static int LINE = -1; +class SyntheticLinkingLeafNode extends LeafNode { private final String text; - private final EObject grammarElement; private final EObject semanticElement; - public SyntheticLinkingLeafNode(EObject semanticElement, String text) { + public SyntheticLinkingLeafNode(EObject semanticElement, String text, int offset, int length, EObject grammarElement, CompositeNode parent) { this.text = text; this.semanticElement = semanticElement; - this.grammarElement = XtextFactory.eINSTANCE.createKeyword(); - } - @Override - public ICompositeNode getParent() { - return null; + basicSetTotalOffset(offset); + basicSetTotalLength(length); + basicSetGrammarElement(grammarElement); + basicSetParent(parent); } - - @Override - public boolean hasSiblings() { - return false; - } - - @Override - public boolean hasPreviousSibling() { - return false; - } - - @Override - public boolean hasNextSibling() { - return false; - } - - @Override - public INode getPreviousSibling() { - return null; - } - - @Override - public INode getNextSibling() { - return null; - } - - @Override - public ICompositeNode getRootNode() { - return null; - } - - @Override - public Iterable getLeafNodes() { - return emptyList(); - } - - @Override - public int getTotalOffset() { - return OFFSET; - } - - @Override - public int getOffset() { - return OFFSET; - } - - @Override - public int getTotalLength() { - return LENGTH; - } - - @Override - public int getLength() { - return LENGTH; - } - - @Override - public int getTotalEndOffset() { - return LENGTH; - } - - @Override - public int getEndOffset() { - return LENGTH; - } - - @Override - public int getTotalStartLine() { - return LINE; - } - - @Override - public int getStartLine() { - return LINE; - } - - @Override - public int getTotalEndLine() { - return LINE; - } - - @Override - public int getEndLine() { - return LINE; - } - + @Override public String getText() { return text; } - - @Override - public EObject getGrammarElement() { - return grammarElement; - } - + @Override public EObject getSemanticElement() { return semanticElement; } - + @Override - public boolean hasDirectSemanticElement() { - return true; - } - - @Override - public SyntaxErrorMessage getSyntaxErrorMessage() { - return null; - } - - @Override - public BidiTreeIterable getAsTreeIterable() { - return this; + protected EObject basicGetSemanticElement() { + return semanticElement; } @Override - public BidiTreeIterator iterator() { - return new NodeTreeIterator(this); + protected boolean basicHasSiblings() { + return false; } @Override - public BidiTreeIterable reverse() { - return new ReversedBidiTreeIterable(this); + protected boolean basicHasNextSibling() { + return false; } - + @Override - public ITextRegion getTextRegion() { - return new TextRegion(OFFSET, LENGTH); - } - - @Override - public ITextRegion getTotalTextRegion() { - return new TextRegion(OFFSET, LENGTH); - } - - @Override - public ITextRegionWithLineInformation getTextRegionWithLineInformation() { - return new TextRegionWithLineInformation(OFFSET, LENGTH, LINE, LINE); - } - - @Override - public ITextRegionWithLineInformation getTotalTextRegionWithLineInformation() { - return new TextRegionWithLineInformation(OFFSET, LENGTH, LINE, LINE); - } - - @Override - public boolean isHidden() { + protected boolean basicHasPreviousSibling() { return false; } diff --git a/tests/org.eclipse.xtext.tests/src/org/eclipse/xtext/linking/Bug437669Test.java b/tests/org.eclipse.xtext.tests/src/org/eclipse/xtext/linking/Bug437669Test.java index d9ac6dfb0..62faf3035 100644 --- a/tests/org.eclipse.xtext.tests/src/org/eclipse/xtext/linking/Bug437669Test.java +++ b/tests/org.eclipse.xtext.tests/src/org/eclipse/xtext/linking/Bug437669Test.java @@ -16,7 +16,10 @@ import org.eclipse.xtext.linking.importedURI.ImportedURIPackage; import org.eclipse.xtext.linking.importedURI.Main; import org.eclipse.xtext.linking.importedURI.Type; import org.eclipse.xtext.linking.lazy.SyntheticLinkingSupport; +import org.eclipse.xtext.nodemodel.INode; +import org.eclipse.xtext.nodemodel.util.NodeModelUtils; import org.eclipse.xtext.resource.XtextResourceSet; +import org.eclipse.xtext.util.LineAndColumn; import org.junit.Test; /** @@ -43,32 +46,64 @@ public class Bug437669Test extends AbstractXtextTests { } @Test - public void testUnresolved() { + public void testUnresolved_01() { Type type = resolve("BlaBlaBla"); Resource resource = type.eResource(); assertEquals(resource.getErrors().toString(), 1, resource.getErrors().size()); Diagnostic diagnostic = (Diagnostic) resource.getErrors().get(0); - assertEquals(-1, diagnostic.getLine()); assertEquals(0, diagnostic.getOffset()); assertEquals(1, diagnostic.getLength()); + assertEquals(1, diagnostic.getLine()); + assertEquals(1, diagnostic.getColumn()); assertEquals("Couldn't resolve reference to Type 'BlaBlaBla'.", diagnostic.getMessage()); } - private Type resolve(String text) { + @Test + public void testUnresolved_02() { + Type type = getContext(); + INode nameNode = NodeModelUtils.findNodesForFeature(type, ImportedURIPackage.Literals.TYPE__NAME).get(0); + resolve(type, "BlaBlaBla", nameNode.getOffset(), nameNode.getLength()); + Resource resource = type.eResource(); + assertEquals(resource.getErrors().toString(), 1, resource.getErrors().size()); + + LineAndColumn lineAndColumn = NodeModelUtils.getLineAndColumn(nameNode, nameNode.getOffset()); + + Diagnostic diagnostic = (Diagnostic) resource.getErrors().get(0); + assertEquals(nameNode.getOffset(), diagnostic.getOffset()); + assertEquals(nameNode.getLength(), diagnostic.getLength()); + assertEquals(lineAndColumn.getLine(), diagnostic.getLine()); + assertEquals(lineAndColumn.getColumn(), diagnostic.getColumn()); + assertEquals("Couldn't resolve reference to Type 'BlaBlaBla'.", diagnostic.getMessage()); + } + + protected Type resolve(String text) { + Type type = getContext(); + return resolve(type, text); + } + + protected Type resolve(Type type, String text) { + SyntheticLinkingSupport syntheticLinkingSupport = get(SyntheticLinkingSupport.class); + syntheticLinkingSupport.createAndSetProxy(type, ImportedURIPackage.Literals.TYPE__EXTENDS, text); + EcoreUtil.resolveAll(type.eResource().getResourceSet()); + return type; + } + + protected Type resolve(Type type, String text, int offset, int length) { + SyntheticLinkingSupport syntheticLinkingSupport = get(SyntheticLinkingSupport.class); + syntheticLinkingSupport.createAndSetProxy(type, ImportedURIPackage.Literals.TYPE__EXTENDS, text, offset, length); + EcoreUtil.resolveAll(type.eResource().getResourceSet()); + return type; + } + + protected Type getContext() { XtextResourceSet resourceSet = get(XtextResourceSet.class); resourceSet.setClasspathURIContext(getClass().getClassLoader()); URI uri = URI.createURI("classpath:/org/eclipse/xtext/linking/02.importuritestlanguage"); Resource resource = resourceSet.getResource(uri, true); Main main = (Main) resource.getContents().get(0); - Type type = main.getTypes().get(0); - - SyntheticLinkingSupport syntheticLinkingSupport = get(SyntheticLinkingSupport.class); - syntheticLinkingSupport.createAndSetProxy(type, ImportedURIPackage.Literals.TYPE__EXTENDS, text); - - EcoreUtil.resolveAll(resourceSet); - return type; + return main.getTypes().get(0); } } \ No newline at end of file