Skip to content

Commit 5f69112

Browse files
gayanperjjohnstn
authored andcommitted
Bug 577919 - Enable callees based on implementors
Enable callees based on implementors search for JDT.UI by letting the configurability to JDT.LS. This fix also improve the callee hierarchy by adding support for showing multiple implementations and expand on those. Also this fix add support for triggering call hierarchies on method declarations on interface methods and abstract methods. Change-Id: I5eb1a309fdce1d93ff5486fce6bad046d5d091c1 Signed-off-by: Gayan Perera <[email protected]> Reviewed-on: https://git.eclipse.org/r/c/jdt/eclipse.jdt.ui/+/189117 Tested-by: JDT Bot <[email protected]> Tested-by: Jeff Johnston <[email protected]> Reviewed-by: Jeff Johnston <[email protected]>
1 parent 72d6f5b commit 5f69112

File tree

14 files changed

+329
-33
lines changed

14 files changed

+329
-33
lines changed

org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/callhierarchy/CallSearchResultCollector.java

+7-5
Original file line numberDiff line numberDiff line change
@@ -43,21 +43,23 @@ public Map<String, MethodCall> getCallers() {
4343
}
4444

4545
protected void addMember(IMember member, IMember calledMember, int start, int end) {
46-
addMember(member, calledMember, start, end, CallLocation.UNKNOWN_LINE_NUMBER);
46+
addMember(member, calledMember, start, end, CallLocation.UNKNOWN_LINE_NUMBER, false);
4747
}
4848

49-
protected void addMember(IMember member, IMember calledMember, int start, int end, int lineNumber) {
49+
protected void addMember(IMember member, IMember calledMember, int start, int end, int lineNumber, boolean potential) {
5050
if ((member != null) && (calledMember != null)) {
5151
if (!isIgnored(calledMember)) {
5252
MethodCall methodCall = fCalledMembers.get(calledMember.getHandleIdentifier());
5353

5454
if (methodCall == null) {
55-
methodCall = new MethodCall(calledMember);
55+
methodCall = new MethodCall(calledMember, potential);
5656
fCalledMembers.put(calledMember.getHandleIdentifier(), methodCall);
5757
}
5858

59-
methodCall.addCallLocation(new CallLocation(member, calledMember, start,
60-
end, lineNumber));
59+
if(start > -1 && end > -1) {
60+
methodCall.addCallLocation(new CallLocation(member, calledMember, start,
61+
end, lineNumber));
62+
}
6163
}
6264
}
6365
}

org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/callhierarchy/CalleeAnalyzerVisitor.java

+42-24
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,16 @@
1515
*******************************************************************************/
1616
package org.eclipse.jdt.internal.corext.callhierarchy;
1717

18+
import java.util.ArrayList;
1819
import java.util.Collection;
1920
import java.util.List;
2021
import java.util.Map;
22+
import java.util.Optional;
2123

2224
import org.eclipse.core.runtime.IProgressMonitor;
2325
import org.eclipse.core.runtime.OperationCanceledException;
2426

27+
import org.eclipse.jdt.core.Flags;
2528
import org.eclipse.jdt.core.IJavaElement;
2629
import org.eclipse.jdt.core.IMember;
2730
import org.eclipse.jdt.core.IMethod;
@@ -39,8 +42,10 @@
3942
import org.eclipse.jdt.core.dom.ITypeBinding;
4043
import org.eclipse.jdt.core.dom.MethodDeclaration;
4144
import org.eclipse.jdt.core.dom.MethodInvocation;
45+
import org.eclipse.jdt.core.dom.Modifier;
4246
import org.eclipse.jdt.core.dom.SuperConstructorInvocation;
4347
import org.eclipse.jdt.core.dom.SuperMethodInvocation;
48+
import org.eclipse.jdt.core.dom.TypeDeclaration;
4449
import org.eclipse.jdt.core.search.IJavaSearchScope;
4550

4651
import org.eclipse.jdt.internal.core.manipulation.JavaManipulationPlugin;
@@ -55,9 +60,11 @@ class CalleeAnalyzerVisitor extends HierarchicalASTVisitor {
5560
private final IProgressMonitor fProgressMonitor;
5661
private int fMethodEndPosition;
5762
private int fMethodStartPosition;
63+
private CallLocation fCalledAt;
5864

59-
CalleeAnalyzerVisitor(IMember member, CompilationUnit compilationUnit, IProgressMonitor progressMonitor) {
60-
fSearchResults = new CallSearchResultCollector();
65+
CalleeAnalyzerVisitor(CallLocation calledAt, IMember member, CompilationUnit compilationUnit, IProgressMonitor progressMonitor) {
66+
fSearchResults = new CallSearchResultCollector();
67+
this.fCalledAt= calledAt;
6168
this.fMember = member;
6269
this.fCompilationUnit= compilationUnit;
6370
this.fProgressMonitor = progressMonitor;
@@ -145,6 +152,10 @@ public boolean visit(AbstractTypeDeclaration node) {
145152
@Override
146153
public boolean visit(MethodDeclaration node) {
147154
progressMonitorWorked(1);
155+
if(Modifier.isAbstract(node.getModifiers()) ||
156+
((node.getParent() instanceof TypeDeclaration) && ((TypeDeclaration)node.getParent()).isInterface())) {
157+
addMethodCall(node.resolveBinding(), node);
158+
}
148159
return isFurtherTraversalNecessary(node);
149160
}
150161

@@ -253,23 +264,41 @@ protected void addMethodCall(IMethodBinding calledMethodBinding, ASTNode node) {
253264
IMethod calledMethod = findIncludingSupertypes(calledMethodBinding,
254265
calledType, fProgressMonitor);
255266

256-
IMember referencedMember= null;
267+
List<IMember> referencedMembers= new ArrayList<>();
268+
boolean implementationResults = false;
257269
if (calledMethod == null) {
258270
if (calledMethodBinding.isConstructor() && calledMethodBinding.getParameterTypes().length == 0) {
259-
referencedMember= calledType;
271+
referencedMembers.add(calledType);
260272
}
261273
} else {
262-
if (calledType.isInterface()) {
263-
calledMethod = findImplementingMethods(calledMethod);
264-
}
265-
266-
if (!isIgnoredBySearchScope(calledMethod)) {
267-
referencedMember= calledMethod;
274+
// only find implementations if we are handling a method declaration.
275+
if (node instanceof MethodDeclaration && (calledType.isInterface() || Flags.isAbstract(calledType.getFlags()))) {
276+
Collection<IJavaElement> implementingMethods= CallHierarchyCore.getDefault().getImplementingMethods(calledMethod);
277+
implementationResults = true;
278+
for (IJavaElement element : implementingMethods) {
279+
if(element instanceof IMethod) {
280+
if(!isIgnoredBySearchScope((IMethod) element)) {
281+
referencedMembers.add((IMethod) element);
282+
}
283+
} else if(element instanceof IMember) {
284+
referencedMembers.add((IMember) element);
285+
}
286+
}
287+
} else {
288+
referencedMembers.add(calledMethod);
268289
}
269290
}
270-
final int position= node.getStartPosition();
271-
final int number= fCompilationUnit.getLineNumber(position);
272-
fSearchResults.addMember(fMember, referencedMember, position, position + node.getLength(), number < 1 ? 1 : number);
291+
292+
Optional<CallLocation> calledAt= Optional.ofNullable(fCalledAt);
293+
Integer ignore = Integer.valueOf(-1);
294+
final int position= implementationResults ? calledAt.map(CallLocation::getStart).orElse(ignore).intValue() : node.getStartPosition();
295+
final int number= implementationResults ? calledAt.map(CallLocation::getLineNumber).orElse(ignore).intValue() : fCompilationUnit.getLineNumber(position);
296+
final int length = implementationResults ? calledAt.map(c -> Integer.valueOf(c.getEnd() - position)).orElse(ignore).intValue() : node.getLength();
297+
final IMember member = implementationResults ? calledAt.map(CallLocation::getMember).orElse(fMember) : fMember;
298+
final boolean potential = implementationResults;
299+
referencedMembers.forEach(m -> {
300+
fSearchResults.addMember(member, m, position, position + length, number < 1 ? 1 : number, potential);
301+
});
273302
}
274303
} catch (JavaModelException jme) {
275304
JavaManipulationPlugin.log(jme);
@@ -330,17 +359,6 @@ private boolean isFurtherTraversalNecessary(ASTNode node) {
330359
return isNodeWithinMethod(node) || isNodeEnclosingMethod(node);
331360
}
332361

333-
private IMethod findImplementingMethods(IMethod calledMethod) {
334-
Collection<IJavaElement> implementingMethods = CallHierarchyCore.getDefault()
335-
.getImplementingMethods(calledMethod);
336-
337-
if ((implementingMethods.isEmpty()) || (implementingMethods.size() > 1)) {
338-
return calledMethod;
339-
} else {
340-
return (IMethod) implementingMethods.iterator().next();
341-
}
342-
}
343-
344362
private void progressMonitorWorked(int work) {
345363
if (fProgressMonitor != null) {
346364
fProgressMonitor.worked(work);

org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/callhierarchy/CalleeMethodWrapper.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ protected Map<String, MethodCall> findChildren(IProgressMonitor progressMonitor)
9696
}
9797

9898
if (cu != null) {
99-
CalleeAnalyzerVisitor visitor = new CalleeAnalyzerVisitor(member, cu, progressMonitor);
99+
CalleeAnalyzerVisitor visitor = new CalleeAnalyzerVisitor(this.getMethodCall().getFirstCallLocation(), member, cu, progressMonitor);
100100

101101
cu.accept(visitor);
102102
return visitor.getCallees();

org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/callhierarchy/Implementors.java

+8-1
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import org.eclipse.core.runtime.IProgressMonitor;
2323
import org.eclipse.core.runtime.SubProgressMonitor;
2424

25+
import org.eclipse.jdt.core.Flags;
2526
import org.eclipse.jdt.core.IJavaElement;
2627
import org.eclipse.jdt.core.IMember;
2728
import org.eclipse.jdt.core.IMethod;
@@ -68,7 +69,7 @@ public IJavaElement[] searchForImplementors(IJavaElement[] elements,
6869
IMember member = (IMember) element;
6970
IType type = member.getDeclaringType();
7071

71-
if (type.isInterface()) {
72+
if (type.isInterface() || Flags.isAbstract(type.getFlags())) {
7273
IType[] implementingTypes = findImplementingTypes(type,
7374
progressMonitor);
7475

@@ -181,6 +182,12 @@ private IJavaElement[] findMethods(IMethod method, IType[] types,
181182

182183
try {
183184
for (IType type : types) {
185+
// we don't want the type we start the searched on be searched again. This happens when
186+
// searching for abstract method implementations on abstract classes.
187+
if(method.getDeclaringType().equals(type)) {
188+
continue;
189+
}
190+
184191
IMethod[] methods = type.findMethods(method);
185192

186193
if (methods != null) {

org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/callhierarchy/MethodCall.java

+25-1
Original file line numberDiff line numberDiff line change
@@ -23,14 +23,27 @@
2323
public class MethodCall {
2424
private IMember fMember;
2525
private List<CallLocation> fCallLocations;
26+
private boolean potential;
2627

2728
/**
2829
* @param enclosingElement
2930
*/
3031
public MethodCall(IMember enclosingElement) {
31-
this.fMember = enclosingElement;
32+
this(enclosingElement, false);
3233
}
3334

35+
/**
36+
* @param enclosingElement enclosing member of this call object
37+
* @param potential indicate whether this call object is a potential item in the hierarchy. A
38+
* item is considered as potential when there is no direct reference, like methods on
39+
* a implementation class which are referred through the interface in actual code.
40+
*/
41+
public MethodCall(IMember enclosingElement, boolean potential) {
42+
this.fMember= enclosingElement;
43+
this.potential = potential;
44+
}
45+
46+
3447
/**
3548
*
3649
*/
@@ -75,13 +88,24 @@ public void addCallLocation(CallLocation location) {
7588
fCallLocations.add(location);
7689
}
7790

91+
/**
92+
* Returns if this is a potential call object.
93+
*
94+
* @return <code>true</code> if its potential.
95+
* @see #MethodCall(IMember, boolean)
96+
*/
97+
public boolean isPotential() {
98+
return potential;
99+
}
100+
78101
@Override
79102
public String toString() {
80103
StringBuilder builder= new StringBuilder();
81104
builder.append("MethodCall ["); //$NON-NLS-1$
82105
if (fMember != null) {
83106
builder.append(fMember);
84107
}
108+
builder.append(',').append(potential);
85109
builder.append("]"); //$NON-NLS-1$
86110
return builder.toString();
87111
}

0 commit comments

Comments
 (0)