Index: search/org/eclipse/jdt/internal/core/search/matching/MatchLocator.java =================================================================== RCS file: /home/eclipse/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MatchLocator.java,v retrieving revision 1.242 diff -u -r1.242 MatchLocator.java --- search/org/eclipse/jdt/internal/core/search/matching/MatchLocator.java 11 May 2005 21:08:37 -0000 1.242 +++ search/org/eclipse/jdt/internal/core/search/matching/MatchLocator.java 13 May 2005 16:32:42 -0000 @@ -38,6 +38,7 @@ import org.eclipse.jdt.internal.compiler.CompilationResult; import org.eclipse.jdt.internal.compiler.DefaultErrorHandlingPolicies; import org.eclipse.jdt.internal.compiler.ast.*; +import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; import org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader; import org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException; import org.eclipse.jdt.internal.compiler.env.*; @@ -396,36 +397,6 @@ } return this.basicParser; } -/** - * Add the possibleMatch to the loop - * -> build compilation unit declarations, their bindings and record their results. - */ -protected void parseAndBuildBindings(PossibleMatch possibleMatch, boolean mustResolve) { - if (this.progressMonitor != null && this.progressMonitor.isCanceled()) - throw new OperationCanceledException(); - - try { - if (BasicSearchEngine.VERBOSE) - System.out.println("Parsing " + possibleMatch.openable.toStringWithAncestors()); //$NON-NLS-1$ - - this.parser.nodeSet = possibleMatch.nodeSet; - CompilationResult unitResult = new CompilationResult(possibleMatch, 1, 1, this.options.maxProblemsPerUnit); - CompilationUnitDeclaration parsedUnit = this.parser.dietParse(possibleMatch, unitResult); - if (parsedUnit != null) { - if (mustResolve && !parsedUnit.isEmpty()) - this.lookupEnvironment.buildTypeBindings(parsedUnit, null /*no access restriction*/); - - // add the possibleMatch with its parsedUnit to matchesToProcess - possibleMatch.parsedUnit = parsedUnit; - int size = this.matchesToProcess.length; - if (this.numberOfMatches == size) - System.arraycopy(this.matchesToProcess, 0, this.matchesToProcess = new PossibleMatch[size == 0 ? 1 : size * 2], 0, this.numberOfMatches); - this.matchesToProcess[this.numberOfMatches++] = possibleMatch; - } - } finally { - this.parser.nodeSet = null; - } -} /* * Caches the given binary type in the lookup environment and returns it. * Returns the existing one if already cached. @@ -711,7 +682,7 @@ protected IType getFocusType() { return this.scope instanceof HierarchyScope ? ((HierarchyScope) this.scope).focusType : null; } -protected void getMethodBodies(CompilationUnitDeclaration unit) { +protected void getMethodBodies(CompilationUnitDeclaration unit, MatchingNodeSet nodeSet) { if (unit.ignoreMethodBodies) { unit.ignoreFurtherInvestigation = true; return; // if initial diet parse did not work, no need to dig into method bodies. @@ -730,7 +701,7 @@ char[] contents = compilationResult.compilationUnit.getContents(); this.parser.javadocParser.scanner.setSource(contents); } - this.parser.nodeSet = this.currentPossibleMatch.nodeSet; + this.parser.nodeSet = nodeSet; this.parser.parseBodies(unit); } finally { this.parser.nodeSet = null; @@ -876,22 +847,43 @@ initialize(javaProject, length); // create and resolve binding (equivalent to beginCompilation() in Compiler) - boolean mustResolve = ((InternalSearchPattern)this.pattern).mustResolve; + boolean mustResolvePattern = ((InternalSearchPattern)this.pattern).mustResolve; + boolean mustResolve = mustResolvePattern; + this.patternLocator.mayBeGeneric = this.options.sourceLevel >= ClassFileConstants.JDK1_5; boolean bindingsWereCreated = mustResolve; try { for (int i = start, maxUnits = start + length; i < maxUnits; i++) { PossibleMatch possibleMatch = possibleMatches[i]; try { - parseAndBuildBindings(possibleMatch, mustResolve); - if (!mustResolve) { + if (!parseAndBuildBindings(possibleMatch, mustResolvePattern)) continue; + // Currently we only need to resolve over pattern flag if there's potential parameterized types + if (this.patternLocator.mayBeGeneric) { + // If pattern does not resolve then rely on possible match node set resolution + // which may have been modified while locator was adding possible matches to it + if (!mustResolvePattern) { + mustResolve = possibleMatch.nodeSet.mustResolve; + bindingsWereCreated = mustResolve; + } + } else { + // Reset matching node resolution with pattern one if there's no potential parameterized type + // to minimize side effect on previous search behavior + possibleMatch.nodeSet.mustResolve = mustResolvePattern; + } + // possible match node resolution has been merged with pattern one, so rely on it to know + // whether we need to process compilation unit now or later + if (!possibleMatch.nodeSet.mustResolve) { if (this.progressMonitor != null) { this.progressWorked++; if ((this.progressWorked%this.progressStep)==0) this.progressMonitor.worked(this.progressStep); } process(possibleMatch, bindingsWereCreated); + if (this.numberOfMatches>0 && this.matchesToProcess[this.numberOfMatches-1] == possibleMatch) { + // forget last possible match as it was processed + this.numberOfMatches--; + } } } finally { - if (!mustResolve) + if (!possibleMatch.nodeSet.mustResolve) possibleMatch.cleanUp(); } } @@ -1073,7 +1065,7 @@ } previousJavaProject = javaProject; } - matchSet.add(new PossibleMatch(this, resource, openable, searchDocument)); + matchSet.add(new PossibleMatch(this, resource, openable, searchDocument, ((InternalSearchPattern) this.pattern).mustResolve)); } // last project @@ -1112,7 +1104,7 @@ IJavaElement focus = ((InternalSearchPattern) searchPattern).focus; if (focus != null) { SearchDocument document = participant.getDocument(focus.getPath().toString()); - this.currentPossibleMatch = new PossibleMatch(this, focus.getResource(), null, document); + this.currentPossibleMatch = new PossibleMatch(this, focus.getResource(), null, document, ((InternalSearchPattern) searchPattern).mustResolve); if (encloses(focus)) { SearchMatch match = newDeclarationMatch(focus.getAncestor(IJavaElement.PACKAGE_FRAGMENT), null/*no binding*/, SearchMatch.A_ACCURATE, -1, -1); report(match); @@ -1153,7 +1145,7 @@ if (resource == null) // case of a file in an external jar resource = javaProject.getProject(); SearchDocument document = participant.getDocument(resource.getFullPath().toString()); - this.currentPossibleMatch = new PossibleMatch(this, resource, null, document); + this.currentPossibleMatch = new PossibleMatch(this, resource, null, document, ((InternalSearchPattern) searchPattern).mustResolve); try { if (encloses(pkg)) { SearchMatch match = newDeclarationMatch(pkg, null/*no binding*/, SearchMatch.A_ACCURATE, -1, -1); @@ -1352,6 +1344,47 @@ return newTypeReferenceMatch(enclosingElement, enclosingBinding, accuracy, reference.sourceStart, reference.sourceEnd-reference.sourceStart+1, reference); } +/** + * Add the possibleMatch to the loop + * -> build compilation unit declarations, their bindings and record their results. + */ +protected boolean parseAndBuildBindings(PossibleMatch possibleMatch, boolean mustResolve) throws CoreException { + if (this.progressMonitor != null && this.progressMonitor.isCanceled()) + throw new OperationCanceledException(); + + try { + if (BasicSearchEngine.VERBOSE) + System.out.println("Parsing " + possibleMatch.openable.toStringWithAncestors()); //$NON-NLS-1$ + + this.parser.nodeSet = possibleMatch.nodeSet; + CompilationResult unitResult = new CompilationResult(possibleMatch, 1, 1, this.options.maxProblemsPerUnit); + CompilationUnitDeclaration parsedUnit = this.parser.dietParse(possibleMatch, unitResult); + if (parsedUnit != null) { + if (!parsedUnit.isEmpty()) { + if (mustResolve) { + this.lookupEnvironment.buildTypeBindings(parsedUnit, null /*no access restriction*/); + } + if (hasAlreadyDefinedType(parsedUnit)) return false; // skip type has it is hidden so not visible + getMethodBodies(parsedUnit, possibleMatch.nodeSet); + if (this.patternLocator.mayBeGeneric && !mustResolve && possibleMatch.nodeSet.mustResolve) { + // special case: possible match node set force resolution although pattern does not + // => we need to build types for this compilation unit + this.lookupEnvironment.buildTypeBindings(parsedUnit, null /*no access restriction*/); + } + } + + // add the possibleMatch with its parsedUnit to matchesToProcess + possibleMatch.parsedUnit = parsedUnit; + int size = this.matchesToProcess.length; + if (this.numberOfMatches == size) + System.arraycopy(this.matchesToProcess, 0, this.matchesToProcess = new PossibleMatch[size == 0 ? 1 : size * 2], 0, this.numberOfMatches); + this.matchesToProcess[this.numberOfMatches++] = possibleMatch; + } + } finally { + this.parser.nodeSet = null; + } + return true; +} /* * Process a compilation unit already parsed and build. */ @@ -1370,9 +1403,10 @@ } if (hasAlreadyDefinedType(unit)) return; // skip type has it is hidden so not visible - getMethodBodies(unit); + // Move getMethodBodies to #parseAndBuildings(...) method to allow possible match resolution management + //getMethodBodies(unit); - boolean mustResolve = ((InternalSearchPattern)this.pattern).mustResolve; + boolean mustResolve = ((InternalSearchPattern)this.pattern).mustResolve || possibleMatch.nodeSet.mustResolve; if (bindingsWereCreated && mustResolve) { if (unit.types != null) { if (BasicSearchEngine.VERBOSE) @@ -1839,6 +1873,7 @@ */ protected void reportMatching(CompilationUnitDeclaration unit, boolean mustResolve) throws CoreException { MatchingNodeSet nodeSet = this.currentPossibleMatch.nodeSet; + if (nodeSet.mustResolve) this.patternLocator.mustResolve = true; if (mustResolve) { this.unitScope= unit.scope.compilationUnitScope(); // move the possible matching nodes that exactly match the search pattern to the matching nodes set Index: search/org/eclipse/jdt/internal/core/search/matching/MatchingNodeSet.java =================================================================== RCS file: /home/eclipse/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MatchingNodeSet.java,v retrieving revision 1.29 diff -u -r1.29 MatchingNodeSet.java --- search/org/eclipse/jdt/internal/core/search/matching/MatchingNodeSet.java 23 Feb 2005 02:47:46 -0000 1.29 +++ search/org/eclipse/jdt/internal/core/search/matching/MatchingNodeSet.java 13 May 2005 16:32:42 -0000 @@ -36,12 +36,23 @@ static Integer ERASURE_MATCH = new Integer(SearchPattern.R_ERASURE_MATCH); /** + * Tell whether locators need to resolve or not for current matching node set. + */ +public boolean mustResolve; + +/** * Set of possible matching ast nodes. They need to be resolved * to determine if they really match the search pattern. */ SimpleSet possibleMatchingNodesSet = new SimpleSet(7); private HashtableOfLong possibleMatchingNodesKeys = new HashtableOfLong(7); + +public MatchingNodeSet(boolean mustResolvePattern) { + super(); + mustResolve = mustResolvePattern; +} + public int addMatch(ASTNode node, int matchLevel) { switch (matchLevel) { case PatternLocator.INACCURATE_MATCH: Index: search/org/eclipse/jdt/internal/core/search/matching/MethodLocator.java =================================================================== RCS file: /home/eclipse/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MethodLocator.java,v retrieving revision 1.51 diff -u -r1.51 MethodLocator.java --- search/org/eclipse/jdt/internal/core/search/matching/MethodLocator.java 9 May 2005 13:19:30 -0000 1.51 +++ search/org/eclipse/jdt/internal/core/search/matching/MethodLocator.java 13 May 2005 16:32:43 -0000 @@ -81,6 +81,8 @@ //public int match(FieldDeclaration node, MatchingNodeSet nodeSet) - SKIP IT public int match(MethodDeclaration node, MatchingNodeSet nodeSet) { if (!this.pattern.findDeclarations) return IMPOSSIBLE_MATCH; + + boolean resolve = ((InternalSearchPattern)this.pattern).mustResolve; // Verify method name if (!matchesName(this.pattern.selector, node.selector)) return IMPOSSIBLE_MATCH; @@ -92,7 +94,14 @@ int argsLength = args == null ? 0 : args.length; if (length != argsLength) return IMPOSSIBLE_MATCH; for (int i = 0; i < argsLength; i++) { - if (!matchesTypeReference(this.pattern.parameterSimpleNames[i], ((Argument) args[i]).type)) return IMPOSSIBLE_MATCH; + if (!matchesTypeReference(this.pattern.parameterSimpleNames[i], ((Argument) args[i]).type)) { + if (!mustResolve) { + // Set resolution flag on node set in case of types was inferred in parameterized types from generic ones... + // (see bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=79990) + nodeSet.mustResolve = true; + resolve = true; + } + } } } @@ -102,7 +111,7 @@ } // Method declaration may match pattern - return nodeSet.addMatch(node, ((InternalSearchPattern)this.pattern).mustResolve ? POSSIBLE_MATCH : ACCURATE_MATCH); + return nodeSet.addMatch(node, resolve ? POSSIBLE_MATCH : ACCURATE_MATCH); } public int match(MemberValuePair node, MatchingNodeSet nodeSet) { if (!this.pattern.findReferences) return IMPOSSIBLE_MATCH; @@ -114,6 +123,8 @@ public int match(MessageSend node, MatchingNodeSet nodeSet) { if (!this.pattern.findReferences) return IMPOSSIBLE_MATCH; + boolean resolve = ((InternalSearchPattern)this.pattern).mustResolve; + if (!matchesName(this.pattern.selector, node.selector)) return IMPOSSIBLE_MATCH; if (this.pattern.parameterSimpleNames != null && (this.pattern.shouldCountParameter() || ((node.bits & ASTNode.InsideJavadoc) != 0))) { int length = this.pattern.parameterSimpleNames.length; @@ -122,7 +133,7 @@ if (length != argsLength) return IMPOSSIBLE_MATCH; } - return nodeSet.addMatch(node, ((InternalSearchPattern)this.pattern).mustResolve ? POSSIBLE_MATCH : ACCURATE_MATCH); + return nodeSet.addMatch(node, resolve ? POSSIBLE_MATCH : ACCURATE_MATCH); } //public int match(Reference node, MatchingNodeSet nodeSet) - SKIP IT public int match(Annotation node, MatchingNodeSet nodeSet) { @@ -215,6 +226,54 @@ return level; } /** + * Return if pattern method may override a method in super classes + * or or implement one in super interfaces of given type. + * @param type + * @return level + */ +int matchOverriddenMethod(ReferenceBinding type) { + if (type == null) return INACCURATE_MATCH; + int level = IMPOSSIBLE_MATCH; + + // matches superclass + if (!type.isInterface() && !CharOperation.equals(type.compoundName, TypeConstants.JAVA_LANG_OBJECT)) { + if (type.superclass().isParameterizedType()) { + TypeBinding erasure = ((ParameterizedTypeBinding)type.superclass()).erasure(); + if (erasure instanceof ReferenceBinding) { + MethodBinding[] methods = ((ReferenceBinding)erasure).getMethods(this.pattern.selector); + int length = methods.length; + for (int i = 0; i