KickJava   Java API By Example, From Geeks To Geeks.

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


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.io.IOException JavaDoc;
14 import java.util.ArrayList JavaDoc;
15 import java.util.HashMap JavaDoc;
16 import java.util.HashSet JavaDoc;
17 import java.util.Iterator JavaDoc;
18 import java.util.Map JavaDoc;
19 import java.util.zip.ZipFile JavaDoc;
20
21 import org.eclipse.core.resources.IResource;
22 import org.eclipse.core.runtime.*;
23 import org.eclipse.jdt.core.Flags;
24 import org.eclipse.jdt.core.IClassFile;
25 import org.eclipse.jdt.core.IJavaElement;
26 import org.eclipse.jdt.core.IJavaModelStatusConstants;
27 import org.eclipse.jdt.core.IJavaProject;
28 import org.eclipse.jdt.core.IMember;
29 import org.eclipse.jdt.core.IMethod;
30 import org.eclipse.jdt.core.IPackageFragment;
31 import org.eclipse.jdt.core.IPackageFragmentRoot;
32 import org.eclipse.jdt.core.ISourceRange;
33 import org.eclipse.jdt.core.IType;
34 import org.eclipse.jdt.core.JavaModelException;
35 import org.eclipse.jdt.core.Signature;
36 import org.eclipse.jdt.core.compiler.*;
37 import org.eclipse.jdt.core.search.*;
38 import org.eclipse.jdt.internal.compiler.ASTVisitor;
39 import org.eclipse.jdt.internal.compiler.CompilationResult;
40 import org.eclipse.jdt.internal.compiler.DefaultErrorHandlingPolicies;
41 import org.eclipse.jdt.internal.compiler.ast.*;
42 import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
43 import org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader;
44 import org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException;
45 import org.eclipse.jdt.internal.compiler.env.*;
46 import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
47 import org.eclipse.jdt.internal.compiler.impl.ITypeRequestor;
48 import org.eclipse.jdt.internal.compiler.lookup.*;
49 import org.eclipse.jdt.internal.compiler.parser.*;
50 import org.eclipse.jdt.internal.compiler.problem.*;
51 import org.eclipse.jdt.internal.compiler.util.HashtableOfIntValues;
52 import org.eclipse.jdt.internal.compiler.util.Messages;
53 import org.eclipse.jdt.internal.compiler.util.SimpleLookupTable;
54 import org.eclipse.jdt.internal.compiler.util.SimpleSet;
55 import org.eclipse.jdt.internal.compiler.util.SuffixConstants;
56 import org.eclipse.jdt.internal.core.hierarchy.HierarchyResolver;
57 import org.eclipse.jdt.internal.core.BinaryMember;
58 import org.eclipse.jdt.internal.core.BinaryType;
59 import org.eclipse.jdt.internal.core.ClassFile;
60 import org.eclipse.jdt.internal.core.CompilationUnit;
61 import org.eclipse.jdt.internal.core.JarPackageFragmentRoot;
62 import org.eclipse.jdt.internal.core.JavaElement;
63 import org.eclipse.jdt.internal.core.JavaModelManager;
64 import org.eclipse.jdt.internal.core.JavaProject;
65 import org.eclipse.jdt.internal.core.LocalVariable;
66 import org.eclipse.jdt.internal.core.NameLookup;
67 import org.eclipse.jdt.internal.core.Openable;
68 import org.eclipse.jdt.internal.core.PackageFragment;
69 import org.eclipse.jdt.internal.core.PackageFragmentRoot;
70 import org.eclipse.jdt.internal.core.SearchableEnvironment;
71 import org.eclipse.jdt.internal.core.SourceMapper;
72 import org.eclipse.jdt.internal.core.SourceMethod;
73 import org.eclipse.jdt.internal.core.SourceTypeElementInfo;
74 import org.eclipse.jdt.internal.core.index.Index;
75 import org.eclipse.jdt.internal.core.search.*;
76 import org.eclipse.jdt.internal.core.util.HandleFactory;
77 import org.eclipse.jdt.internal.core.util.Util;
78
79 public class MatchLocator implements ITypeRequestor {
80
81 public static final int MAX_AT_ONCE;
82 static {
83     long maxMemory = Runtime.getRuntime().maxMemory();
84     int ratio = (int) Math.round(((double) maxMemory) / (64 * 0x100000));
85     switch (ratio) {
86         case 0:
87         case 1:
88             MAX_AT_ONCE = 100;
89             break;
90         case 2:
91             MAX_AT_ONCE = 200;
92             break;
93         case 3:
94             MAX_AT_ONCE = 300;
95             break;
96         default:
97             MAX_AT_ONCE = 400;
98             break;
99     }
100 }
101
102 // permanent state
103
public SearchPattern pattern;
104 public PatternLocator patternLocator;
105 public int matchContainer;
106 public SearchRequestor requestor;
107 public IJavaSearchScope scope;
108 public IProgressMonitor progressMonitor;
109
110 public org.eclipse.jdt.core.ICompilationUnit[] workingCopies;
111 public HandleFactory handleFactory;
112
113 // cache of all super type names if scope is hierarchy scope
114
public char[][][] allSuperTypeNames;
115
116 // the following is valid for the current project
117
public MatchLocatorParser parser;
118 private Parser basicParser;
119 public INameEnvironment nameEnvironment;
120 public NameLookup nameLookup;
121 public LookupEnvironment lookupEnvironment;
122 public HierarchyResolver hierarchyResolver;
123
124 public CompilerOptions options;
125
126 // management of PossibleMatch to be processed
127
public int numberOfMatches; // (numberOfMatches - 1) is the last unit in matchesToProcess
128
public PossibleMatch[] matchesToProcess;
129 public PossibleMatch currentPossibleMatch;
130
131 /*
132  * Time spent in the IJavaSearchResultCollector
133  */

134 public long resultCollectorTime = 0;
135
136 // Progress information
137
int progressStep;
138 int progressWorked;
139
140 // Binding resolution and cache
141
CompilationUnitScope unitScope;
142 SimpleLookupTable bindings;
143
144 // Cache for method handles
145
HashSet JavaDoc methodHandles;
146
147 /**
148  * An ast visitor that visits local type declarations.
149  */

150 public class LocalDeclarationVisitor extends ASTVisitor {
151     IJavaElement enclosingElement;
152     Binding enclosingElementBinding;
153     MatchingNodeSet nodeSet;
154     HashtableOfIntValues occurrencesCounts = new HashtableOfIntValues(); // key = class name (char[]), value = occurrenceCount (int)
155
public LocalDeclarationVisitor(IJavaElement enclosingElement, Binding enclosingElementBinding, MatchingNodeSet nodeSet) {
156         this.enclosingElement = enclosingElement;
157         this.enclosingElementBinding = enclosingElementBinding;
158         this.nodeSet = nodeSet;
159     }
160     public boolean visit(TypeDeclaration typeDeclaration, BlockScope unused) {
161         try {
162             char[] simpleName;
163             if ((typeDeclaration.bits & ASTNode.IsAnonymousType) != 0) {
164                 simpleName = CharOperation.NO_CHAR;
165             } else {
166                 simpleName = typeDeclaration.name;
167             }
168             int occurrenceCount = occurrencesCounts.get(simpleName);
169             if (occurrenceCount == HashtableOfIntValues.NO_VALUE) {
170                 occurrenceCount = 1;
171             } else {
172                 occurrenceCount = occurrenceCount + 1;
173             }
174             occurrencesCounts.put(simpleName, occurrenceCount);
175             if ((typeDeclaration.bits & ASTNode.IsAnonymousType) != 0) {
176                 reportMatching(typeDeclaration, this.enclosingElement, -1, nodeSet, occurrenceCount);
177             } else {
178                 Integer JavaDoc level = (Integer JavaDoc) nodeSet.matchingNodes.removeKey(typeDeclaration);
179                 reportMatching(typeDeclaration, this.enclosingElement, level != null ? level.intValue() : -1, nodeSet, occurrenceCount);
180             }
181             return false; // don't visit members as this was done during reportMatching(...)
182
} catch (CoreException e) {
183             throw new WrappedCoreException(e);
184         }
185     }
186 }
187
188 public static class WorkingCopyDocument extends JavaSearchDocument {
189     public org.eclipse.jdt.core.ICompilationUnit workingCopy;
190     WorkingCopyDocument(org.eclipse.jdt.core.ICompilationUnit workingCopy, SearchParticipant participant) {
191         super(workingCopy.getPath().toString(), participant);
192         this.charContents = ((CompilationUnit)workingCopy).getContents();
193         this.workingCopy = workingCopy;
194     }
195     public String JavaDoc toString() {
196         return "WorkingCopyDocument for " + getPath(); //$NON-NLS-1$
197
}
198 }
199     
200 public static class WrappedCoreException extends RuntimeException JavaDoc {
201     private static final long serialVersionUID = 8354329870126121212L; // backward compatible
202
public CoreException coreException;
203     public WrappedCoreException(CoreException coreException) {
204         this.coreException = coreException;
205     }
206 }
207
208 public static SearchDocument[] addWorkingCopies(InternalSearchPattern pattern, SearchDocument[] indexMatches, org.eclipse.jdt.core.ICompilationUnit[] copies, SearchParticipant participant) {
209     // working copies take precedence over corresponding compilation units
210
HashMap JavaDoc workingCopyDocuments = workingCopiesThatCanSeeFocus(copies, pattern.focus, pattern.isPolymorphicSearch(), participant);
211     SearchDocument[] matches = null;
212     int length = indexMatches.length;
213     for (int i = 0; i < length; i++) {
214         SearchDocument searchDocument = indexMatches[i];
215         if (searchDocument.getParticipant() == participant) {
216             SearchDocument workingCopyDocument = (SearchDocument) workingCopyDocuments.remove(searchDocument.getPath());
217             if (workingCopyDocument != null) {
218                 if (matches == null) {
219                     System.arraycopy(indexMatches, 0, matches = new SearchDocument[length], 0, length);
220                 }
221                 matches[i] = workingCopyDocument;
222             }
223         }
224     }
225     if (matches == null) { // no working copy
226
matches = indexMatches;
227     }
228     int remainingWorkingCopiesSize = workingCopyDocuments.size();
229     if (remainingWorkingCopiesSize != 0) {
230         System.arraycopy(matches, 0, matches = new SearchDocument[length+remainingWorkingCopiesSize], 0, length);
231         Iterator JavaDoc iterator = workingCopyDocuments.values().iterator();
232         int index = length;
233         while (iterator.hasNext()) {
234             matches[index++] = (SearchDocument) iterator.next();
235         }
236     }
237     return matches;
238 }
239
240 public static void setFocus(InternalSearchPattern pattern, IJavaElement focus) {
241     pattern.focus = focus;
242 }
243
244 /*
245  * Returns the working copies that can see the given focus.
246  */

247 private static HashMap JavaDoc workingCopiesThatCanSeeFocus(org.eclipse.jdt.core.ICompilationUnit[] copies, IJavaElement focus, boolean isPolymorphicSearch, SearchParticipant participant) {
248     if (copies == null) return new HashMap JavaDoc();
249     if (focus != null) {
250         while (!(focus instanceof IJavaProject) && !(focus instanceof JarPackageFragmentRoot)) {
251             focus = focus.getParent();
252         }
253     }
254     HashMap JavaDoc result = new HashMap JavaDoc();
255     for (int i=0, length = copies.length; i<length; i++) {
256         org.eclipse.jdt.core.ICompilationUnit workingCopy = copies[i];
257         IPath projectOrJar = MatchLocator.getProjectOrJar(workingCopy).getPath();
258         if (focus == null || IndexSelector.canSeeFocus(focus, isPolymorphicSearch, projectOrJar)) {
259             result.put(
260                 workingCopy.getPath().toString(),
261                 new WorkingCopyDocument(workingCopy, participant)
262             );
263         }
264     }
265     return result;
266 }
267
268 public static ClassFileReader classFileReader(IType type) {
269     IClassFile classFile = type.getClassFile();
270     JavaModelManager manager = JavaModelManager.getJavaModelManager();
271     if (classFile.isOpen())
272         return (ClassFileReader) manager.getInfo(type);
273
274     PackageFragment pkg = (PackageFragment) type.getPackageFragment();
275     IPackageFragmentRoot root = (IPackageFragmentRoot) pkg.getParent();
276     try {
277         if (!root.isArchive())
278             return Util.newClassFileReader(type.getResource());
279
280         ZipFile JavaDoc zipFile = null;
281         try {
282             IPath zipPath = root.getPath();
283             if (JavaModelManager.ZIP_ACCESS_VERBOSE)
284                 System.out.println("(" + Thread.currentThread() + ") [MatchLocator.classFileReader()] Creating ZipFile on " + zipPath); //$NON-NLS-1$ //$NON-NLS-2$
285
zipFile = manager.getZipFile(zipPath);
286             String JavaDoc classFileName = classFile.getElementName();
287             String JavaDoc path = Util.concatWith(pkg.names, classFileName, '/');
288             return ClassFileReader.read(zipFile, path);
289         } finally {
290             manager.closeZipFile(zipFile);
291         }
292     } catch (ClassFormatException e) {
293         // invalid class file: return null
294
} catch (CoreException e) {
295         // cannot read class file: return null
296
} catch (IOException JavaDoc e) {
297         // cannot read class file: return null
298
}
299     return null;
300 }
301
302 public static SearchPattern createAndPattern(final SearchPattern leftPattern, final SearchPattern rightPattern) {
303     return new AndPattern(0/*no kind*/, 0/*no rule*/) {
304         SearchPattern current = leftPattern;
305         public SearchPattern currentPattern() {
306             return this.current;
307         }
308         protected boolean hasNextQuery() {
309             if (this.current == leftPattern) {
310                 this.current = rightPattern;
311                 return true;
312             }
313             return false;
314         }
315         protected void resetQuery() {
316             this.current = leftPattern;
317         }
318     };
319 }
320
321 /**
322  * Query a given index for matching entries. Assumes the sender has opened the index and will close when finished.
323  */

324 public static void findIndexMatches(InternalSearchPattern pattern, Index index, IndexQueryRequestor requestor, SearchParticipant participant, IJavaSearchScope scope, IProgressMonitor monitor) throws IOException JavaDoc {
325     pattern.findIndexMatches(index, requestor, participant, scope, monitor);
326 }
327
328 public static IJavaElement getProjectOrJar(IJavaElement element) {
329     while (!(element instanceof IJavaProject) && !(element instanceof JarPackageFragmentRoot)) {
330         element = element.getParent();
331     }
332     return element;
333 }
334
335 public static IJavaElement projectOrJarFocus(InternalSearchPattern pattern) {
336     return pattern == null || pattern.focus == null ? null : getProjectOrJar(pattern.focus);
337 }
338
339 public MatchLocator(
340     SearchPattern pattern,
341     SearchRequestor requestor,
342     IJavaSearchScope scope,
343     IProgressMonitor progressMonitor) {
344         
345     this.pattern = pattern;
346     this.patternLocator = PatternLocator.patternLocator(this.pattern);
347     this.matchContainer = this.patternLocator.matchContainer();
348     this.requestor = requestor;
349     this.scope = scope;
350     this.progressMonitor = progressMonitor;
351 }
352 /**
353  * Add an additional binary type
354  */

355 public void accept(IBinaryType binaryType, PackageBinding packageBinding, AccessRestriction accessRestriction) {
356     this.lookupEnvironment.createBinaryTypeFrom(binaryType, packageBinding, accessRestriction);
357 }
358 /**
359  * Add an additional compilation unit into the loop
360  * -> build compilation unit declarations, their bindings and record their results.
361  */

362 public void accept(ICompilationUnit sourceUnit, AccessRestriction accessRestriction) {
363     // Switch the current policy and compilation result for this unit to the requested one.
364
CompilationResult unitResult = new CompilationResult(sourceUnit, 1, 1, this.options.maxProblemsPerUnit);
365     try {
366         CompilationUnitDeclaration parsedUnit = basicParser().dietParse(sourceUnit, unitResult);
367         this.lookupEnvironment.buildTypeBindings(parsedUnit, accessRestriction);
368         this.lookupEnvironment.completeTypeBindings(parsedUnit, true);
369     } catch (AbortCompilationUnit e) {
370         // at this point, currentCompilationUnitResult may not be sourceUnit, but some other
371
// one requested further along to resolve sourceUnit.
372
if (unitResult.compilationUnit == sourceUnit) { // only report once
373
//requestor.acceptResult(unitResult.tagAsAccepted());
374
} else {
375             throw e; // want to abort enclosing request to compile
376
}
377     }
378     // Display unit error in debug mode
379
if (BasicSearchEngine.VERBOSE) {
380         if (unitResult.problemCount > 0) {
381             System.out.println(unitResult);
382         }
383     }
384 }
385 /**
386  * Add additional source types
387  */

388 public void accept(ISourceType[] sourceTypes, PackageBinding packageBinding, AccessRestriction accessRestriction) {
389     // case of SearchableEnvironment of an IJavaProject is used
390
ISourceType sourceType = sourceTypes[0];
391     while (sourceType.getEnclosingType() != null)
392         sourceType = sourceType.getEnclosingType();
393     if (sourceType instanceof SourceTypeElementInfo) {
394         // get source
395
SourceTypeElementInfo elementInfo = (SourceTypeElementInfo) sourceType;
396         IType type = elementInfo.getHandle();
397         ICompilationUnit sourceUnit = (ICompilationUnit) type.getCompilationUnit();
398         accept(sourceUnit, accessRestriction);
399     } else {
400         CompilationResult result = new CompilationResult(sourceType.getFileName(), 1, 1, 0);
401         CompilationUnitDeclaration unit =
402             SourceTypeConverter.buildCompilationUnit(
403                 sourceTypes,
404                 SourceTypeConverter.FIELD_AND_METHOD // need field and methods
405
| SourceTypeConverter.MEMBER_TYPE, // need member types
406
// no need for field initialization
407
this.lookupEnvironment.problemReporter,
408                 result);
409         this.lookupEnvironment.buildTypeBindings(unit, accessRestriction);
410         this.lookupEnvironment.completeTypeBindings(unit, true);
411     }
412 }
413 protected Parser basicParser() {
414     if (this.basicParser == null) {
415         ProblemReporter problemReporter =
416             new ProblemReporter(
417                 DefaultErrorHandlingPolicies.proceedWithAllProblems(),
418                 this.options,
419                 new DefaultProblemFactory());
420         this.basicParser = new Parser(problemReporter, false);
421         this.basicParser.reportOnlyOneSyntaxError = true;
422     }
423     return this.basicParser;
424 }
425 /*
426  * Caches the given binary type in the lookup environment and returns it.
427  * Returns the existing one if already cached.
428  * Returns null if source type binding was cached.
429  */

430 protected BinaryTypeBinding cacheBinaryType(IType type, IBinaryType binaryType) throws JavaModelException {
431     IType enclosingType = type.getDeclaringType();
432     if (enclosingType != null)
433         cacheBinaryType(enclosingType, null); // cache enclosing types first, so that binary type can be found in lookup enviroment
434
if (binaryType == null) {
435         ClassFile classFile = (ClassFile) type.getClassFile();
436         try {
437             binaryType = getBinaryInfo(classFile, classFile.getResource());
438         } catch (CoreException e) {
439             if (e instanceof JavaModelException) {
440                 throw (JavaModelException) e;
441             } else {
442                 throw new JavaModelException(e);
443             }
444         }
445     }
446     BinaryTypeBinding binding = this.lookupEnvironment.cacheBinaryType(binaryType, null /*no access restriction*/);
447     if (binding == null) { // it was already cached as a result of a previous query
448
char[][] compoundName = CharOperation.splitOn('.', type.getFullyQualifiedName().toCharArray());
449         ReferenceBinding referenceBinding = this.lookupEnvironment.getCachedType(compoundName);
450         if (referenceBinding != null && (referenceBinding instanceof BinaryTypeBinding))
451             binding = (BinaryTypeBinding) referenceBinding; // if the binding could be found and if it comes from a binary type
452
}
453     return binding;
454 }
455 /*
456  * Computes the super type names of the focus type if any.
457  */

458 protected char[][][] computeSuperTypeNames(IType focusType) {
459     String JavaDoc fullyQualifiedName = focusType.getFullyQualifiedName();
460     int lastDot = fullyQualifiedName.lastIndexOf('.');
461     char[] qualification = lastDot == -1 ? CharOperation.NO_CHAR : fullyQualifiedName.substring(0, lastDot).toCharArray();
462     char[] simpleName = focusType.getElementName().toCharArray();
463
464     SuperTypeNamesCollector superTypeNamesCollector =
465         new SuperTypeNamesCollector(
466             this.pattern,
467             simpleName,
468             qualification,
469             new MatchLocator(this.pattern, this.requestor, this.scope, this.progressMonitor), // clone MatchLocator so that it has no side effect
470
focusType,
471             this.progressMonitor);
472     try {
473         this.allSuperTypeNames = superTypeNamesCollector.collect();
474     } catch (JavaModelException e) {
475         // problem collecting super type names: leave it null
476
}
477     return this.allSuperTypeNames;
478 }
479 /**
480  * Creates an IMethod from the given method declaration and type.
481  */

482 protected IJavaElement createHandle(AbstractMethodDeclaration method, IJavaElement parent) {
483     if (!(parent instanceof IType)) return parent;
484
485     IType type = (IType) parent;
486     Argument[] arguments = method.arguments;
487     int argCount = arguments == null ? 0 : arguments.length;
488     if (type.isBinary()) {
489         // don't cache the methods of the binary type
490
// fall thru if its a constructor with a synthetic argument... find it the slower way
491
ClassFileReader reader = classFileReader(type);
492         if (reader != null) {
493             IBinaryMethod[] methods = reader.getMethods();
494             if (methods != null) {
495                 // build arguments names
496
boolean firstIsSynthetic = false;
497                 if (reader.isMember() && method.isConstructor() && !Flags.isStatic(reader.getModifiers())) { // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=48261
498
firstIsSynthetic = true;
499                     argCount++;
500                 }
501                 char[][] argumentTypeNames = new char[argCount][];
502                 for (int i = 0; i < argCount; i++) {
503                     char[] typeName = null;
504                     if (i == 0 && firstIsSynthetic) {
505                         typeName = type.getDeclaringType().getFullyQualifiedName().toCharArray();
506                     } else if (arguments != null) {
507                         TypeReference typeRef = arguments[firstIsSynthetic ? i - 1 : i].type;
508                         typeName = CharOperation.concatWith(typeRef.getTypeName(), '.');
509                         for (int k = 0, dim = typeRef.dimensions(); k < dim; k++)
510                             typeName = CharOperation.concat(typeName, new char[] {'[', ']'});
511                     }
512                     if (typeName == null) {
513                         // invalid type name
514
return null;
515                     }
516                     argumentTypeNames[i] = typeName;
517                 }
518                 
519                 // return binary method
520
return createBinaryMethodHandle(type, method.selector, argumentTypeNames);
521             }
522         }
523         return null;
524     }
525
526     String JavaDoc[] parameterTypeSignatures = new String JavaDoc[argCount];
527     if (arguments != null) {
528         for (int i = 0; i < argCount; i++) {
529             TypeReference typeRef = arguments[i].type;
530             char[] typeName = CharOperation.concatWith(typeRef.getParameterizedTypeName(), '.');
531             parameterTypeSignatures[i] = Signature.createTypeSignature(typeName, false);
532         }
533     }
534
535     return createMethodHandle(type, new String JavaDoc(method.selector), parameterTypeSignatures);
536 }
537 /*
538  * Create binary method handle
539  */

540 IMethod createBinaryMethodHandle(IType type, char[] methodSelector, char[][] argumentTypeNames) {
541     ClassFileReader reader = MatchLocator.classFileReader(type);
542     if (reader != null) {
543         IBinaryMethod[] methods = reader.getMethods();
544         if (methods != null) {
545             int argCount = argumentTypeNames == null ? 0 : argumentTypeNames.length;
546             nextMethod : for (int i = 0, methodsLength = methods.length; i < methodsLength; i++) {
547                 IBinaryMethod binaryMethod = methods[i];
548                 char[] selector = binaryMethod.isConstructor() ? type.getElementName().toCharArray() : binaryMethod.getSelector();
549                 if (CharOperation.equals(selector, methodSelector)) {
550                     char[] signature = binaryMethod.getGenericSignature();
551                     if (signature == null) signature = binaryMethod.getMethodDescriptor();
552                     char[][] parameterTypes = Signature.getParameterTypes(signature);
553                     if (argCount != parameterTypes.length) continue nextMethod;
554                     if (argumentTypeNames != null) {
555                         for (int j = 0; j < argCount; j++) {
556                             char[] parameterTypeName = ClassFileMatchLocator.convertClassFileFormat(parameterTypes[j]);
557                             if (!CharOperation.endsWith(Signature.toCharArray(Signature.getTypeErasure(parameterTypeName)), CharOperation.replaceOnCopy(argumentTypeNames[j], '$', '.')))
558                                 continue nextMethod;
559                             parameterTypes[j] = parameterTypeName;
560                         }
561                     }
562                     return (IMethod) createMethodHandle(type, new String JavaDoc(selector), CharOperation.toStrings(parameterTypes));
563                 }
564             }
565         }
566     }
567     return null;
568 }
569 /*
570  * Create method handle.
571  * Store occurences for create handle to retrieve possible duplicate ones.
572  */

573 private IJavaElement createMethodHandle(IType type, String JavaDoc methodName, String JavaDoc[] parameterTypeSignatures) {
574     IMethod methodHandle = type.getMethod(methodName, parameterTypeSignatures);
575     if (methodHandle instanceof SourceMethod) {
576         while (this.methodHandles.contains(methodHandle)) {
577             ((SourceMethod) methodHandle).occurrenceCount++;
578         }
579     }
580     this.methodHandles.add(methodHandle);
581     return methodHandle;
582 }
583 /**
584  * Creates an IField from the given field declaration and type.
585  */

586 protected IJavaElement createHandle(FieldDeclaration fieldDeclaration, TypeDeclaration typeDeclaration, IJavaElement parent) {
587     if (!(parent instanceof IType)) return parent;
588     IType type = (IType) parent;
589
590     switch (fieldDeclaration.getKind()) {
591         case AbstractVariableDeclaration.FIELD :
592         case AbstractVariableDeclaration.ENUM_CONSTANT :
593             return ((IType) parent).getField(new String JavaDoc(fieldDeclaration.name));
594     }
595     if (type.isBinary()) {
596         // do not return initializer for binary types
597
// see bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=98378
598
return type;
599     }
600     // find occurence count of the given initializer in its type declaration
601
int occurrenceCount = 0;
602     FieldDeclaration[] fields = typeDeclaration.fields;
603     for (int i = 0, length = fields.length; i < length; i++) {
604         if (fields[i].getKind() == AbstractVariableDeclaration.INITIALIZER) {
605             occurrenceCount++;
606             if (fields[i].equals(fieldDeclaration)) break;
607         }
608     }
609     return ((IType) parent).getInitializer(occurrenceCount);
610 }
611 /**
612  * Create an handle for a local variable declartion (may be a local variable or type parameter).
613  */

614 protected IJavaElement createHandle(AbstractVariableDeclaration variableDeclaration, IJavaElement parent) {
615     switch (variableDeclaration.getKind()) {
616         case AbstractVariableDeclaration.LOCAL_VARIABLE:
617             return new LocalVariable((JavaElement)parent,
618                 new String JavaDoc(variableDeclaration.name),
619                 variableDeclaration.declarationSourceStart,
620                 variableDeclaration.declarationSourceEnd,
621                 variableDeclaration.sourceStart,
622                 variableDeclaration.sourceEnd,
623                 new String JavaDoc(variableDeclaration.type.resolvedType.signature())
624             );
625         case AbstractVariableDeclaration.PARAMETER:
626             return new LocalVariable((JavaElement)parent,
627                 new String JavaDoc(variableDeclaration.name),
628                 variableDeclaration.declarationSourceStart,
629                 variableDeclaration.declarationSourceEnd,
630                 variableDeclaration.sourceStart,
631                 variableDeclaration.sourceEnd,
632                 new String JavaDoc(variableDeclaration.type.resolvedType.signature())
633             );
634         case AbstractVariableDeclaration.TYPE_PARAMETER:
635             return new org.eclipse.jdt.internal.core.TypeParameter((JavaElement)parent, new String JavaDoc(variableDeclaration.name));
636     }
637     return null;
638 }
639 /*
640  * Creates hierarchy resolver if needed.
641  * Returns whether focus is visible.
642  */

643 protected boolean createHierarchyResolver(IType focusType, PossibleMatch[] possibleMatches) {
644     // cache focus type if not a possible match
645
char[][] compoundName = CharOperation.splitOn('.', focusType.getFullyQualifiedName().toCharArray());
646     boolean isPossibleMatch = false;
647     for (int i = 0, length = possibleMatches.length; i < length; i++) {
648         if (CharOperation.equals(possibleMatches[i].compoundName, compoundName)) {
649             isPossibleMatch = true;
650             break;
651         }
652     }
653     if (!isPossibleMatch) {
654         if (focusType.isBinary()) {
655             try {
656                 cacheBinaryType(focusType, null);
657             } catch (JavaModelException e) {
658                 return false;
659             }
660         } else {
661             // cache all types in the focus' compilation unit (even secondary types)
662
accept((ICompilationUnit) focusType.getCompilationUnit(), null /*TODO no access restriction*/);
663         }
664     }
665
666     // resolve focus type
667
this.hierarchyResolver = new HierarchyResolver(this.lookupEnvironment, null/*hierarchy is not going to be computed*/);
668     ReferenceBinding binding = this.hierarchyResolver.setFocusType(compoundName);
669     return binding != null && binding.isValidBinding() && (binding.tagBits & TagBits.HierarchyHasProblems) == 0;
670 }
671 /**
672  * Creates an IImportDeclaration from the given import statement
673  */

674 protected IJavaElement createImportHandle(ImportReference importRef) {
675     char[] importName = CharOperation.concatWith(importRef.getImportName(), '.');
676     if ((importRef.bits & ASTNode.OnDemand) != 0)
677         importName = CharOperation.concat(importName, ".*" .toCharArray()); //$NON-NLS-1$
678
Openable openable = this.currentPossibleMatch.openable;
679     if (openable instanceof CompilationUnit)
680         return ((CompilationUnit) openable).getImport(new String JavaDoc(importName));
681
682     // binary types do not contain import statements so just answer the top-level type as the element
683
IType binaryType = ((ClassFile) openable).getType();
684     String JavaDoc typeName = binaryType.getElementName();
685     int lastDollar = typeName.lastIndexOf('$');
686     if (lastDollar == -1) return binaryType;
687     return createTypeHandle(typeName.substring(0, lastDollar));
688 }
689 /**
690  * Creates an IImportDeclaration from the given import statement
691  */

692 protected IJavaElement createPackageDeclarationHandle(CompilationUnitDeclaration unit) {
693     if (unit.isPackageInfo()) {
694         char[] packName = CharOperation.concatWith(unit.currentPackage.getImportName(), '.');
695         Openable openable = this.currentPossibleMatch.openable;
696         if (openable instanceof CompilationUnit) {
697             return ((CompilationUnit) openable).getPackageDeclaration(new String JavaDoc(packName));
698         }
699     }
700     return createTypeHandle(new String JavaDoc(unit.getMainTypeName()));
701 }
702 /**
703  * Creates an IType from the given simple top level type name.
704  */

705 protected IType createTypeHandle(String JavaDoc simpleTypeName) {
706     Openable openable = this.currentPossibleMatch.openable;
707     if (openable instanceof CompilationUnit)
708         return ((CompilationUnit) openable).getType(simpleTypeName);
709
710     IType binaryType = ((ClassFile) openable).getType();
711     String JavaDoc binaryTypeQualifiedName = binaryType.getTypeQualifiedName();
712     if (simpleTypeName.equals(binaryTypeQualifiedName))
713         return binaryType; // answer only top-level types, sometimes the classFile is for a member/local type
714

715     // type name may be null for anonymous (see bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=164791)
716
String JavaDoc classFileName = simpleTypeName.length() == 0 ? binaryTypeQualifiedName : simpleTypeName;
717     IClassFile classFile = binaryType.getPackageFragment().getClassFile(classFileName + SuffixConstants.SUFFIX_STRING_class);
718     return classFile.getType();
719 }
720 protected boolean encloses(IJavaElement element) {
721     return element != null && this.scope.encloses(element);
722 }
723 /* (non-Javadoc)
724  * Return info about last type argument of a parameterized type reference.
725  * These info are made of concatenation of 2 int values which are respectively
726  * depth and end position of the last type argument.
727  * For example, this method will return 0x300000020 for type ref List<List<List<String>>>
728  * if end position of type reference "String" equals 32.
729  */

730 private long findLastTypeArgumentInfo(TypeReference typeRef) {
731     // Get last list of type arguments for parameterized qualified type reference
732
TypeReference lastTypeArgument = typeRef;
733     int depth = 0;
734     while (true) {
735         TypeReference[] lastTypeArguments = null;
736         if (lastTypeArgument instanceof ParameterizedQualifiedTypeReference) {
737             ParameterizedQualifiedTypeReference pqtRef = (ParameterizedQualifiedTypeReference) lastTypeArgument;
738             for (int i=pqtRef.typeArguments.length-1; i>=0 && lastTypeArguments==null; i--) {
739                 lastTypeArguments = pqtRef.typeArguments[i];
740             }
741         }
742         // Get last type argument for single type reference of last list of argument of parameterized qualified type reference
743
TypeReference last = null;
744         if (lastTypeArgument instanceof ParameterizedSingleTypeReference || lastTypeArguments != null) {
745             if (lastTypeArguments == null) {
746                 lastTypeArguments = ((ParameterizedSingleTypeReference)lastTypeArgument).typeArguments;
747             }
748             if (lastTypeArguments != null) {
749                 for (int i=lastTypeArguments.length-1; i>=0 && last==null; i++) {
750                     last = lastTypeArguments[i];
751                 }
752             }
753         }
754         if (last == null) break;
755         depth++;
756         lastTypeArgument = last;
757     }
758     // Current type reference is not parameterized. So, it is the last type argument
759
return (((long) depth) << 32) + lastTypeArgument.sourceEnd;
760 }
761 protected IBinaryType getBinaryInfo(ClassFile classFile, IResource resource) throws CoreException {
762     BinaryType binaryType = (BinaryType) classFile.getType();
763     if (classFile.isOpen())
764         return (IBinaryType) binaryType.getElementInfo(); // reuse the info from the java model cache
765

766     // create a temporary info
767
IBinaryType info;
768     try {
769         PackageFragment pkg = (PackageFragment) classFile.getParent();
770         PackageFragmentRoot root = (PackageFragmentRoot) pkg.getParent();
771         if (root.isArchive()) {
772             // class file in a jar
773
String JavaDoc classFileName = classFile.getElementName();
774             String JavaDoc classFilePath = Util.concatWith(pkg.names, classFileName, '/');
775             ZipFile JavaDoc zipFile = null;
776             try {
777                 zipFile = ((JarPackageFragmentRoot) root).getJar();
778                 info = ClassFileReader.read(zipFile, classFilePath);
779             } finally {
780                 JavaModelManager.getJavaModelManager().closeZipFile(zipFile);
781             }
782         } else {
783             // class file in a directory
784
info = Util.newClassFileReader(resource);
785         }
786         if (info == null) throw binaryType.newNotPresentException();
787         return info;
788     } catch (ClassFormatException e) {
789         //e.printStackTrace();
790
return null;
791     } catch (java.io.IOException JavaDoc e) {
792         throw new JavaModelException(e, IJavaModelStatusConstants.IO_EXCEPTION);
793     }
794 }
795 protected IType getFocusType() {
796     return this.scope instanceof HierarchyScope ? ((HierarchyScope) this.scope).focusType : null;
797 }
798 protected void getMethodBodies(CompilationUnitDeclaration unit, MatchingNodeSet nodeSet) {
799     if (unit.ignoreMethodBodies) {
800         unit.ignoreFurtherInvestigation = true;
801         return; // if initial diet parse did not work, no need to dig into method bodies.
802
}
803
804     // save existing values to restore them at the end of the parsing process
805
// see bug 47079 for more details
806
int[] oldLineEnds = this.parser.scanner.lineEnds;
807     int oldLinePtr = this.parser.scanner.linePtr;
808     
809     try {
810         CompilationResult compilationResult = unit.compilationResult;
811         this.parser.scanner.setSource(compilationResult);
812
813         if (this.parser.javadocParser.checkDocComment) {
814             char[] contents = compilationResult.compilationUnit.getContents();
815             this.parser.javadocParser.scanner.setSource(contents);
816         }
817         this.parser.nodeSet = nodeSet;
818         this.parser.parseBodies(unit);
819     } finally {
820         this.parser.nodeSet = null;
821         // this is done to prevent any side effects on the compilation unit result
822
// line separator positions array.
823
this.parser.scanner.lineEnds = oldLineEnds;
824         this.parser.scanner.linePtr = oldLinePtr;
825     }
826 }
827 protected TypeBinding getType(Object JavaDoc typeKey, char[] typeName) {
828     if (this.unitScope == null || typeName == null || typeName.length == 0) return null;
829     // Try to get binding from cache
830
Binding binding = (Binding) this.bindings.get(typeKey);
831     if (binding != null) {
832         if (binding instanceof TypeBinding && binding.isValidBinding())
833             return (TypeBinding) binding;
834         return null;
835     }
836     // Get binding from unit scope
837
char[][] compoundName = CharOperation.splitOn('.', typeName);
838     TypeBinding typeBinding = this.unitScope.getType(compoundName, compoundName.length);
839     this.bindings.put(typeKey, typeBinding);
840     return typeBinding.isValidBinding() ? typeBinding : null;
841 }
842 public MethodBinding getMethodBinding(MethodPattern methodPattern) {
843     if (this.unitScope == null) return null;
844     // Try to get binding from cache
845
Binding binding = (Binding) this.bindings.get(methodPattern);
846     if (binding != null) {
847         if (binding instanceof MethodBinding && binding.isValidBinding())
848             return (MethodBinding) binding;
849         return null;
850     }
851     // Get binding from unit scope
852
char[] typeName = PatternLocator.qualifiedPattern(methodPattern.declaringSimpleName, methodPattern.declaringQualification);
853     if (typeName == null) {
854         if (methodPattern.declaringType == null) return null;
855         typeName = methodPattern.declaringType.getFullyQualifiedName().toCharArray();
856     }
857     TypeBinding declaringTypeBinding = getType(typeName, typeName);
858     if (declaringTypeBinding != null) {
859         if (declaringTypeBinding.isArrayType()) {
860             declaringTypeBinding = declaringTypeBinding.leafComponentType();
861         }
862         if (!declaringTypeBinding.isBaseType()) {
863             char[][] parameterTypes = methodPattern.parameterSimpleNames;
864             if (parameterTypes == null) return null;
865             int paramTypeslength = parameterTypes.length;
866             ReferenceBinding referenceBinding = (ReferenceBinding) declaringTypeBinding;
867             MethodBinding[] methods = referenceBinding.getMethods(methodPattern.selector);
868             int methodsLength = methods.length;
869             TypeVariableBinding[] refTypeVariables = referenceBinding.typeVariables();
870             int typeVarLength = refTypeVariables==null ? 0 : refTypeVariables.length;
871             for (int i=0; i<methodsLength; i++) {
872                 TypeBinding[] methodParameters = methods[i].parameters;
873                 int paramLength = methodParameters==null ? 0 : methodParameters.length;
874                 TypeVariableBinding[] methodTypeVariables = methods[i].typeVariables;
875                 int methTypeVarLength = methodTypeVariables==null ? 0 : methodTypeVariables.length;
876                 boolean found = false;
877                 if (methodParameters != null && paramLength == paramTypeslength) {
878                     for (int p=0; p<paramLength; p++) {
879                         if (CharOperation.equals(methodParameters[p].sourceName(), parameterTypes[p])) {
880                             // param erasure match
881
found = true;
882                         } else {
883                             // type variable
884
found = false;
885                             if (refTypeVariables != null) {
886                                 for (int v=0; v<typeVarLength; v++) {
887                                     if (!CharOperation.equals(refTypeVariables[v].sourceName, parameterTypes[p])) {
888                                         found = false;
889                                         break;
890                                     }
891                                     found = true;
892                                 }
893                             }
894                             if (!found && methodTypeVariables != null) {
895                                 for (int v=0; v<methTypeVarLength; v++) {
896                                     if (!CharOperation.equals(methodTypeVariables[v].sourceName, parameterTypes[p])) {
897                                         found = false;
898                                         break;
899                                     }
900                                     found = true;
901                                 }
902                             }
903                             if (!found) break;
904                         }
905                     }
906                 }
907                 if (found) {
908                     this.bindings.put(methodPattern, methods[i]);
909                     return methods[i];
910                 }
911             }
912         }
913     }
914     this.bindings.put(methodPattern, new ProblemMethodBinding(methodPattern.selector, null, ProblemReasons.NotFound));
915     return null;
916 }
917 protected boolean hasAlreadyDefinedType(CompilationUnitDeclaration parsedUnit) {
918     CompilationResult result = parsedUnit.compilationResult;
919     if (result == null) return false;
920     for (int i = 0; i < result.problemCount; i++)
921         if (result.problems[i].getID() == IProblem.DuplicateTypes)
922             return true;
923     return false;
924 }
925 /**
926  * Create a new parser for the given project, as well as a lookup environment.
927  */

928 public void initialize(JavaProject project, int possibleMatchSize) throws JavaModelException {
929     // clean up name environment only if there are several possible match as it is reused
930
// when only one possible match (bug 58581)
931
if (this.nameEnvironment != null && possibleMatchSize != 1)
932         this.nameEnvironment.cleanup();
933
934     SearchableEnvironment searchableEnvironment = project.newSearchableNameEnvironment(this.workingCopies);
935     
936     // if only one possible match, a file name environment costs too much,
937
// so use the existing searchable environment which will populate the java model
938
// only for this possible match and its required types.
939
this.nameEnvironment = possibleMatchSize == 1
940         ? (INameEnvironment) searchableEnvironment
941         : (INameEnvironment) new JavaSearchNameEnvironment(project, this.workingCopies);
942
943     // create lookup environment
944
Map JavaDoc map = project.getOptions(true);
945     map.put(CompilerOptions.OPTION_TaskTags, ""); //$NON-NLS-1$
946
this.options = new CompilerOptions(map);
947     ProblemReporter problemReporter =
948         new ProblemReporter(
949             DefaultErrorHandlingPolicies.proceedWithAllProblems(),
950             this.options,
951             new DefaultProblemFactory());
952     this.lookupEnvironment = new LookupEnvironment(this, this.options, problemReporter, this.nameEnvironment);
953
954     this.parser = MatchLocatorParser.createParser(problemReporter, this);
955     
956     // basic parser needs also to be reset as project options may have changed
957
// see bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=163072
958
this.basicParser = null;
959
960     // remember project's name lookup
961
this.nameLookup = searchableEnvironment.nameLookup;
962
963     // initialize queue of units
964
this.numberOfMatches = 0;
965     this.matchesToProcess = new PossibleMatch[possibleMatchSize];
966 }
967 protected void locateMatches(JavaProject javaProject, PossibleMatch[] possibleMatches, int start, int length) throws CoreException {
968     initialize(javaProject, length);
969
970     // create and resolve binding (equivalent to beginCompilation() in Compiler)
971
boolean mustResolvePattern = ((InternalSearchPattern)this.pattern).mustResolve;
972     boolean mustResolve = mustResolvePattern;
973     this.patternLocator.mayBeGeneric = this.options.sourceLevel >= ClassFileConstants.JDK1_5;
974     boolean bindingsWereCreated = mustResolve;
975     try {
976         for (int i = start, maxUnits = start + length; i < maxUnits; i++) {
977             PossibleMatch possibleMatch = possibleMatches[i];
978             try {
979                 if (!parseAndBuildBindings(possibleMatch, mustResolvePattern)) continue;
980                 // Currently we only need to resolve over pattern flag if there's potential parameterized types
981
if (this.patternLocator.mayBeGeneric) {
982                     // If pattern does not resolve then rely on possible match node set resolution
983
// which may have been modified while locator was adding possible matches to it
984
if (!mustResolvePattern && !mustResolve) {
985                         mustResolve = possibleMatch.nodeSet.mustResolve;
986                         bindingsWereCreated = mustResolve;
987                     }
988                 } else {
989                     // Reset matching node resolution with pattern one if there's no potential parameterized type
990
// to minimize side effect on previous search behavior
991
possibleMatch.nodeSet.mustResolve = mustResolvePattern;
992                 }
993                 // possible match node resolution has been merged with pattern one, so rely on it to know
994
// whether we need to process compilation unit now or later
995
if (!possibleMatch.nodeSet.mustResolve) {
996                     if (this.progressMonitor != null) {
997                         this.progressWorked++;
998                         if ((this.progressWorked%this.progressStep)==0) this.progressMonitor.worked(this.progressStep);
999                     }
1000                    process(possibleMatch, bindingsWereCreated);
1001                    if (this.numberOfMatches>0 && this.matchesToProcess[this.numberOfMatches-1] == possibleMatch) {
1002                        // forget last possible match as it was processed
1003
this.numberOfMatches--;
1004                    }
1005                }
1006            } finally {
1007                if (!possibleMatch.nodeSet.mustResolve)
1008                    possibleMatch.cleanUp();
1009            }
1010        }
1011        if (mustResolve)
1012            this.lookupEnvironment.completeTypeBindings();
1013
1014        // create hierarchy resolver if needed
1015
IType focusType = getFocusType();
1016        if (focusType == null) {
1017            this.hierarchyResolver = null;
1018        } else if (!createHierarchyResolver(focusType, possibleMatches)) {
1019            // focus type is not visible, use the super type names instead of the bindings
1020
if (computeSuperTypeNames(focusType) == null) return;
1021        }
1022    } catch (AbortCompilation e) {
1023        bindingsWereCreated = false;
1024    }
1025
1026    if (!mustResolve) {
1027        return;
1028    }
1029    
1030    // possible match resolution
1031
for (int i = 0; i < this.numberOfMatches; i++) {
1032        if (this.progressMonitor != null && this.progressMonitor.isCanceled())
1033            throw new OperationCanceledException();
1034        PossibleMatch possibleMatch = this.matchesToProcess[i];
1035        this.matchesToProcess[i] = null; // release reference to processed possible match
1036
try {
1037            process(possibleMatch, bindingsWereCreated);
1038        } catch (AbortCompilation e) {
1039            // problem with class path: it could not find base classes
1040
// continue and try next matching openable reporting innacurate matches (since bindings will be null)
1041
bindingsWereCreated = false;
1042        } catch (JavaModelException e) {
1043            // problem with class path: it could not find base classes
1044
// continue and try next matching openable reporting innacurate matches (since bindings will be null)
1045
bindingsWereCreated = false;
1046        } finally {
1047            if (this.progressMonitor != null) {
1048                this.progressWorked++;
1049                if ((this.progressWorked%this.progressStep)==0) this.progressMonitor.worked(this.progressStep);
1050            }
1051            if (this.options.verbose)
1052                System.out.println(
1053                    Messages.bind(Messages.compilation_done,
1054                        new String JavaDoc[] {
1055                            String.valueOf(i + 1),
1056                            String.valueOf(this.numberOfMatches),
1057                            new String JavaDoc(possibleMatch.parsedUnit.getFileName())
1058                        }));
1059            // cleanup compilation unit result
1060
possibleMatch.cleanUp();
1061        }
1062    }
1063}
1064/**
1065 * Locate the matches amongst the possible matches.
1066 */

1067protected void locateMatches(JavaProject javaProject, PossibleMatchSet matchSet, int expected) throws CoreException {
1068    PossibleMatch[] possibleMatches = matchSet.getPossibleMatches(javaProject.getPackageFragmentRoots());
1069    int length = possibleMatches.length;
1070    // increase progress from duplicate matches not stored in matchSet while adding...
1071
if (this.progressMonitor != null && expected>length) {
1072        this.progressWorked += expected-length;
1073        this.progressMonitor.worked( expected-length);
1074    }
1075    // locate matches (processed matches are limited to avoid problem while using VM default memory heap size)
1076
for (int index = 0; index < length;) {
1077        int max = Math.min(MAX_AT_ONCE, length - index);
1078        locateMatches(javaProject, possibleMatches, index, max);
1079        index += max;
1080    }
1081    this.patternLocator.clear();
1082}
1083/**
1084 * Locate the matches in the given files and report them using the search requestor.
1085 */

1086public void locateMatches(SearchDocument[] searchDocuments) throws CoreException {
1087    int docsLength = searchDocuments.length;
1088    if (BasicSearchEngine.VERBOSE) {
1089        System.out.println("Locating matches in documents ["); //$NON-NLS-1$
1090
for (int i = 0; i < docsLength; i++)
1091            System.out.println("\t" + searchDocuments[i]); //$NON-NLS-1$
1092
System.out.println("]"); //$NON-NLS-1$
1093
}
1094
1095    // init infos for progress increasing
1096
int n = docsLength<1000 ? Math.min(Math.max(docsLength/200+1, 2),4) : 5 *(docsLength/1000);
1097    this.progressStep = docsLength < n ? 1 : docsLength / n; // step should not be 0
1098
this.progressWorked = 0;
1099
1100    // extract working copies
1101
ArrayList JavaDoc copies = new ArrayList JavaDoc();
1102    for (int i = 0; i < docsLength; i++) {
1103        SearchDocument document = searchDocuments[i];
1104        if (document instanceof WorkingCopyDocument) {
1105            copies.add(((WorkingCopyDocument)document).workingCopy);
1106        }
1107    }
1108    int copiesLength = copies.size();
1109    this.workingCopies = new org.eclipse.jdt.core.ICompilationUnit[copiesLength];
1110    copies.toArray(this.workingCopies);
1111
1112    JavaModelManager manager = JavaModelManager.getJavaModelManager();
1113    this.bindings = new SimpleLookupTable();
1114    try {
1115        // optimize access to zip files during search operation
1116
manager.cacheZipFiles();
1117
1118        // initialize handle factory (used as a cache of handles so as to optimize space)
1119
if (this.handleFactory == null)
1120            this.handleFactory = new HandleFactory();
1121
1122        if (this.progressMonitor != null) {
1123            this.progressMonitor.beginTask("", searchDocuments.length); //$NON-NLS-1$
1124
}
1125
1126        // initialize pattern for polymorphic search (ie. method reference pattern)
1127
this.patternLocator.initializePolymorphicSearch(this);
1128
1129        JavaProject previousJavaProject = null;
1130        PossibleMatchSet matchSet = new PossibleMatchSet();
1131        Util.sort(searchDocuments, new Util.Comparer() {
1132            public int compare(Object JavaDoc a, Object JavaDoc b) {
1133                return ((SearchDocument)a).getPath().compareTo(((SearchDocument)b).getPath());
1134            }
1135        });
1136        int displayed = 0; // progress worked displayed
1137
String JavaDoc previousPath = null;
1138        for (int i = 0; i < docsLength; i++) {
1139            if (this.progressMonitor != null && this.progressMonitor.isCanceled()) {
1140                throw new OperationCanceledException();
1141            }
1142
1143            // skip duplicate paths
1144
SearchDocument searchDocument = searchDocuments[i];
1145            searchDocuments[i] = null; // free current document
1146
String JavaDoc pathString = searchDocument.getPath();
1147            if (i > 0 && pathString.equals(previousPath)) {
1148                if (this.progressMonitor != null) {
1149                    this.progressWorked++;
1150                    if ((this.progressWorked%this.progressStep)==0) this.progressMonitor.worked(this.progressStep);
1151                }
1152                displayed++;
1153                continue;
1154            }
1155            previousPath = pathString;
1156
1157            Openable openable;
1158            org.eclipse.jdt.core.ICompilationUnit workingCopy = null;
1159            if (searchDocument instanceof WorkingCopyDocument) {
1160                workingCopy = ((WorkingCopyDocument)searchDocument).workingCopy;
1161                openable = (Openable) workingCopy;
1162            } else {
1163                openable = this.handleFactory.createOpenable(pathString, this.scope);
1164            }
1165            if (openable == null) {
1166                if (this.progressMonitor != null) {
1167                    this.progressWorked++;
1168                    if ((this.progressWorked%this.progressStep)==0) this.progressMonitor.worked(this.progressStep);
1169                }
1170                displayed++;
1171                continue; // match is outside classpath
1172
}
1173
1174            // create new parser and lookup environment if this is a new project
1175
IResource resource = null;
1176            JavaProject javaProject = (JavaProject) openable.getJavaProject();
1177            resource = workingCopy != null ? workingCopy.getResource() : openable.getResource();
1178            if (resource == null)
1179                resource = javaProject.getProject(); // case of a file in an external jar
1180
if (!javaProject.equals(previousJavaProject)) {
1181                // locate matches in previous project
1182
if (previousJavaProject != null) {
1183                    try {
1184                        locateMatches(previousJavaProject, matchSet, i-displayed);
1185                        displayed = i;
1186                    } catch (JavaModelException e) {
1187                        // problem with classpath in this project -> skip it
1188
}
1189                    matchSet.reset();
1190                }
1191                previousJavaProject = javaProject;
1192            }
1193            matchSet.add(new PossibleMatch(this, resource, openable, searchDocument, ((InternalSearchPattern) this.pattern).mustResolve));
1194        }
1195
1196        // last project
1197
if (previousJavaProject != null) {
1198            try {
1199                locateMatches(previousJavaProject, matchSet, docsLength-displayed);
1200            } catch (JavaModelException e) {
1201                // problem with classpath in last project -> ignore
1202
}
1203        }
1204
1205    } finally {
1206        if (this.progressMonitor != null)
1207            this.progressMonitor.done();
1208        if (this.nameEnvironment != null)
1209            this.nameEnvironment.cleanup();
1210        manager.flushZipFiles();
1211        this.bindings = null;
1212    }
1213}
1214/**
1215 * Locates the package declarations corresponding to this locator's pattern.
1216 */

1217public void locatePackageDeclarations(SearchParticipant participant) throws CoreException {
1218    locatePackageDeclarations(this.pattern, participant);
1219}
1220/**
1221 * Locates the package declarations corresponding to the search pattern.
1222 */

1223protected void locatePackageDeclarations(SearchPattern searchPattern, SearchParticipant participant) throws CoreException {
1224    if (searchPattern instanceof OrPattern) {
1225        SearchPattern[] patterns = ((OrPattern) searchPattern).patterns;
1226        for (int i = 0, length = patterns.length; i < length; i++)
1227            locatePackageDeclarations(patterns[i], participant);
1228    } else if (searchPattern instanceof PackageDeclarationPattern) {
1229        IJavaElement focus = ((InternalSearchPattern) searchPattern).focus;
1230        if (focus != null) {
1231            if (encloses(focus)) {
1232                SearchMatch match = new PackageDeclarationMatch(focus.getAncestor(IJavaElement.PACKAGE_FRAGMENT), SearchMatch.A_ACCURATE, -1, -1, participant, focus.getResource());
1233                report(match);
1234            }
1235            return;
1236        }
1237        PackageDeclarationPattern pkgPattern = (PackageDeclarationPattern) searchPattern;
1238        boolean isWorkspaceScope = this.scope == JavaModelManager.getJavaModelManager().getWorkspaceScope();
1239        IPath[] scopeProjectsAndJars = isWorkspaceScope ? null : this.scope.enclosingProjectsAndJars();
1240        int scopeLength = isWorkspaceScope ? 0 : scopeProjectsAndJars.length;
1241        IJavaProject[] projects = JavaModelManager.getJavaModelManager().getJavaModel().getJavaProjects();
1242        SimpleSet packages = new SimpleSet();
1243        for (int i = 0, length = projects.length; i < length; i++) {
1244            IJavaProject javaProject = projects[i];
1245            // Verify that project belongs to the scope
1246
if (!isWorkspaceScope) {
1247                boolean found = false;
1248                for (int j=0; j<scopeLength; j++) {
1249                    if (javaProject.getPath().equals(scopeProjectsAndJars[j])) {
1250                        found = true;
1251                        break;
1252                    }
1253                }
1254                if (!found) continue;
1255            }
1256            // Get all project package fragment names
1257
this.nameLookup = ((JavaProject) projects[i]).newNameLookup(this.workingCopies);
1258            IPackageFragment[] packageFragments = this.nameLookup.findPackageFragments(new String JavaDoc(pkgPattern.pkgName), false, true);
1259            int pLength = packageFragments == null ? 0 : packageFragments.length;
1260            // Report matches avoiding duplicate names
1261
for (int p=0; p<pLength; p++) {
1262                IPackageFragment fragment = packageFragments[p];
1263                if (packages.addIfNotIncluded(fragment) == null) continue;
1264                if (encloses(fragment)) {
1265                    IResource resource = fragment.getResource();
1266                    if (resource == null) // case of a file in an external jar
1267
resource = javaProject.getProject();
1268                    try {
1269                        if (encloses(fragment)) {
1270                            SearchMatch match = new PackageDeclarationMatch(fragment, SearchMatch.A_ACCURATE, -1, -1, participant, resource);
1271                            report(match);
1272                        }
1273                    } catch (JavaModelException e) {
1274                        throw e;
1275                    } catch (CoreException e) {
1276                        throw new JavaModelException(e);
1277                    }
1278                }
1279            }
1280        }
1281    }
1282}
1283//*/
1284
protected IType lookupType(ReferenceBinding typeBinding) {
1285    if (typeBinding == null) return null;
1286
1287    char[] packageName = typeBinding.qualifiedPackageName();
1288    IPackageFragment[] pkgs = this.nameLookup.findPackageFragments(
1289        (packageName == null || packageName.length == 0)
1290            ? IPackageFragment.DEFAULT_PACKAGE_NAME
1291            : new String JavaDoc(packageName),
1292        false);
1293
1294    // iterate type lookup in each package fragment
1295
char[] sourceName = typeBinding.qualifiedSourceName();
1296    String JavaDoc typeName = new String JavaDoc(sourceName);
1297    int acceptFlag = 0;
1298    if (typeBinding.isAnnotationType()) {
1299        acceptFlag = NameLookup.ACCEPT_ANNOTATIONS;
1300    } else if (typeBinding.isEnum()) {
1301        acceptFlag = NameLookup.ACCEPT_ENUMS;
1302    } else if (typeBinding.isInterface()) {
1303        acceptFlag = NameLookup.ACCEPT_INTERFACES;
1304    } else if (typeBinding.isClass()) {
1305        acceptFlag = NameLookup.ACCEPT_CLASSES;
1306    }
1307    if (pkgs != null) {
1308        for (int i = 0, length = pkgs.length; i < length; i++) {
1309            IType type = this.nameLookup.findType(typeName, pkgs[i], false, acceptFlag, true/*consider secondary types*/);
1310            if (type != null) return type;
1311        }
1312    }
1313
1314    // search inside enclosing element
1315
char[][] qualifiedName = CharOperation.splitOn('.', sourceName);
1316    int length = qualifiedName.length;
1317    if (length == 0) return null;
1318
1319    IType type = createTypeHandle(new String JavaDoc(qualifiedName[0])); // find the top-level type
1320
if (type == null) return null;
1321
1322    for (int i = 1; i < length; i++) {
1323        type = type.getType(new String JavaDoc(qualifiedName[i]));
1324        if (type == null) return null;
1325    }
1326    if (type.exists()) return type;
1327    return null;
1328}
1329public SearchMatch newDeclarationMatch(
1330        IJavaElement element,
1331        Binding binding,
1332        int accuracy,
1333        int offset,
1334        int length) {
1335    SearchParticipant participant = getParticipant();
1336    IResource resource = this.currentPossibleMatch.resource;
1337    return newDeclarationMatch(element, binding, accuracy, offset, length, participant, resource);
1338}
1339
1340public SearchMatch newDeclarationMatch(
1341        IJavaElement element,
1342        Binding binding,
1343        int accuracy,
1344        int offset,
1345        int length,
1346        SearchParticipant participant,
1347        IResource resource) {
1348    switch (element.getElementType()) {
1349        case IJavaElement.PACKAGE_FRAGMENT:
1350            return new PackageDeclarationMatch(element, accuracy, offset, length, participant, resource);
1351        case IJavaElement.TYPE:
1352            return new TypeDeclarationMatch(binding == null ? element : ((JavaElement) element).resolved(binding), accuracy, offset, length, participant, resource);
1353        case IJavaElement.FIELD:
1354            return new FieldDeclarationMatch(binding == null ? element : ((JavaElement) element).resolved(binding), accuracy, offset, length, participant, resource);
1355        case IJavaElement.METHOD:
1356            return new MethodDeclarationMatch(binding == null ? element : ((JavaElement) element).resolved(binding), accuracy, offset, length, participant, resource);
1357        case IJavaElement.LOCAL_VARIABLE:
1358            return new LocalVariableDeclarationMatch(element, accuracy, offset, length, participant, resource);
1359        case IJavaElement.PACKAGE_DECLARATION:
1360            return new PackageDeclarationMatch(element, accuracy, offset, length, participant, resource);
1361        case IJavaElement.TYPE_PARAMETER:
1362            return new TypeParameterDeclarationMatch(element, accuracy, offset, length, participant, resource);
1363        default:
1364            return null;
1365    }
1366}
1367
1368public SearchMatch newFieldReferenceMatch(
1369        IJavaElement enclosingElement,
1370        Binding enclosingBinding,
1371        int accuracy,
1372        int offset,
1373        int length,
1374        ASTNode reference) {
1375    int bits = reference.bits;
1376    boolean isCoupoundAssigned = (bits & ASTNode.IsCompoundAssigned) != 0;
1377    boolean isReadAccess = isCoupoundAssigned || (bits & ASTNode.IsStrictlyAssigned) == 0;
1378    boolean isWriteAccess = isCoupoundAssigned || (bits & ASTNode.IsStrictlyAssigned) != 0;
1379    boolean insideDocComment = (bits & ASTNode.InsideJavadoc) != 0;
1380    SearchParticipant participant = getParticipant();
1381    IResource resource = this.currentPossibleMatch.resource;
1382    if (enclosingBinding != null)
1383        enclosingElement = ((JavaElement) enclosingElement).resolved(enclosingBinding);
1384    return new FieldReferenceMatch(enclosingElement, accuracy, offset, length, isReadAccess, isWriteAccess, insideDocComment, participant, resource);
1385}
1386
1387public SearchMatch newLocalVariableReferenceMatch(
1388        IJavaElement enclosingElement,
1389        int accuracy,
1390        int offset,
1391        int length,
1392        ASTNode reference) {
1393    int bits = reference.bits;
1394    boolean isCoupoundAssigned = (bits & ASTNode.IsCompoundAssigned) != 0;
1395    boolean isReadAccess = isCoupoundAssigned || (bits & ASTNode.IsStrictlyAssigned) == 0;
1396    boolean isWriteAccess = isCoupoundAssigned || (bits & ASTNode.IsStrictlyAssigned) != 0;
1397    boolean insideDocComment = (bits & ASTNode.InsideJavadoc) != 0;
1398    SearchParticipant participant = getParticipant();
1399    IResource resource = this.currentPossibleMatch.resource;
1400    return new LocalVariableReferenceMatch(enclosingElement, accuracy, offset, length, isReadAccess, isWriteAccess, insideDocComment, participant, resource);
1401}
1402
1403public SearchMatch newMethodReferenceMatch(
1404        IJavaElement enclosingElement,
1405        Binding enclosingBinding,
1406        int accuracy,
1407        int offset,
1408        int length,
1409        boolean isConstructor,
1410        boolean isSynthetic,
1411        ASTNode reference) {
1412    SearchParticipant participant = getParticipant();
1413    IResource resource = this.currentPossibleMatch.resource;
1414    boolean insideDocComment = (reference.bits & ASTNode.InsideJavadoc) != 0;
1415    if (enclosingBinding != null)
1416        enclosingElement = ((JavaElement) enclosingElement).resolved(enclosingBinding);
1417    boolean isOverridden = (accuracy & PatternLocator.SUPER_INVOCATION_FLAVOR) != 0;
1418    return new MethodReferenceMatch(enclosingElement, accuracy, offset, length, isConstructor, isSynthetic, isOverridden, insideDocComment, participant, resource);
1419}
1420
1421public SearchMatch newPackageReferenceMatch(
1422        IJavaElement enclosingElement,
1423        int accuracy,
1424        int offset,
1425        int length,
1426        ASTNode reference) {
1427    SearchParticipant participant = getParticipant();
1428    IResource resource = this.currentPossibleMatch.resource;
1429    boolean insideDocComment = (reference.bits & ASTNode.InsideJavadoc) != 0;
1430    return new PackageReferenceMatch(enclosingElement, accuracy, offset, length, insideDocComment, participant, resource);
1431}
1432
1433public SearchMatch newTypeParameterReferenceMatch(
1434        IJavaElement enclosingElement,
1435        int accuracy,
1436        int offset,
1437        int length,
1438        ASTNode reference) {
1439    int bits = reference.bits;
1440    boolean insideDocComment = (bits & ASTNode.InsideJavadoc) != 0;
1441    SearchParticipant participant = getParticipant();
1442    IResource resource = this.currentPossibleMatch.resource;
1443    return new TypeParameterReferenceMatch(enclosingElement, accuracy, offset, length, insideDocComment, participant, resource);
1444}
1445
1446public TypeReferenceMatch newTypeReferenceMatch(
1447        IJavaElement enclosingElement,
1448        Binding enclosingBinding,
1449        int accuracy,
1450        int offset,
1451        int length,
1452        ASTNode reference) {
1453    SearchParticipant participant = getParticipant();
1454    IResource resource = this.currentPossibleMatch.resource;
1455    boolean insideDocComment = (reference.bits & ASTNode.InsideJavadoc) != 0;
1456    if (enclosingBinding != null)
1457        enclosingElement = ((JavaElement) enclosingElement).resolved(enclosingBinding);
1458    return new TypeReferenceMatch(enclosingElement, accuracy, offset, length, insideDocComment, participant, resource);
1459}
1460
1461public TypeReferenceMatch newTypeReferenceMatch(
1462        IJavaElement enclosingElement,
1463        Binding enclosingBinding,
1464        int accuracy,
1465        ASTNode reference) {
1466    return newTypeReferenceMatch(enclosingElement, enclosingBinding, accuracy, reference.sourceStart, reference.sourceEnd-reference.sourceStart+1, reference);
1467}
1468
1469/**
1470 * Add the possibleMatch to the loop
1471 * -> build compilation unit declarations, their bindings and record their results.
1472 */

1473protected boolean parseAndBuildBindings(PossibleMatch possibleMatch, boolean mustResolve) throws CoreException {
1474    if (this.progressMonitor != null && this.progressMonitor.isCanceled())
1475        throw new OperationCanceledException();
1476
1477    try {
1478        if (BasicSearchEngine.VERBOSE)
1479            System.out.println("Parsing " + possibleMatch.openable.toStringWithAncestors()); //$NON-NLS-1$
1480

1481        this.parser.nodeSet = possibleMatch.nodeSet;
1482        CompilationResult unitResult = new CompilationResult(possibleMatch, 1, 1, this.options.maxProblemsPerUnit);
1483        CompilationUnitDeclaration parsedUnit = this.parser.dietParse(possibleMatch, unitResult);
1484        if (parsedUnit != null) {
1485            if (!parsedUnit.isEmpty()) {
1486                if (mustResolve) {
1487                    this.lookupEnvironment.buildTypeBindings(parsedUnit, null /*no access restriction*/);
1488                }
1489                if (hasAlreadyDefinedType(parsedUnit)) return false; // skip type has it is hidden so not visible
1490
getMethodBodies(parsedUnit, possibleMatch.nodeSet);
1491                if (this.patternLocator.mayBeGeneric && !mustResolve && possibleMatch.nodeSet.mustResolve) {
1492                    // special case: possible match node set force resolution although pattern does not
1493
// => we need to build types for this compilation unit
1494
this.lookupEnvironment.buildTypeBindings(parsedUnit, null /*no access restriction*/);
1495                }
1496            }
1497    
1498            // add the possibleMatch with its parsedUnit to matchesToProcess
1499
possibleMatch.parsedUnit = parsedUnit;
1500            int size = this.matchesToProcess.length;
1501            if (this.numberOfMatches == size)
1502                System.arraycopy(this.matchesToProcess, 0, this.matchesToProcess = new PossibleMatch[size == 0 ? 1 : size * 2], 0, this.numberOfMatches);
1503            this.matchesToProcess[this.numberOfMatches++] = possibleMatch;
1504        }
1505    } finally {
1506        this.parser.nodeSet = null;
1507    }
1508    return true;
1509}
1510/*
1511 * Process a compilation unit already parsed and build.
1512 */

1513protected void process(PossibleMatch possibleMatch, boolean bindingsWereCreated) throws CoreException {
1514    this.currentPossibleMatch = possibleMatch;
1515    CompilationUnitDeclaration unit = possibleMatch.parsedUnit;
1516    try {
1517        if (unit.isEmpty()) {
1518            if (this.currentPossibleMatch.openable instanceof ClassFile) {
1519                ClassFile classFile = (ClassFile) this.currentPossibleMatch.openable;
1520                IBinaryType info = getBinaryInfo(classFile, this.currentPossibleMatch.resource);
1521                if (info != null) {
1522                    boolean mayBeGeneric = this.patternLocator.mayBeGeneric;
1523                    this.patternLocator.mayBeGeneric = false; // there's no longer generics in class files
1524
try {
1525                        new ClassFileMatchLocator().locateMatches(this, classFile, info);
1526                    }
1527                    finally {
1528                        this.patternLocator.mayBeGeneric = mayBeGeneric;
1529                    }
1530                }
1531            }
1532            return;
1533        }
1534        if (hasAlreadyDefinedType(unit)) return; // skip type has it is hidden so not visible
1535

1536        // Move getMethodBodies to #parseAndBuildings(...) method to allow possible match resolution management
1537
//getMethodBodies(unit);
1538

1539        boolean mustResolve = (((InternalSearchPattern)this.pattern).mustResolve || possibleMatch.nodeSet.mustResolve);
1540        if (bindingsWereCreated && mustResolve) {
1541            if (unit.types != null) {
1542                if (BasicSearchEngine.VERBOSE)
1543                    System.out.println("Resolving " + this.currentPossibleMatch.openable.toStringWithAncestors()); //$NON-NLS-1$
1544

1545                this.lookupEnvironment.unitBeingCompleted = unit;
1546                reduceParseTree(unit);
1547    
1548                if (unit.scope != null) {
1549                    // fault in fields & methods
1550
unit.scope.faultInTypes();
1551                }
1552                unit.resolve();
1553            } else if (unit.isPackageInfo()) {
1554                if (BasicSearchEngine.VERBOSE)
1555                    System.out.println("Resolving " + this.currentPossibleMatch.openable.toStringWithAncestors()); //$NON-NLS-1$
1556
unit.resolve();
1557            }
1558        }
1559        reportMatching(unit, mustResolve);
1560    } catch (AbortCompilation e) {
1561        // could not resolve: report inaccurate matches
1562
reportMatching(unit, false); // do not resolve when cu has errors
1563
if (!(e instanceof AbortCompilationUnit)) {
1564            // problem with class path
1565
throw e;
1566        }
1567    } finally {
1568        this.lookupEnvironment.unitBeingCompleted = null;
1569        this.currentPossibleMatch = null;
1570    }
1571}
1572protected void purgeMethodStatements(TypeDeclaration type, boolean checkEachMethod) {
1573    checkEachMethod = checkEachMethod
1574        && this.currentPossibleMatch.nodeSet.hasPossibleNodes(type.declarationSourceStart, type.declarationSourceEnd);
1575    AbstractMethodDeclaration[] methods = type.methods;
1576    if (methods != null) {
1577        if (checkEachMethod) {
1578            for (int j = 0, length = methods.length; j < length; j++) {
1579                AbstractMethodDeclaration method = methods[j];
1580                if (!this.currentPossibleMatch.nodeSet.hasPossibleNodes(method.declarationSourceStart, method.declarationSourceEnd)) {
1581                    method.statements = null;
1582                    method.javadoc = null;
1583                }
1584            }
1585        } else {
1586            for (int j = 0, length = methods.length; j < length; j++) {
1587                methods[j].statements = null;
1588                methods[j].javadoc = null;
1589            }
1590        }
1591    }
1592
1593    TypeDeclaration[] memberTypes = type.memberTypes;
1594    if (memberTypes != null)
1595        for (int i = 0, l = memberTypes.length; i < l; i++)
1596            purgeMethodStatements(memberTypes[i], checkEachMethod);
1597}
1598/**
1599 * Called prior to the unit being resolved. Reduce the parse tree where possible.
1600 */

1601protected void reduceParseTree(CompilationUnitDeclaration unit) {
1602    // remove statements from methods that have no possible matching nodes
1603
TypeDeclaration[] types = unit.types;
1604    for (int i = 0, l = types.length; i < l; i++)
1605        purgeMethodStatements(types[i], true);
1606}
1607public SearchParticipant getParticipant() {
1608    return this.currentPossibleMatch.document.getParticipant();
1609}
1610
1611protected void report(SearchMatch match) throws CoreException {
1612    long start = -1;
1613    if (BasicSearchEngine.VERBOSE) {
1614        start = System.currentTimeMillis();
1615        System.out.println("Reporting match"); //$NON-NLS-1$
1616
System.out.println("\tResource: " + match.getResource());//$NON-NLS-1$
1617
System.out.println("\tPositions: [offset=" + match.getOffset() + ", length=" + match.getLength() + "]"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
1618
try {
1619            if (this.parser != null && match.getOffset() > 0 && match.getLength() > 0 && !(match.getElement() instanceof BinaryMember)) {
1620                String JavaDoc selection = new String JavaDoc(this.parser.scanner.source, match.getOffset(), match.getLength());
1621                System.out.println("\tSelection: -->" + selection + "<--"); //$NON-NLS-1$ //$NON-NLS-2$
1622
}
1623        } catch (Exception JavaDoc e) {
1624            // it's just for debug purposes... ignore all exceptions in this area
1625
}
1626        try {
1627            JavaElement javaElement = (JavaElement)match.getElement();
1628            System.out.println("\tJava element: "+ javaElement.toStringWithAncestors()); //$NON-NLS-1$
1629
if (!javaElement.exists()) {
1630                System.out.println("\t\tWARNING: this element does NOT exist!"); //$NON-NLS-1$
1631
}
1632        } catch (Exception JavaDoc e) {
1633            // it's just for debug purposes... ignore all exceptions in this area
1634
}
1635        if (match instanceof TypeReferenceMatch) {
1636            try {
1637                TypeReferenceMatch typeRefMatch = (TypeReferenceMatch) match;
1638                JavaElement local = (JavaElement) typeRefMatch.getLocalElement();
1639                if (local != null) {
1640                    System.out.println("\tLocal element: "+ local.toStringWithAncestors()); //$NON-NLS-1$
1641
}
1642                IJavaElement[] others = typeRefMatch.getOtherElements();
1643                if (others != null) {
1644                    int length = others.length;
1645                    if (length > 0) {
1646                        System.out.println("\tOther elements:"); //$NON-NLS-1$
1647
for (int i=0; i<length; i++) {
1648                            JavaElement other = (JavaElement) others[i];
1649                            System.out.println("\t\t- "+ other.toStringWithAncestors()); //$NON-NLS-1$
1650
}
1651                    }
1652                }
1653            } catch (Exception JavaDoc e) {
1654                // it's just for debug purposes... ignore all exceptions in this area
1655
}
1656        }
1657        System.out.println(match.getAccuracy() == SearchMatch.A_ACCURATE
1658            ? "\tAccuracy: EXACT_MATCH" //$NON-NLS-1$
1659
: "\tAccuracy: POTENTIAL_MATCH"); //$NON-NLS-1$
1660
System.out.print("\tRule: "); //$NON-NLS-1$
1661
if (match.isExact()) {
1662            System.out.print("EXACT"); //$NON-NLS-1$
1663
} else if (match.isEquivalent()) {
1664            System.out.print("EQUIVALENT"); //$NON-NLS-1$
1665
} else if (match.isErasure()) {
1666            System.out.print("ERASURE"); //$NON-NLS-1$
1667
} else {
1668            System.out.print("INVALID RULE"); //$NON-NLS-1$
1669
}
1670        if (match instanceof MethodReferenceMatch) {
1671            MethodReferenceMatch methodReferenceMatch = (MethodReferenceMatch) match;
1672            if (methodReferenceMatch.isSuperInvocation()) {
1673                System.out.print("+SUPER INVOCATION"); //$NON-NLS-1$
1674
}
1675            if (methodReferenceMatch.isImplicit()) {
1676                System.out.print("+IMPLICIT"); //$NON-NLS-1$
1677
}
1678            if (methodReferenceMatch.isSynthetic()) {
1679                System.out.print("+SYNTHETIC"); //$NON-NLS-1$
1680
}
1681        }
1682        System.out.println("\n\tRaw: "+match.isRaw()); //$NON-NLS-1$
1683
}
1684    this.requestor.acceptSearchMatch(match);
1685    if (BasicSearchEngine.VERBOSE)
1686        this.resultCollectorTime += System.currentTimeMillis()-start;
1687}
1688/**
1689 * Finds the accurate positions of the sequence of tokens given by qualifiedName
1690 * in the source and reports a reference to this this qualified name
1691 * to the search requestor.
1692 */

1693protected void reportAccurateTypeReference(SearchMatch match, ASTNode typeRef, char[] name) throws CoreException {
1694    if (match.getRule() == 0) return;
1695    if (!encloses((IJavaElement)match.getElement())) return;
1696    
1697    // Compute source positions of the qualified reference
1698
int sourceStart = typeRef.sourceStart;
1699    int sourceEnd = typeRef.sourceEnd;
1700    Scanner scanner = this.parser.scanner;
1701    scanner.setSource(this.currentPossibleMatch.getContents());
1702    scanner.resetTo(sourceStart, sourceEnd);
1703
1704    int token = -1;
1705    int currentPosition;
1706    do {
1707        currentPosition = scanner.currentPosition;
1708        try {
1709            token = scanner.getNextToken();
1710        } catch (InvalidInputException e) {
1711            // ignore
1712
}
1713        if (token == TerminalTokens.TokenNameIdentifier && this.pattern.matchesName(name, scanner.getCurrentTokenSource())) {
1714            int length = scanner.currentPosition-currentPosition;
1715            match.setOffset(currentPosition);
1716            match.setLength(length);
1717            report(match);
1718            return;
1719        }
1720    } while (token != TerminalTokens.TokenNameEOF);
1721
1722    // Report match
1723
match.setOffset(sourceStart);
1724    match.setLength(sourceEnd-sourceStart+1);
1725    report(match);
1726}
1727
1728/**
1729 * Finds the accurate positions of the sequence of tokens given by qualifiedName
1730 * in the source and reports a reference to this parameterized type name
1731 * to the search requestor.
1732 * @since 3.1
1733 */

1734protected void reportAccurateParameterizedMethodReference(SearchMatch match, ASTNode statement, TypeReference[] typeArguments) throws CoreException {
1735    if (match.getRule() == 0) return;
1736    if (!encloses((IJavaElement)match.getElement())) return;
1737
1738    // If there's type arguments, look for end (ie. char '>') of last one.
1739
int start = match.getOffset();
1740    if (typeArguments != null && typeArguments.length > 0) {
1741        boolean isErasureMatch= (pattern instanceof OrPattern) ? ((OrPattern)pattern).isErasureMatch() : ((JavaSearchPattern)pattern).isErasureMatch();
1742        if (!isErasureMatch) {
1743            
1744            // Initialize scanner
1745
Scanner scanner = this.parser.scanner;
1746            char[] source = this.currentPossibleMatch.getContents();
1747            scanner.setSource(source);
1748
1749            // Search previous opening '<'
1750
start = typeArguments[0].sourceStart;
1751            int end = statement.sourceEnd;
1752            scanner.resetTo(start, end);
1753            int lineStart = start;
1754            try {
1755                linesUp: while (true) {
1756                    while (scanner.source[scanner.currentPosition] != '\n') {
1757                        scanner.currentPosition--;
1758                        if (scanner.currentPosition == 0) break linesUp;
1759                    }
1760                    lineStart = scanner.currentPosition+1;
1761                    scanner.resetTo(lineStart, end);
1762                    while (!scanner.atEnd()) {
1763                        if (scanner.getNextToken() == TerminalTokens.TokenNameLESS) {
1764                            start = scanner.getCurrentTokenStartPosition();
1765                            break linesUp;
1766                        }
1767                    }
1768                    end = lineStart - 2;
1769                    scanner.currentPosition = end;
1770                }
1771            }
1772            catch (InvalidInputException ex) {
1773                // give up
1774
}
1775        }
1776    }
1777    
1778    // Report match
1779
match.setOffset(start);
1780    match.setLength(statement.sourceEnd-start+1);
1781    report(match);
1782}
1783
1784/**
1785 * Finds the accurate positions of the sequence of tokens given by qualifiedName
1786 * in the source and reports a reference to this parameterized type name
1787 * to the search requestor.
1788 * @since 3.1
1789 */

1790protected void reportAccurateParameterizedTypeReference(SearchMatch match, TypeReference typeRef, int index, TypeReference[] typeArguments) throws CoreException {
1791    if (match.getRule() == 0) return;
1792    if (!encloses((IJavaElement)match.getElement())) return;
1793
1794    // If there's type arguments, look for end (ie. char '>') of last one.
1795
int end = typeRef.sourceEnd;
1796    if (typeArguments != null) {
1797        // Initialize scanner
1798
Scanner scanner = this.parser.scanner;
1799        char[] source = this.currentPossibleMatch.getContents();
1800        scanner.setSource(source);
1801
1802        boolean shouldMatchErasure= (pattern instanceof OrPattern) ? ((OrPattern)pattern).isErasureMatch() : ((JavaSearchPattern)pattern).isErasureMatch();
1803        boolean hasSignatures = (pattern instanceof OrPattern) ? ((OrPattern)pattern).hasSignatures() : ((JavaSearchPattern)pattern).hasSignatures();
1804        if (shouldMatchErasure || !hasSignatures) {
1805            // if pattern is erasure only, then select the end of the reference
1806
if (typeRef instanceof QualifiedTypeReference && index >= 0) {
1807                long[] positions = ((QualifiedTypeReference) typeRef).sourcePositions;
1808                end = (int) positions[index];
1809            } else if (typeRef instanceof ArrayTypeReference) {
1810                end = ((ArrayTypeReference) typeRef).originalSourceEnd;
1811            }
1812        } else {
1813            // Set scanner position at end of last type argument
1814
scanner.resetTo(end, source.length-1);
1815            int depth = 0;
1816            for (int i=typeArguments.length-1; i>=0; i--) {
1817                if (typeArguments[i] != null) {
1818                    long lastTypeArgInfo = findLastTypeArgumentInfo(typeArguments[i]);
1819                    depth = (int) (lastTypeArgInfo >>> 32)+1;
1820                    scanner.resetTo(((int)lastTypeArgInfo)+1, scanner.eofPosition-1);
1821                    break;
1822                }
1823            }
1824    
1825            // Now, scan to search next closing '>'
1826
while (depth-- > 0) {
1827                while (!scanner.atEnd()) {
1828                    if (scanner.getNextChar() == '>') {
1829                        end = scanner.currentPosition - 1;
1830                        break;
1831                    }
1832                }
1833            }
1834        }
1835    }
1836    
1837    // Report match
1838
match.setLength(end-match.getOffset()+1);
1839    report(match);
1840}
1841/**
1842 * Finds the accurate positions of each valid token in the source and
1843 * reports a reference to this token to the search requestor.
1844 * A token is valid if it has an accuracy which is not -1.
1845 */

1846protected void reportAccurateEnumConstructorReference(SearchMatch match, FieldDeclaration field, AllocationExpression allocation) throws CoreException {
1847    // Verify that field declaration is really an enum constant
1848
if (allocation == null || allocation.enumConstant == null) {
1849        report(match);
1850        return;
1851    }
1852
1853    // Get scan area
1854
int sourceStart = match.getOffset()+match.getLength();
1855    if (allocation.arguments != null && allocation.arguments.length > 0) {
1856        sourceStart = allocation.arguments[allocation.arguments.length-1].sourceEnd+1;
1857    }
1858    int sourceEnd = field.declarationSourceEnd;
1859    if (allocation instanceof QualifiedAllocationExpression) {
1860        QualifiedAllocationExpression qualifiedAllocation = (QualifiedAllocationExpression) allocation;
1861        if (qualifiedAllocation.anonymousType != null) {
1862            sourceEnd = qualifiedAllocation.anonymousType.sourceStart - 1;
1863        }
1864    }
1865    
1866    // Scan to find last closing parenthesis
1867
Scanner scanner = this.parser.scanner;
1868    scanner.setSource(this.currentPossibleMatch.getContents());
1869    scanner.resetTo(sourceStart, sourceEnd);
1870    try {
1871        int token = scanner.getNextToken();
1872        while (token != TerminalTokens.TokenNameEOF) {
1873            if (token == TerminalTokens.TokenNameRPAREN) {
1874                sourceEnd = scanner.getCurrentTokenEndPosition();
1875            }
1876            token = scanner.getNextToken();
1877        }
1878    }
1879    catch (InvalidInputException iie) {
1880        // give up
1881
}
1882
1883    // Report match
1884
match.setLength(sourceEnd-match.getOffset()+1);
1885    report(match);
1886}
1887/**
1888 * Finds the accurate positions of each valid token in the source and
1889 * reports a reference to this token to the search requestor.
1890 * A token is valid if it has an accuracy which is not -1.
1891 */

1892protected void reportAccurateFieldReference(SearchMatch[] matches, QualifiedNameReference qNameRef) throws CoreException {
1893    if (matches == null) return; // there's nothing to accurate in this case
1894
int matchesLength = matches.length;
1895
1896    int sourceStart = qNameRef.sourceStart;
1897    int sourceEnd = qNameRef.sourceEnd;
1898    char[][] tokens = qNameRef.tokens;
1899    
1900    // compute source positions of the qualified reference
1901
Scanner scanner = this.parser.scanner;
1902    scanner.setSource(this.currentPossibleMatch.getContents());
1903    scanner.resetTo(sourceStart, sourceEnd);
1904    int sourceLength = sourceEnd-sourceStart+1;
1905
1906    int refSourceStart = -1, refSourceEnd = -1;
1907    int length = tokens.length;
1908    int token = -1;
1909    int previousValid = -1;
1910    int i = 0;
1911    int index = 0;
1912    do {
1913        int currentPosition = scanner.currentPosition;
1914        // read token
1915
try {
1916            token = scanner.getNextToken();
1917        } catch (InvalidInputException e) {
1918            //ignore
1919
}
1920        if (token != TerminalTokens.TokenNameEOF) {
1921            char[] currentTokenSource = scanner.getCurrentTokenSource();
1922            boolean equals = false;
1923            while (i < length && !(equals = this.pattern.matchesName(tokens[i++], currentTokenSource))){/*empty*/}
1924            if (equals && (previousValid == -1 || previousValid == i - 2)) {
1925                previousValid = i - 1;
1926                if (refSourceStart == -1)
1927                    refSourceStart = currentPosition;
1928                refSourceEnd = scanner.currentPosition - 1;
1929            } else {
1930                i = 0;
1931                refSourceStart = -1;
1932                previousValid = -1;
1933            }
1934            // read '.'
1935
try {
1936                token = scanner.getNextToken();
1937            } catch (InvalidInputException e) {
1938                // ignore
1939
}
1940        }
1941        SearchMatch match = matches[index];
1942        if (match != null && match.getRule() != 0) {
1943            if (!encloses((IJavaElement)match.getElement())) return;
1944            // accept reference
1945
if (refSourceStart != -1) {
1946                match.setOffset(refSourceStart);
1947                match.setLength(refSourceEnd-refSourceStart+1);
1948                report(match);
1949            } else {
1950                match.setOffset(sourceStart);
1951                match.setLength(sourceLength);
1952                report(match);
1953            }
1954            i = 0;
1955        }
1956        refSourceStart = -1;
1957        previousValid = -1;
1958        if (index < matchesLength - 1) {
1959            index++;
1960        }
1961    } while (token != TerminalTokens.TokenNameEOF);
1962
1963}
1964protected void reportBinaryMemberDeclaration(IResource resource, IMember binaryMember, Binding binaryMemberBinding, IBinaryType info, int accuracy) throws CoreException {
1965    ClassFile classFile = (ClassFile) binaryMember.getClassFile();
1966    ISourceRange range = classFile.isOpen() ? binaryMember.getNameRange() : SourceMapper.UNKNOWN_RANGE;
1967    if (range.getOffset() == -1) {
1968        BinaryType type = (BinaryType) classFile.getType();
1969        String JavaDoc sourceFileName = type.sourceFileName(info);
1970        if (sourceFileName != null) {
1971            SourceMapper mapper = classFile.getSourceMapper();
1972            if (mapper != null) {
1973                char[] contents = mapper.findSource(type, sourceFileName);
1974                if (contents != null)
1975                    range = mapper.mapSource(type, contents, info, binaryMember);
1976            }
1977        }
1978    }
1979    if (resource == null) resource = this.currentPossibleMatch.resource;
1980    SearchMatch match = newDeclarationMatch(binaryMember, binaryMemberBinding, accuracy, range.getOffset(), range.getLength(), getParticipant(), resource);
1981    report(match);
1982}
1983/**
1984 * Visit the given method declaration and report the nodes that match exactly the
1985 * search pattern (ie. the ones in the matching nodes set)
1986 * Note that the method declaration has already been checked.
1987 */

1988protected void reportMatching(TypeDeclaration type, AbstractMethodDeclaration method, IJavaElement parent, int accuracy, boolean typeInHierarchy, MatchingNodeSet nodeSet) throws CoreException {
1989    IJavaElement enclosingElement = null;
1990    if (accuracy > -1) {
1991        enclosingElement = createHandle(method, parent);
1992        if (enclosingElement != null) { // skip if unable to find method
1993
// compute source positions of the selector
1994
Scanner scanner = parser.scanner;
1995            int nameSourceStart = method.sourceStart;
1996            scanner.setSource(this.currentPossibleMatch.getContents());
1997            scanner.resetTo(nameSourceStart, method.sourceEnd);
1998            try {
1999                scanner.getNextToken();
2000            } catch (InvalidInputException e) {
2001                // ignore
2002
}
2003            if (encloses(enclosingElement)) {
2004                SearchMatch match = null;
2005                if (method.isDefaultConstructor()) {
2006                    // Use type for match associated element as default constructor does not exist in source
2007
int offset = type.sourceStart;
2008                    match = this.patternLocator.newDeclarationMatch(type, parent, type.binding, accuracy, type.sourceEnd-offset+1, this);
2009                } else {
2010                    int length = scanner.currentPosition - nameSourceStart;
2011                    match = this.patternLocator.newDeclarationMatch(method, enclosingElement, method.binding, accuracy, length, this);
2012                }
2013                if (match != null) {
2014                    report(match);
2015                }
2016            }
2017        }
2018    }
2019
2020    // handle nodes for the local type first
2021
if ((method.bits & ASTNode.HasLocalType) != 0) {
2022        if (enclosingElement == null)
2023            enclosingElement = createHandle(method, parent);
2024        LocalDeclarationVisitor localDeclarationVisitor = new LocalDeclarationVisitor(enclosingElement, method.binding, nodeSet);
2025        try {
2026            method.traverse(localDeclarationVisitor, (ClassScope) null);
2027        } catch (WrappedCoreException e) {
2028            throw e.coreException;
2029        }
2030    }
2031
2032    // report the type parameters
2033
TypeParameter[] typeParameters = method.typeParameters();
2034    if (typeParameters != null) {
2035        if (enclosingElement == null) {
2036            enclosingElement = createHandle(method, parent);
2037        }
2038        reportMatching(typeParameters, enclosingElement, parent, method.binding, nodeSet);
2039    }
2040
2041    // report annotations
2042
if (method.annotations != null) {
2043        if (enclosingElement == null) {
2044            enclosingElement = createHandle(method, parent);
2045        }
2046        reportMatching(method.annotations, enclosingElement, method.binding, nodeSet, true, true);
2047    }
2048
2049    // references in this method
2050
if (typeInHierarchy) {
2051        ASTNode[] nodes = nodeSet.matchingNodes(method.declarationSourceStart, method.declarationSourceEnd);
2052        if (nodes != null) {
2053            if ((this.matchContainer & PatternLocator.METHOD_CONTAINER) != 0) {
2054                if (enclosingElement == null)
2055                    enclosingElement = createHandle(method, parent);
2056                if (encloses(enclosingElement)) {
2057                    for (int i = 0, l = nodes.length; i < l; i++) {
2058                        ASTNode node = nodes[i];
2059                        Integer JavaDoc level = (Integer JavaDoc) nodeSet.matchingNodes.removeKey(node);
2060                        this.patternLocator.matchReportReference(node, enclosingElement, method.binding, method.scope, level.intValue(), this);
2061                    }
2062                    return;
2063                }
2064            }
2065            for (int i = 0, l = nodes.length; i < l; i++)
2066                nodeSet.matchingNodes.removeKey(nodes[i]);
2067        }
2068    }
2069}
2070/**
2071 * Report matching in annotations.
2072 */

2073protected void reportMatching(Annotation[] annotations, IJavaElement enclosingElement, Binding elementBinding, MatchingNodeSet nodeSet, boolean matchedContainer, boolean enclosesElement) throws CoreException {
2074    for (int i=0, al=annotations.length; i<al; i++) {
2075        Annotation annotationType = annotations[i];
2076
2077        // Look for annotation type ref
2078
TypeReference typeRef = annotationType.type;
2079        Integer JavaDoc level = (Integer JavaDoc) nodeSet.matchingNodes.removeKey(typeRef);
2080        if (level != null && matchedContainer) {
2081            this.patternLocator.matchReportReference(typeRef, enclosingElement, elementBinding, level.intValue(), this);
2082        }
2083        
2084        // Look for attribute ref
2085
MemberValuePair[] pairs = annotationType.memberValuePairs();
2086        for (int j = 0, pl = pairs.length; j < pl; j++) {
2087            MemberValuePair pair = pairs[j];
2088            level = (Integer JavaDoc) nodeSet.matchingNodes.removeKey(pair);
2089            if (level != null && enclosesElement) {
2090                ASTNode reference = (annotationType instanceof SingleMemberAnnotation) ? (ASTNode) annotationType: pair;
2091                this.patternLocator.matchReportReference(reference, enclosingElement, pair.binding, level.intValue(), this);
2092            }
2093        }
2094        
2095        // Look for reference inside annotation
2096
ASTNode[] nodes = nodeSet.matchingNodes(annotationType.sourceStart, annotationType.declarationSourceEnd);
2097        if (nodes != null) {
2098            if (!matchedContainer) {
2099                for (int j = 0, nl = nodes.length; j < nl; j++) {
2100                    nodeSet.matchingNodes.removeKey(nodes[j]);
2101                }
2102            } else {
2103                for (int j = 0, nl = nodes.length; j < nl; j++) {
2104                    ASTNode node = nodes[j];
2105                    level = (Integer JavaDoc) nodeSet.matchingNodes.removeKey(node);
2106                    if (enclosesElement) {
2107                        this.patternLocator.matchReportReference(node, enclosingElement, elementBinding, level.intValue(), this);
2108                    }
2109                }
2110            }
2111        }
2112    }
2113}
2114/**
2115 * Visit the given resolved parse tree and report the nodes that match the search pattern.
2116 */

2117protected void reportMatching(CompilationUnitDeclaration unit, boolean mustResolve) throws CoreException {
2118    MatchingNodeSet nodeSet = this.currentPossibleMatch.nodeSet;
2119    boolean locatorMustResolve = this.patternLocator.mustResolve;
2120    if (nodeSet.mustResolve) this.patternLocator.mustResolve = true;
2121    if (BasicSearchEngine.VERBOSE) {
2122        System.out.println("Report matching: "); //$NON-NLS-1$
2123
int size = nodeSet.matchingNodes==null ? 0 : nodeSet.matchingNodes.elementSize;
2124        System.out.print(" - node set: accurate="+ size); //$NON-NLS-1$
2125
size = nodeSet.possibleMatchingNodesSet==null ? 0 : nodeSet.possibleMatchingNodesSet.elementSize;
2126        System.out.println(", possible="+size); //$NON-NLS-1$
2127
System.out.print(" - must resolve: "+mustResolve); //$NON-NLS-1$
2128
System.out.print(" (locator: "+this.patternLocator.mustResolve); //$NON-NLS-1$
2129
System.out.println(", nodeSet: "+nodeSet.mustResolve+')'); //$NON-NLS-1$
2130
}
2131    if (mustResolve) {
2132        this.unitScope= unit.scope.compilationUnitScope();
2133        // move the possible matching nodes that exactly match the search pattern to the matching nodes set
2134
Object JavaDoc[] nodes = nodeSet.possibleMatchingNodesSet.values;
2135        for (int i = 0, l = nodes.length; i < l; i++) {
2136            ASTNode node = (ASTNode) nodes[i];
2137            if (node == null) continue;
2138            if (node instanceof ImportReference) {
2139                // special case for import refs: they don't know their binding
2140
// import ref cannot be in the hierarchy of a type
2141
if (this.hierarchyResolver != null) continue;
2142
2143                ImportReference importRef = (ImportReference) node;
2144                Binding binding = (importRef.bits & ASTNode.OnDemand) != 0
2145                    ? unitScope.getImport(CharOperation.subarray(importRef.tokens, 0, importRef.tokens.length), true, importRef.isStatic())
2146                    : unitScope.getImport(importRef.tokens, false, importRef.isStatic());
2147                this.patternLocator.matchLevelAndReportImportRef(importRef, binding, this);
2148            }
2149            nodeSet.addMatch(node, this.patternLocator.resolveLevel(node));
2150        }
2151        nodeSet.possibleMatchingNodesSet = new SimpleSet(3);
2152        if (BasicSearchEngine.VERBOSE) {
2153            int size = nodeSet.matchingNodes==null ? 0 : nodeSet.matchingNodes.elementSize;
2154            System.out.print(" - node set: accurate="+size); //$NON-NLS-1$
2155
size = nodeSet.possibleMatchingNodesSet==null ? 0 : nodeSet.possibleMatchingNodesSet.elementSize;
2156            System.out.println(", possible="+size); //$NON-NLS-1$
2157
}
2158    } else {
2159        this.unitScope = null;
2160    }
2161
2162    if (nodeSet.matchingNodes.elementSize == 0) return; // no matching nodes were found
2163
this.methodHandles = new HashSet JavaDoc();
2164
2165    boolean matchedUnitContainer = (this.matchContainer & PatternLocator.COMPILATION_UNIT_CONTAINER) != 0;
2166
2167    // report references in javadoc
2168
if (unit.javadoc != null) {
2169        ASTNode[] nodes = nodeSet.matchingNodes(unit.javadoc.sourceStart, unit.javadoc.sourceEnd);
2170        if (nodes != null) {
2171            if (!matchedUnitContainer) {
2172                for (int i = 0, l = nodes.length; i < l; i++)
2173                    nodeSet.matchingNodes.removeKey(nodes[i]);
2174            } else {
2175                IJavaElement element = createPackageDeclarationHandle(unit);
2176                for (int i = 0, l = nodes.length; i < l; i++) {
2177                    ASTNode node = nodes[i];
2178                    Integer JavaDoc level = (Integer JavaDoc) nodeSet.matchingNodes.removeKey(node);
2179                    if (encloses(element))
2180                        this.patternLocator.matchReportReference(node, element, null/*no binding*/, level.intValue(), this);
2181                }
2182            }
2183        }
2184    }
2185
2186    if (matchedUnitContainer) {
2187        ImportReference pkg = unit.currentPackage;
2188        if (pkg != null && pkg.annotations != null) {
2189            IJavaElement element = createPackageDeclarationHandle(unit);
2190            if (element != null) {
2191                reportMatching(pkg.annotations, element, null, nodeSet, true, encloses(element));
2192            }
2193        }
2194
2195        ImportReference[] imports = unit.imports;
2196        if (imports != null) {
2197            for (int i = 0, l = imports.length; i < l; i++) {
2198                ImportReference importRef = imports[i];
2199                Integer JavaDoc level = (Integer JavaDoc) nodeSet.matchingNodes.removeKey(importRef);
2200                if (level != null)
2201                    this.patternLocator.matchReportImportRef(importRef, null/*no binding*/, createImportHandle(importRef), level.intValue(), this);
2202            }
2203        }
2204    }
2205
2206    TypeDeclaration[] types = unit.types;
2207    if (types != null) {
2208        for (int i = 0, l = types.length; i < l; i++) {
2209            if (nodeSet.matchingNodes.elementSize == 0) return; // reported all the matching nodes
2210
TypeDeclaration type = types[i];
2211            Integer JavaDoc level = (Integer JavaDoc) nodeSet.matchingNodes.removeKey(type);
2212            int accuracy = (level != null && matchedUnitContainer) ? level.intValue() : -1;
2213            reportMatching(type, null, accuracy, nodeSet, 1);
2214        }
2215    }
2216    
2217    // Clear handle cache
2218
this.methodHandles = null;
2219    this.bindings.removeKey(this.pattern);
2220    this.patternLocator.mustResolve = locatorMustResolve;
2221}
2222/**
2223 * Visit the given field declaration and report the nodes that match exactly the
2224 * search pattern (ie. the ones in the matching nodes set)
2225 */

2226protected void reportMatching(FieldDeclaration field, FieldDeclaration[] otherFields, TypeDeclaration type, IJavaElement parent, int accuracy, boolean typeInHierarchy, MatchingNodeSet nodeSet) throws CoreException {
2227    IJavaElement enclosingElement = null;
2228    if (accuracy > -1) {
2229        enclosingElement = createHandle(field, type, parent);
2230        if (encloses(enclosingElement)) {
2231            int offset = field.sourceStart;
2232            SearchMatch match = newDeclarationMatch(enclosingElement, field.binding, accuracy, offset, field.sourceEnd-offset+1);
2233            if (field.initialization instanceof AllocationExpression) {
2234                reportAccurateEnumConstructorReference(match, field, (AllocationExpression) field.initialization);
2235            } else {
2236                report(match);
2237            }
2238        }
2239    }
2240
2241    // handle the nodes for the local type first
2242
if ((field.bits & ASTNode.HasLocalType) != 0) {
2243        if (enclosingElement == null)
2244            enclosingElement = createHandle(field, type, parent);
2245        LocalDeclarationVisitor localDeclarationVisitor = new LocalDeclarationVisitor(enclosingElement, field.binding, nodeSet);
2246        try {
2247            field.traverse(localDeclarationVisitor, null);
2248        } catch (WrappedCoreException e) {
2249            throw e.coreException;
2250        }
2251    }
2252
2253    // report annotations
2254
if (field.annotations != null) {
2255        if (enclosingElement == null) {
2256            enclosingElement = createHandle(field, type, parent);
2257        }
2258        reportMatching(field.annotations, enclosingElement, field.binding, nodeSet, true, true);
2259    }
2260
2261    if (typeInHierarchy) {
2262        // Look at field declaration
2263
if (field.endPart1Position != 0) { // not necessary if field is an initializer
2264
ASTNode[] nodes = nodeSet.matchingNodes(field.declarationSourceStart, field.endPart1Position);
2265            if (nodes != null) {
2266                if ((this.matchContainer & PatternLocator.FIELD_CONTAINER) == 0) {
2267                    for (int i = 0, l = nodes.length; i < l; i++)
2268                        nodeSet.matchingNodes.removeKey(nodes[i]);
2269                } else {
2270                    if (enclosingElement == null)
2271                        enclosingElement = createHandle(field, type, parent);
2272                    if (encloses(enclosingElement)) {
2273                        for (int i = 0, l = nodes.length; i < l; i++) {
2274                            ASTNode node = nodes[i];
2275                            Integer JavaDoc level = (Integer JavaDoc) nodeSet.matchingNodes.removeKey(node);
2276                            IJavaElement[] otherElements = null;
2277                            if (otherFields != null) {
2278                                int length = otherFields.length;
2279                                int size = 0;
2280                                while (size<length && otherFields[size] != null) {
2281                                    size++;
2282                                }
2283                                otherElements = new IJavaElement[size];
2284                                for (int j=0; j<size; j++) {
2285                                    otherElements[j] = createHandle(otherFields[j], type, parent);
2286                                }
2287                            }
2288                            this.patternLocator.matchReportReference(node, enclosingElement, null, otherElements, field.binding, level.intValue(), this);
2289                        }
2290                    }
2291                }
2292            }
2293        }
2294
2295        // Look in initializer
2296
int fieldEnd = field.endPart2Position == 0 ? field.declarationSourceEnd : field.endPart2Position;
2297        ASTNode[] nodes = nodeSet.matchingNodes(field.sourceStart, fieldEnd);
2298        if (nodes != null) {
2299            if ((this.matchContainer & PatternLocator.FIELD_CONTAINER) == 0) {
2300                for (int i = 0, l = nodes.length; i < l; i++)
2301                    nodeSet.matchingNodes.removeKey(nodes[i]);
2302            } else {
2303                if (enclosingElement == null) {
2304                    enclosingElement = createHandle(field, type, parent);
2305                }
2306                if (encloses(enclosingElement)) {
2307                    for (int i = 0, l = nodes.length; i < l; i++) {
2308                        ASTNode node = nodes[i];
2309                        Integer JavaDoc level = (Integer JavaDoc) nodeSet.matchingNodes.removeKey(node);
2310                        if (node instanceof TypeDeclaration) {
2311                            // use field declaration to report match (see bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=88174)
2312
AllocationExpression allocation = ((TypeDeclaration)node).allocation;
2313                            if (allocation != null && allocation.enumConstant != null) {
2314                                node = field;
2315                            }
2316                        }
2317                        // Set block scope for initializer in case there would have other local and other elements to report
2318
BlockScope blockScope = null;
2319                        if (field.getKind() == AbstractVariableDeclaration.INITIALIZER) {
2320                            Block block = ((Initializer)field).block;
2321                            if (block != null) blockScope = block.scope;
2322                        }
2323                        this.patternLocator.matchReportReference(node, enclosingElement, field.binding, blockScope, level.intValue(), this);
2324                    }
2325                }
2326            }
2327        }
2328    }
2329}
2330/**
2331 * Visit the given type declaration and report the nodes that match exactly the
2332 * search pattern (ie. the ones in the matching nodes set)
2333 */

2334protected void reportMatching(TypeDeclaration type, IJavaElement parent, int accuracy, MatchingNodeSet nodeSet, int occurrenceCount) throws CoreException {
2335    // create type handle
2336
IJavaElement enclosingElement = parent;
2337    if (enclosingElement == null) {
2338        enclosingElement = createTypeHandle(new String JavaDoc(type.name));
2339    } else if (enclosingElement instanceof IType) {
2340        enclosingElement = ((IType) parent).getType(new String JavaDoc(type.name));
2341    } else if (enclosingElement instanceof IMember) {
2342        IMember member = (IMember) parent;
2343        if (member.isBinary()) {
2344            enclosingElement = ((IClassFile)this.currentPossibleMatch.openable).getType();
2345        } else {
2346            enclosingElement = member.getType(new String JavaDoc(type.name), occurrenceCount);
2347        }
2348    }
2349    if (enclosingElement == null) return;
2350    boolean enclosesElement = encloses(enclosingElement);
2351
2352    // report the type declaration
2353
if (accuracy > -1 && enclosesElement) {
2354        int offset = type.sourceStart;
2355        SearchMatch match = this.patternLocator.newDeclarationMatch(type, enclosingElement, type.binding, accuracy, type.sourceEnd-offset+1, this);
2356        report(match);
2357    }
2358
2359    boolean matchedClassContainer = (this.matchContainer & PatternLocator.CLASS_CONTAINER) != 0;
2360
2361    // report the type parameters
2362
if (type.typeParameters != null) {
2363        reportMatching(type.typeParameters, enclosingElement, parent, type.binding, nodeSet);
2364    }
2365
2366    // report annotations
2367
if (type.annotations != null) {
2368        reportMatching(type.annotations, enclosingElement, type.binding, nodeSet, matchedClassContainer, enclosesElement);
2369    }
2370
2371    // report references in javadoc
2372
if (type.javadoc != null) {
2373        ASTNode[] nodes = nodeSet.matchingNodes(type.declarationSourceStart, type.sourceStart);
2374        if (nodes != null) {
2375            if (!matchedClassContainer) {
2376                for (int i = 0, l = nodes.length; i < l; i++)
2377                    nodeSet.matchingNodes.removeKey(nodes[i]);
2378            } else {
2379                for (int i = 0, l = nodes.length; i < l; i++) {
2380                    ASTNode node = nodes[i];
2381                    Integer JavaDoc level = (Integer JavaDoc) nodeSet.matchingNodes.removeKey(node);
2382                    if (enclosesElement) {
2383                        this.patternLocator.matchReportReference(node, enclosingElement, type.binding, level.intValue(), this);
2384                    }
2385                }
2386            }
2387        }
2388    }
2389    
2390    // super types
2391
if ((type.bits & ASTNode.IsAnonymousType) != 0) {
2392        TypeReference superType =type.allocation.type;
2393        if (superType != null) {
2394            Integer JavaDoc level = (Integer JavaDoc) nodeSet.matchingNodes.removeKey(superType);
2395            if (level != null && matchedClassContainer)
2396                this.patternLocator.matchReportReference(superType, enclosingElement, type.binding, level.intValue(), this);
2397        }
2398    } else {
2399        TypeReference superClass = type.superclass;
2400        if (superClass != null) {
2401            reportMatchingSuper(superClass, enclosingElement, type.binding, nodeSet, matchedClassContainer);
2402        }
2403        TypeReference[] superInterfaces = type.superInterfaces;
2404        if (superInterfaces != null) {
2405            for (int i = 0, l = superInterfaces.length; i < l; i++) {
2406                reportMatchingSuper(superInterfaces[i], enclosingElement, type.binding, nodeSet, matchedClassContainer);
2407            }
2408        }
2409    }
2410
2411    // filter out element not in hierarchy scope
2412
boolean typeInHierarchy = type.binding == null || typeInHierarchy(type.binding);
2413    matchedClassContainer = matchedClassContainer && typeInHierarchy;
2414
2415    // Visit fields
2416
FieldDeclaration[] fields = type.fields;
2417    if (fields != null) {
2418        if (nodeSet.matchingNodes.elementSize == 0) return; // end as all matching nodes were reported
2419
FieldDeclaration[] otherFields = null;
2420        int first = -1;
2421        int length = fields.length;
2422        for (int i = 0; i < length; i++) {
2423            FieldDeclaration field = fields[i];
2424            boolean last = field.endPart2Position == 0 || field.declarationEnd == field.endPart2Position;
2425            // Store first index of multiple field declaration
2426
if (!last) {
2427                if (first == -1) {
2428                    first = i;
2429                }
2430            }
2431            if (first >= 0) {
2432                // Store all multiple fields but first one for other elements
2433
if (i > first) {
2434                    if (otherFields == null) {
2435                        otherFields = new FieldDeclaration[length-i];
2436                    }
2437                    otherFields[i-1-first] = field;
2438                }
2439                // On last field, report match with all other elements
2440
if (last) {
2441                    for (int j=first; j<=i; j++) {
2442                        Integer JavaDoc level = (Integer JavaDoc) nodeSet.matchingNodes.removeKey(fields[j]);
2443                        int value = (level != null && matchedClassContainer) ? level.intValue() : -1;
2444                        reportMatching(fields[j], otherFields, type, enclosingElement, value, typeInHierarchy, nodeSet);
2445                    }
2446                    first = -1;
2447                    otherFields = null;
2448                }
2449            } else {
2450                // Single field, report normally
2451
Integer JavaDoc level = (Integer JavaDoc) nodeSet.matchingNodes.removeKey(field);
2452                int value = (level != null && matchedClassContainer) ? level.intValue() : -1;
2453                reportMatching(field, null, type, enclosingElement, value, typeInHierarchy, nodeSet);
2454            }
2455        }
2456    }
2457
2458    // Visit methods
2459
AbstractMethodDeclaration[] methods = type.methods;
2460    if (methods != null) {
2461        if (nodeSet.matchingNodes.elementSize == 0) return; // end as all matching nodes were reported
2462
for (int i = 0, l = methods.length; i < l; i++) {
2463            AbstractMethodDeclaration method = methods[i];
2464            Integer JavaDoc level = (Integer JavaDoc) nodeSet.matchingNodes.removeKey(method);
2465            int value = (level != null && matchedClassContainer) ? level.intValue() : -1;
2466            reportMatching(type, method, enclosingElement, value, typeInHierarchy, nodeSet);
2467        }
2468    }
2469
2470    // Visit types
2471
TypeDeclaration[] memberTypes = type.memberTypes;
2472    if (memberTypes != null) {
2473        for (int i = 0, l = memberTypes.length; i < l; i++) {
2474            if (nodeSet.matchingNodes.elementSize == 0) return; // end as all matching nodes were reported
2475
TypeDeclaration memberType = memberTypes[i];
2476            Integer JavaDoc level = (Integer JavaDoc) nodeSet.matchingNodes.removeKey(memberType);
2477            int value = (level != null && matchedClassContainer) ? level.intValue() : -1;
2478            reportMatching(memberType, enclosingElement, value, nodeSet, 1);
2479        }
2480    }
2481}
2482/**
2483 * Report matches in type parameters.
2484 */

2485protected void reportMatching(TypeParameter[] typeParameters, IJavaElement enclosingElement, IJavaElement parent, Binding binding, MatchingNodeSet nodeSet) throws CoreException {
2486    if (typeParameters == null) return;
2487    for (int i=0, l=typeParameters.length; i<l; i++) {
2488        TypeParameter typeParameter = typeParameters[i];
2489        if (typeParameter != null) {
2490            Integer JavaDoc level = (Integer JavaDoc) nodeSet.matchingNodes.removeKey(typeParameter);
2491            if (level != null) {
2492                if (level.intValue() > -1 && encloses(enclosingElement)) {
2493                    int offset = typeParameter.sourceStart;
2494                    SearchMatch match = this.patternLocator.newDeclarationMatch(typeParameter, enclosingElement, binding, level.intValue(), typeParameter.sourceEnd-offset+1, this);
2495                    report(match);
2496                }
2497            }
2498            if (typeParameter.type != null) {
2499                level = (Integer JavaDoc) nodeSet.matchingNodes.removeKey(typeParameter.type);
2500                if (level != null) {
2501                    IJavaElement localElement = createHandle(typeParameter, enclosingElement);
2502                    this.patternLocator.matchReportReference(typeParameter.type, enclosingElement, localElement, null, binding, level.intValue(), this);
2503                }
2504            }
2505            if (typeParameter.bounds != null) {
2506                for (int j=0, b=typeParameter.bounds.length; j<b; j++) {
2507                    level = (Integer JavaDoc) nodeSet.matchingNodes.removeKey(typeParameter.bounds[j]);
2508                    if (level != null) {
2509                        IJavaElement localElement = createHandle(typeParameter, enclosingElement);
2510                        this.patternLocator.matchReportReference(typeParameter.bounds[j], enclosingElement, localElement, null, binding, level.intValue(), this);
2511                    }
2512                }
2513            }
2514        }
2515    }
2516}
2517protected void reportMatchingSuper(TypeReference superReference, IJavaElement enclosingElement, Binding elementBinding, MatchingNodeSet nodeSet, boolean matchedClassContainer) throws CoreException {
2518    ASTNode[] nodes = null;
2519    if (superReference instanceof ParameterizedSingleTypeReference || superReference instanceof ParameterizedQualifiedTypeReference) {
2520        long lastTypeArgumentInfo = findLastTypeArgumentInfo(superReference);
2521        nodes = nodeSet.matchingNodes(superReference.sourceStart, (int)lastTypeArgumentInfo);
2522    }
2523    if (nodes != null) {
2524        if ((this.matchContainer & PatternLocator.CLASS_CONTAINER) == 0) {
2525            for (int i = 0, l = nodes.length; i < l; i++)
2526                nodeSet.matchingNodes.removeKey(nodes[i]);
2527        } else {
2528            if (encloses(enclosingElement))
2529                for (int i = 0, l = nodes.length; i < l; i++) {
2530                    ASTNode node = nodes[i];
2531                    Integer JavaDoc level = (Integer JavaDoc) nodeSet.matchingNodes.removeKey(node);
2532                    this.patternLocator.matchReportReference(node, enclosingElement, elementBinding, level.intValue(), this);
2533                }
2534        }
2535    } else {
2536        Integer JavaDoc level = (Integer JavaDoc) nodeSet.matchingNodes.removeKey(superReference);
2537        if (level != null && matchedClassContainer)
2538            this.patternLocator.matchReportReference(superReference, enclosingElement, elementBinding, level.intValue(), this);
2539    }
2540}
2541protected boolean typeInHierarchy(ReferenceBinding binding) {
2542    if (this.hierarchyResolver == null) return true; // not a hierarchy scope
2543
if (this.hierarchyResolver.subOrSuperOfFocus(binding)) return true;
2544
2545    if (this.allSuperTypeNames != null) {
2546        char[][] compoundName = binding.compoundName;
2547        for (int i = 0, length = this.allSuperTypeNames.length; i < length; i++)
2548            if (CharOperation.equals(compoundName, this.allSuperTypeNames[i]))
2549                return true;
2550    }
2551    return false;
2552}
2553}
2554
Popular Tags