diff options
author | Vladimir Piskarev | 2019-05-20 13:45:06 +0000 |
---|---|---|
committer | Vladimir Piskarev | 2019-05-20 13:48:41 +0000 |
commit | 2a7372fc418f6aba9fb4b9951fe1e94c8ca79c05 (patch) | |
tree | 7f719605a778eb97397bc5cd10b3cd0d84e9c9e1 | |
parent | aa70c699d62da37286591df8e3c237e5047d5c2a (diff) | |
download | org.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
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); + }); + } +} |