### Eclipse Workspace Patch 1.0 #P org.eclipse.jdt.core Index: search/org/eclipse/jdt/internal/core/search/matching/MatchLocator.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MatchLocator.java,v retrieving revision 1.255 diff -u -r1.255 MatchLocator.java --- search/org/eclipse/jdt/internal/core/search/matching/MatchLocator.java 17 Nov 2005 11:08:57 -0000 1.255 +++ search/org/eclipse/jdt/internal/core/search/matching/MatchLocator.java 21 Nov 2005 09:36:14 -0000 @@ -61,6 +61,7 @@ import org.eclipse.jdt.internal.core.JavaElement; import org.eclipse.jdt.internal.core.JavaModelManager; import org.eclipse.jdt.internal.core.JavaProject; +import org.eclipse.jdt.internal.core.LocalVariable; import org.eclipse.jdt.internal.core.NameLookup; import org.eclipse.jdt.internal.core.Openable; import org.eclipse.jdt.internal.core.PackageFragment; @@ -124,6 +125,11 @@ // Cache for method handles HashSet methodHandles; +// Inner-most local element to add while reporting search match +// when requestor requires it (see bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=110336) +// TODO (frederic) This field should be removed while implementing design for bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=79866 +private IJavaElement localElement = null; + /** * An ast visitor that visits local type declarations. */ @@ -165,7 +171,6 @@ } } - public static class WorkingCopyDocument extends JavaSearchDocument { public org.eclipse.jdt.core.ICompilationUnit workingCopy; WorkingCopyDocument(org.eclipse.jdt.core.ICompilationUnit workingCopy, SearchParticipant participant) { @@ -562,6 +567,25 @@ } return ((IType) parent).getInitializer(occurrenceCount); } +/** + * Create an handle for a local variable declartion (may be a local variable or type parameter). + */ +protected IJavaElement createHandle(AbstractVariableDeclaration variableDeclaration, IJavaElement parent) { + switch (variableDeclaration.getKind()) { + case AbstractVariableDeclaration.LOCAL_VARIABLE: + return new LocalVariable((JavaElement)parent, + new String(variableDeclaration.name), + variableDeclaration.declarationSourceStart, + variableDeclaration.declarationSourceEnd, + variableDeclaration.sourceStart, + variableDeclaration.sourceEnd, + new String(variableDeclaration.type.resolvedType.signature()) + ); + case AbstractVariableDeclaration.TYPE_PARAMETER : + return new org.eclipse.jdt.internal.core.TypeParameter((JavaElement)parent, new String(variableDeclaration.name)); + } + return null; +} /* * Creates hierarchy resolver if needed. * Returns whether focus is visible. @@ -1556,7 +1580,9 @@ } System.out.println("\tRaw: "+match.isRaw()); //$NON-NLS-1$ } + match.setLocalElement(this.localElement); this.requestor.acceptSearchMatch(match); + this.localElement = null; if (BasicSearchEngine.VERBOSE) this.resultCollectorTime += System.currentTimeMillis()-start; } @@ -1848,6 +1874,15 @@ } } + // report the type parameters + TypeParameter[] typeParameters = method.typeParameters(); + if (typeParameters != null) { + if (enclosingElement == null) { + enclosingElement = createHandle(method, parent); + } + reportMatching(typeParameters, enclosingElement, parent, method.binding, nodeSet); + } + // report annotations if (method.annotations != null) { if (enclosingElement == null) { @@ -1867,6 +1902,14 @@ for (int i = 0, l = nodes.length; i < l; i++) { ASTNode node = nodes[i]; Integer level = (Integer) nodeSet.matchingNodes.removeKey(node); + this.localElement = null; + if (method.scope != null /* no error */ && this.requestor.provideLocalElements()) { + LocalDeclaration localDecl = method.scope.findLocalVariableDeclaration(node.sourceStart); + if (localDecl != null) { + // Set local element as it's different from enclosing one + this.localElement = createHandle(localDecl, enclosingElement); + } + } this.patternLocator.matchReportReference(node, enclosingElement, method.binding, level.intValue(), this); } return; @@ -2121,36 +2164,10 @@ } boolean matchedClassContainer = (this.matchContainer & PatternLocator.CLASS_CONTAINER) != 0; - + // report the type parameters if (type.typeParameters != null) { - for (int i=0, l=type.typeParameters.length; i -1 && enclosesElement) { - int offset = typeParameter.sourceStart; - SearchMatch match = this.patternLocator.newDeclarationMatch(typeParameter, enclosingElement, type.binding, level.intValue(), typeParameter.sourceEnd-offset+1, this); - report(match); - } - } - if (typeParameter.type != null) { - level = (Integer) nodeSet.matchingNodes.removeKey(typeParameter.type); - if (level != null && matchedClassContainer) { - this.patternLocator.matchReportReference(typeParameter.type, enclosingElement, type.binding, level.intValue(), this); - } - } - if (typeParameter.bounds != null) { - for (int j=0, b=typeParameter.bounds.length; j -1 && encloses(enclosingElement)) { + int offset = typeParameter.sourceStart; + SearchMatch match = this.patternLocator.newDeclarationMatch(typeParameter, enclosingElement, binding, level.intValue(), typeParameter.sourceEnd-offset+1, this); + report(match); + } + } + if (typeParameter.type != null) { + level = (Integer) nodeSet.matchingNodes.removeKey(typeParameter.type); + if (level != null) { + this.localElement = null; + if (this.requestor.provideLocalElements()) { + // Set local element as it's different from enclosing one + this.localElement = createHandle(typeParameter, enclosingElement); + } + this.patternLocator.matchReportReference(typeParameter.type, enclosingElement, binding, level.intValue(), this); + } + } + if (typeParameter.bounds != null) { + for (int j=0, b=typeParameter.bounds.length; j 0; + + // scope init + int iscope = 0, maxScopes = this.subscopeCount; + boolean hasMoreScopes = maxScopes > 0; + + // iterate scopes and variables in parallel + while (hasMoreVariables || hasMoreScopes) { + if (hasMoreScopes + && (!hasMoreVariables || (subscopes[iscope].startIndex() <= ilocal))) { + // consider subscope first + Scope subscope = subscopes[iscope]; + if (subscope.kind == Scope.BLOCK_SCOPE) { // do not dive in nested types + LocalDeclaration localDecl = ((BlockScope)subscope).findLocalVariableDeclaration(position); + if (localDecl != null) { + return localDecl; + } + } + hasMoreScopes = ++iscope < maxScopes; + } else { + + // consider variable first + LocalVariableBinding local = locals[ilocal]; // if no local at all, will be locals[ilocal]==null + if (local != null) { + LocalDeclaration localDecl = local.declaration; + if (localDecl != null) { + if (localDecl.declarationSourceStart <= position) { + if (position <= localDecl.declarationSourceEnd) { + return localDecl; + } + } else { + return null; + } + } + } + hasMoreVariables = ++ilocal < maxLocals; + } + } + return null; + } + /* Note that it must never produce a direct access to the targetEnclosingType, * but instead a field sequence (this$2.this$1.this$0) so as to handle such a test case: * Index: search/org/eclipse/jdt/core/search/SearchRequestor.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/SearchRequestor.java,v retrieving revision 1.8 diff -u -r1.8 SearchRequestor.java --- search/org/eclipse/jdt/core/search/SearchRequestor.java 23 Feb 2005 02:47:30 -0000 1.8 +++ search/org/eclipse/jdt/core/search/SearchRequestor.java 21 Nov 2005 09:36:13 -0000 @@ -92,4 +92,19 @@ public void exitParticipant(SearchParticipant participant) { // do nothing } + + /** + * Returns whether search engine should provide local elements while + * performing requested query. + * + * If sublcass overrides this method to return true instead, search engine then + * will store in each search match the innermost local element if different than + * the one already stored in element ({@link SearchMatch#getElement()}). + * + * @see SearchMatch#getLocalElement() + * @since 3.2 + */ + public boolean provideLocalElements() { + return false; + } } Index: search/org/eclipse/jdt/core/search/SearchMatch.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/SearchMatch.java,v retrieving revision 1.26 diff -u -r1.26 SearchMatch.java --- search/org/eclipse/jdt/core/search/SearchMatch.java 9 May 2005 13:19:30 -0000 1.26 +++ search/org/eclipse/jdt/core/search/SearchMatch.java 21 Nov 2005 09:36:13 -0000 @@ -47,6 +47,7 @@ public static final int A_INACCURATE = 1; private Object element; + private Object localElement; private int length; private int offset; @@ -108,7 +109,7 @@ /** * Returns the element of this search match. - * In case of a reference match, this is the inner-most enclosing element of the reference. + * In case of a reference match, this is the enclosing element of the reference. * In case of a declaration match, this is the declaration. * * @return the element of the search match, or null if none @@ -118,6 +119,18 @@ } /** + * Returns the innermost local element of this search match. + * In case of a reference match, this is the inner-most enclosing element of the reference. + * In case of a declaration match, this is always null. + * + * @return the element of the search match, or null if none or there's + * no more inner-most enclosing than the element itself ({@link SearchMatch#getElement()}). + */ + public final Object getLocalElement() { + return this.localElement; + } + + /** * Returns the length of this search match. * * @return the length of this search match, or -1 if unknown @@ -258,6 +271,16 @@ } /** + * Sets the innert-most element of this search match. + * + * @param element the inner-most local element that encloses or corresponds to the match, + * or null if none + */ + public final void setLocalElement (Object element) { + this.localElement = element; + } + + /** * Sets whether this search match is inside a doc comment of a Java * source file. * #P org.eclipse.jdt.core.tests.model Index: src/org/eclipse/jdt/core/tests/model/JavaSearchBugsTests.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/JavaSearchBugsTests.java,v retrieving revision 1.53 diff -u -r1.53 JavaSearchBugsTests.java --- src/org/eclipse/jdt/core/tests/model/JavaSearchBugsTests.java 4 Nov 2005 15:21:02 -0000 1.53 +++ src/org/eclipse/jdt/core/tests/model/JavaSearchBugsTests.java 21 Nov 2005 09:36:23 -0000 @@ -46,7 +46,7 @@ // org.eclipse.jdt.internal.codeassist.SelectionEngine.DEBUG = true; // TESTS_PREFIX = "testBug110060"; // TESTS_NAMES = new String[] { "testBug113671" }; -// TESTS_NUMBERS = new int[] { 114539 }; +// TESTS_NUMBERS = new int[] { 110336 }; // TESTS_RANGE = new int[] { 83304, -1 }; } @@ -57,6 +57,20 @@ matches.add(match); } } +class LocalVariablesCollector extends JavaSearchResultCollector { + + protected IJavaElement getElement(SearchMatch match) { + Object localElement= match.getLocalElement(); + if (localElement != null) { + return (IJavaElement) localElement; + } + return super.getElement(match); + } + + public boolean provideLocalElements() { + return true; + } +} IJavaSearchScope getJavaSearchScopeBugs() { return SearchEngine.createJavaSearchScope(new IJavaProject[] {getJavaProject("JavaSearchBugs")}); @@ -5268,7 +5282,6 @@ * @test Bug 114539: [search] Internal error when refactoring code with errors * @see "https://bugs.eclipse.org/bugs/show_bug.cgi?id=114539" */ -// Types search public void testBug114539() throws CoreException { workingCopies = new ICompilationUnit[2]; workingCopies[0] = getWorkingCopy("/JavaSearchBugs/src/b114539/Foo.java", @@ -5285,9 +5298,86 @@ ); IField field = this.workingCopies[1].getType("Bar").getField("FOO"); search(field, REFERENCES); - this.discard = false; assertSearchResults( "src/b114539/Foo.java b114539.Foo.bar [FOO] POTENTIAL_MATCH" ); } + +/** + * @test Bug 110336: [plan][search] Should optionaly return the local variable for type reference + * @see "https://bugs.eclipse.org/bugs/show_bug.cgi?id=110336" + */ +public void testBug110336a() throws CoreException { + workingCopies = new ICompilationUnit[1]; + workingCopies[0] = getWorkingCopy("/JavaSearchBugs/src/b110336/Test.java", + "package b110336;\n" + + "public class Test {\n" + + " void method(Class clazz) {\n" + + " Test localVar1 = new Test();\n" + + " Class localVar2 = new Class();\n" + + " localVar1.method(localVar2);\n" + + " }\n" + + "}\n" + ); + IType type = this.workingCopies[0].getType("Test"); + LocalVariablesCollector collector = new LocalVariablesCollector(); + search(type, REFERENCES, EXACT_RULE, getJavaSearchScopeBugs(), collector); + assertSearchResults( + "src/b110336/Test.java void b110336.Test.method(Class).TP [Test]\n" + + "src/b110336/Test.java void b110336.Test.method(Class) [Test]\n" + + "src/b110336/Test.java void b110336.Test.method(Class).localVar1 [Test]\n" + + "src/b110336/Test.java void b110336.Test.method(Class).localVar1 [Test]\n" + + "src/b110336/Test.java void b110336.Test.method(Class).localVar2 [Test]\n" + + "src/b110336/Test.java void b110336.Test.method(Class).localVar2 [Test]", + collector + ); +} +public void testBug110336b() throws CoreException { + workingCopies = new ICompilationUnit[1]; + workingCopies[0] = getWorkingCopy("/JavaSearchBugs/src/b110336/Test.java", + "package b110336;\n" + + "public class Test {\n" + + " void method1(Test methodParam) {\n" + + " Test localVar1 = new Test(){\n" + + " Class c = Test.class;\n" + + " void foo(){\n" + + " Test o = (Test) null;\n" + + " }\n" + + " };\n" + + " } \n" + + "}\n" + ); + IType type = this.workingCopies[0].getType("Test"); + LocalVariablesCollector collector = new LocalVariablesCollector(); + search(type, REFERENCES, EXACT_RULE, getJavaSearchScopeBugs(), collector); + assertSearchResults( + "src/b110336/Test.java void b110336.Test.method1(Test):#1 [Test]\n" + + "src/b110336/Test.java void b110336.Test.method1(Test):#1.c [Test]\n" + + "src/b110336/Test.java void void b110336.Test.method1(Test):#1.foo().TP [Test]\n" + + "src/b110336/Test.java void void b110336.Test.method1(Test):#1.foo().o [Test]\n" + + "src/b110336/Test.java void void b110336.Test.method1(Test):#1.foo().o [Test]\n" + + "src/b110336/Test.java void b110336.Test.method1(Test) [Test]\n" + + "src/b110336/Test.java void b110336.Test.method1(Test).localVar1 [Test]", + collector + ); +} +public void testBug110336c() throws CoreException { + workingCopies = new ICompilationUnit[1]; + workingCopies[0] = getWorkingCopy("/JavaSearchBugs/src/b110336/Test.java", + "package b110336;\n" + + "public class Test {\n" + + " X x;\n" + + "\n" + + "}\n" + + "class X {}\n" + ); + IType type = this.workingCopies[0].getType("X"); + LocalVariablesCollector collector = new LocalVariablesCollector(); + search(type, REFERENCES, EXACT_RULE, getJavaSearchScopeBugs(), collector); + assertSearchResults( + "src/b110336/Test.java b110336.Test.TP [X]\n" + + "src/b110336/Test.java b110336.Test.x [X]", + collector + ); +} } Index: src/org/eclipse/jdt/core/tests/model/AbstractJavaSearchTests.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/AbstractJavaSearchTests.java,v retrieving revision 1.14 diff -u -r1.14 AbstractJavaSearchTests.java --- src/org/eclipse/jdt/core/tests/model/AbstractJavaSearchTests.java 26 Oct 2005 18:00:59 -0000 1.14 +++ src/org/eclipse/jdt/core/tests/model/AbstractJavaSearchTests.java 21 Nov 2005 09:36:19 -0000 @@ -58,7 +58,7 @@ count++; try { IResource resource = match.getResource(); - IJavaElement element = (IJavaElement) match.getElement(); + IJavaElement element = getElement(match); line = new StringBuffer(getPathString(resource, element)); if (this.showProject) { IProject project = element.getJavaProject().getProject(); @@ -104,6 +104,24 @@ line.append("."); line.append(localVar.getElementName()); unit = (ICompilationUnit)localVar.getAncestor(IJavaElement.COMPILATION_UNIT); + } else if (element instanceof ITypeParameter) { + line.append(" "); + ITypeParameter typeParam = (ITypeParameter)element; + IJavaElement parent = typeParam.getParent(); + if (parent instanceof IType) { + IType type = (IType)parent; + append(type); + unit = type.getCompilationUnit(); + } else if (parent instanceof IMethod) { + IMethod method = (IMethod)parent; + append(method); + unit = method.getCompilationUnit(); + } else { + line.append(""); + unit = (ICompilationUnit)typeParam.getAncestor(IJavaElement.COMPILATION_UNIT); + } + line.append("."); + line.append(typeParam.getElementName()); } else if (element instanceof IImportDeclaration) { IImportDeclaration importDeclaration = (IImportDeclaration)element; unit = (ICompilationUnit)importDeclaration.getAncestor(IJavaElement.COMPILATION_UNIT); @@ -288,6 +306,9 @@ line.append(((SourceRefElement)type).occurrenceCount); } } + protected IJavaElement getElement(SearchMatch match) { + return (IJavaElement) match.getElement(); + } protected String getPathString(IResource resource, IJavaElement element) { String pathString; if (resource != null) {