### Eclipse Workspace Patch 1.0 #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 23 Nov 2005 17:11:38 -0000 @@ -44,17 +44,45 @@ static { // org.eclipse.jdt.internal.core.search.BasicSearchEngine.VERBOSE = true; // org.eclipse.jdt.internal.codeassist.SelectionEngine.DEBUG = true; -// TESTS_PREFIX = "testBug110060"; -// TESTS_NAMES = new String[] { "testBug113671" }; -// TESTS_NUMBERS = new int[] { 114539 }; +// TESTS_PREFIX = "testBug110336"; +// TESTS_NAMES = new String[] { "testBug110336e" }; +// TESTS_NUMBERS = new int[] { 79267 }; // TESTS_RANGE = new int[] { 83304, -1 }; } class TestCollector extends JavaSearchResultCollector { public List matches = new ArrayList(); - public void acceptSearchMatch(SearchMatch match) throws CoreException { - super.acceptSearchMatch(match); - matches.add(match); + public void acceptSearchMatch(SearchMatch searchMatch) throws CoreException { + super.acceptSearchMatch(searchMatch); + matches.add(searchMatch); + } +} +class TypeReferencesCollector extends JavaSearchResultCollector { + + protected IJavaElement getElement(SearchMatch searchMatch) { + IJavaElement element = super.getElement(searchMatch); + IJavaElement localElement = null; + TypeReferenceMatch typeRefMatch = (TypeReferenceMatch) match; + localElement = typeRefMatch.getLocalElement(); + if (localElement != null) { + return localElement; + } + return element; + } + protected void writeLine() throws CoreException { + super.writeLine(); + TypeReferenceMatch typeRefMatch = (TypeReferenceMatch) this.match; + IJavaElement[] others = typeRefMatch.getOtherElements(); + int length = others==null ? 0 : others.length; + if (length > 0) { + line.append("+["); + for (int i=0; i0) line.append(','); + line.append(other.getElementName()); + } + line.append(']'); + } } } @@ -5268,7 +5296,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 +5312,163 @@ ); 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"); + TypeReferencesCollector collector = new TypeReferencesCollector(); + 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).clazz [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"); + TypeReferencesCollector collector = new TypeReferencesCollector(); + 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).methodParam [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"); + TypeReferencesCollector collector = new TypeReferencesCollector(); + 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 + ); +} +public void testBug110336d() throws CoreException { + workingCopies = new ICompilationUnit[1]; + workingCopies[0] = getWorkingCopy("/JavaSearchBugs/src/b110336/Test.java", + "package b110336;\n" + + "public class Test {\n" + + " Test a1Test = null, b1Test = new Test(), c1Test;\n" + + " Test a2Test = new Test(), b2Test, c2Test = null;\n" + + " Test a3Test, b3Test = null, c3Test = new Test();\n" + + "}\n" + ); + IType type = this.workingCopies[0].getType("Test"); + TypeReferencesCollector collector = new TypeReferencesCollector(); + search(type, REFERENCES, EXACT_RULE, getJavaSearchScopeBugs(), collector); + assertSearchResults( + "src/b110336/Test.java b110336.Test.a1Test [Test]+[b1Test,c1Test]\n" + + "src/b110336/Test.java b110336.Test.b1Test [Test]\n" + + "src/b110336/Test.java b110336.Test.a2Test [Test]+[b2Test,c2Test]\n" + + "src/b110336/Test.java b110336.Test.a2Test [Test]\n" + + "src/b110336/Test.java b110336.Test.a3Test [Test]+[b3Test,c3Test]\n" + + "src/b110336/Test.java b110336.Test.c3Test [Test]", + collector + ); +} +public void testBug110336e() throws CoreException { + workingCopies = new ICompilationUnit[1]; + workingCopies[0] = getWorkingCopy("/JavaSearchBugs/src/b110336/Test.java", + "package b110336;\n" + + "public class Test {\n" + + " void foo() {\n" + + " Test lv1 = null, lv2 = new Test(), lv3;\n" + + " Test lv4 = new Test(), lv5, lv6 = null;\n" + + " Test lv7, lv8 = null, lv9 = new Test();\n" + + " }\n" + + "}\n" + ); + IType type = this.workingCopies[0].getType("Test"); + TypeReferencesCollector collector = new TypeReferencesCollector(); + search(type, REFERENCES, EXACT_RULE, getJavaSearchScopeBugs(), collector); + assertSearchResults( + "src/b110336/Test.java void b110336.Test.foo().lv1 [Test]+[lv2,lv3]\n" + + "src/b110336/Test.java void b110336.Test.foo().lv2 [Test]\n" + + "src/b110336/Test.java void b110336.Test.foo().lv4 [Test]+[lv5,lv6]\n" + + "src/b110336/Test.java void b110336.Test.foo().lv4 [Test]\n" + + "src/b110336/Test.java void b110336.Test.foo().lv7 [Test]+[lv8,lv9]\n" + + "src/b110336/Test.java void b110336.Test.foo().lv9 [Test]", + collector + ); +} +public void testBug110336f() throws CoreException { + workingCopies = new ICompilationUnit[1]; + workingCopies[0] = getWorkingCopy("/JavaSearchBugs/src/b110336/Test.java", + "package b110336;\n" + + "public class Test extends Exception {\n" + + " void foo(Test test1) { // <- no local element\n" + + " Test test2; // <- local element\n" + + " try {\n" + + " throw new Test();\n" + + " }\n" + + " catch (Test test4) { // <- no local element\n" + + " }\n" + + " for(Test test3;;) {} // <- local element\n" + + " }\n" + + "\n" + + "}\n" + ); + IType type = this.workingCopies[0].getType("Test"); + TypeReferencesCollector collector = new TypeReferencesCollector(); + search(type, REFERENCES, EXACT_RULE, getJavaSearchScopeBugs(), collector); + assertSearchResults( + "src/b110336/Test.java void b110336.Test.foo(Test).test1 [Test]\n" + + "src/b110336/Test.java void b110336.Test.foo(Test).test2 [Test]\n" + + "src/b110336/Test.java void b110336.Test.foo(Test) [Test]\n" + + "src/b110336/Test.java void b110336.Test.foo(Test).test4 [Test]\n" + + "src/b110336/Test.java void b110336.Test.foo(Test).test3 [Test]", + collector + ); +} } Index: src/org/eclipse/jdt/core/tests/model/JavaSearchTests.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/JavaSearchTests.java,v retrieving revision 1.143 diff -u -r1.143 JavaSearchTests.java --- src/org/eclipse/jdt/core/tests/model/JavaSearchTests.java 26 Oct 2005 18:01:00 -0000 1.143 +++ src/org/eclipse/jdt/core/tests/model/JavaSearchTests.java 23 Nov 2005 17:11:40 -0000 @@ -40,7 +40,7 @@ static { // org.eclipse.jdt.internal.core.search.BasicSearchEngine.VERBOSE = true; // TESTS_PREFIX = "testCamelCase"; -// TESTS_NAMES = new String[] { "testMethodDeclaration11" }; + TESTS_NAMES = new String[] { "testTypeReference11" }; // TESTS_NUMBERS = new int[] { 113671 }; // TESTS_RANGE = new int[] { 16, -1 }; } 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 23 Nov 2005 17:11:34 -0000 @@ -45,6 +45,7 @@ * Collects results as a string. */ public static class JavaSearchResultCollector extends SearchRequestor { + protected SearchMatch match; public StringBuffer results = new StringBuffer(), line; public boolean showAccuracy; public boolean showContext; @@ -54,11 +55,22 @@ public boolean showProject; public boolean showSynthetic; public int count = 0; - public void acceptSearchMatch(SearchMatch match) throws CoreException { + public void acceptSearchMatch(SearchMatch searchMatch) throws CoreException { count++; + this.match = searchMatch; + writeLine(); + writeLineToResult(); + } + protected void writeLineToResult() { + if (match.getAccuracy() == SearchMatch.A_ACCURATE || showPotential) { + if (results.length() > 0) results.append("\n"); + results.append(line); + } + } + protected void writeLine() throws CoreException { 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 +116,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); @@ -180,16 +210,12 @@ } } } - if (match.getAccuracy() == SearchMatch.A_ACCURATE || showPotential) { - if (results.length() > 0) results.append("\n"); - results.append(line); - } } catch (JavaModelException e) { results.append("\n"); results.append(e.toString()); } } - private void append(IField field) throws JavaModelException { + protected void append(IField field) throws JavaModelException { append(field.getDeclaringType()); line.append("."); line.append(field.getElementName()); @@ -288,6 +314,9 @@ line.append(((SourceRefElement)type).occurrenceCount); } } + protected IJavaElement getElement(SearchMatch searchMatch) { + return (IJavaElement) searchMatch.getElement(); + } protected String getPathString(IResource resource, IJavaElement element) { String pathString; if (resource != null) { #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 23 Nov 2005 17:11:45 -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; @@ -165,7 +166,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 +562,34 @@ } 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.PARAMETER: + 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. @@ -1364,7 +1392,7 @@ return new TypeParameterReferenceMatch(enclosingElement, accuracy, offset, length, insideDocComment, participant, resource); } -public SearchMatch newTypeReferenceMatch( +public TypeReferenceMatch newTypeReferenceMatch( IJavaElement enclosingElement, Binding enclosingBinding, int accuracy, @@ -1379,7 +1407,7 @@ return new TypeReferenceMatch(enclosingElement, accuracy, offset, length, insideDocComment, participant, resource); } -public SearchMatch newTypeReferenceMatch( +public TypeReferenceMatch newTypeReferenceMatch( IJavaElement enclosingElement, Binding enclosingBinding, int accuracy, @@ -1541,6 +1569,26 @@ } catch (Exception e) { // it's just for debug purposes... ignore all exceptions in this area } + if (match instanceof TypeReferenceMatch) { + try { + TypeReferenceMatch typeRefMatch = (TypeReferenceMatch) match; + JavaElement local = (JavaElement) typeRefMatch.getLocalElement(); + if (local != null) { + System.out.println("\tLocal element: "+ local.toStringWithAncestors()); //$NON-NLS-1$ + } + IJavaElement[] others = typeRefMatch.getOtherElements(); + int length = others==null ? 0 : others.length; + if (length > 0) { + System.out.println("\tOther elements:"); //$NON-NLS-1$ + for (int i=0; i -1) { enclosingElement = createHandle(field, type, parent); @@ -2065,17 +2122,39 @@ } if (typeInHierarchy) { - // limit scan to end part position for multiple fields declaration (see bug 73112) - int end = field.endPart2Position==0 ? field.declarationSourceEnd : field.endPart2Position; - ASTNode[] nodes = nodeSet.matchingNodes(field.declarationSourceStart, end); + // Look at field declaration + if (field.endPart1Position != 0) { // not an initializer + ASTNode[] nodes = nodeSet.matchingNodes(field.declarationSourceStart, field.endPart1Position); + if (nodes != null) { + if ((this.matchContainer & PatternLocator.FIELD_CONTAINER) == 0) { + for (int i = 0, l = nodes.length; i < l; i++) + nodeSet.matchingNodes.removeKey(nodes[i]); + } else { + if (enclosingElement == null) + enclosingElement = createHandle(field, type, parent); + if (encloses(enclosingElement)) { + for (int i = 0, l = nodes.length; i < l; i++) { + ASTNode node = nodes[i]; + Integer level = (Integer) nodeSet.matchingNodes.removeKey(node); + this.patternLocator.matchReportReference(node, enclosingElement, null, otherElements, field.binding, level.intValue(), this); + } + } + } + } + } + + // Look in initializers + int fieldEnd = field.endPart2Position == 0 ? field.declarationSourceEnd : field.endPart2Position; + ASTNode[] nodes = nodeSet.matchingNodes(field.sourceStart, fieldEnd); if (nodes != null) { if ((this.matchContainer & PatternLocator.FIELD_CONTAINER) == 0) { for (int i = 0, l = nodes.length; i < l; i++) nodeSet.matchingNodes.removeKey(nodes[i]); } else { - if (enclosingElement == null) + if (enclosingElement == null) { enclosingElement = createHandle(field, type, parent); - if (encloses(enclosingElement)) + } + if (encloses(enclosingElement)) { for (int i = 0, l = nodes.length; i < l; i++) { ASTNode node = nodes[i]; Integer level = (Integer) nodeSet.matchingNodes.removeKey(node); @@ -2088,6 +2167,7 @@ } this.patternLocator.matchReportReference(node, enclosingElement, field.binding, level.intValue(), this); } + } } } } @@ -2121,36 +2201,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= 0) { + // Create handle for all multiple fields except first one as it would be returned through the match + if (i > first) { + if (otherElements == null) { + otherElements = new IJavaElement[] { createHandle(field, type, enclosingElement) }; + } else { + int length = otherElements.length; + System.arraycopy(otherElements, 0, otherElements = new IJavaElement[length+1], 0, length); + otherElements[length] = createHandle(field, type, enclosingElement); + } + } + // On last field, report match with all other elements + if (last) { + for (int j=first; j<=i; j++) { + Integer level = (Integer) nodeSet.matchingNodes.removeKey(fields[j]); + int value = (level != null && matchedClassContainer) ? level.intValue() : -1; + reportMatching(fields[j], type, enclosingElement, otherElements, value, typeInHierarchy, nodeSet); + } + first = -1; + otherElements = null; + } + } else { + // Single field, report normally + Integer level = (Integer) nodeSet.matchingNodes.removeKey(field); + int value = (level != null && matchedClassContainer) ? level.intValue() : -1; + reportMatching(field, type, enclosingElement, null, value, typeInHierarchy, nodeSet); + } } } + // Visit methods AbstractMethodDeclaration[] methods = type.methods; if (methods != null) { - if (nodeSet.matchingNodes.elementSize == 0) return; // reported all the matching nodes + if (nodeSet.matchingNodes.elementSize == 0) return; // end as all matching nodes were reported for (int i = 0, l = methods.length; i < l; i++) { AbstractMethodDeclaration method = methods[i]; Integer level = (Integer) nodeSet.matchingNodes.removeKey(method); @@ -2224,10 +2314,11 @@ } } + // Visit types TypeDeclaration[] memberTypes = type.memberTypes; if (memberTypes != null) { for (int i = 0, l = memberTypes.length; i < l; i++) { - if (nodeSet.matchingNodes.elementSize == 0) return; // reported all the matching nodes + if (nodeSet.matchingNodes.elementSize == 0) return; // end as all matching nodes were reported TypeDeclaration memberType = memberTypes[i]; Integer level = (Integer) nodeSet.matchingNodes.removeKey(memberType); int value = (level != null && matchedClassContainer) ? level.intValue() : -1; @@ -2235,6 +2326,41 @@ } } } +/** + * Report matches in type parameters. + */ +protected void reportMatching(TypeParameter[] typeParameters, IJavaElement enclosingElement, IJavaElement parent, Binding binding, MatchingNodeSet nodeSet) throws CoreException { + if (typeParameters == null) return; + for (int i=0, l=typeParameters.length; i -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) { + IJavaElement localElement = createHandle(typeParameter, enclosingElement); + this.patternLocator.matchReportReference(typeParameter.type, enclosingElement, localElement, null, binding, level.intValue(), this); + } + } + if (typeParameter.bounds != null) { + for (int j=0, b=typeParameter.bounds.length; j 0) { + // Set other elements to as it's different from enclosing one + int idx = 0; + for (; idx0 && localDeclarations[idx].sourceStart > reference.sourceStart) { + localElement = locator.createHandle(localDeclarations[idx-1], element); + break; + } + } + if (localElement == null && idx > 0) { + if (reference.sourceEnd < localDeclarations[idx-1].declarationEnd) { + localElement = locator.createHandle(localDeclarations[idx-1], element); + } + } + int size = 0; + for (int j=1; j 0 && size != (length-1)) { + System.arraycopy(otherElements, 0, otherElements = new IJavaElement[size], 0, size); + } + } + matchReportReference(reference, element, localElement, otherElements, elementBinding, accuracy, locator); +} protected void matchReportReference(QualifiedNameReference qNameRef, IJavaElement element, Binding elementBinding, int accuracy, MatchLocator locator) throws CoreException { Binding binding = qNameRef.binding; TypeBinding typeBinding = null; @@ -325,7 +388,9 @@ } // Create search match to report - match = locator.newTypeReferenceMatch(element, elementBinding, accuracy, qNameRef); + if (this.match == null) { + this.match = locator.newTypeReferenceMatch(element, elementBinding, accuracy, qNameRef); + } // try to match all enclosing types for which the token matches as well. if (typeBinding instanceof ReferenceBinding) { @@ -368,7 +433,9 @@ } // Create search match to report - match = locator.newTypeReferenceMatch(element, elementBinding, accuracy, qTypeRef); + if (this.match == null) { + this.match = locator.newTypeReferenceMatch(element, elementBinding, accuracy, qTypeRef); + } // try to match all enclosing types for which the token matches as well if (typeBinding instanceof ReferenceBinding) { Index: search/org/eclipse/jdt/core/search/TypeReferenceMatch.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/TypeReferenceMatch.java,v retrieving revision 1.14 diff -u -r1.14 TypeReferenceMatch.java --- search/org/eclipse/jdt/core/search/TypeReferenceMatch.java 23 Feb 2005 02:47:30 -0000 1.14 +++ search/org/eclipse/jdt/core/search/TypeReferenceMatch.java 23 Nov 2005 17:11:43 -0000 @@ -24,6 +24,9 @@ */ public class TypeReferenceMatch extends SearchMatch { + private IJavaElement[] otherElements; + private IJavaElement localElement; + /** * Creates a new type reference match. * @@ -40,4 +43,45 @@ super(enclosingElement, accuracy, offset, length, participant, resource); setInsideDocComment(insideDocComment); } + + /** + * Returns the local element of this search match. + * This may be a local variable or a type parameter. + * + * @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 IJavaElement getLocalElement() { + return this.localElement; + } + + /** + * Returns other elements of this search match. + * These may be other fields of a multiple fields declaration. + * + * @return the other elements of the search match, or null if none. + */ + public final IJavaElement[] getOtherElements() { + return this.otherElements; + } + + /** + * Sets the local element of this search match. + * + * @param element the local element that encloses or corresponds to the match, + * or null if none + */ + public final void setLocalElement(IJavaElement element) { + this.localElement = element; + } + + /** + * Sets the other elements of this search match. + * + * @param elements the other elements of the match, + * or null if none + */ + public final void setOtherElements(IJavaElement[] elements) { + this.otherElements = elements; + } } Index: compiler/org/eclipse/jdt/internal/compiler/lookup/BlockScope.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BlockScope.java,v retrieving revision 1.94 diff -u -r1.94 BlockScope.java --- compiler/org/eclipse/jdt/internal/compiler/lookup/BlockScope.java 18 Nov 2005 16:46:23 -0000 1.94 +++ compiler/org/eclipse/jdt/internal/compiler/lookup/BlockScope.java 23 Nov 2005 17:11:43 -0000 @@ -299,6 +299,63 @@ } } + /** + * Returns all declarations of most specific locals containing a given position in their source range. + * This code does not recurse in nested types. + * Returned array may have null values at trailing indexes. + */ + public LocalDeclaration[] findLocalVariableDeclarations(int position) { + + // local variable init + int ilocal = 0, maxLocals = this.localIndex; + boolean hasMoreVariables = maxLocals > 0; + LocalDeclaration[] localDeclarations = null; + int declPtr = 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 + localDeclarations = ((BlockScope)subscope).findLocalVariableDeclarations(position); + if (localDeclarations != null) { + return localDeclarations; + } + } + 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) { + if (localDeclarations == null) { + localDeclarations = new LocalDeclaration[maxLocals]; + } + localDeclarations[declPtr++] = localDecl; + } + } else { + return localDeclarations; + } + } + } + hasMoreVariables = ++ilocal < maxLocals; + if (!hasMoreVariables && localDeclarations != null) { + return localDeclarations; + } + } + } + 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: *