+ * Default implementation of a call hierarchy builder. + *
+ * + * @author kosyakov - Initial contribution and API + * @since 2.10 + */ +class DefaultCallHierarchyBuilder extends AbstractHierarchyBuilder { + + override buildRoots(URI rootURI, IProgressMonitor progressMonitor) { + val rootDeclaration = rootURI.rootDeclaration + if(rootDeclaration === null) return emptyList + return #[rootDeclaration.createRoot] + } + + override buildChildren(HierarchyNode parent, IProgressMonitor progressMonitor) { + if (!parent.mayHaveChildren) + return emptyList + + val children = newLinkedHashMap + parent.element.EObjectURI.findDeclarations(progressMonitor) [ declaration, reference | + var childNode = children.get(declaration.EObjectURI) + if (childNode === null) { + childNode = createChild(declaration, parent) + children.put(declaration.EObjectURI, childNode) + } + childNode.locations += reference.createLocation + ] + return children.values + } + + protected def void findDeclarations( + URI targetURI, + IProgressMonitor progressMonitor, + (IEObjectDescription, IReferenceDescription)=>void acceptor + ) { + val targetURIs = targetURI.collectTargetURIs + + referenceFinder.findAllReferences( + targetURIs, + resourceAccess, + indexData, + new ReferenceAcceptor(resourceServiceProviderRegistry) [ reference | + val declaration = reference.declaration + if (declaration !== null) + acceptor.apply(declaration, reference) + ], + progressMonitor + ) + } + + protected def TargetURIs collectTargetURIs(URI targetURI) { + val targetURIs = targetURIProvider.get + if(targetURI === null) return targetURIs + + return resourceAccess.readOnly(targetURI) [ resourceSet | + val targetObject = resourceSet.getEObject(targetURI, true) + if(targetObject === null) return targetURIs + + targetURICollector.add(targetObject, targetURIs) + return targetURIs + ] + } + + protected def IEObjectDescription getRootDeclaration(URI rootURI) { + return rootURI.declaration.rootDeclaration + } + + /** + * @returns a declaration representing a root hierarchy node for the given element; can returnnull if the hierarchy does not support such kind of declarations
+ */
+ protected def IEObjectDescription getRootDeclaration(IEObjectDescription declaration) {
+ return declaration
+ }
+
+ /**
+ * @returns a declaration representing a child node that can be reached with the given reference; can return null
if the hierarchy does not support such kind of references
+ */
+ protected def IEObjectDescription getDeclaration(IReferenceDescription reference) {
+ if(reference === null) return null
+
+ val declarationURI = reference.containerEObjectURI ?: reference.sourceEObjectUri
+ return declarationURI.declaration
+ }
+
+ protected def IEObjectDescription getDeclaration(URI declarationURI) {
+ val resourceDescription = indexData.getResourceDescription(declarationURI.trimFragment)
+ if(resourceDescription === null) return null
+
+ return resourceDescription.exportedObjects.findFirst[EObjectURI == declarationURI]
+ }
+
+ /**
+ * @returns a root hierarchy node for the given declaration; cannot be null
+ */
+ protected def HierarchyNode createRoot(IEObjectDescription declaration) {
+ val node = new DefaultHierarchyNode
+ node.element = declaration
+ node.mayHaveChildren = true
+ return node
+ }
+
+ /**
+ * @returns a child node for the given declaration and the parent node; cannot be null
+ */
+ protected def HierarchyNode createChild(IEObjectDescription declaration, HierarchyNode parent) {
+ val node = new DefaultHierarchyNode
+ node.parent = parent
+ node.element = declaration
+ node.mayHaveChildren = !node.recursive
+ return node
+ }
+
+ /**
+ * @returns a location for the given reference; cannot be null
+ */
+ protected def HierarchyNodeLocation createLocation(IReferenceDescription reference) {
+ return resourceAccess.readOnly(reference.sourceEObjectUri) [ resourceSet |
+ val obj = resourceSet.getEObject(reference.sourceEObjectUri, true)
+ val textRegion = obj.getTextRegion(reference)
+ val text = obj.getText(textRegion)
+ return new DefaultHierarchyNodeLocation(text, textRegion, reference)
+ ]
+ }
+
+ protected def ITextRegionWithLineInformation getTextRegion(EObject obj, IReferenceDescription reference) {
+ return hierarchyNodeLocationProvider.getTextRegion(obj, reference.EReference, reference.indexInList)
+ }
+
+ protected def String getText(EObject obj, ITextRegionWithLineInformation textRegion) {
+ if (obj === null || textRegion === ITextRegionWithLineInformation.EMPTY_REGION)
+ return ''
+
+ val node = obj.rootContainer.node
+ if (node === null)
+ return ''
+
+ val endOffset = textRegion.offset + textRegion.length
+ return node.rootNode.text.substring(textRegion.offset, endOffset)
+ }
+
+}
diff --git a/plugins/org.eclipse.xtext.ide/src/org/eclipse/xtext/ide/editor/hierarchy/DefaultHierarchyNode.xtend b/plugins/org.eclipse.xtext.ide/src/org/eclipse/xtext/ide/editor/hierarchy/DefaultHierarchyNode.xtend
new file mode 100644
index 000000000..3ffd92c1b
--- /dev/null
+++ b/plugins/org.eclipse.xtext.ide/src/org/eclipse/xtext/ide/editor/hierarchy/DefaultHierarchyNode.xtend
@@ -0,0 +1,58 @@
+/*******************************************************************************
+ * Copyright (c) 2016 TypeFox GmbH (http://www.typefox.io) and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+package org.eclipse.xtext.ide.editor.hierarchy
+
+import org.eclipse.xtend.lib.annotations.Accessors
+import org.eclipse.xtext.resource.IEObjectDescription
+import org.eclipse.xtext.util.Wrapper
+
+/**
+ * @author kosyakov - Initial contribution and API
+ * @since 2.10
+ */
+class DefaultHierarchyNode implements HierarchyNode {
+
+ @Accessors
+ HierarchyNode parent
+
+ @Accessors(PUBLIC_SETTER)
+ boolean mayHaveChildren
+
+ @Accessors
+ IEObjectDescription element
+
+ @Accessors(PUBLIC_GETTER)
+ val locations = newArrayList
+
+ Wrapper recursive
+
+ override getNavigationElement() {
+ return locations.head ?: element
+ }
+
+ override boolean isRecursive() {
+ if (recursive === null)
+ recursive = Wrapper.wrap(internalIsRecursive)
+ return recursive.get
+ }
+
+ protected def boolean internalIsRecursive() {
+ var node = parent
+ while (node !== null) {
+ if (node.element.EObjectURI == element.EObjectURI)
+ return true
+ node = node.parent
+ }
+ return false
+ }
+
+ override mayHaveChildren() {
+ mayHaveChildren
+ }
+
+}
diff --git a/plugins/org.eclipse.xtext.ide/src/org/eclipse/xtext/ide/editor/hierarchy/DefaultHierarchyNodeLocation.xtend b/plugins/org.eclipse.xtext.ide/src/org/eclipse/xtext/ide/editor/hierarchy/DefaultHierarchyNodeLocation.xtend
new file mode 100644
index 000000000..a22beca79
--- /dev/null
+++ b/plugins/org.eclipse.xtext.ide/src/org/eclipse/xtext/ide/editor/hierarchy/DefaultHierarchyNodeLocation.xtend
@@ -0,0 +1,26 @@
+/*******************************************************************************
+ * Copyright (c) 2016 TypeFox GmbH (http://www.typefox.io) and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+package org.eclipse.xtext.ide.editor.hierarchy
+
+import org.eclipse.xtend.lib.annotations.Accessors
+import org.eclipse.xtend.lib.annotations.Delegate
+import org.eclipse.xtend.lib.annotations.FinalFieldsConstructor
+import org.eclipse.xtext.util.ITextRegionWithLineInformation
+
+/**
+ * @author kosyakov - Initial contribution and API
+ * @since 2.10
+ */
+@Accessors
+@FinalFieldsConstructor
+class DefaultHierarchyNodeLocation implements HierarchyNodeLocation {
+ val String text
+ @Delegate
+ val ITextRegionWithLineInformation textRegion
+ val Object navigationElement
+}
diff --git a/plugins/org.eclipse.xtext.ide/src/org/eclipse/xtext/ide/editor/hierarchy/DefaultHierarchyNodeLocationProvider.xtend b/plugins/org.eclipse.xtext.ide/src/org/eclipse/xtext/ide/editor/hierarchy/DefaultHierarchyNodeLocationProvider.xtend
new file mode 100644
index 000000000..46be3279a
--- /dev/null
+++ b/plugins/org.eclipse.xtext.ide/src/org/eclipse/xtext/ide/editor/hierarchy/DefaultHierarchyNodeLocationProvider.xtend
@@ -0,0 +1,61 @@
+/*******************************************************************************
+ * Copyright (c) 2016 TypeFox GmbH (http://www.typefox.io) and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+package org.eclipse.xtext.ide.editor.hierarchy
+
+import com.google.inject.Inject
+import com.google.inject.Singleton
+import org.eclipse.emf.ecore.EObject
+import org.eclipse.emf.ecore.EStructuralFeature
+import org.eclipse.xtext.resource.ILocationInFileProvider
+import org.eclipse.xtext.util.ITextRegion
+import org.eclipse.xtext.util.ITextRegionWithLineInformation
+import org.eclipse.xtext.util.TextRegionWithLineInformation
+
+import static extension org.eclipse.xtext.nodemodel.util.NodeModelUtils.*
+
+/**
+ * @author kosyakov - Initial contribution and API
+ * @since 2.10
+ */
+@Singleton
+class DefaultHierarchyNodeLocationProvider implements HierarchyNodeLocationProvider {
+
+ @Inject
+ protected ILocationInFileProvider locationInFileProvider
+
+ override getTextRegion(EObject obj) {
+ if(obj === null) return ITextRegionWithLineInformation.EMPTY_REGION
+
+ val textRegion = locationInFileProvider.getSignificantTextRegion(obj)
+ return obj.toTextRegionWithLineInformation(textRegion)
+ }
+
+ override getTextRegion(EObject owner, EStructuralFeature feature, int indexInList) {
+ if(owner === null) return ITextRegionWithLineInformation.EMPTY_REGION
+
+ val textRegion = locationInFileProvider.getSignificantTextRegion(owner, feature, indexInList)
+ return owner.toTextRegionWithLineInformation(textRegion)
+ }
+
+ protected def toTextRegionWithLineInformation(EObject obj, ITextRegion textRegion) {
+ if (textRegion === null)
+ return ITextRegionWithLineInformation.EMPTY_REGION
+
+ if (textRegion instanceof ITextRegionWithLineInformation)
+ return textRegion
+
+ val node = obj.node
+ if (node === null) {
+ return new TextRegionWithLineInformation(textRegion.offset, textRegion.length, 0, 0)
+ }
+ val startLine = node.getLineAndColumn(textRegion.offset).line - 1
+ val endLine = node.getLineAndColumn(textRegion.offset + textRegion.length).line - 1
+ return new TextRegionWithLineInformation(textRegion.offset, textRegion.length, startLine, endLine)
+ }
+
+}
diff --git a/plugins/org.eclipse.xtext.ide/src/org/eclipse/xtext/ide/editor/hierarchy/DefaultHierarchyRoot.xtend b/plugins/org.eclipse.xtext.ide/src/org/eclipse/xtext/ide/editor/hierarchy/DefaultHierarchyRoot.xtend
new file mode 100644
index 000000000..b8af629f7
--- /dev/null
+++ b/plugins/org.eclipse.xtext.ide/src/org/eclipse/xtext/ide/editor/hierarchy/DefaultHierarchyRoot.xtend
@@ -0,0 +1,19 @@
+/*******************************************************************************
+ * Copyright (c) 2016 TypeFox GmbH (http://www.typefox.io) and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+package org.eclipse.xtext.ide.editor.hierarchy
+
+import org.eclipse.xtend.lib.annotations.Accessors
+
+/**
+ * @author kosyakov - Initial contribution and API
+ * @since 2.10
+ */
+@Accessors
+class DefaultHierarchyRoot implements HierarchyRoot {
+ val roots = newArrayList
+}
diff --git a/plugins/org.eclipse.xtext.ide/src/org/eclipse/xtext/ide/editor/hierarchy/HierarchyBuilder.xtend b/plugins/org.eclipse.xtext.ide/src/org/eclipse/xtext/ide/editor/hierarchy/HierarchyBuilder.xtend
new file mode 100644
index 000000000..ba6a4b877
--- /dev/null
+++ b/plugins/org.eclipse.xtext.ide/src/org/eclipse/xtext/ide/editor/hierarchy/HierarchyBuilder.xtend
@@ -0,0 +1,32 @@
+/*******************************************************************************
+ * Copyright (c) 2016 TypeFox GmbH (http://www.typefox.io) and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+package org.eclipse.xtext.ide.editor.hierarchy
+
+import java.util.Collection
+import org.eclipse.core.runtime.IProgressMonitor
+import org.eclipse.emf.common.util.URI
+
+/**
+ * This class is used to build a hierarchy structure.
+ *
+ * @author kosyakov - Initial contribution and API
+ * @since 2.10
+ */
+interface HierarchyBuilder {
+
+ /**
+ * @returns root hierarchy nodes for the given URI; empty if the hierarchy cannot be built for the given URI
+ */
+ def Collection buildRoots(URI rootURI, IProgressMonitor monitor)
+
+ /**
+ * @returns child nodes for the given parent node; empty if {@link HierarchyNode#mayHaveChildren} returns false
for the parent
+ */
+ def Collection buildChildren(HierarchyNode parent, IProgressMonitor monitor)
+
+}
diff --git a/plugins/org.eclipse.xtext.ide/src/org/eclipse/xtext/ide/editor/hierarchy/HierarchyNode.xtend b/plugins/org.eclipse.xtext.ide/src/org/eclipse/xtext/ide/editor/hierarchy/HierarchyNode.xtend
new file mode 100644
index 000000000..209ed6a8d
--- /dev/null
+++ b/plugins/org.eclipse.xtext.ide/src/org/eclipse/xtext/ide/editor/hierarchy/HierarchyNode.xtend
@@ -0,0 +1,46 @@
+/*******************************************************************************
+ * Copyright (c) 2016 TypeFox GmbH (http://www.typefox.io) and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+package org.eclipse.xtext.ide.editor.hierarchy
+
+import java.util.Collection
+import org.eclipse.xtext.ide.editor.navigation.Navigatable
+import org.eclipse.xtext.resource.IEObjectDescription
+
+/**
+ * Represents a hierarchy node.
+ *
+ * @author kosyakov - Initial contribution and API
+ * @since 2.10
+ */
+interface HierarchyNode extends Navigatable {
+
+ /**
+ * @returns an associated element that is used to build child nodes
+ */
+ def IEObjectDescription getElement()
+
+ /**
+ * @returns a parent; null
if the node is a root
+ */
+ def HierarchyNode getParent()
+
+ /**
+ * @returns locations used to reach the node from a parent; empty if the node is a root
+ */
+ def Collection getLocations()
+
+ /**
+ * @returns whether there is a parent (can be transitive) containing the same element as the node
+ */
+ def boolean isRecursive()
+
+ /**
+ * @returns whether the node may have children; e.g. a recursive node cannot have children
+ */
+ def boolean mayHaveChildren()
+}
diff --git a/plugins/org.eclipse.xtext.ide/src/org/eclipse/xtext/ide/editor/hierarchy/HierarchyNodeLocation.xtend b/plugins/org.eclipse.xtext.ide/src/org/eclipse/xtext/ide/editor/hierarchy/HierarchyNodeLocation.xtend
new file mode 100644
index 000000000..b7e5b300b
--- /dev/null
+++ b/plugins/org.eclipse.xtext.ide/src/org/eclipse/xtext/ide/editor/hierarchy/HierarchyNodeLocation.xtend
@@ -0,0 +1,21 @@
+/*******************************************************************************
+ * Copyright (c) 2016 TypeFox GmbH (http://www.typefox.io) and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+package org.eclipse.xtext.ide.editor.hierarchy
+
+import org.eclipse.xtext.ide.editor.navigation.Navigatable
+import org.eclipse.xtext.util.ITextRegionWithLineInformation
+
+/**
+ * Represents a reference between parent and child nodes. Each location is backed up with a region and a text.
+ *
+ * @author kosyakov - Initial contribution and API
+ * @since 2.10
+ */
+interface HierarchyNodeLocation extends Navigatable, ITextRegionWithLineInformation {
+ def String getText()
+}
diff --git a/plugins/org.eclipse.xtext.ide/src/org/eclipse/xtext/ide/editor/hierarchy/HierarchyNodeLocationProvider.xtend b/plugins/org.eclipse.xtext.ide/src/org/eclipse/xtext/ide/editor/hierarchy/HierarchyNodeLocationProvider.xtend
new file mode 100644
index 000000000..a4897361d
--- /dev/null
+++ b/plugins/org.eclipse.xtext.ide/src/org/eclipse/xtext/ide/editor/hierarchy/HierarchyNodeLocationProvider.xtend
@@ -0,0 +1,25 @@
+/*******************************************************************************
+ * Copyright (c) 2016 TypeFox GmbH (http://www.typefox.io) and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+package org.eclipse.xtext.ide.editor.hierarchy
+
+import com.google.inject.ImplementedBy
+import org.eclipse.emf.ecore.EObject
+import org.eclipse.emf.ecore.EStructuralFeature
+import org.eclipse.xtext.util.ITextRegionWithLineInformation
+
+/**
+ * This class is used to identify a region for {@link HierarchyNode} and {@link HierarchyNodeLocation}.
+ * @author kosyakov - Initial contribution and API
+ * @since 2.10
+ */
+@ImplementedBy(DefaultHierarchyNodeLocationProvider)
+interface HierarchyNodeLocationProvider {
+ def ITextRegionWithLineInformation getTextRegion(EObject obj)
+
+ def ITextRegionWithLineInformation getTextRegion(EObject owner, EStructuralFeature feature, int indexInList)
+}
diff --git a/plugins/org.eclipse.xtext.ide/src/org/eclipse/xtext/ide/editor/hierarchy/HierarchyRoot.xtend b/plugins/org.eclipse.xtext.ide/src/org/eclipse/xtext/ide/editor/hierarchy/HierarchyRoot.xtend
new file mode 100644
index 000000000..4328b02d9
--- /dev/null
+++ b/plugins/org.eclipse.xtext.ide/src/org/eclipse/xtext/ide/editor/hierarchy/HierarchyRoot.xtend
@@ -0,0 +1,30 @@
+/*******************************************************************************
+ * Copyright (c) 2016 TypeFox GmbH (http://www.typefox.io) and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+package org.eclipse.xtext.ide.editor.hierarchy
+
+import java.util.Collection
+
+/**
+ * Represents a hierarchy root.
+ *
+ * @author kosyakov - Initial contribution and API
+ * @since 2.10
+ */
+interface HierarchyRoot {
+
+ def Collection getRoots()
+
+ val EMPTY = new HierarchyRoot() {
+
+ override getRoots() {
+ emptyList
+ }
+
+ }
+
+}
diff --git a/plugins/org.eclipse.xtext.ide/src/org/eclipse/xtext/ide/editor/navigation/Navigatable.xtend b/plugins/org.eclipse.xtext.ide/src/org/eclipse/xtext/ide/editor/navigation/Navigatable.xtend
new file mode 100644
index 000000000..9ce725bf1
--- /dev/null
+++ b/plugins/org.eclipse.xtext.ide/src/org/eclipse/xtext/ide/editor/navigation/Navigatable.xtend
@@ -0,0 +1,30 @@
+/*******************************************************************************
+ * Copyright (c) 2016 TypeFox GmbH (http://www.typefox.io) and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+package org.eclipse.xtext.ide.editor.navigation
+
+/**
+ * Represents an instance that can be opened in an editor.
+ *
+ * @author kosyakov - Initial contribution and API
+ * @since 2.10
+ */
+interface Navigatable {
+
+ /**
+ *
+ * Returns an instance containing enough information to identify an editor that should be opened and a region that should be revealed.
+ *
+ *
+ * Typical navigation elements are resource, object and reference descriptions as well as another navigatable element.
+ *
+ *
+ * Avoid usage of resource sets, resources and eobjects as navigation elements, since it can lead to memory leaks.
+ *
+ */
+ def Object getNavigationElement()
+}
diff --git a/plugins/org.eclipse.xtext.junit4/META-INF/MANIFEST.MF b/plugins/org.eclipse.xtext.junit4/META-INF/MANIFEST.MF
index 851a19c93..db3456245 100644
--- a/plugins/org.eclipse.xtext.junit4/META-INF/MANIFEST.MF
+++ b/plugins/org.eclipse.xtext.junit4/META-INF/MANIFEST.MF
@@ -8,7 +8,8 @@ Bundle-RequiredExecutionEnvironment: JavaSE-1.6
Export-Package: org.eclipse.xtext.junit4,
org.eclipse.xtext.junit4.build,
org.eclipse.xtext.junit4.formatter;x-friends:="org.eclipse.xtext.xbase.tests",
- org.eclipse.xtext.junit4.internal;x-friends:="org.eclipse.xtext.tests,org.eclipse.xtext.junit4.tests",
+ org.eclipse.xtext.junit4.ide;x-friends:="org.eclipse.xtext.xtext.ui.tests",
+ org.eclipse.xtext.junit4.internal;x-friends:="org.eclipse.xtext.tests,org.eclipse.xtext.junit4.tests,org.eclipse.xtext.xtext.ui.tests",
org.eclipse.xtext.junit4.logging;x-internal:=true,
org.eclipse.xtext.junit4.serializer;x-internal:=true,
org.eclipse.xtext.junit4.smoketest,
diff --git a/plugins/org.eclipse.xtext.junit4/src/org/eclipse/xtext/junit4/ide/AbstractHierarchyBuilderTest.xtend b/plugins/org.eclipse.xtext.junit4/src/org/eclipse/xtext/junit4/ide/AbstractHierarchyBuilderTest.xtend
new file mode 100644
index 000000000..14f3a1da8
--- /dev/null
+++ b/plugins/org.eclipse.xtext.junit4/src/org/eclipse/xtext/junit4/ide/AbstractHierarchyBuilderTest.xtend
@@ -0,0 +1,119 @@
+/*******************************************************************************
+ * Copyright (c) 2016 TypeFox GmbH (http://www.typefox.io) and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+package org.eclipse.xtext.junit4.ide
+
+import com.google.inject.Inject
+import java.util.Collection
+import javax.inject.Provider
+import org.eclipse.emf.common.util.URI
+import org.eclipse.emf.ecore.resource.ResourceSet
+import org.eclipse.xtend.lib.annotations.Accessors
+import org.eclipse.xtext.ide.editor.hierarchy.AbstractHierarchyBuilder
+import org.eclipse.xtext.ide.editor.hierarchy.HierarchyBuilder
+import org.eclipse.xtext.ide.editor.hierarchy.HierarchyNode
+import org.eclipse.xtext.ide.editor.hierarchy.HierarchyNodeLocation
+import org.eclipse.xtext.junit4.validation.ValidationTestHelper
+import org.eclipse.xtext.resource.EObjectAtOffsetHelper
+import org.eclipse.xtext.resource.IResourceDescriptionsProvider
+import org.eclipse.xtext.resource.XtextResource
+import org.eclipse.xtext.resource.XtextResourceSet
+import org.eclipse.xtext.ui.editor.findrefs.SimpleLocalResourceAccess
+import org.eclipse.xtext.util.LazyStringInputStream
+
+import static org.junit.Assert.*
+
+import static extension org.eclipse.xtext.EcoreUtil2.*
+
+/**
+ * @author kosyakov - Initial contribution and API
+ * @since 2.10
+ */
+abstract class AbstractHierarchyBuilderTest {
+
+ @Inject
+ extension ValidationTestHelper
+
+ @Inject
+ extension EObjectAtOffsetHelper
+
+ @Inject
+ Provider resourceSetProvider
+
+ @Inject
+ IResourceDescriptionsProvider resourceDescriptionsProvider
+
+ protected def testBuildHierarchy((HierarchyBuilderTestConfiguration)=>void configurator) {
+ val extension configuration = new HierarchyBuilderTestConfiguration
+ configurator.apply(configuration)
+
+ val resourceSet = configuration.createResourceSet
+ val hierarchyBuilder = hierarchyBuilderProvider.apply(resourceSet)
+
+ val resourceURI = if(resourceURI === null) models.last.key else resourceURI
+ val resource = resourceSet.getResource(URI.createURI(resourceURI), false) as XtextResource
+ val rootURI = resource.resolveElementAt(index).platformResourceOrNormalizedURI
+ val actualHierarchy = rootURI.toExpectation(hierarchyBuilder)
+ assertEquals(expectedHierarchy, actualHierarchy)
+ }
+
+ protected def ResourceSet createResourceSet(extension HierarchyBuilderTestConfiguration configuration) {
+ val resourceSet = resourceSetProvider.get
+ for (model : models) {
+ val resource = resourceSet.createResource(URI.createURI(model.key))
+ resource.load(new LazyStringInputStream(model.value, 'UTF-8'), null)
+ resource.assertNoIssues
+ }
+ return resourceSet
+ }
+
+ protected def T configureBuilderWith(
+ T hierarchyBuilder,
+ ResourceSet resourceSet
+ ) {
+ hierarchyBuilder.resourceAccess = new SimpleLocalResourceAccess(resourceSet)
+ hierarchyBuilder.indexData = resourceDescriptionsProvider.getResourceDescriptions(resourceSet)
+ return hierarchyBuilder
+ }
+
+ protected def String toExpectation(URI rootURI, HierarchyBuilder builder) '''
+ «FOR root : builder.buildRoots(rootURI, null)»
+ «root.toExpectation(builder)»
+ «ENDFOR»
+ '''
+
+ protected def String toExpectation(HierarchyNode node, HierarchyBuilder builder) '''
+ «node.element» {
+ «node.internalToExpectation(builder)»
+ }
+ '''
+
+ protected def String internalToExpectation(HierarchyNode node, HierarchyBuilder builder) '''
+ «FOR location : node.locations»
+ «location.toExpectation»
+ «ENDFOR»
+ «IF node.mayHaveChildren»
+ «FOR childNode : builder.buildChildren(node, null)»
+ «childNode.toExpectation(builder)»
+ «ENDFOR»
+ «ENDIF»
+ '''
+
+ protected def String toExpectation(HierarchyNodeLocation location) {
+ ''''«location.text»' [«location.offset», «location.length»]'''
+ }
+
+ @Accessors
+ protected static class HierarchyBuilderTestConfiguration {
+ (ResourceSet)=>HierarchyBuilder hierarchyBuilderProvider
+ Collection> models = newArrayList
+ int index
+ String resourceURI
+ String expectedHierarchy
+ }
+
+}
diff --git a/plugins/org.eclipse.xtext/.settings/org.eclipse.jdt.ui.prefs b/plugins/org.eclipse.xtext/.settings/org.eclipse.jdt.ui.prefs
index e5f3622ad..efcfb71c6 100644
--- a/plugins/org.eclipse.xtext/.settings/org.eclipse.jdt.ui.prefs
+++ b/plugins/org.eclipse.xtext/.settings/org.eclipse.jdt.ui.prefs
@@ -63,7 +63,7 @@ org.eclipse.jdt.ui.keywordthis=false
org.eclipse.jdt.ui.ondemandthreshold=99
org.eclipse.jdt.ui.overrideannotation=true
org.eclipse.jdt.ui.staticondemandthreshold=1
-org.eclipse.jdt.ui.text.custom_code_templates=/*******************************************************************************\n * Copyright (c) ${year} itemis AG (http\://www.itemis.eu) and others.\n * All rights reserved. This program and the accompanying materials\n * are made available under the terms of the Eclipse Public License v1.0\n * which accompanies this distribution, and is available at\n * http\://www.eclipse.org/legal/epl-v10.html\n *******************************************************************************//**\n * @author ${user} - Initial contribution and API\n */${filecomment}\n${package_declaration}\n\n${typecomment}\n${type_declaration}\n\n\n\n// ${todo} Auto-generated catch block\n${exception_var}.printStackTrace();// ${todo} Auto-generated method stub\n${body_statement}${body_statement}\n// ${todo} Auto-generated constructor stubreturn ${field};${field} \= ${param};/**\n * @return the ${bare_field_name}\n *//**\n * @param ${param} the ${bare_field_name} to set\n *//**\n * ${tags}\n *//**\n * \n *//**\n * @author ${user}\n *\n * ${tags}\n *//**\n * \n *//**\n * ${tags}\n *//* (non-JSDoc)\n * ${see_to_overridden}\n *//**\n * ${tags}\n * ${see_to_target}\n */${filecomment}\n${package_declaration}\n\n${typecomment}\n${type_declaration}\n// ${todo} Auto-generated catch block\n${exception_var}.printStackTrace();// ${todo} Auto-generated function stub\n${body_statement}${body_statement}\n// ${todo} Auto-generated constructor stubreturn ${field};${field} \= ${param};
+org.eclipse.jdt.ui.text.custom_code_templates=/*******************************************************************************\n * Copyright (c) ${year} TypeFox GmbH (http\://www.typefox.io) and others.\n * All rights reserved. This program and the accompanying materials\n * are made available under the terms of the Eclipse Public License v1.0\n * which accompanies this distribution, and is available at\n * http\://www.eclipse.org/legal/epl-v10.html\n *******************************************************************************//**\n * @author ${user} - Initial contribution and API\n */${filecomment}\n${package_declaration}\n\n${typecomment}\n${type_declaration}\n\n\n\n// ${todo} Auto-generated catch block\n${exception_var}.printStackTrace();// ${todo} Auto-generated method stub\n${body_statement}${body_statement}\n// ${todo} Auto-generated constructor stubreturn ${field};${field} \= ${param};/**\n * @return the ${bare_field_name}\n *//**\n * @param ${param} the ${bare_field_name} to set\n *//**\n * ${tags}\n *//**\n * \n *//**\n * @author ${user}\n *\n * ${tags}\n *//**\n * \n *//**\n * ${tags}\n *//* (non-JSDoc)\n * ${see_to_overridden}\n *//**\n * ${tags}\n * ${see_to_target}\n */${filecomment}\n${package_declaration}\n\n${typecomment}\n${type_declaration}\n// ${todo} Auto-generated catch block\n${exception_var}.printStackTrace();// ${todo} Auto-generated function stub\n${body_statement}${body_statement}\n// ${todo} Auto-generated constructor stubreturn ${field};${field} \= ${param};
sp_cleanup.add_default_serial_version_id=true
sp_cleanup.add_generated_serial_version_id=false
sp_cleanup.add_missing_annotations=true
diff --git a/plugins/org.eclipse.xtext/META-INF/MANIFEST.MF b/plugins/org.eclipse.xtext/META-INF/MANIFEST.MF
index 79cd16538..88fc098ba 100644
--- a/plugins/org.eclipse.xtext/META-INF/MANIFEST.MF
+++ b/plugins/org.eclipse.xtext/META-INF/MANIFEST.MF
@@ -20,7 +20,7 @@ Export-Package: org.eclipse.xtext,
org.eclipse.xtext.diagnostics,
org.eclipse.xtext.documentation,
org.eclipse.xtext.documentation.impl,
- org.eclipse.xtext.findReferences;x-friends:="org.eclipse.xtext.xbase",
+ org.eclipse.xtext.findReferences,
org.eclipse.xtext.formatting,
org.eclipse.xtext.formatting.impl,
org.eclipse.xtext.formatting2;
diff --git a/plugins/org.eclipse.xtext/src/org/eclipse/xtext/findReferences/IReferenceFinder.java b/plugins/org.eclipse.xtext/src/org/eclipse/xtext/findReferences/IReferenceFinder.java
index 119d440ef..365e6cd3b 100644
--- a/plugins/org.eclipse.xtext/src/org/eclipse/xtext/findReferences/IReferenceFinder.java
+++ b/plugins/org.eclipse.xtext/src/org/eclipse/xtext/findReferences/IReferenceFinder.java
@@ -37,7 +37,7 @@ import com.google.inject.ImplementedBy;
* @author Jan Koehnlein - Initial contribution and API in xtext.ui
* @author Sebastian Zarnekow - Extracted headless API
*
- * @since 2.7
+ * @since 2.10
*/
@ImplementedBy(ReferenceFinder.class)
public interface IReferenceFinder {
@@ -47,7 +47,7 @@ public interface IReferenceFinder {
* shared resource set.
*/
interface IResourceAccess {
- R readOnly(URI resourceURI, IUnitOfWork work);
+ R readOnly(URI targetURI, IUnitOfWork work);
}
/**
diff --git a/plugins/org.eclipse.xtext/src/org/eclipse/xtext/findReferences/ReferenceAcceptor.xtend b/plugins/org.eclipse.xtext/src/org/eclipse/xtext/findReferences/ReferenceAcceptor.xtend
new file mode 100644
index 000000000..11e799cbc
--- /dev/null
+++ b/plugins/org.eclipse.xtext/src/org/eclipse/xtext/findReferences/ReferenceAcceptor.xtend
@@ -0,0 +1,104 @@
+/*******************************************************************************
+ * Copyright (c) 2016 TypeFox GmbH (http://www.typefox.io) and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+package org.eclipse.xtext.findReferences
+
+import java.util.Map
+import org.eclipse.emf.common.util.URI
+import org.eclipse.emf.ecore.EObject
+import org.eclipse.emf.ecore.EReference
+import org.eclipse.emf.ecore.resource.Resource
+import org.eclipse.xtend.lib.annotations.FinalFieldsConstructor
+import org.eclipse.xtext.resource.IReferenceDescription
+import org.eclipse.xtext.resource.IResourceServiceProvider
+import org.eclipse.xtext.resource.impl.DefaultReferenceDescription
+import org.eclipse.xtext.util.IAcceptor
+
+/**
+ * For local references, populates an {@link IReferenceDescription} that knows its exported container URI.
+ *
+ * @author Sebastian Zarnekow - Initial contribution and API
+ * @author kosyakov - Pulled up to the runtime project
+ *
+ * @since 2.10
+ */
+@FinalFieldsConstructor
+class ReferenceAcceptor implements IReferenceFinder.Acceptor {
+
+ val IResourceServiceProvider.Registry resourceServiceProviderRegistry
+ val IAcceptor delegate
+
+ Resource currentResource
+ Map exportedContainersInCurrentResource
+
+ override void accept(
+ EObject source,
+ URI sourceURI,
+ EReference eReference,
+ int index,
+ EObject targetOrProxy,
+ URI targetURI
+ ) {
+ if (currentResource === null || source.eResource() !== currentResource) {
+ computeExportedObjectsMap(source)
+ currentResource = source.eResource()
+ }
+ accept(createReferenceDescription(sourceURI, targetURI, eReference, index, findExportedContainer(source)))
+ }
+
+ protected def void computeExportedObjectsMap(EObject source) {
+ val resource = source.eResource
+ val resourceServiceProvider = resourceServiceProviderRegistry.getResourceServiceProvider(resource.URI)
+ if (resourceServiceProvider !== null) {
+ val resourceDescription = resourceServiceProvider.resourceDescriptionManager.getResourceDescription(resource)
+ exportedContainersInCurrentResource = newHashMap
+ for (description : resourceDescription.exportedObjects) {
+ var instance = description.EObjectOrProxy
+ if (instance.eIsProxy) {
+ instance = resource.getEObject(description.EObjectURI.fragment)
+ }
+ exportedContainersInCurrentResource.put(instance, description.EObjectURI)
+ }
+ } else {
+ exportedContainersInCurrentResource = emptyMap
+ }
+ }
+
+ protected def URI findExportedContainer(EObject obj) {
+ var source = obj
+ if (exportedContainersInCurrentResource.isEmpty()) {
+ return null
+ }
+ var result = exportedContainersInCurrentResource.get(source)
+ while (result === null) {
+ if (exportedContainersInCurrentResource.containsKey(source)) {
+ return result
+ }
+ source = source.eContainer
+ if (source === null) {
+ return null
+ }
+ result = exportedContainersInCurrentResource.get(source)
+ }
+ exportedContainersInCurrentResource.put(source, result)
+ return result
+ }
+
+ override void accept(IReferenceDescription description) {
+ this.delegate.accept(description)
+ }
+
+ protected def IReferenceDescription createReferenceDescription(
+ URI sourceURI,
+ URI targetURI,
+ EReference eReference,
+ int index,
+ URI containerURI
+ ) {
+ return new DefaultReferenceDescription(sourceURI, targetURI, eReference, index, containerURI)
+ }
+}
diff --git a/plugins/org.eclipse.xtext/src/org/eclipse/xtext/findReferences/ReferenceFinder.java b/plugins/org.eclipse.xtext/src/org/eclipse/xtext/findReferences/ReferenceFinder.java
index e7177bf1e..2bf2ca234 100644
--- a/plugins/org.eclipse.xtext/src/org/eclipse/xtext/findReferences/ReferenceFinder.java
+++ b/plugins/org.eclipse.xtext/src/org/eclipse/xtext/findReferences/ReferenceFinder.java
@@ -34,7 +34,7 @@ import com.google.inject.Singleton;
/**
* @author Sebastian Zarnekow - Initial contribution and API
- * @since 2.7
+ * @since 2.10
*/
@Singleton
public class ReferenceFinder implements IReferenceFinder {
diff --git a/plugins/org.eclipse.xtext/src/org/eclipse/xtext/findReferences/TargetURICollector.java b/plugins/org.eclipse.xtext/src/org/eclipse/xtext/findReferences/TargetURICollector.java
index 0b96840ca..60310a4e3 100644
--- a/plugins/org.eclipse.xtext/src/org/eclipse/xtext/findReferences/TargetURICollector.java
+++ b/plugins/org.eclipse.xtext/src/org/eclipse/xtext/findReferences/TargetURICollector.java
@@ -27,6 +27,8 @@ import com.google.inject.Singleton;
* targets.
*
* @author Sebastian Zarnekow - Initial contribution and API
+ *
+ * @since 2.10
*/
@Singleton
public class TargetURICollector {
diff --git a/plugins/org.eclipse.xtext/src/org/eclipse/xtext/findReferences/TargetURISet.java b/plugins/org.eclipse.xtext/src/org/eclipse/xtext/findReferences/TargetURISet.java
index 55e96f318..8eea4ebf5 100644
--- a/plugins/org.eclipse.xtext/src/org/eclipse/xtext/findReferences/TargetURISet.java
+++ b/plugins/org.eclipse.xtext/src/org/eclipse/xtext/findReferences/TargetURISet.java
@@ -26,7 +26,7 @@ import com.google.common.collect.Sets;
* the old APIs.
*
* @author Sebastian Zarnekow - Initial contribution and API
- * @since 2.7
+ * @since 2.10
*/
public class TargetURISet extends AbstractSet implements TargetURIs {
diff --git a/plugins/org.eclipse.xtext/src/org/eclipse/xtext/findReferences/TargetURIs.java b/plugins/org.eclipse.xtext/src/org/eclipse/xtext/findReferences/TargetURIs.java
index 40c35373e..2e9cb5ba7 100644
--- a/plugins/org.eclipse.xtext/src/org/eclipse/xtext/findReferences/TargetURIs.java
+++ b/plugins/org.eclipse.xtext/src/org/eclipse/xtext/findReferences/TargetURIs.java
@@ -23,7 +23,7 @@ import com.google.inject.ImplementedBy;
* a given {@link Key key}.
*
* @author Sebastian Zarnekow - Initial contribution and API
- * @since 2.7
+ * @since 2.10
*/
@ImplementedBy(TargetURISet.class)
public interface TargetURIs extends Iterable {