KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > jdt > internal > core > search > matching > MethodLocator


1 /*******************************************************************************
2  * Copyright (c) 2000, 2007 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.jdt.internal.core.search.matching;
12
13 import java.util.HashMap JavaDoc;
14
15 import org.eclipse.core.resources.IResource;
16 import org.eclipse.core.runtime.*;
17 import org.eclipse.jdt.core.*;
18 import org.eclipse.jdt.core.compiler.CharOperation;
19 import org.eclipse.jdt.core.search.*;
20 import org.eclipse.jdt.internal.compiler.ast.*;
21 import org.eclipse.jdt.internal.compiler.env.IBinaryType;
22 import org.eclipse.jdt.internal.compiler.lookup.*;
23 import org.eclipse.jdt.internal.compiler.util.SimpleSet;
24 import org.eclipse.jdt.internal.core.JavaElement;
25 import org.eclipse.jdt.internal.core.search.BasicSearchEngine;
26
27 public class MethodLocator extends PatternLocator {
28
29 protected MethodPattern pattern;
30 protected boolean isDeclarationOfReferencedMethodsPattern;
31
32 //extra reference info
33
public char[][][] allSuperDeclaringTypeNames;
34
35 //method declarations which parameters verification fail
36
private HashMap JavaDoc methodDeclarationsWithInvalidParam = new HashMap JavaDoc();
37
38 public MethodLocator(MethodPattern pattern) {
39     super(pattern);
40
41     this.pattern = pattern;
42     this.isDeclarationOfReferencedMethodsPattern = this.pattern instanceof DeclarationOfReferencedMethodsPattern;
43 }
44 /*
45  * Clear caches
46  */

47 protected void clear() {
48     this.methodDeclarationsWithInvalidParam = new HashMap JavaDoc();
49 }
50 public void initializePolymorphicSearch(MatchLocator locator) {
51     long start = 0;
52     if (BasicSearchEngine.VERBOSE) {
53         start = System.currentTimeMillis();
54     }
55     try {
56         this.allSuperDeclaringTypeNames =
57             new SuperTypeNamesCollector(
58                 this.pattern,
59                 this.pattern.declaringSimpleName,
60                 this.pattern.declaringQualification,
61                 locator,
62                 this.pattern.declaringType,
63                 locator.progressMonitor).collect();
64     } catch (JavaModelException e) {
65         // inaccurate matches will be found
66
}
67     if (BasicSearchEngine.VERBOSE) {
68         System.out.println("Time to initialize polymorphic search: "+(System.currentTimeMillis()-start)); //$NON-NLS-1$
69
}
70 }
71 /*
72  * Return whether a type name is in pattern all super declaring types names.
73  */

74 private boolean isTypeInSuperDeclaringTypeNames(char[][] typeName) {
75     if (allSuperDeclaringTypeNames == null) return false;
76     int length = allSuperDeclaringTypeNames.length;
77     for (int i= 0; i<length; i++) {
78         if (CharOperation.equals(allSuperDeclaringTypeNames[i], typeName)) {
79             return true;
80         }
81     }
82     return false;
83 }
84 /**
85  * Returns whether the code gen will use an invoke virtual for
86  * this message send or not.
87  */

88 protected boolean isVirtualInvoke(MethodBinding method, MessageSend messageSend) {
89     return !method.isStatic() && !method.isPrivate() && !messageSend.isSuperAccess();
90 }
91 public int match(ASTNode node, MatchingNodeSet nodeSet) {
92     int declarationsLevel = IMPOSSIBLE_MATCH;
93     if (this.pattern.findReferences) {
94         if (node instanceof ImportReference) {
95             // With static import, we can have static method reference in import reference
96
ImportReference importRef = (ImportReference) node;
97             int length = importRef.tokens.length-1;
98             if (importRef.isStatic() && ((importRef.bits & ASTNode.OnDemand) == 0) && matchesName(this.pattern.selector, importRef.tokens[length])) {
99                 char[][] compoundName = new char[length][];
100                 System.arraycopy(importRef.tokens, 0, compoundName, 0, length);
101                 char[] declaringType = CharOperation.concat(pattern.declaringQualification, pattern.declaringSimpleName, '.');
102                 if (matchesName(declaringType, CharOperation.concatWith(compoundName, '.'))) {
103                     declarationsLevel = ((InternalSearchPattern)this.pattern).mustResolve ? POSSIBLE_MATCH : ACCURATE_MATCH;
104                 }
105             }
106         }
107     }
108     return nodeSet.addMatch(node, declarationsLevel);
109 }
110 //public int match(ConstructorDeclaration node, MatchingNodeSet nodeSet) - SKIP IT
111
//public int match(Expression node, MatchingNodeSet nodeSet) - SKIP IT
112
//public int match(FieldDeclaration node, MatchingNodeSet nodeSet) - SKIP IT
113
public int match(MethodDeclaration node, MatchingNodeSet nodeSet) {
114     if (!this.pattern.findDeclarations) return IMPOSSIBLE_MATCH;
115
116     // Verify method name
117
if (!matchesName(this.pattern.selector, node.selector)) return IMPOSSIBLE_MATCH;
118     
119     // Verify parameters types
120
boolean resolve = ((InternalSearchPattern)this.pattern).mustResolve;
121     if (this.pattern.parameterSimpleNames != null) {
122         int length = this.pattern.parameterSimpleNames.length;
123         ASTNode[] args = node.arguments;
124         int argsLength = args == null ? 0 : args.length;
125         if (length != argsLength) return IMPOSSIBLE_MATCH;
126         for (int i = 0; i < argsLength; i++) {
127             if (args != null && !matchesTypeReference(this.pattern.parameterSimpleNames[i], ((Argument) args[i]).type)) {
128                 // Do not return as impossible when source level is at least 1.5
129
if (this.mayBeGeneric) {
130                     if (!((InternalSearchPattern)this.pattern).mustResolve) {
131                         // Set resolution flag on node set in case of types was inferred in parameterized types from generic ones...
132
// (see bugs https://bugs.eclipse.org/bugs/show_bug.cgi?id=79990, 96761, 96763)
133
nodeSet.mustResolve = true;
134                         resolve = true;
135                     }
136                     this.methodDeclarationsWithInvalidParam.put(node, null);
137                 } else {
138                     return IMPOSSIBLE_MATCH;
139                 }
140             }
141         }
142     }
143
144     // Verify type arguments (do not reject if pattern has no argument as it can be an erasure match)
145
if (this.pattern.hasMethodArguments()) {
146         if (node.typeParameters == null || node.typeParameters.length != this.pattern.methodArguments.length) return IMPOSSIBLE_MATCH;
147     }
148
149     // Method declaration may match pattern
150
return nodeSet.addMatch(node, resolve ? POSSIBLE_MATCH : ACCURATE_MATCH);
151 }
152 public int match(MemberValuePair node, MatchingNodeSet nodeSet) {
153     if (!this.pattern.findReferences) return IMPOSSIBLE_MATCH;
154
155     if (!matchesName(this.pattern.selector, node.name)) return IMPOSSIBLE_MATCH;
156
157     return nodeSet.addMatch(node, ((InternalSearchPattern)this.pattern).mustResolve ? POSSIBLE_MATCH : ACCURATE_MATCH);
158 }
159 public int match(MessageSend node, MatchingNodeSet nodeSet) {
160     if (!this.pattern.findReferences) return IMPOSSIBLE_MATCH;
161
162     if (!matchesName(this.pattern.selector, node.selector)) return IMPOSSIBLE_MATCH;
163     if (this.pattern.parameterSimpleNames != null && (!this.pattern.varargs || ((node.bits & ASTNode.InsideJavadoc) != 0))) {
164         int length = this.pattern.parameterSimpleNames.length;
165         ASTNode[] args = node.arguments;
166         int argsLength = args == null ? 0 : args.length;
167         if (length != argsLength) return IMPOSSIBLE_MATCH;
168     }
169
170     return nodeSet.addMatch(node, ((InternalSearchPattern)this.pattern).mustResolve ? POSSIBLE_MATCH : ACCURATE_MATCH);
171 }
172 //public int match(Reference node, MatchingNodeSet nodeSet) - SKIP IT
173
public int match(Annotation node, MatchingNodeSet nodeSet) {
174     if (!this.pattern.findReferences) return IMPOSSIBLE_MATCH;
175     MemberValuePair[] pairs = node.memberValuePairs();
176     if (pairs == null || pairs.length == 0) return IMPOSSIBLE_MATCH;
177
178     int length = pairs.length;
179     MemberValuePair pair = null;
180     for (int i=0; i<length; i++) {
181         pair = node.memberValuePairs()[i];
182         if (matchesName(this.pattern.selector, pair.name)) {
183             ASTNode possibleNode = (node instanceof SingleMemberAnnotation) ? (ASTNode) node : pair;
184             return nodeSet.addMatch(possibleNode, ((InternalSearchPattern)this.pattern).mustResolve ? POSSIBLE_MATCH : ACCURATE_MATCH);
185         }
186     }
187     return IMPOSSIBLE_MATCH;
188 }
189 //public int match(TypeDeclaration node, MatchingNodeSet nodeSet) - SKIP IT
190
//public int match(TypeReference node, MatchingNodeSet nodeSet) - SKIP IT
191

192 protected int matchContainer() {
193     if (this.pattern.findReferences) {
194         // need to look almost everywhere to find in javadocs and static import
195
return ALL_CONTAINER;
196     }
197     return CLASS_CONTAINER;
198 }
199 /* (non-Javadoc)
200  * @see org.eclipse.jdt.internal.core.search.matching.PatternLocator#matchLevelAndReportImportRef(org.eclipse.jdt.internal.compiler.ast.ImportReference, org.eclipse.jdt.internal.compiler.lookup.Binding, org.eclipse.jdt.internal.core.search.matching.MatchLocator)
201  * Accept to report match of static field on static import
202  */

203 protected void matchLevelAndReportImportRef(ImportReference importRef, Binding binding, MatchLocator locator) throws CoreException {
204     if (importRef.isStatic() && binding instanceof MethodBinding) {
205         super.matchLevelAndReportImportRef(importRef, binding, locator);
206     }
207 }
208 protected int matchMethod(MethodBinding method, boolean skipImpossibleArg) {
209     if (!matchesName(this.pattern.selector, method.selector)) return IMPOSSIBLE_MATCH;
210
211     int level = ACCURATE_MATCH;
212     // look at return type only if declaring type is not specified
213
if (this.pattern.declaringSimpleName == null) {
214         // TODO (frederic) use this call to refine accuracy on return type
215
// int newLevel = resolveLevelForType(this.pattern.returnSimpleName, this.pattern.returnQualification, this.pattern.returnTypeArguments, 0, method.returnType);
216
int newLevel = resolveLevelForType(this.pattern.returnSimpleName, this.pattern.returnQualification, method.returnType);
217         if (level > newLevel) {
218             if (newLevel == IMPOSSIBLE_MATCH) return IMPOSSIBLE_MATCH;
219             level = newLevel; // can only be downgraded
220
}
221     }
222
223     // parameter types
224
int parameterCount = this.pattern.parameterSimpleNames == null ? -1 : this.pattern.parameterSimpleNames.length;
225     if (parameterCount > -1) {
226         // global verification
227
if (method.parameters == null) return INACCURATE_MATCH;
228         if (parameterCount != method.parameters.length) return IMPOSSIBLE_MATCH;
229         if (!method.isValidBinding() && ((ProblemMethodBinding)method).problemId() == ProblemReasons.Ambiguous) {
230             // return inaccurate match for ambiguous call (bug 80890)
231
return INACCURATE_MATCH;
232         }
233
234         // verify each parameter
235
for (int i = 0; i < parameterCount; i++) {
236             TypeBinding argType = method.parameters[i];
237             int newLevel = IMPOSSIBLE_MATCH;
238             if (argType.isMemberType()) {
239                 // only compare source name for member type (bug 41018)
240
newLevel = CharOperation.match(this.pattern.parameterSimpleNames[i], argType.sourceName(), this.isCaseSensitive)
241                     ? ACCURATE_MATCH
242                     : IMPOSSIBLE_MATCH;
243             } else {
244                 // TODO (frederic) use this call to refine accuracy on parameter types
245
// newLevel = resolveLevelForType(this.pattern.parameterSimpleNames[i], this.pattern.parameterQualifications[i], this.pattern.parametersTypeArguments[i], 0, argType);
246
newLevel = resolveLevelForType(this.pattern.parameterSimpleNames[i], this.pattern.parameterQualifications[i], argType);
247             }
248             if (level > newLevel) {
249                 if (newLevel == IMPOSSIBLE_MATCH) {
250                     if (skipImpossibleArg) {
251                         // Do not consider match as impossible while finding declarations and source level >= 1.5
252
// (see bugs https://bugs.eclipse.org/bugs/show_bug.cgi?id=79990, 96761, 96763)
253
newLevel = level;
254                     } else {
255                         return IMPOSSIBLE_MATCH;
256                     }
257                 }
258                 level = newLevel; // can only be downgraded
259
}
260         }
261     }
262
263     return level;
264 }
265 private boolean matchOverriddenMethod(ReferenceBinding type, MethodBinding method, MethodBinding matchMethod) {
266     if (type == null || this.pattern.selector == null) return false;
267
268     // matches superclass
269
if (!type.isInterface() && !CharOperation.equals(type.compoundName, TypeConstants.JAVA_LANG_OBJECT)) {
270         ReferenceBinding superClass = type.superclass();
271         if (superClass.isParameterizedType()) {
272             MethodBinding[] methods = superClass.getMethods(this.pattern.selector);
273             int length = methods.length;
274             for (int i = 0; i<length; i++) {
275                 if (methods[i].areParametersEqual(method)) {
276                     if (matchMethod == null) {
277                         if (methodParametersEqualsPattern(methods[i].original())) return true;
278                     } else {
279                         if (methods[i].original().areParametersEqual(matchMethod)) return true;
280                     }
281                 }
282             }
283         }
284         if (matchOverriddenMethod(superClass, method, matchMethod)) {
285             return true;
286         }
287     }
288
289     // matches interfaces
290
ReferenceBinding[] interfaces = type.superInterfaces();
291     if (interfaces == null) return false;
292     int iLength = interfaces.length;
293     for (int i = 0; i<iLength; i++) {
294         if (interfaces[i].isParameterizedType()) {
295             MethodBinding[] methods = interfaces[i].getMethods(this.pattern.selector);
296             int length = methods.length;
297             for (int j = 0; j<length; j++) {
298                 if (methods[j].areParametersEqual(method)) {
299                     if (matchMethod == null) {
300                         if (methodParametersEqualsPattern(methods[j].original())) return true;
301                     } else {
302                         if (methods[j].original().areParametersEqual(matchMethod)) return true;
303                     }
304                 }
305             }
306         }
307         if (matchOverriddenMethod(interfaces[i], method, matchMethod)) {
308             return true;
309         }
310     }
311     return false;
312 }
313 /**
314  * @see org.eclipse.jdt.internal.core.search.matching.PatternLocator#matchReportReference(org.eclipse.jdt.internal.compiler.ast.ASTNode, org.eclipse.jdt.core.IJavaElement, Binding, int, org.eclipse.jdt.internal.core.search.matching.MatchLocator)
315  */

316 protected void matchReportReference(ASTNode reference, IJavaElement element, Binding elementBinding, int accuracy, MatchLocator locator) throws CoreException {
317     MethodBinding methodBinding = (reference instanceof MessageSend) ? ((MessageSend)reference).binding: ((elementBinding instanceof MethodBinding) ? (MethodBinding) elementBinding : null);
318     if (this.isDeclarationOfReferencedMethodsPattern) {
319         if (methodBinding == null) return;
320         // need exact match to be able to open on type ref
321
if (accuracy != SearchMatch.A_ACCURATE) return;
322
323         // element that references the method must be included in the enclosing element
324
DeclarationOfReferencedMethodsPattern declPattern = (DeclarationOfReferencedMethodsPattern) this.pattern;
325         while (element != null && !declPattern.enclosingElement.equals(element))
326             element = element.getParent();
327         if (element != null) {
328             reportDeclaration(methodBinding, locator, declPattern.knownMethods);
329         }
330     } else {
331         match = locator.newMethodReferenceMatch(element, elementBinding, accuracy, -1, -1, false /*not constructor*/, false/*not synthetic*/, reference);
332         if (this.pattern.findReferences && reference instanceof MessageSend) {
333             IJavaElement focus = ((InternalSearchPattern) this.pattern).focus;
334             // verify closest match if pattern was bound
335
// (see bug 70827)
336
if (focus != null && focus.getElementType() == IJavaElement.METHOD) {
337                 if (methodBinding != null && methodBinding.declaringClass != null) {
338                     boolean isPrivate = Flags.isPrivate(((IMethod) focus).getFlags());
339                     if (isPrivate && !CharOperation.equals(methodBinding.declaringClass.sourceName, focus.getParent().getElementName().toCharArray())) {
340                         return; // finally the match was not possible
341
}
342                 }
343             }
344             matchReportReference((MessageSend)reference, locator, ((MessageSend)reference).binding);
345         } else {
346             if (reference instanceof SingleMemberAnnotation) {
347                 reference = ((SingleMemberAnnotation)reference).memberValuePairs()[0];
348                 match.setImplicit(true);
349             }
350             int offset = reference.sourceStart;
351             int length = reference.sourceEnd - offset + 1;
352             match.setOffset(offset);
353             match.setLength(length);
354             locator.report(match);
355         }
356     }
357 }
358 void matchReportReference(MessageSend messageSend, MatchLocator locator, MethodBinding methodBinding) throws CoreException {
359
360     // Look if there's a need to special report for parameterized type
361
boolean isParameterized = false;
362     if (methodBinding instanceof ParameterizedGenericMethodBinding) { // parameterized generic method
363
isParameterized = true;
364
365         // Update match regarding method type arguments
366
ParameterizedGenericMethodBinding parameterizedMethodBinding = (ParameterizedGenericMethodBinding) methodBinding;
367         match.setRaw(parameterizedMethodBinding.isRaw);
368         TypeBinding[] typeArguments = /*parameterizedMethodBinding.isRaw ? null :*/ parameterizedMethodBinding.typeArguments;
369         updateMatch(typeArguments, locator, this.pattern.methodArguments, this.pattern.hasMethodParameters());
370
371         // Update match regarding declaring class type arguments
372
if (methodBinding.declaringClass.isParameterizedType() || methodBinding.declaringClass.isRawType()) {
373             ParameterizedTypeBinding parameterizedBinding = (ParameterizedTypeBinding)methodBinding.declaringClass;
374             if (!this.pattern.hasTypeArguments() && this.pattern.hasMethodArguments() || parameterizedBinding.isParameterizedWithOwnVariables()) {
375                 // special case for pattern which defines method arguments but not its declaring type
376
// in this case, we do not refine accuracy using declaring type arguments...!
377
} else {
378                 updateMatch(parameterizedBinding, this.pattern.getTypeArguments(), this.pattern.hasTypeParameters(), 0, locator);
379             }
380         } else if (this.pattern.hasTypeArguments()) {
381             match.setRule(SearchPattern.R_ERASURE_MATCH);
382         }
383
384         // Update match regarding method parameters
385
// TODO ? (frederic)
386

387         // Update match regarding method return type
388
// TODO ? (frederic)
389

390         // Special case for errors
391
if (match.getRule() != 0 && messageSend.resolvedType == null) {
392             match.setRule(SearchPattern.R_ERASURE_MATCH);
393         }
394     } else if (methodBinding instanceof ParameterizedMethodBinding) {
395         isParameterized = true;
396         if (methodBinding.declaringClass.isParameterizedType() || methodBinding.declaringClass.isRawType()) {
397             ParameterizedTypeBinding parameterizedBinding = (ParameterizedTypeBinding)methodBinding.declaringClass;
398             if (!parameterizedBinding.isParameterizedWithOwnVariables()) {
399                 updateMatch(parameterizedBinding, this.pattern.getTypeArguments(), this.pattern.hasTypeParameters(), 0, locator);
400             }
401         } else if (this.pattern.hasTypeArguments()) {
402             match.setRule(SearchPattern.R_ERASURE_MATCH);
403         }
404
405         // Update match regarding method parameters
406
// TODO ? (frederic)
407

408         // Update match regarding method return type
409
// TODO ? (frederic)
410

411         // Special case for errors
412
if (match.getRule() != 0 && messageSend.resolvedType == null) {
413             match.setRule(SearchPattern.R_ERASURE_MATCH);
414         }
415     } else if (this.pattern.hasMethodArguments()) { // binding has no type params, compatible erasure if pattern does
416
match.setRule(SearchPattern.R_ERASURE_MATCH);
417     }
418
419     // See whether it is necessary to report or not
420
if (match.getRule() == 0) return; // impossible match
421
boolean report = (this.isErasureMatch && match.isErasure()) || (this.isEquivalentMatch && match.isEquivalent()) || match.isExact();
422     if (!report) return;
423
424     // Report match
425
int offset = (int) (messageSend.nameSourcePosition >>> 32);
426     match.setOffset(offset);
427     match.setLength(messageSend.sourceEnd - offset + 1);
428      if (isParameterized && this.pattern.hasMethodArguments()) {
429         locator.reportAccurateParameterizedMethodReference(match, messageSend, messageSend.typeArguments);
430     } else {
431         locator.report(match);
432     }
433 }
434 /*
435  * Return whether method parameters are equals to pattern ones.
436  */

437 private boolean methodParametersEqualsPattern(MethodBinding method) {
438     TypeBinding[] methodParameters = method.parameters;
439
440     int length = methodParameters.length;
441     if (length != this.pattern.parameterSimpleNames.length) return false;
442
443     for (int i = 0; i < length; i++) {
444         char[] paramQualifiedName = qualifiedPattern(this.pattern.parameterSimpleNames[i], this.pattern.parameterQualifications[i]);
445         if (!CharOperation.match(paramQualifiedName, methodParameters[i].readableName(), this.isCaseSensitive)) {
446             return false;
447         }
448     }
449     return true;
450 }
451 public SearchMatch newDeclarationMatch(ASTNode reference, IJavaElement element, Binding elementBinding, int accuracy, int length, MatchLocator locator) {
452     if (elementBinding != null) {
453         MethodBinding methodBinding = (MethodBinding) elementBinding;
454         // If method parameters verification was not valid, then try to see if method arguments can match a method in hierarchy
455
if (this.methodDeclarationsWithInvalidParam.containsKey(reference)) {
456             // First see if this reference has already been resolved => report match if validated
457
Boolean JavaDoc report = (Boolean JavaDoc) this.methodDeclarationsWithInvalidParam.get(reference);
458             if (report != null) {
459                 if (report.booleanValue()) {
460                     return super.newDeclarationMatch(reference, element, elementBinding, accuracy, length, locator);
461                 }
462                 return null;
463             }
464             if (matchOverriddenMethod(methodBinding.declaringClass, methodBinding, null)) {
465                 this.methodDeclarationsWithInvalidParam.put(reference, Boolean.TRUE);
466                 return super.newDeclarationMatch(reference, element, elementBinding, accuracy, length, locator);
467             }
468             if (isTypeInSuperDeclaringTypeNames(methodBinding.declaringClass.compoundName)) {
469                 MethodBinding patternBinding = locator.getMethodBinding(this.pattern);
470                 if (patternBinding != null) {
471                     if (!matchOverriddenMethod(patternBinding.declaringClass, patternBinding, methodBinding)) {
472                         this.methodDeclarationsWithInvalidParam.put(reference, Boolean.FALSE);
473                         return null;
474                     }
475                 }
476                 this.methodDeclarationsWithInvalidParam.put(reference, Boolean.TRUE);
477                 return super.newDeclarationMatch(reference, element, elementBinding, accuracy, length, locator);
478             }
479             this.methodDeclarationsWithInvalidParam.put(reference, Boolean.FALSE);
480             return null;
481         }
482     }
483     return super.newDeclarationMatch(reference, element, elementBinding, accuracy, length, locator);
484 }
485 protected int referenceType() {
486     return IJavaElement.METHOD;
487 }
488 protected void reportDeclaration(MethodBinding methodBinding, MatchLocator locator, SimpleSet knownMethods) throws CoreException {
489     ReferenceBinding declaringClass = methodBinding.declaringClass;
490     IType type = locator.lookupType(declaringClass);
491     if (type == null) return; // case of a secondary type
492

493     char[] bindingSelector = methodBinding.selector;
494     boolean isBinary = type.isBinary();
495     IMethod method = null;
496     TypeBinding[] parameters = methodBinding.original().parameters;
497     int parameterLength = parameters.length;
498     if (isBinary) {
499         char[][] parameterTypes = new char[parameterLength][];
500         for (int i = 0; i<parameterLength; i++) {
501             char[] typeName = parameters[i].qualifiedSourceName();
502             for (int j=0, dim=parameters[i].dimensions(); j<dim; j++) {
503                 typeName = CharOperation.concat(typeName, new char[] {'[', ']'});
504             }
505             parameterTypes[i] = typeName;
506         }
507         method = locator.createBinaryMethodHandle(type, methodBinding.selector, parameterTypes);
508     } else {
509         String JavaDoc[] parameterTypes = new String JavaDoc[parameterLength];
510         for (int i = 0; i < parameterLength; i++) {
511             char[] typeName = parameters[i].shortReadableName();
512             if (parameters[i].isMemberType()) {
513                 typeName = CharOperation.subarray(typeName, CharOperation.indexOf('.', typeName)+1, typeName.length);
514             }
515             parameterTypes[i] = Signature.createTypeSignature(typeName, false);
516         }
517         method = type.getMethod(new String JavaDoc(bindingSelector), parameterTypes);
518     }
519     if (method == null || knownMethods.addIfNotIncluded(method) == null) return;
520
521     IResource resource = type.getResource();
522     IBinaryType info = null;
523     if (isBinary) {
524         if (resource == null)
525             resource = type.getJavaProject().getProject();
526         info = locator.getBinaryInfo((org.eclipse.jdt.internal.core.ClassFile)type.getClassFile(), resource);
527         locator.reportBinaryMemberDeclaration(resource, method, methodBinding, info, SearchMatch.A_ACCURATE);
528     } else {
529         if (declaringClass instanceof ParameterizedTypeBinding)
530             declaringClass = ((ParameterizedTypeBinding) declaringClass).genericType();
531         ClassScope scope = ((SourceTypeBinding) declaringClass).scope;
532         if (scope != null) {
533             TypeDeclaration typeDecl = scope.referenceContext;
534             AbstractMethodDeclaration methodDecl = null;
535             AbstractMethodDeclaration[] methodDecls = typeDecl.methods;
536             for (int i = 0, length = methodDecls.length; i < length; i++) {
537                 if (CharOperation.equals(bindingSelector, methodDecls[i].selector)) {
538                     methodDecl = methodDecls[i];
539                     break;
540                 }
541             }
542             if (methodDecl != null) {
543                 int offset = methodDecl.sourceStart;
544                 Binding binding = methodDecl.binding;
545                 if (binding != null)
546                     method = (IMethod) ((JavaElement) method).resolved(binding);
547                 match = new MethodDeclarationMatch(method, SearchMatch.A_ACCURATE, offset, methodDecl.sourceEnd-offset+1, locator.getParticipant(), resource);
548                 locator.report(match);
549             }
550         }
551     }
552 }
553 public int resolveLevel(ASTNode possibleMatchingNode) {
554     if (this.pattern.findReferences) {
555         if (possibleMatchingNode instanceof MessageSend) {
556             return resolveLevel((MessageSend) possibleMatchingNode);
557         }
558         if (possibleMatchingNode instanceof SingleMemberAnnotation) {
559             SingleMemberAnnotation annotation = (SingleMemberAnnotation) possibleMatchingNode;
560             return resolveLevel(annotation.memberValuePairs()[0].binding);
561         }
562         if (possibleMatchingNode instanceof MemberValuePair) {
563             MemberValuePair memberValuePair = (MemberValuePair) possibleMatchingNode;
564             return resolveLevel(memberValuePair.binding);
565         }
566     }
567     if (this.pattern.findDeclarations) {
568         if (possibleMatchingNode instanceof MethodDeclaration) {
569             return resolveLevel(((MethodDeclaration) possibleMatchingNode).binding);
570         }
571     }
572     return IMPOSSIBLE_MATCH;
573 }
574 public int resolveLevel(Binding binding) {
575     if (binding == null) return INACCURATE_MATCH;
576     if (!(binding instanceof MethodBinding)) return IMPOSSIBLE_MATCH;
577
578     MethodBinding method = (MethodBinding) binding;
579     boolean skipVerif = this.pattern.findDeclarations && this.mayBeGeneric;
580     int methodLevel = matchMethod(method, skipVerif);
581     if (methodLevel == IMPOSSIBLE_MATCH) {
582         if (method != method.original()) methodLevel = matchMethod(method.original(), skipVerif);
583         if (methodLevel == IMPOSSIBLE_MATCH) {
584             return IMPOSSIBLE_MATCH;
585         } else {
586             method = method.original();
587         }
588     }
589
590     // declaring type
591
char[] qualifiedPattern = qualifiedPattern(this.pattern.declaringSimpleName, this.pattern.declaringQualification);
592     if (qualifiedPattern == null) return methodLevel; // since any declaring class will do
593

594     boolean subType = !method.isStatic() && !method.isPrivate();
595     if (subType && this.pattern.declaringQualification != null && method.declaringClass != null && method.declaringClass.fPackage != null) {
596         subType = CharOperation.compareWith(this.pattern.declaringQualification, method.declaringClass.fPackage.shortReadableName()) == 0;
597     }
598     int declaringLevel = subType
599         ? resolveLevelAsSubtype(qualifiedPattern, method.declaringClass, null)
600         : resolveLevelForType(qualifiedPattern, method.declaringClass);
601     return methodLevel > declaringLevel ? declaringLevel : methodLevel; // return the weaker match
602
}
603 protected int resolveLevel(MessageSend messageSend) {
604     MethodBinding method = messageSend.binding;
605     if (method == null) {
606         return INACCURATE_MATCH;
607     }
608     if (messageSend.resolvedType == null) {
609         // Closest match may have different argument numbers when ProblemReason is NotFound
610
// see MessageSend#resolveType(BlockScope)
611
// see bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=97322
612
int argLength = messageSend.arguments == null ? 0 : messageSend.arguments.length;
613         if (pattern.parameterSimpleNames == null || argLength == pattern.parameterSimpleNames.length) {
614             return INACCURATE_MATCH;
615         }
616         return IMPOSSIBLE_MATCH;
617     }
618     
619     int methodLevel = matchMethod(method, false);
620     if (methodLevel == IMPOSSIBLE_MATCH) {
621         if (method != method.original()) methodLevel = matchMethod(method.original(), false);
622         if (methodLevel == IMPOSSIBLE_MATCH) return IMPOSSIBLE_MATCH;
623         method = method.original();
624     }
625
626     // receiver type
627
char[] qualifiedPattern = qualifiedPattern(this.pattern.declaringSimpleName, this.pattern.declaringQualification);
628     if (qualifiedPattern == null) return methodLevel; // since any declaring class will do
629

630     int declaringLevel;
631     if (isVirtualInvoke(method, messageSend) && (messageSend.actualReceiverType instanceof ReferenceBinding)) {
632         ReferenceBinding methodReceiverType = (ReferenceBinding) messageSend.actualReceiverType;
633         declaringLevel = resolveLevelAsSubtype(qualifiedPattern, methodReceiverType, method.parameters);
634         if (declaringLevel == IMPOSSIBLE_MATCH) {
635             if (method.declaringClass == null || this.allSuperDeclaringTypeNames == null) {
636                 declaringLevel = INACCURATE_MATCH;
637             } else {
638                 char[][] compoundName = methodReceiverType.compoundName;
639                 for (int i = 0, max = this.allSuperDeclaringTypeNames.length; i < max; i++) {
640                     if (CharOperation.equals(this.allSuperDeclaringTypeNames[i], compoundName)) {
641                         return methodLevel // since this is an ACCURATE_MATCH so return the possibly weaker match
642
| SUPER_INVOCATION_FLAVOR; // this is an overridden method => add flavor to returned level
643
}
644                 }
645                 /* Do not return interfaces potential matches
646                  * @see "https://bugs.eclipse.org/bugs/show_bug.cgi?id=157814#c8"
647                 if (methodReceiverType.isInterface()) {
648                     // all methods interface with same name and parameters are potential matches
649                     // see bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=156491
650                     return INACCURATE_MATCH | POLYMORPHIC_FLAVOR;
651                 }
652                 */

653             }
654         }
655         if ((declaringLevel & FLAVORS_MASK) != 0) {
656             // level got some flavors => return it
657
return declaringLevel;
658         }
659     } else {
660         declaringLevel = resolveLevelForType(qualifiedPattern, method.declaringClass);
661     }
662     return methodLevel > declaringLevel ? declaringLevel : methodLevel; // return the weaker match
663
}
664 /**
665  * Returns whether the given reference type binding matches or is a subtype of a type
666  * that matches the given qualified pattern.
667  * Returns ACCURATE_MATCH if it does.
668  * Returns INACCURATE_MATCH if resolve fails
669  * Returns IMPOSSIBLE_MATCH if it doesn't.
670  */

671 protected int resolveLevelAsSubtype(char[] qualifiedPattern, ReferenceBinding type, TypeBinding[] argumentTypes) {
672     if (type == null) return INACCURATE_MATCH;
673
674     int level = resolveLevelForType(qualifiedPattern, type);
675     if (level != IMPOSSIBLE_MATCH) {
676         if (!type.isAbstract() && !type.isInterface()) { // if concrete class, then method is overridden
677
level |= OVERRIDDEN_METHOD_FLAVOR;
678         }
679         return level;
680     }
681
682     // matches superclass
683
if (!type.isInterface() && !CharOperation.equals(type.compoundName, TypeConstants.JAVA_LANG_OBJECT)) {
684         level = resolveLevelAsSubtype(qualifiedPattern, type.superclass(), argumentTypes);
685         if (level != IMPOSSIBLE_MATCH) {
686             if (argumentTypes != null) {
687                 // need to verify if method may be overridden
688
MethodBinding[] methods = type.getMethods(this.pattern.selector);
689                 for (int i=0, length=methods.length; i<length; i++) {
690                     MethodBinding method = methods[i];
691                     TypeBinding[] parameters = method.parameters;
692                     if (argumentTypes.length == parameters.length) {
693                         boolean found = true;
694                         for (int j=0,l=parameters.length; j<l; j++) {
695                             if (parameters[j].erasure() != argumentTypes[j].erasure()) {
696                                 found = false;
697                                 break;
698                             }
699                         }
700                         if (found) { // one method match in hierarchy
701
if ((level & OVERRIDDEN_METHOD_FLAVOR) != 0) {
702                                 // this method is already overridden on a super class, current match is impossible
703
return IMPOSSIBLE_MATCH;
704                             }
705                             if (!method.isAbstract() && !type.isInterface()) {
706                                 // store the fact that the method is overridden
707
level |= OVERRIDDEN_METHOD_FLAVOR;
708                             }
709                         }
710                     }
711                 }
712             }
713             return level | SUB_INVOCATION_FLAVOR; // add flavor to returned level
714
}
715     }
716
717     // matches interfaces
718
ReferenceBinding[] interfaces = type.superInterfaces();
719     if (interfaces == null) return INACCURATE_MATCH;
720     for (int i = 0; i < interfaces.length; i++) {
721         level = resolveLevelAsSubtype(qualifiedPattern, interfaces[i], null);
722         if (level != IMPOSSIBLE_MATCH) {
723             if (!type.isAbstract() && !type.isInterface()) { // if concrete class, then method is overridden
724
level |= OVERRIDDEN_METHOD_FLAVOR;
725             }
726             return level | SUB_INVOCATION_FLAVOR; // add flavor to returned level
727
}
728     }
729     return IMPOSSIBLE_MATCH;
730 }
731 public String JavaDoc toString() {
732     return "Locator for " + this.pattern.toString(); //$NON-NLS-1$
733
}
734 }
735
Popular Tags