### Eclipse Workspace Patch 1.0 #P org.eclipse.jdt.core Index: model/org/eclipse/jdt/internal/core/SearchableEnvironment.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SearchableEnvironment.java,v retrieving revision 1.74 diff -u -r1.74 SearchableEnvironment.java --- model/org/eclipse/jdt/internal/core/SearchableEnvironment.java 13 Oct 2008 20:06:01 -0000 1.74 +++ model/org/eclipse/jdt/internal/core/SearchableEnvironment.java 12 Dec 2008 14:27:09 -0000 @@ -24,6 +24,7 @@ import org.eclipse.jdt.internal.compiler.env.NameEnvironmentAnswer; import org.eclipse.jdt.internal.core.search.BasicSearchEngine; import org.eclipse.jdt.internal.core.search.IRestrictedAccessTypeRequestor; +import org.eclipse.jdt.internal.core.util.Util; /** * This class provides a SearchableBuilderEnvironment for code assist which @@ -35,6 +36,7 @@ public NameLookup nameLookup; protected ICompilationUnit unitToSkip; protected org.eclipse.jdt.core.ICompilationUnit[] workingCopies; + protected WorkingCopyOwner owner; protected JavaProject project; protected IJavaSearchScope searchScope; @@ -58,6 +60,7 @@ */ public SearchableEnvironment(JavaProject project, WorkingCopyOwner owner) throws JavaModelException { this(project, owner == null ? null : JavaModelManager.getJavaModelManager().getWorkingCopies(owner, true/*add primary WCs*/)); + this.owner = owner; } private static int convertSearchFilterToModelFilter(int searchFilter) { @@ -85,6 +88,13 @@ protected NameEnvironmentAnswer find(String typeName, String packageName) { if (packageName == null) packageName = IPackageFragment.DEFAULT_PACKAGE_NAME; + if (this.owner != null) { + String source = this.owner.findSource(typeName, packageName); + if (source != null) { + ICompilationUnit cu = new BasicCompilationUnit(source.toCharArray(), CharOperation.splitOn('.', packageName.toCharArray()), typeName + Util.defaultJavaExtension()); + return new NameEnvironmentAnswer(cu, null); + } + } NameLookup.Answer answer = this.nameLookup.findType( typeName, @@ -98,7 +108,7 @@ try { return new NameEnvironmentAnswer((IBinaryType) ((BinaryType) answer.type).getElementInfo(), answer.restriction); } catch (JavaModelException npe) { - return null; + // fall back to using owner } } else { //SourceType try { @@ -123,7 +133,7 @@ } return new NameEnvironmentAnswer(sourceTypes, answer.restriction); } catch (JavaModelException npe) { - return null; + // fall back to using owner } } } @@ -501,7 +511,9 @@ pkgName[i] = new String(parentPackageName[i]); pkgName[length] = new String(subPackageName); } - return this.nameLookup.isPackage(pkgName); + return + (this.owner != null && this.owner.isPackage(pkgName)) + || this.nameLookup.isPackage(pkgName); } /** Index: model/org/eclipse/jdt/core/WorkingCopyOwner.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/model/org/eclipse/jdt/core/WorkingCopyOwner.java,v retrieving revision 1.26 diff -u -r1.26 WorkingCopyOwner.java --- model/org/eclipse/jdt/core/WorkingCopyOwner.java 27 May 2008 23:40:20 -0000 1.26 +++ model/org/eclipse/jdt/core/WorkingCopyOwner.java 12 Dec 2008 14:27:09 -0000 @@ -89,6 +89,80 @@ public IProblemRequestor getProblemRequestor(ICompilationUnit workingCopy) { return null; } + + /** + * Returns the source of the compilation unit that defines the given type in + * the given package, or null if the type is unknown to this + * owner. + *

This method is called before the normal lookup (i.e. before looking + * at the project's classpath and before looking at the working copies of this + * owner.)

+ *

This allows to provide types that are not normally available, or to hide + * types that would normally be available by returning an empty source for + * the given type and package.

+ *

Example of use: + *

+	 * WorkingCopyOwner owner = new WorkingCopyOwner() {
+	 *   public String findSource(String typeName, String packageName) {
+	 *     if ("to.be".equals(packageName) && "Generated".equals(typeName)) {
+	 *       return
+	 *         "package to.be;\n" +
+	 *         "public class Generated {\n" +
+	 *         "}";
+	 *     }
+	 *     return super.findSource(typeName, packageName);
+	 *   }
+	 *   public boolean isPackage(String[] pkg) {
+	 *     switch (pkg.length) {
+	 *     case 1:
+	 *       return "to".equals(pkg[0]);
+	 *     case 2:
+	 *       return "to".equals(pkg[0]) && "be".equals(pkg[1]);
+	 *     }
+	 *     return false;
+	 *   }
+	 * };
+	 * // Working copy on X.java with the following contents:
+	 * //    public class X extends to.be.Generated {
+	 * //    }
+	 * ICompilationUnit workingCopy = ... 
+	 * ASTParser parser = ASTParser.newParser(AST.JLS3);
+	 * parser.setSource(workingCopy);
+	 * parser.setResolveBindings(true);
+	 * parser.setWorkingCopyOwner(owner);
+	 * CompilationUnit cu = (CompilationUnit) parser.createAST(null);
+	 * assert cu.getProblems().length == 0;
+	 * 
+ *

+ * + * @param typeName the simple name of the type to lookup + * @param packageName the dot-separated name of the package of type + * @return the source of the compilation unit that defines the given type in + * the given package, or null if the type is unknown + * @see #isPackage(String[]) + * @since 3.5 + */ + public String findSource(String typeName, String packageName) { + return null; + } + + /** + * Returns whether the given package segments represent a package. + *

This method is called before the normal lookup (i.e. before looking + * at the project's classpath and before looking at the working copies of this + * owner.)

+ *

This allows to provide packages that are not normally available.

+ *

If false is returned, then normal lookup is used on + * this package.

+ * + * @param pkg the segments of a package to lookup + * @return whether the given package segments represent a package. + * @see #findSource(String, String) + * @since 3.5 + */ + public boolean isPackage(String[] pkg) { + return false; + } /** * Returns a new working copy with the given name using this working copy owner to #P org.eclipse.jdt.core.tests.model Index: src/org/eclipse/jdt/core/tests/model/AbstractJavaModelTests.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/AbstractJavaModelTests.java,v retrieving revision 1.227 diff -u -r1.227 AbstractJavaModelTests.java --- src/org/eclipse/jdt/core/tests/model/AbstractJavaModelTests.java 23 Oct 2008 13:56:38 -0000 1.227 +++ src/org/eclipse/jdt/core/tests/model/AbstractJavaModelTests.java 12 Dec 2008 14:27:11 -0000 @@ -696,6 +696,14 @@ assertEquals("Unexpected member value pair", expected, actual); } + protected void assertProblems(String message, String expected, IProblem[] problems, char[] source) { + ProblemRequestor pbRequestor = new ProblemRequestor(); + pbRequestor.unitSource = source; + for (int i = 0, length = problems.length; i < length; i++) { + pbRequestor.acceptProblem(problems[i]); + } + assertProblems(message, expected, pbRequestor); + } protected void assertProblems(String message, String expected, ProblemRequestor problemRequestor) { String actual = org.eclipse.jdt.core.tests.util.Util.convertToIndependantLineDelimiter(problemRequestor.problems.toString()); String independantExpectedString = org.eclipse.jdt.core.tests.util.Util.convertToIndependantLineDelimiter(expected); Index: src/org/eclipse/jdt/core/tests/model/WorkingCopyOwnerTests.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/WorkingCopyOwnerTests.java,v retrieving revision 1.63 diff -u -r1.63 WorkingCopyOwnerTests.java --- src/org/eclipse/jdt/core/tests/model/WorkingCopyOwnerTests.java 1 Sep 2008 14:46:52 -0000 1.63 +++ src/org/eclipse/jdt/core/tests/model/WorkingCopyOwnerTests.java 12 Dec 2008 14:27:11 -0000 @@ -79,6 +79,16 @@ super.tearDown(); } + private void assertProblems(String expectedProblems, String path, String source, WorkingCopyOwner owner) throws JavaModelException { + this.workingCopy = getWorkingCopy(path, source); + ASTParser parser = ASTParser.newParser(AST.JLS3); + parser.setSource(this.workingCopy); + parser.setResolveBindings(true); + parser.setWorkingCopyOwner(owner); + CompilationUnit cu = (CompilationUnit) parser.createAST(null); + assertProblems("Unexpected problems", expectedProblems, cu.getProblems(), source.toCharArray()); + } + protected void assertTypeBindingsEqual(String message, String expected, ITypeBinding[] types) { StringBuffer buffer = new StringBuffer(); if (types == null) { @@ -617,6 +627,67 @@ } /* + * Ensures that a type that is otherwise missing can be looked up using the working copy owner. + */ + public void testFindType1() throws Exception { + WorkingCopyOwner owner = new WorkingCopyOwner() { + public String findSource(String typeName, String packageName) { + if ("to.be".equals(packageName) && "Generated".equals(typeName)) { + return + "package to.be;\n" + + "public class Generated {\n" + + "}"; + } + return super.findSource(typeName, packageName); + } + public boolean isPackage(String[] pkg) { + switch (pkg.length) { + case 1: + return "to".equals(pkg[0]); + case 2: + return "to".equals(pkg[0]) && "be".equals(pkg[1]); + } + return false; + } + }; + assertProblems( + "", + "/P/X.java", + "public class X extends to.be.Generated {\n" + + "}", + owner); + } + + /* + * Ensures that a type that is otherwise available can be hidden using the working copy owner. + */ + public void testFindType2() throws Exception { + try { + createFile("/P/Y.java", "public class Y {}"); + WorkingCopyOwner owner = new WorkingCopyOwner() { + public String findSource(String typeName, String packageName) { + if ("".equals(packageName) && "Y".equals(typeName)) { + return ""; + } + return super.findSource(typeName, packageName); + } + }; + assertProblems( + "1. ERROR in /P/X.java (at line 1)\n" + + " public class X extends Y {\n" + + " ^\n" + + "Y cannot be resolved to a type\n" + + "----------\n", + "/P/X.java", + "public class X extends Y {\n" + + "}", + owner); + } finally { + deleteFile("/P/Y.java"); + } + } + + /* * Ensures that getCorrespondingResource() returns a non-null value for a primary working copy. * (regression test for bug 44065 NPE during hot code replace) */