Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVladimir Piskarev2019-05-20 13:45:06 +0000
committerVladimir Piskarev2019-05-20 13:48:41 +0000
commit2a7372fc418f6aba9fb4b9951fe1e94c8ca79c05 (patch)
tree7f719605a778eb97397bc5cd10b3cd0d84e9c9e1
parentaa70c699d62da37286591df8e3c237e5047d5c2a (diff)
downloadorg.eclipse.handly-2a7372fc418f6aba9fb4b9951fe1e94c8ca79c05.tar.gz
org.eclipse.handly-2a7372fc418f6aba9fb4b9951fe1e94c8ca79c05.tar.xz
org.eclipse.handly-2a7372fc418f6aba9fb4b9951fe1e94c8ca79c05.zip
Bug 547482 - Support for Xtext-based Call Hierarchy view
-rw-r--r--org.eclipse.handly.ui/src/org/eclipse/handly/ui/callhierarchy/CallHierarchyViewManager.java6
-rw-r--r--org.eclipse.handly.ui/src/org/eclipse/handly/ui/callhierarchy/CallLocation.java15
-rw-r--r--org.eclipse.handly.ui/src/org/eclipse/handly/ui/callhierarchy/CallTextInfo.java94
-rw-r--r--org.eclipse.handly.ui/src/org/eclipse/handly/ui/callhierarchy/ICallLocation.java23
-rw-r--r--org.eclipse.handly.xtext.ui/.settings/.api_filters23
-rw-r--r--org.eclipse.handly.xtext.ui/META-INF/MANIFEST.MF3
-rw-r--r--org.eclipse.handly.xtext.ui/src/org/eclipse/handly/xtext/ui/callhierarchy/XtextCallHierarchyNode.java173
-rw-r--r--org.eclipse.handly.xtext.ui/src/org/eclipse/handly/xtext/ui/callhierarchy/XtextCallHierarchyUtility.java297
8 files changed, 625 insertions, 9 deletions
diff --git a/org.eclipse.handly.ui/src/org/eclipse/handly/ui/callhierarchy/CallHierarchyViewManager.java b/org.eclipse.handly.ui/src/org/eclipse/handly/ui/callhierarchy/CallHierarchyViewManager.java
index 0acd0118..efad48e9 100644
--- a/org.eclipse.handly.ui/src/org/eclipse/handly/ui/callhierarchy/CallHierarchyViewManager.java
+++ b/org.eclipse.handly.ui/src/org/eclipse/handly/ui/callhierarchy/CallHierarchyViewManager.java
@@ -17,9 +17,9 @@ import java.util.Collections;
import java.util.List;
/**
- * An instance of <code>CallHierarchyViewManager</code> may be shared between
- * multiple {@link CallHierarchyViewPart} instances. It can therefore contain
- * the state that is common to those view instances.
+ * A manager for instances of {@link CallHierarchyViewPart}. An instance
+ * of the manager may be shared between multiple view instances and can
+ * therefore contain the state that is common to those view instances.
*
* @see CallHierarchyViewPart#getViewManager()
*/
diff --git a/org.eclipse.handly.ui/src/org/eclipse/handly/ui/callhierarchy/CallLocation.java b/org.eclipse.handly.ui/src/org/eclipse/handly/ui/callhierarchy/CallLocation.java
index 6645cd7c..8214ec80 100644
--- a/org.eclipse.handly.ui/src/org/eclipse/handly/ui/callhierarchy/CallLocation.java
+++ b/org.eclipse.handly.ui/src/org/eclipse/handly/ui/callhierarchy/CallLocation.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2018 1C-Soft LLC.
+ * Copyright (c) 2018, 2019 1C-Soft LLC.
*
* This program and the accompanying materials are made available under
* the terms of the Eclipse Public License 2.0 which is available at
@@ -55,6 +55,19 @@ public final class CallLocation
this.snapshot = snapshot;
}
+ /**
+ * Creates a new call location object based on a {@link CallTextInfo}.
+ *
+ * @param caller the caller element, or <code>null</code> if unknown
+ * @param callee the callee element, or <code>null</code> if unknown
+ * @param info the call text info (not <code>null</code>)
+ */
+ public CallLocation(Object caller, Object callee, CallTextInfo info)
+ {
+ this(caller, callee, info.getCallText(), info.getCallRange(),
+ info.getLineNumber(), info.getSnapshot());
+ }
+
@Override
public Object getCaller()
{
diff --git a/org.eclipse.handly.ui/src/org/eclipse/handly/ui/callhierarchy/CallTextInfo.java b/org.eclipse.handly.ui/src/org/eclipse/handly/ui/callhierarchy/CallTextInfo.java
new file mode 100644
index 00000000..d49cde21
--- /dev/null
+++ b/org.eclipse.handly.ui/src/org/eclipse/handly/ui/callhierarchy/CallTextInfo.java
@@ -0,0 +1,94 @@
+/*******************************************************************************
+ * Copyright (c) 2019 1C-Soft LLC.
+ *
+ * This program and the accompanying materials are made available under
+ * the terms of the Eclipse Public License 2.0 which is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * Vladimir Piskarev (1C) - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.handly.ui.callhierarchy;
+
+import org.eclipse.handly.snapshot.ISnapshot;
+import org.eclipse.handly.util.TextRange;
+
+/**
+ * Holds information about the text of a call, including the text range.
+ */
+public final class CallTextInfo
+{
+ private final String callText;
+ private final TextRange callRange;
+ private final int lineNumber;
+ private final ISnapshot snapshot;
+
+ /**
+ * Creates a new call text info object.
+ *
+ * @param callText the text of the call (not <code>null</code>)
+ * @param callRange the text range of the call,
+ * or <code>null</code> if unknown
+ * @param lineNumber the 0-based line number of the call,
+ * or {@link ICallLocation#UNKOWN_LINE_NUMBER} if unknown
+ * @param snapshot the base snapshot for the call text info,
+ * or <code>null</code> if unknown
+ */
+ public CallTextInfo(String callText, TextRange callRange, int lineNumber,
+ ISnapshot snapshot)
+ {
+ if (callText == null)
+ throw new IllegalArgumentException();
+ if (lineNumber < 0 && lineNumber != ICallLocation.UNKOWN_LINE_NUMBER)
+ throw new IllegalArgumentException();
+ this.callText = callText;
+ this.callRange = callRange;
+ this.lineNumber = lineNumber;
+ this.snapshot = snapshot;
+ }
+
+ /**
+ * Returns the textual representation of the call.
+ *
+ * @return the text of the call (never <code>null</code>)
+ */
+ public String getCallText()
+ {
+ return callText;
+ }
+
+ /**
+ * Returns the text range of the call.
+ *
+ * @return the text range of the call, or <code>null</code> if unknown
+ */
+ public TextRange getCallRange()
+ {
+ return callRange;
+ }
+
+ /**
+ * Returns the line number of the call. Note that the first line has
+ * the line number 0.
+ *
+ * @return the zero-based line number of the call,
+ * or {@link ICallLocation#UNKOWN_LINE_NUMBER} if unknown
+ */
+ public int getLineNumber()
+ {
+ return lineNumber;
+ }
+
+ /**
+ * Returns the snapshot on which the call text info is based.
+ *
+ * @return the base snapshot for the call text info,
+ * or <code>null</code> if unknown
+ */
+ public ISnapshot getSnapshot()
+ {
+ return snapshot;
+ }
+}
diff --git a/org.eclipse.handly.ui/src/org/eclipse/handly/ui/callhierarchy/ICallLocation.java b/org.eclipse.handly.ui/src/org/eclipse/handly/ui/callhierarchy/ICallLocation.java
index 57c45674..eb7f69cf 100644
--- a/org.eclipse.handly.ui/src/org/eclipse/handly/ui/callhierarchy/ICallLocation.java
+++ b/org.eclipse.handly.ui/src/org/eclipse/handly/ui/callhierarchy/ICallLocation.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2018 1C-Soft LLC.
+ * Copyright (c) 2018, 2019 1C-Soft LLC.
*
* This program and the accompanying materials are made available under
* the terms of the Eclipse Public License 2.0 which is available at
@@ -63,21 +63,36 @@ public interface ICallLocation
Object getCallee();
/**
- * Returns the textual representation of this call.
+ * Returns the call text info for this call location.
+ * <p>
+ * Default implementation returns a new instance of the call text info
+ * based on the information from this call location.
+ * </p>
+ *
+ * @return the call text info (never <code>null</code>)
+ */
+ default CallTextInfo getCallTextInfo()
+ {
+ return new CallTextInfo(getCallText(), getCallRange(), getLineNumber(),
+ getSnapshot());
+ }
+
+ /**
+ * Returns the textual representation of the call.
*
* @return the text of the call (never <code>null</code>)
*/
String getCallText();
/**
- * Returns the text range of this call.
+ * Returns the text range of the call.
*
* @return the text range of the call, or <code>null</code> if unknown
*/
TextRange getCallRange();
/**
- * Returns the line number of this call. Note that the first line has
+ * Returns the line number of the call. Note that the first line has
* the line number 0.
*
* @return the zero-based line number of the call,
diff --git a/org.eclipse.handly.xtext.ui/.settings/.api_filters b/org.eclipse.handly.xtext.ui/.settings/.api_filters
index dc6759ec..ae687276 100644
--- a/org.eclipse.handly.xtext.ui/.settings/.api_filters
+++ b/org.eclipse.handly.xtext.ui/.settings/.api_filters
@@ -1,5 +1,28 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<component id="org.eclipse.handly.xtext.ui" version="2">
+ <resource path="src/org/eclipse/handly/xtext/ui/callhierarchy/XtextCallHierarchyUtility.java" type="org.eclipse.handly.xtext.ui.callhierarchy.XtextCallHierarchyUtility">
+ <filter id="627060751">
+ <message_arguments>
+ <message_argument value="IReferenceFinder"/>
+ <message_argument value="XtextCallHierarchyUtility"/>
+ <message_argument value="referenceFinder"/>
+ </message_arguments>
+ </filter>
+ <filter id="627060751">
+ <message_arguments>
+ <message_argument value="IResourceAccess"/>
+ <message_argument value="XtextCallHierarchyUtility"/>
+ <message_argument value="resourceAccess"/>
+ </message_arguments>
+ </filter>
+ <filter id="643846161">
+ <message_arguments>
+ <message_argument value="IResourceAccess"/>
+ <message_argument value="XtextCallHierarchyUtility"/>
+ <message_argument value="setResourceAccess(IReferenceFinderIResourceAccess)"/>
+ </message_arguments>
+ </filter>
+ </resource>
<resource path="src/org/eclipse/handly/xtext/ui/editor/HandlyXtextDocument.java" type="org.eclipse.handly.xtext.ui.editor.HandlyXtextDocument">
<filter id="576725006">
<message_arguments>
diff --git a/org.eclipse.handly.xtext.ui/META-INF/MANIFEST.MF b/org.eclipse.handly.xtext.ui/META-INF/MANIFEST.MF
index e1acd0f3..44198870 100644
--- a/org.eclipse.handly.xtext.ui/META-INF/MANIFEST.MF
+++ b/org.eclipse.handly.xtext.ui/META-INF/MANIFEST.MF
@@ -16,6 +16,7 @@ Require-Bundle: org.eclipse.core.runtime;bundle-version="[3.13.0,4.0.0)",
org.eclipse.xtext.common.types;bundle-version="[2.12.0,2.18.0)";resolution:=optional,
org.eclipse.ui.ide;bundle-version="[3.13.0,4.0.0)"
Import-Package: org.apache.log4j;version="[1.2.15,2.0.0)"
-Export-Package: org.eclipse.handly.xtext.ui.editor,
+Export-Package: org.eclipse.handly.xtext.ui.callhierarchy,
+ org.eclipse.handly.xtext.ui.editor,
org.eclipse.handly.xtext.ui.outline,
org.eclipse.handly.xtext.ui.quickoutline
diff --git a/org.eclipse.handly.xtext.ui/src/org/eclipse/handly/xtext/ui/callhierarchy/XtextCallHierarchyNode.java b/org.eclipse.handly.xtext.ui/src/org/eclipse/handly/xtext/ui/callhierarchy/XtextCallHierarchyNode.java
new file mode 100644
index 00000000..d9ab4cd3
--- /dev/null
+++ b/org.eclipse.handly.xtext.ui/src/org/eclipse/handly/xtext/ui/callhierarchy/XtextCallHierarchyNode.java
@@ -0,0 +1,173 @@
+/*******************************************************************************
+ * Copyright (c) 2019 1C-Soft LLC.
+ *
+ * This program and the accompanying materials are made available under
+ * the terms of the Eclipse Public License 2.0 which is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * Vladimir Piskarev (1C) - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.handly.xtext.ui.callhierarchy;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.function.Consumer;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.handly.ui.callhierarchy.CallHierarchyNode;
+import org.eclipse.handly.ui.callhierarchy.CallLocation;
+import org.eclipse.handly.ui.callhierarchy.ICallHierarchyNode;
+import org.eclipse.handly.ui.callhierarchy.ICallLocation;
+import org.eclipse.xtext.resource.IReferenceDescription;
+
+/**
+ * A partial implementation for {@link ICallHierarchyNode} based on Xtext.
+ */
+public abstract class XtextCallHierarchyNode
+ extends CallHierarchyNode
+{
+ private static final XtextCallHierarchyNode[] EMPTY_ARRAY =
+ new XtextCallHierarchyNode[0];
+
+ /**
+ * Creates a new Xtext call hierarchy node.
+ *
+ * @param parent the parent node, or <code>null</code> if this is a root node
+ * @param element the underlying model element (not <code>null</code>)
+ */
+ protected XtextCallHierarchyNode(XtextCallHierarchyNode parent,
+ Object element)
+ {
+ super(parent, element);
+ }
+
+ /**
+ * {@inheritDoc}
+ * <p>
+ * This implementation computes the child nodes based on the call references
+ * reported by {@link #findCallReferences(Consumer, IProgressMonitor)
+ * findCallReferences}. To obtain a child node, it calls {@link
+ * #createChildIfAbsent(Map, IReferenceDescription)}. To create a call location,
+ * it invokes {@link #createCallLocation(Object, Object, IReferenceDescription)}.
+ * </p>
+ */
+ @Override
+ protected ICallHierarchyNode[] computeChildren(IProgressMonitor monitor)
+ {
+ Map<URI, XtextCallHierarchyNode> children = new LinkedHashMap<>();
+ findCallReferences(callReference ->
+ {
+ XtextCallHierarchyNode child = createChildIfAbsent(children,
+ callReference);
+ if (child != null)
+ {
+ Object caller, callee;
+ switch (getKind())
+ {
+ case CALLER:
+ caller = child.getElement();
+ callee = getElement();
+ break;
+ case CALLEE:
+ caller = getElement();
+ callee = child.getElement();
+ break;
+ default:
+ throw new AssertionError();
+ }
+ child.addCallLocation(createCallLocation(caller, callee,
+ callReference));
+ }
+ }, monitor);
+ return children.values().toArray(EMPTY_ARRAY);
+ }
+
+ /**
+ * Finds the call references for this node.
+ * <p>
+ * This implementation uses the {@link #getCallHierarchyUtility()
+ * call hierarchy utility} to find the call references. Depending on
+ * the {@link #getKind() kind} of this node, it will find either {@link
+ * XtextCallHierarchyUtility#findCallerReferences(URI, Consumer, IProgressMonitor)
+ * caller references} or {@link XtextCallHierarchyUtility#findCalleeReferences(
+ * URI, Consumer, IProgressMonitor) callee references}.
+ * </p>
+ *
+ * @param acceptor accepts the matches (never <code>null</code>)
+ * @param monitor a progress monitor, or <code>null</code>
+ * if progress reporting is not desired. The caller must not rely on
+ * {@link IProgressMonitor#done()} having been called by the receiver
+ */
+ protected void findCallReferences(Consumer<IReferenceDescription> acceptor,
+ IProgressMonitor monitor)
+ {
+ switch (getKind())
+ {
+ case CALLER:
+ getCallHierarchyUtility().findCallerReferences(getUri(), acceptor,
+ monitor);
+ break;
+ case CALLEE:
+ getCallHierarchyUtility().findCalleeReferences(getUri(), acceptor,
+ monitor);
+ break;
+ default:
+ throw new AssertionError();
+ }
+ }
+
+ /**
+ * Creates and returns a call location based on the given call reference.
+ * <p>
+ * This implementation returns a new instance of {@link CallLocation}.
+ * It uses the {@link #getCallHierarchyUtility() call hierarchy utility}
+ * to obtain the {@link XtextCallHierarchyUtility#getCallTextInfo(IReferenceDescription)
+ * call text info}.
+ * </p>
+ *
+ * @param caller the caller element, or <code>null</code> if unknown
+ * @param callee the callee element, or <code>null</code> if unknown
+ * @param callReference never <code>null</code>
+ * @return the created call location (not <code>null</code>)
+ */
+ protected ICallLocation createCallLocation(Object caller, Object callee,
+ IReferenceDescription callReference)
+ {
+ return new CallLocation(caller, callee,
+ getCallHierarchyUtility().getCallTextInfo(callReference));
+ }
+
+ /**
+ * Returns the corresponding URI for this node.
+ *
+ * @return the corresponding URI (not <code>null</code>)
+ */
+ protected abstract URI getUri();
+
+ /**
+ * Returns a child node for the given call reference, creating it
+ * if necessary. If the given map does not already contain a mapping for
+ * the requested node, this method will attempt to create it and enter it
+ * into the map. Note that this method must not add call locations to
+ * the child node; they are added separately.
+ *
+ * @param children never <code>null</code>
+ * @param callReference never <code>null</code>
+ * @return the corresponding (existing or created) child node, or <code>null</code>
+ * if no child node can be created for the given call reference
+ */
+ protected abstract XtextCallHierarchyNode createChildIfAbsent(
+ Map<URI, XtextCallHierarchyNode> children,
+ IReferenceDescription callReference);
+
+ /**
+ * Returns the call hierarchy utility used by this node.
+ *
+ * @return the call hierarchy utility (not <code>null</code>)
+ */
+ protected abstract XtextCallHierarchyUtility getCallHierarchyUtility();
+}
diff --git a/org.eclipse.handly.xtext.ui/src/org/eclipse/handly/xtext/ui/callhierarchy/XtextCallHierarchyUtility.java b/org.eclipse.handly.xtext.ui/src/org/eclipse/handly/xtext/ui/callhierarchy/XtextCallHierarchyUtility.java
new file mode 100644
index 00000000..fac68b5a
--- /dev/null
+++ b/org.eclipse.handly.xtext.ui/src/org/eclipse/handly/xtext/ui/callhierarchy/XtextCallHierarchyUtility.java
@@ -0,0 +1,297 @@
+/*******************************************************************************
+ * Copyright (c) 2019 1C-Soft LLC.
+ *
+ * This program and the accompanying materials are made available under
+ * the terms of the Eclipse Public License 2.0 which is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * Vladimir Piskarev (1C) - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.handly.xtext.ui.callhierarchy;
+
+import java.util.function.Consumer;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.EReference;
+import org.eclipse.handly.snapshot.ISnapshot;
+import org.eclipse.handly.snapshot.Snapshot;
+import org.eclipse.handly.ui.callhierarchy.CallTextInfo;
+import org.eclipse.handly.ui.callhierarchy.ICallLocation;
+import org.eclipse.handly.util.TextRange;
+import org.eclipse.xtext.findReferences.IReferenceFinder;
+import org.eclipse.xtext.findReferences.IReferenceFinder.IResourceAccess;
+import org.eclipse.xtext.findReferences.ReferenceAcceptor;
+import org.eclipse.xtext.findReferences.TargetURIs;
+import org.eclipse.xtext.nodemodel.INode;
+import org.eclipse.xtext.nodemodel.util.NodeModelUtils;
+import org.eclipse.xtext.resource.ILocationInFileProvider;
+import org.eclipse.xtext.resource.IReferenceDescription;
+import org.eclipse.xtext.resource.IResourceDescriptions;
+import org.eclipse.xtext.resource.IResourceServiceProvider;
+import org.eclipse.xtext.util.ITextRegion;
+import org.eclipse.xtext.util.concurrent.IUnitOfWork;
+
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+
+/**
+ * Serves as a basis for the implementation of {@link XtextCallHierarchyNode}
+ * by providing API and default implementation to find the call references
+ * and obtain the call text info.
+ * <p>
+ * Usually, clients need to override methods {@link #isCallReference(IReferenceDescription)}
+ * and/or {@link #getCallRegion(EObject, EReference, int)} in a language-specific
+ * subclass.
+ * </p>
+ * <p>
+ * An instance of this class is intended to be created by Guice. Also, clients
+ * need to set a {@link #setResourceAccess(IReferenceFinder.IResourceAccess)
+ * resource access} and an {@link #setIndexData(IResourceDescriptions)
+ * index data} before using an instance of this class.
+ * </p>
+ */
+@SuppressWarnings("restriction")
+public class XtextCallHierarchyUtility
+{
+ protected IResourceAccess resourceAccess;
+ protected IResourceDescriptions indexData;
+
+ @Inject
+ protected IReferenceFinder referenceFinder;
+
+ @Inject
+ protected Provider<TargetURIs> targetUrisProvider;
+
+ @Inject
+ protected IResourceServiceProvider.Registry resourceServiceProviderRegistry;
+
+ @Inject
+ protected ILocationInFileProvider locationInFileProvider;
+
+ /**
+ * Prevents direct instantiation. An instance of this class is intended
+ * to be created by Guice.
+ */
+ protected XtextCallHierarchyUtility()
+ {
+ }
+
+ /**
+ * Sets the resource access.
+ *
+ * @param resourceAccess not <code>null</code>
+ */
+ public void setResourceAccess(IResourceAccess resourceAccess)
+ {
+ this.resourceAccess = resourceAccess;
+ }
+
+ /**
+ * Sets the index data.
+ *
+ * @param indexData not <code>null</code>
+ */
+ public void setIndexData(IResourceDescriptions indexData)
+ {
+ this.indexData = indexData;
+ }
+
+ /**
+ * Finds the caller references to the callee identified by the given URI.
+ * <p>
+ * This implementation calls {@link #isCallReference(IReferenceDescription)}
+ * to filter the references reported by the {@link #referenceFinder}
+ * before they are passed to the given acceptor.
+ * </p>
+ *
+ * @param calleeUri not <code>null</code>
+ * @param acceptor accepts the matches (not <code>null</code>)
+ * @param monitor a progress monitor, or <code>null</code>
+ * if progress reporting is not desired. The caller must not rely on
+ * {@link IProgressMonitor#done()} having been called by the receiver
+ */
+ public void findCallerReferences(URI calleeUri,
+ Consumer<IReferenceDescription> acceptor, IProgressMonitor monitor)
+ {
+ if (calleeUri == null)
+ throw new IllegalArgumentException();
+ if (acceptor == null)
+ throw new IllegalArgumentException();
+
+ TargetURIs targetUris = targetUrisProvider.get();
+ targetUris.addURI(calleeUri);
+ referenceFinder.findAllReferences(targetUris, resourceAccess, indexData,
+ getReferenceAcceptor(acceptor), monitor);
+ }
+
+ /**
+ * Finds the callee references from the caller identified by the given URI.
+ * <p>
+ * This implementation calls {@link #isCallReference(IReferenceDescription)}
+ * to filter the references reported by the {@link #referenceFinder}
+ * before they are passed to the given acceptor.
+ * </p>
+ *
+ * @param callerUri not <code>null</code>
+ * @param acceptor accepts the matches (not <code>null</code>)
+ * @param monitor a progress monitor, or <code>null</code>
+ * if progress reporting is not desired. The caller must not rely on
+ * {@link IProgressMonitor#done()} having been called by the receiver
+ */
+ public void findCalleeReferences(URI callerUri,
+ Consumer<IReferenceDescription> acceptor, IProgressMonitor monitor)
+ {
+ if (callerUri == null)
+ throw new IllegalArgumentException();
+ if (acceptor == null)
+ throw new IllegalArgumentException();
+ readOnly(callerUri, caller ->
+ {
+ referenceFinder.findAllReferences(caller, getReferenceAcceptor(
+ acceptor), monitor);
+ return null;
+ });
+ }
+
+ /**
+ * Returns the call text info based on the given call reference.
+ * <p>
+ * This implementation invokes {@link #getCallRegion(EObject, EReference, int)}
+ * to obtain the call text region.
+ * </p>
+ *
+ * @param callReference not <code>null</code>
+ * @return the call text info (never <code>null</code>)
+ */
+ public CallTextInfo getCallTextInfo(IReferenceDescription callReference)
+ {
+ if (callReference == null)
+ throw new IllegalArgumentException();
+ CallTextInfo info = readOnly(callReference.getSourceEObjectUri(),
+ sourceObject ->
+ {
+ String callText = ""; //$NON-NLS-1$
+ TextRange callRange = null;
+ int lineNumber = ICallLocation.UNKOWN_LINE_NUMBER;
+ ISnapshot snapshot = null;
+
+ ITextRegion callRegion = getCallRegion(sourceObject,
+ callReference.getEReference(),
+ callReference.getIndexInList());
+ if (callRegion != null
+ && callRegion != ITextRegion.EMPTY_REGION)
+ {
+ callRange = new TextRange(callRegion.getOffset(),
+ callRegion.getLength());
+
+ INode node = NodeModelUtils.getNode(sourceObject);
+ if (node != null)
+ {
+ String text = node.getRootNode().getText();
+
+ callText = text.substring(callRange.getOffset(),
+ callRange.getEndOffset());
+
+ lineNumber = NodeModelUtils.getLineAndColumn(node,
+ callRange.getOffset()).getLine() - 1;
+
+ snapshot = new Snapshot()
+ {
+ @Override
+ public String getContents()
+ {
+ return text;
+ }
+ };
+ }
+ }
+
+ return new CallTextInfo(callText, callRange, lineNumber,
+ snapshot);
+ });
+ if (info == null)
+ info = new CallTextInfo("", null, //$NON-NLS-1$
+ ICallLocation.UNKOWN_LINE_NUMBER, null);
+ return info;
+ }
+
+ /**
+ * Returns whether the given reference is a call reference.
+ * <p>
+ * Default implementation returns <code>true</code> iff the given reference
+ * is not <code>null</code>. Clients usually need to override this method
+ * for a specific language.
+ * </p>
+ *
+ * @param reference may be <code>null</code>,
+ * in which case <code>false</code> is returned
+ * @return <code>true</code> if the given reference is a call reference,
+ * and <code>false</code> otherwise
+ */
+ protected boolean isCallReference(IReferenceDescription reference)
+ {
+ return reference != null;
+ }
+
+ /**
+ * Returns the text region for the given call reference.
+ * <p>
+ * Default implementation returns the <i>significant region</i> as reported
+ * by the {@link #locationInFileProvider}. Clients may need to override
+ * this method for a specific language.
+ * </p>
+ *
+ * @param owner the owner of the reference (never <code>null</code>)
+ * @param callReference never <code>null</code>
+ * @param indexInList the index of the reference,
+ * or -1 if it is a single value reference
+ * @return the call region (not <code>null</code>)
+ */
+ protected ITextRegion getCallRegion(EObject owner, EReference callReference,
+ int indexInList)
+ {
+ return locationInFileProvider.getSignificantTextRegion(owner,
+ callReference, indexInList);
+ }
+
+ /**
+ * Executes the given unit of work while providing it with safe read access
+ * to the {@link EObject} identified by the given URI. Note that this method
+ * may return <code>null</code> if it was not able to start executing the
+ * unit of work for some reason.
+ * <p>
+ * This implementation uses the {@link #resourceAccess} to provide
+ * safe read access to the object.
+ * </p>
+ *
+ * @param objectUri never <code>null</code>
+ * @param work never <code>null</code>
+ * @return the execution result (may be <code>null</code>)
+ */
+ protected <R> R readOnly(URI objectUri, IUnitOfWork<R, EObject> work)
+ {
+ return resourceAccess.readOnly(objectUri, resourceSet ->
+ {
+ EObject object = resourceSet.getEObject(objectUri, true);
+ if (object == null)
+ return null;
+ return work.exec(object);
+ });
+ }
+
+ private ReferenceAcceptor getReferenceAcceptor(
+ Consumer<IReferenceDescription> acceptor)
+ {
+ return new ReferenceAcceptor(resourceServiceProviderRegistry,
+ reference ->
+ {
+ if (isCallReference(reference))
+ acceptor.accept(reference);
+ });
+ }
+}

Back to the top