### Eclipse Workspace Patch 1.0 #P org.eclipse.jdt.core.tests.model Index: src/org/eclipse/jdt/core/tests/dom/AbstractASTTests.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/AbstractASTTests.java,v retrieving revision 1.34 diff -u -r1.34 AbstractASTTests.java --- src/org/eclipse/jdt/core/tests/dom/AbstractASTTests.java 24 Oct 2007 13:50:40 -0000 1.34 +++ src/org/eclipse/jdt/core/tests/dom/AbstractASTTests.java 26 Nov 2007 17:25:41 -0000 @@ -50,6 +50,7 @@ import org.eclipse.jdt.core.dom.TypeDeclaration; import org.eclipse.jdt.core.dom.TypeDeclarationStatement; import org.eclipse.jdt.core.dom.TypeParameter; +import org.eclipse.jdt.core.dom.VariableDeclarationFragment; import org.eclipse.jdt.core.dom.WildcardType; import org.eclipse.jdt.core.tests.model.ModifyingResourceTests; import org.eclipse.jdt.core.tests.util.Util; @@ -528,6 +529,8 @@ return ((NormalAnnotation) node).resolveAnnotationBinding(); case ASTNode.SINGLE_MEMBER_ANNOTATION: return ((SingleMemberAnnotation) node).resolveAnnotationBinding(); + case ASTNode.VARIABLE_DECLARATION_FRAGMENT: + return ((VariableDeclarationFragment) node).resolveBinding(); default: throw new Error("Not yet implemented for this type of node: " + node); } Index: src/org/eclipse/jdt/core/tests/dom/ASTModelBridgeTests.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTModelBridgeTests.java,v retrieving revision 1.51 diff -u -r1.51 ASTModelBridgeTests.java --- src/org/eclipse/jdt/core/tests/dom/ASTModelBridgeTests.java 24 Oct 2007 13:50:40 -0000 1.51 +++ src/org/eclipse/jdt/core/tests/dom/ASTModelBridgeTests.java 26 Nov 2007 17:25:41 -0000 @@ -47,6 +47,15 @@ // TESTS_RANGE = new int[] { 83304, -1 }; } + private void assertFindElement(String key, String expectedElement) throws JavaModelException { + IJavaElement element = getJavaProject("P").findElement(key, this.workingCopy.getOwner()); + assertElementEquals( + "Unexpected found element", + expectedElement, + element + ); + } + /* * Removes the marker comments "*start*" and "*end*" from the given contents, * builds an AST from the resulting source, and returns the AST node that was delimited @@ -56,6 +65,19 @@ return buildAST(contents, this.workingCopy); } + /* + * Removes the marker comments "*start*" and "*end*" from the given contents, + * builds an AST from the resulting source, gets the binding from the AST node that was delimited + * by "*start*" and "*end*", and returns the binding key. + */ + private String buildBindingKey(String contents) throws JavaModelException { + ASTNode node = buildAST(contents); + if (node == null) return null; + IBinding binding = resolveBinding(node); + if (binding == null) return null; + return binding.getKey(); + } + private IBinding[] createBindings(String contents, IJavaElement element) throws JavaModelException { this.workingCopy.getBuffer().setContents(contents); this.workingCopy.makeConsistent(null); @@ -145,7 +167,7 @@ tearDownJavaProject(); super.tearDownSuite(); } - + private void tearDownJavaProject() throws JavaModelException, CoreException { if (this.workingCopy != null) this.workingCopy.discardWorkingCopy(); @@ -1003,6 +1025,198 @@ } /* + * Ensures that an IType can be found using its binding key. + */ + public void testFindElement01() throws JavaModelException { + String bindingKey = buildBindingKey( + "/*start*/public class X {\n" + + "}/*end*/" + ); + assertFindElement( + bindingKey, + "X [in [Working copy] X.java [in [in src [in P]]]]" + ); + } + + /* + * Ensures that an IMethod can be found using its binding key. + */ + public void testFindElement02() throws JavaModelException { + String bindingKey = buildBindingKey( + "public class X {\n" + + " /*start*/void foo() {\n" + + " }/*end*/\n" + + "}" + ); + assertFindElement( + bindingKey, + "foo() [in X [in [Working copy] X.java [in [in src [in P]]]]]" + ); + } + + /* + * Ensures that an IField can be found using its binding key. + */ + public void testFindElement03() throws JavaModelException { + String bindingKey = buildBindingKey( + "public class X {\n" + + " int /*start*/field/*end*/;\n" + + "}" + ); + assertFindElement( + bindingKey, + "field [in X [in [Working copy] X.java [in [in src [in P]]]]]" + ); + } + + /* + * Ensures that a member IType can be found using its binding key. + */ + public void testFindElement04() throws JavaModelException { + String bindingKey = buildBindingKey( + "public class X {\n" + + " /*start*/class Member {\n" + + " }/*end*/\n" + + "}" + ); + assertFindElement( + bindingKey, + "Member [in X [in [Working copy] X.java [in [in src [in P]]]]]" + ); + } + + /* + * Ensures that a local IType can be found using its binding key. + */ + public void testFindElement05() throws JavaModelException { + String bindingKey = buildBindingKey( + "public class X {\n" + + " void foo() {\n" + + " /*start*/class Local {\n" + + " }/*end*/\n" + + " }\n" + + "}" + ); + assertFindElement( + bindingKey, + "Local [in foo() [in X [in [Working copy] X.java [in [in src [in P]]]]]]" + ); + } + + /* + * Ensures that an anonymous IType can be found using its binding key. + */ + public void testFindElement06() throws JavaModelException { + String bindingKey = buildBindingKey( + "public class X {\n" + + " void foo() {\n" + + " new X() /*start*/{\n" + + " }/*end*/;\n" + + " }\n" + + "}" + ); + assertFindElement( + bindingKey, + " [in foo() [in X [in [Working copy] X.java [in [in src [in P]]]]]]" + ); + } + + /* + * Ensures that a secondary IType can be found using its binding key. + */ + public void testFindElement07() throws JavaModelException { + String bindingKey = buildBindingKey( + "public class X {\n" + + "}\n" + + "/*start*/class Secondary {\n" + + "}/*end*/" + ); + assertFindElement( + bindingKey, + "Secondary [in [Working copy] X.java [in [in src [in P]]]]" + ); + } + + /* + * Ensures that an IAnnotation can be found using its binding key. + */ + public void testFindElement08() throws JavaModelException { + String bindingKey = buildBindingKey( + "/*start*/@MyAnnot/*end*/\n" + + "public class X {\n" + + "}\n" + + "@interface MyAnnot {\n" + + "}" + ); + assertFindElement( + bindingKey, + "@MyAnnot [in X [in [Working copy] X.java [in [in src [in P]]]]]" + ); + } + + /* + * Ensures that an IPackageFragment can be found using its binding key. + */ + public void testFindElement09() throws JavaModelException { + String bindingKey = buildBindingKey( + "public class X {\n" + + " /*start*/java.lang/*end*/.String field;\n" + + "}" + ); + assertFindElement( + bindingKey, + "java.lang [in "+ getExternalJCLPathString("1.5") + "]" + ); + } + + /* + * Ensures that an ITypeParameter can be found using its binding key. + */ + public void testFindElement10() throws JavaModelException { + String bindingKey = buildBindingKey( + "public class X {\n" + + "}" + ); + assertFindElement( + bindingKey, + " [in X [in [Working copy] X.java [in [in src [in P]]]]]" + ); + } + + /* + * Ensures that a binary top level IType can be found using its binding key. + */ + public void testFindElement11() throws JavaModelException { + String bindingKey = getClassFile("/P/lib.jar/p/Y.class").getType().getKey(); + assertFindElement( + bindingKey, + "Y [in Y.class [in p [in lib.jar [in P]]]]" + ); + } + + /* + * Ensures that a binary member IType can be found using its binding key. + */ + public void testFindElement12() throws JavaModelException { + String bindingKey = getClassFile("/P/lib.jar/p/Z$Member.class").getType().getKey(); + assertFindElement( + bindingKey, + "Member [in Z$Member.class [in p [in lib.jar [in P]]]]" + ); + } + + /* + * Ensures that a binary anonymous IType can be found using its binding key. + */ + public void testFindElement13() throws JavaModelException { + String bindingKey = getClassFile("/P/lib.jar/p/Z$1.class").getType().getKey(); + assertFindElement( + bindingKey, + "Z$1.class [in p [in lib.jar [in P]]]" + ); + } + + /* * Ensures that the IJavaElement of an IBinding representing a local type is correct. */ public void testLocalType() throws JavaModelException { #P org.eclipse.jdt.core Index: model/org/eclipse/jdt/internal/core/JavaProject.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaProject.java,v retrieving revision 1.391 diff -u -r1.391 JavaProject.java --- model/org/eclipse/jdt/internal/core/JavaProject.java 21 Sep 2007 13:16:47 -0000 1.391 +++ model/org/eclipse/jdt/internal/core/JavaProject.java 26 Nov 2007 17:25:44 -0000 @@ -69,6 +69,7 @@ import org.eclipse.jdt.internal.core.JavaProjectElementInfo.ProjectCache; import org.eclipse.jdt.internal.core.builder.JavaBuilder; import org.eclipse.jdt.internal.core.eval.EvaluationContextWrapper; +import org.eclipse.jdt.internal.core.util.JavaElementFinder; import org.eclipse.jdt.internal.core.util.MementoTokenizer; import org.eclipse.jdt.internal.core.util.Messages; import org.eclipse.jdt.internal.core.util.Util; @@ -1023,24 +1024,7 @@ String extension = path.getFileExtension(); if (extension == null) { String packageName = path.toString().replace(IPath.SEPARATOR, '.'); - - NameLookup lookup = newNameLookup((WorkingCopyOwner)null/*no need to look at working copies for pkgs*/); - IPackageFragment[] pkgFragments = lookup.findPackageFragments(packageName, false); - if (pkgFragments == null) { - return null; - - } else { - // try to return one that is a child of this project - for (int i = 0, length = pkgFragments.length; i < length; i++) { - - IPackageFragment pkgFragment = pkgFragments[i]; - if (this.equals(pkgFragment.getParent().getParent())) { - return pkgFragment; - } - } - // default to the first one - return pkgFragments[0]; - } + return findPackageFragment(packageName); } else if (Util.isJavaLikeFileName(path.lastSegment()) || extension.equalsIgnoreCase(EXTENSION_class)) { IPath packagePath = path.removeLastSegments(1); @@ -1084,6 +1068,35 @@ } } + public IJavaElement findPackageFragment(String packageName) + throws JavaModelException { + NameLookup lookup = newNameLookup((WorkingCopyOwner)null/*no need to look at working copies for pkgs*/); + IPackageFragment[] pkgFragments = lookup.findPackageFragments(packageName, false); + if (pkgFragments == null) { + return null; + + } else { + // try to return one that is a child of this project + for (int i = 0, length = pkgFragments.length; i < length; i++) { + + IPackageFragment pkgFragment = pkgFragments[i]; + if (this.equals(pkgFragment.getParent().getParent())) { + return pkgFragment; + } + } + // default to the first one + return pkgFragments[0]; + } + } + + public IJavaElement findElement(String bindingKey, WorkingCopyOwner owner) throws JavaModelException { + JavaElementFinder elementFinder = new JavaElementFinder(bindingKey, this, owner); + elementFinder.parse(); + if (elementFinder.exception != null) + throw elementFinder.exception; + return elementFinder.element; + } + /** * @see IJavaProject */ Index: model/org/eclipse/jdt/core/IJavaProject.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IJavaProject.java,v retrieving revision 1.92 diff -u -r1.92 IJavaProject.java --- model/org/eclipse/jdt/core/IJavaProject.java 20 Aug 2007 14:58:34 -0000 1.92 +++ model/org/eclipse/jdt/core/IJavaProject.java 26 Nov 2007 17:25:43 -0000 @@ -23,6 +23,11 @@ import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IPath; +import org.eclipse.jdt.core.dom.IAnnotationBinding; +import org.eclipse.jdt.core.dom.IMethodBinding; +import org.eclipse.jdt.core.dom.IPackageBinding; +import org.eclipse.jdt.core.dom.ITypeBinding; +import org.eclipse.jdt.core.dom.IVariableBinding; import org.eclipse.jdt.core.eval.IEvaluationContext; /** @@ -128,6 +133,43 @@ IJavaElement findElement(IPath path, WorkingCopyOwner owner) throws JavaModelException; /** + * Finds the Java element corresponding to the given binding key. Elements are + * looked up using this project's classpath. The first element corresponding to + * the given key on this project's classpath is returned. + * Returns null if the element is not found. + *

Possible elements are: + *

    + *
  • {@link IPackageFragment} for a binding key from an + * {@link IPackageBinding}
  • + *
  • {@link IType} for a binding key from an {@link ITypeBinding}
  • + *
  • {@link IMethod} for a binding key from an {@link IMethodBinding}
  • + *
  • {@link IField} for a binding key from an {@link IVariableBinding} + * representing a {@link IVariableBinding#isField() field}
  • + *
  • {@link ITypeParameter} for a binding key from an {@link ITypeBinding} + * representing a {@link ITypeBinding#isTypeVariable() type + * variable}
  • + *
  • {@link IAnnotation} for a binding key from an + * {@link IAnnotationBinding}
  • + *

+ *

As Java elements are not resolved, if a binding key contains resolved + * information (see {@link IMethod#isResolved()} for example), this information + * cannot be used to retrieve the method. Thus the first method with matching + * simple parameter types (see {@link IType#findMethods(IMethod)} is returned. + *

+ * + * @param bindingKey the given binding key + * @param owner the owner of the returned element's compilation unit, + * or null if the default working copy owner must be + * used + * @exception JavaModelException if this project does not exist or if an + * exception occurs while accessing its corresponding resource + * @return the Java element corresponding to the given key, + * or null if no such Java element is found + * @since 3.4 + */ + IJavaElement findElement(String bindingKey, WorkingCopyOwner owner) throws JavaModelException; + + /** * Returns the first existing package fragment on this project's classpath * whose path matches the given (absolute) path, or null if none * exist. Index: model/org/eclipse/jdt/internal/core/util/JavaElementFinder.java =================================================================== RCS file: model/org/eclipse/jdt/internal/core/util/JavaElementFinder.java diff -N model/org/eclipse/jdt/internal/core/util/JavaElementFinder.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ model/org/eclipse/jdt/internal/core/util/JavaElementFinder.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,145 @@ +/******************************************************************************* + * Copyright (c) 2000, 2007 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.core.util; + +import java.util.ArrayList; + +import org.eclipse.jdt.core.IAnnotatable; +import org.eclipse.jdt.core.ICompilationUnit; +import org.eclipse.jdt.core.IJavaElement; +import org.eclipse.jdt.core.IMethod; +import org.eclipse.jdt.core.IOpenable; +import org.eclipse.jdt.core.IPackageFragment; +import org.eclipse.jdt.core.IType; +import org.eclipse.jdt.core.ITypeRoot; +import org.eclipse.jdt.core.JavaModelException; +import org.eclipse.jdt.core.Signature; +import org.eclipse.jdt.core.WorkingCopyOwner; +import org.eclipse.jdt.core.compiler.CharOperation; +import org.eclipse.jdt.internal.compiler.util.SuffixConstants; +import org.eclipse.jdt.internal.core.*; + +public class JavaElementFinder extends BindingKeyParser { + + private JavaProject project; + private WorkingCopyOwner owner; + public IJavaElement element; + public JavaModelException exception; + private ArrayList types = new ArrayList(); + + public JavaElementFinder(String key, JavaProject project, WorkingCopyOwner owner) { + super(key); + this.project = project; + this.owner = owner; + } + + private JavaElementFinder(BindingKeyParser parser, JavaProject project, WorkingCopyOwner owner) { + super(parser); + this.project = project; + this.owner = owner; + } + + public void consumeAnnotation() { + if (!(this.element instanceof IAnnotatable)) return; + int size = this.types.size(); + if (size == 0) return; + IJavaElement annotationType = ((JavaElementFinder) this.types.get(size-1)).element; + this.element = ((IAnnotatable) this.element).getAnnotation(annotationType.getElementName()); + } + + public void consumeField(char[] fieldName) { + if (!(this.element instanceof IType)) return; + this.element = ((IType) this.element).getField(new String(fieldName)); + } + + public void consumeFullyQualifiedName(char[] fullyQualifiedName) { + try { + this.element = this.project.findType(new String(CharOperation.replaceOnCopy(fullyQualifiedName, '/', '.')), owner); + } catch (JavaModelException e) { + this.exception = e; + } + } + + public void consumeLocalType(char[] uniqueKey) { + if (this.element == null) return; + if (this.element instanceof BinaryType) { + int lastSlash = CharOperation.lastIndexOf('/', uniqueKey); + int end = CharOperation.indexOf(';', uniqueKey, lastSlash+1); + char[] localName = CharOperation.subarray(uniqueKey, lastSlash+1, end); + IPackageFragment pkg = (IPackageFragment) this.element.getAncestor(IJavaElement.PACKAGE_FRAGMENT); + this.element = pkg.getClassFile(new String(localName) + SuffixConstants.SUFFIX_STRING_class); + } else { + int firstDollar = CharOperation.indexOf('$', uniqueKey); + int end = CharOperation.indexOf('$', uniqueKey, firstDollar+1); + if (end == -1) + end = CharOperation.indexOf(';', uniqueKey, firstDollar+1); + char[] sourceStart = CharOperation.subarray(uniqueKey, firstDollar+1, end); + int position = Integer.parseInt(new String(sourceStart)); + try { + this.element = ((ITypeRoot) this.element.getOpenable()).getElementAt(position); + } catch (JavaModelException e) { + this.exception = e; + } + } + } + + public void consumeMemberType(char[] simpleTypeName) { + if (!(this.element instanceof IType)) return; + this.element = ((IType) this.element).getType(new String(simpleTypeName)); + } + + public void consumeMethod(char[] selector, char[] signature) { + if (!(this.element instanceof IType)) return; + String[] parameterTypes = Signature.getParameterTypes(new String(signature)); + IType type = (IType) this.element; + IMethod method = type.getMethod(new String(selector), parameterTypes); + IMethod[] methods = type.findMethods(method); + if (methods.length > 0) + this.element = methods[0]; + } + + public void consumePackage(char[] pkgName) { + pkgName = CharOperation.replaceOnCopy(pkgName, '/', '.'); + try { + this.element = this.project.findPackageFragment(new String(pkgName)); + } catch (JavaModelException e) { + this.exception = e; + } + } + + public void consumeParser(BindingKeyParser parser) { + this.types.add(parser); + } + + public void consumeSecondaryType(char[] simpleTypeName) { + if (this.element == null) return; + IOpenable openable = this.element.getOpenable(); + if (!(openable instanceof ICompilationUnit)) return; + this.element = ((ICompilationUnit) openable).getType(new String(simpleTypeName)); + } + + public void consumeTypeVariable(char[] position, char[] typeVariableName) { + if (this.element == null) return; + switch (this.element.getElementType()) { + case IJavaElement.TYPE: + this.element = ((IType) this.element).getTypeParameter(new String(typeVariableName)); + break; + case IJavaElement.METHOD: + this.element = ((IMethod) this.element).getTypeParameter(new String(typeVariableName)); + break; + } + } + + public BindingKeyParser newParser() { + return new JavaElementFinder(this, this.project, this.owner); + } + +}