### Eclipse Workspace Patch 1.0 #P org.eclipse.jdt.core.tests.builder Index: src/org/eclipse/jdt/core/tests/builder/TestingEnvironment.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core.tests.builder/src/org/eclipse/jdt/core/tests/builder/TestingEnvironment.java,v retrieving revision 1.44 diff -u -r1.44 TestingEnvironment.java --- src/org/eclipse/jdt/core/tests/builder/TestingEnvironment.java 29 Mar 2006 03:16:23 -0000 1.44 +++ src/org/eclipse/jdt/core/tests/builder/TestingEnvironment.java 14 Oct 2006 20:22:07 -0000 @@ -21,6 +21,8 @@ import org.eclipse.jdt.internal.core.JavaProject; import java.io.*; import java.util.*; +import java.util.jar.JarOutputStream; +import java.util.zip.ZipEntry; public class TestingEnvironment { @@ -109,6 +111,10 @@ return addClass(packageFragmentRootPath, className, contents); } +public void addClassFolder(IPath projectPath, IPath classFolderPath) throws JavaModelException { + addEntry(projectPath, JavaCore.newLibraryEntry(classFolderPath, null, null)); +} + /** Adds a package to the given package fragment root * in the workspace. The package fragment root is created * if necessary. If a package with the same name already @@ -288,6 +294,42 @@ return path; } +public IPath addInternalJar(IPath projectPath, String zipName, + String[] entryNames, String [] fileNames, boolean isExported) + throws JavaModelException { + try { + checkAssertion("entryNames must not be null", entryNames != null); + checkAssertion("fileNames must not be null", fileNames != null); + int entriesNb = entryNames.length; + checkAssertion("entryNames and fileNames must have the same length", + entriesNb == fileNames.length); + ByteArrayOutputStream sinkArray = new ByteArrayOutputStream(); + BufferedOutputStream outputBuffer = new BufferedOutputStream(sinkArray); + BufferedInputStream inputBuffer; + IProject project = getProject(projectPath); + JarOutputStream jar = new JarOutputStream(outputBuffer); + byte[] bytes = new byte[1024]; + for (int i = 0; i < entriesNb; i++) { + ZipEntry classFile = new ZipEntry(entryNames[i]); + jar.putNextEntry(classFile); + inputBuffer = new BufferedInputStream( + project.getFile(fileNames[i]).getContents()); + int bytesNb; + while ((bytesNb = inputBuffer.read(bytes)) != -1) { + jar.write(bytes, 0, bytesNb); + } + inputBuffer.close(); + } + jar.close(); + outputBuffer.close(); + return addInternalJar(projectPath, zipName, sinkArray.toByteArray()); + } catch (Exception e) { + e.printStackTrace(); + checkAssertion("could not create jar file", false); + return null; // won't get here + } +} + private void checkAssertion(String message, boolean b) { Assert.isTrue(b, message); } Index: src/org/eclipse/jdt/core/tests/builder/MultiProjectTests.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core.tests.builder/src/org/eclipse/jdt/core/tests/builder/MultiProjectTests.java,v retrieving revision 1.41 diff -u -r1.41 MultiProjectTests.java --- src/org/eclipse/jdt/core/tests/builder/MultiProjectTests.java 6 Apr 2006 19:16:04 -0000 1.41 +++ src/org/eclipse/jdt/core/tests/builder/MultiProjectTests.java 14 Oct 2006 20:22:07 -0000 @@ -14,8 +14,17 @@ import junit.framework.Test; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IResourceChangeEvent; +import org.eclipse.core.resources.IResourceChangeListener; +import org.eclipse.core.resources.IWorkspaceDescription; +import org.eclipse.core.resources.WorkspaceJob; +import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Path; +import org.eclipse.core.runtime.Status; import org.eclipse.jdt.core.IAccessRule; import org.eclipse.jdt.core.JavaCore; import org.eclipse.jdt.core.JavaModelException; @@ -780,6 +789,178 @@ } } +// https://bugs.eclipse.org/bugs/show_bug.cgi?id=114349 +// this one fails; compare with testCycle7 (only one change in Object source), +// which passes + public void testCycle6() throws JavaModelException { + Hashtable options = JavaCore.getOptions(); + Hashtable newOptions = JavaCore.getOptions(); + newOptions.put(JavaCore.CORE_CIRCULAR_CLASSPATH, JavaCore.WARNING); + + JavaCore.setOptions(newOptions); + + //---------------------------- + // Project1 + //---------------------------- + IPath p1 = env.addProject("P1"); + // remove old package fragment root so that names don't collide + env.removePackageFragmentRoot(p1, ""); + IPath root1 = env.addPackageFragmentRoot(p1, "src"); + env.setOutputFolder(p1, "bin"); + + env.addClass(root1, "java/lang", "Object", + "package java.lang;\n" + + "public class Object {\n" + + " Class getClass() { return null; }\n" + + " String toString() { return \"\"; }\n" + // the line that changes + "}\n" + ); + + //---------------------------- + // Project2 + //---------------------------- + IPath p2 = env.addProject("P2"); + // remove old package fragment root so that names don't collide + env.removePackageFragmentRoot(p2, ""); + IPath root2 = env.addPackageFragmentRoot(p2, "src"); + env.setOutputFolder(p2, "bin"); + + env.addClass(root2, "java/lang", "Class", + "package java.lang;\n" + + "public class Class {\n" + + " String getName() { return \"\"; };\n" + + "}\n" + ); + + //---------------------------- + // Project3 + //---------------------------- + IPath p3 = env.addProject("P3"); + // remove old package fragment root so that names don't collide + env.removePackageFragmentRoot(p3, ""); + IPath root3 = env.addPackageFragmentRoot(p3, "src"); + env.setOutputFolder(p3, "bin"); + + env.addClass(root3, "java/lang", "String", + "package java.lang;\n" + + "public class String {\n" + + "}\n" + ); + + // Dependencies + IPath[] accessiblePaths = new IPath[] {new Path("java/lang/*")}; + IPath[] forbiddenPaths = new IPath[] {new Path("**/*")}; + env.addRequiredProject(p1, p2, accessiblePaths, forbiddenPaths, false); + env.addRequiredProject(p1, p3, accessiblePaths, forbiddenPaths, false); + env.addRequiredProject(p2, p1, accessiblePaths, forbiddenPaths, false); + env.addRequiredProject(p2, p3, accessiblePaths, forbiddenPaths, false); + env.addRequiredProject(p3, p1, accessiblePaths, forbiddenPaths, false); + env.addRequiredProject(p3, p2, accessiblePaths, forbiddenPaths, false); + + try { + fullBuild(); + + expectingOnlySpecificProblemsFor(p1,new Problem[]{ + new Problem("p1", "A cycle was detected in the build path of project: P1", p1, -1, -1, CategorizedProblem.CAT_BUILDPATH)//$NON-NLS-1$ //$NON-NLS-2$ + }); + expectingOnlySpecificProblemsFor(p2,new Problem[]{ + new Problem("p2", "A cycle was detected in the build path of project: P2", p2, -1, -1, CategorizedProblem.CAT_BUILDPATH)//$NON-NLS-1$ //$NON-NLS-2$ + }); + expectingOnlySpecificProblemsFor(p3,new Problem[]{ + new Problem("p3", "A cycle was detected in the build path of project: P3", p3, -1, -1, CategorizedProblem.CAT_BUILDPATH)//$NON-NLS-1$ //$NON-NLS-2$ + }); + + } finally { + JavaCore.setOptions(options); + } + } + +// https://bugs.eclipse.org/bugs/show_bug.cgi?id=114349 +// this one passes; compare with testCycle6 (only one change in Object source), +// which fails + public void testCycle7() throws JavaModelException { + Hashtable options = JavaCore.getOptions(); + Hashtable newOptions = JavaCore.getOptions(); + newOptions.put(JavaCore.CORE_CIRCULAR_CLASSPATH, JavaCore.WARNING); + + JavaCore.setOptions(newOptions); + + //---------------------------- + // Project1 + //---------------------------- + IPath p1 = env.addProject("P1"); + // remove old package fragment root so that names don't collide + env.removePackageFragmentRoot(p1, ""); + IPath root1 = env.addPackageFragmentRoot(p1, "src"); + env.setOutputFolder(p1, "bin"); + + env.addClass(root1, "java/lang", "Object", + "package java.lang;\n" + + "public class Object {\n" + + " Class getClass() { return null; }\n" + + " String toString() { return null; }\n" + // the line that changes + "}\n" + ); + + //---------------------------- + // Project2 + //---------------------------- + IPath p2 = env.addProject("P2"); + // remove old package fragment root so that names don't collide + env.removePackageFragmentRoot(p2, ""); + IPath root2 = env.addPackageFragmentRoot(p2, "src"); + env.setOutputFolder(p2, "bin"); + + env.addClass(root2, "java/lang", "Class", + "package java.lang;\n" + + "public class Class {\n" + + " String getName() { return \"\"; };\n" + + "}\n" + ); + + //---------------------------- + // Project3 + //---------------------------- + IPath p3 = env.addProject("P3"); + // remove old package fragment root so that names don't collide + env.removePackageFragmentRoot(p3, ""); + IPath root3 = env.addPackageFragmentRoot(p3, "src"); + env.setOutputFolder(p3, "bin"); + + env.addClass(root3, "java/lang", "String", + "package java.lang;\n" + + "public class String {\n" + + "}\n" + ); + + // Dependencies + IPath[] accessiblePaths = new IPath[] {new Path("java/lang/*")}; + IPath[] forbiddenPaths = new IPath[] {new Path("**/*")}; + env.addRequiredProject(p1, p2, accessiblePaths, forbiddenPaths, false); + env.addRequiredProject(p1, p3, accessiblePaths, forbiddenPaths, false); + env.addRequiredProject(p2, p1, accessiblePaths, forbiddenPaths, false); + env.addRequiredProject(p2, p3, accessiblePaths, forbiddenPaths, false); + env.addRequiredProject(p3, p1, accessiblePaths, forbiddenPaths, false); + env.addRequiredProject(p3, p2, accessiblePaths, forbiddenPaths, false); + + try { + fullBuild(); + + expectingOnlySpecificProblemsFor(p1,new Problem[]{ + new Problem("p1", "A cycle was detected in the build path of project: P1", p1, -1, -1, CategorizedProblem.CAT_BUILDPATH)//$NON-NLS-1$ //$NON-NLS-2$ + }); + expectingOnlySpecificProblemsFor(p2,new Problem[]{ + new Problem("p2", "A cycle was detected in the build path of project: P2", p2, -1, -1, CategorizedProblem.CAT_BUILDPATH)//$NON-NLS-1$ //$NON-NLS-2$ + }); + expectingOnlySpecificProblemsFor(p3,new Problem[]{ + new Problem("p3", "A cycle was detected in the build path of project: P3", p3, -1, -1, CategorizedProblem.CAT_BUILDPATH)//$NON-NLS-1$ //$NON-NLS-2$ + }); + + } finally { + JavaCore.setOptions(options); + } + } + /* * Full buid case */ @@ -1223,5 +1404,262 @@ env.setBuildOrder(null); } } - + // https://bugs.eclipse.org/bugs/show_bug.cgi?id=160550 + public void test0100_cycle_with_bad_library() throws CoreException { + Hashtable options = JavaCore.getOptions(); + Hashtable newOptions = JavaCore.getOptions(); + newOptions.put(JavaCore.CORE_CIRCULAR_CLASSPATH, JavaCore.WARNING); + JavaCore.setOptions(newOptions); + try { + // jar preparation (broken jar: l/Super.class missing) + IPath brokenLibProjectPath = env.addProject("Lib"); + env.addExternalJars(brokenLibProjectPath, Util.getJavaClassLibs()); + IProject brokenLibProject = env.getProject(brokenLibProjectPath); + env.removePackageFragmentRoot(brokenLibProjectPath, ""); + IPath root0 = env.addPackageFragmentRoot(brokenLibProjectPath, "src"); + env.setOutputFolder(brokenLibProjectPath, "bin"); + env.addClass(root0, "l", "Super", + "package l;\n" + + "public class Super {\n" + + "}\n" + ); + env.addClass(root0, "l", "Sub", + "package l;\n" + + "public class Sub extends Super {\n" + + "}\n" + ); + fullBuild(); + String brokenLibJarExternalPath = + env.addInternalJar(brokenLibProjectPath, "broken.jar", + new String[] {"l/Sub.class"}, new String[]{"bin/l/Sub.class"}, + // avoid to include Super on purpose + false).toString(); + //---------------------------- + // Project1 + //---------------------------- + IPath p1 = env.addProject("P1"); + // remove old package fragment root so that names don't collide + env.removePackageFragmentRoot(p1, ""); + IPath root1 = env.addPackageFragmentRoot(p1, "src"); + env.setOutputFolder(p1, "bin"); + env.addExternalJars(p1, Util.getJavaClassLibs()); + env.addExternalJar(p1, brokenLibJarExternalPath); + /* IPath xPath = */ env.addClass(root1, "p", "X", + "package p;\n" + + "public class X extends l.Sub {\n" + + " q.Y m;\n" + + "}\n" + ); + //---------------------------- + // Project2 + //---------------------------- + IPath p2 = env.addProject("P2"); + // remove old package fragment root so that names don't collide + env.removePackageFragmentRoot(p2, ""); + IPath root2 = env.addPackageFragmentRoot(p2, "src"); + env.setOutputFolder(p2, "bin"); + env.addExternalJars(p2, Util.getJavaClassLibs()); + env.addExternalJar(p2, brokenLibJarExternalPath); + /* IPath yPath = */ env.addClass(root2, "q", "Y", + "package q;\n" + + "public class Y extends l.Sub {\n" + + " p.X m;\n" + + "}\n" + ); + // Dependencies + env.addRequiredProject(p1, p2, null, null, false); + env.addRequiredProject(p2, p1, null, null, false); + // Re-launcher + class PostBuildJob extends WorkspaceJob implements IResourceChangeListener { + int invocationsNb = 0; + public PostBuildJob() { + super("Post build"); + } + public void resourceChanged(IResourceChangeEvent event) { + invocationsNb++; + if (DEBUG) { + System.out.println("event #" + invocationsNb); + } + schedule(100); + } + public IStatus runInWorkspace(IProgressMonitor monitor) throws CoreException { + try { + Thread.sleep(500); + } catch (InterruptedException e) { /* */ } + return Status.OK_STATUS; + } + } + PostBuildJob listener = new PostBuildJob(); + try { + fullBuild(); + // TODO the problems layout is changed by patches, hence they are deactivated for now + // expectingOnlySpecificProblemsFor(p1, new Problem[] { + // new Problem("p1", "A cycle was detected in the build path of project: P1", + // p1, -1, -1, CategorizedProblem.CAT_BUILDPATH), + // new Problem("p1", "The project was not built since its build path is incomplete. Cannot find the class file for l.Super. Fix the build path then try building this project", + // p1, -1, -1, CategorizedProblem.CAT_BUILDPATH), + // new Problem("p1", "The type l.Super cannot be resolved. It is indirectly referenced from required .class files", + // xPath, 34, 39, CategorizedProblem.CAT_BUILDPATH), + // }); + // expectingOnlySpecificProblemsFor(p2, new Problem[] { + // new Problem("p2", "A cycle was detected in the build path of project: P2", + // p2, -1, -1, CategorizedProblem.CAT_BUILDPATH), + // new Problem("p2", "The project was not built since its build path is incomplete. Cannot find the class file for l.Super. Fix the build path then try building this project", + // p2, -1, -1, CategorizedProblem.CAT_BUILDPATH), + // new Problem("p2", "The type l.Super cannot be resolved. It is indirectly referenced from required .class files", + // yPath, 34, 39, CategorizedProblem.CAT_BUILDPATH), + // }); + IWorkspaceDescription description = brokenLibProject.getWorkspace().getDescription(); + description.setAutoBuilding(true); + brokenLibProject.getWorkspace().setDescription(description); + brokenLibProject.getWorkspace(). + addResourceChangeListener(listener, IResourceChangeEvent.POST_BUILD); + env.addClass(root1, "p", "X", + "package p;\n" + + "public class X extends l.Sub {\n" + + " q.Y m;\n" + + "}\n" + ); + try { + Thread.sleep(3000); // beware, too low a delay would miss the point + } catch (InterruptedException e) { /* */ } + if (listener.invocationsNb > 1) { + fail("looping in build (" + listener.invocationsNb + " invocations)"); + } + } finally { + brokenLibProject.getWorkspace().removeResourceChangeListener(listener); + brokenLibProject.getWorkspace().getDescription().setAutoBuilding(false); + } + } finally { + JavaCore.setOptions(options); + } + } + // https://bugs.eclipse.org/bugs/show_bug.cgi?id=160550 + public void test0101_cycle_with_bad_class_folder() throws CoreException { + Hashtable options = JavaCore.getOptions(); + Hashtable newOptions = JavaCore.getOptions(); + newOptions.put(JavaCore.CORE_CIRCULAR_CLASSPATH, JavaCore.WARNING); + JavaCore.setOptions(newOptions); + try { + // jar preparation (broken jar: l/Super.class missing) + IPath brokenLibProjectPath = env.addProject("Lib"); + env.addExternalJars(brokenLibProjectPath, Util.getJavaClassLibs()); + IProject brokenLibProject = env.getProject(brokenLibProjectPath); + env.removePackageFragmentRoot(brokenLibProjectPath, ""); + IPath root0 = env.addPackageFragmentRoot(brokenLibProjectPath, + "src1", null, false, "bin1"); + env.addClass(root0, "l", "Super", + "package l;\n" + + "public class Super {\n" + + "}\n" + ); + root0 = env.addPackageFragmentRoot(brokenLibProjectPath, + "src2", null, false, "bin2"); + env.addClass(root0, "l", "Sub", + "package l;\n" + + "public class Sub extends Super {\n" + + "}\n" + ); + fullBuild(); + IPath brokenClassFolderPath = brokenLibProjectPath.append("bin2"); + //---------------------------- + // Project1 + //---------------------------- + IPath p1 = env.addProject("P1"); + // remove old package fragment root so that names don't collide + env.removePackageFragmentRoot(p1, ""); + IPath root1 = env.addPackageFragmentRoot(p1, "src"); + env.setOutputFolder(p1, "bin"); + env.addExternalJars(p1, Util.getJavaClassLibs()); + env.addClassFolder(p1, brokenClassFolderPath); + /* IPath xPath = */ env.addClass(root1, "p", "X", + "package p;\n" + + "public class X extends l.Sub {\n" + + " q.Y m;\n" + + "}\n" + ); + //---------------------------- + // Project2 + //---------------------------- + IPath p2 = env.addProject("P2"); + // remove old package fragment root so that names don't collide + env.removePackageFragmentRoot(p2, ""); + IPath root2 = env.addPackageFragmentRoot(p2, "src"); + env.setOutputFolder(p2, "bin"); + env.addExternalJars(p2, Util.getJavaClassLibs()); + env.addClassFolder(p2, brokenClassFolderPath); + /* IPath yPath = */ env.addClass(root2, "q", "Y", + "package q;\n" + + "public class Y extends l.Sub {\n" + + " p.X m;\n" + + "}\n" + ); + // Dependencies + env.addRequiredProject(p1, p2, null, null, false); + env.addRequiredProject(p2, p1, null, null, false); + // Re-launcher + class PostBuildJob extends WorkspaceJob implements IResourceChangeListener { + int invocationsNb = 0; + public PostBuildJob() { + super("Post build"); + } + public void resourceChanged(IResourceChangeEvent event) { + invocationsNb++; + if (DEBUG) { + System.out.println("event #" + invocationsNb); + } + schedule(100); + } + public IStatus runInWorkspace(IProgressMonitor monitor) throws CoreException { + try { + Thread.sleep(500); + } catch (InterruptedException e) { /* */ } + return Status.OK_STATUS; + } + } + PostBuildJob listener = new PostBuildJob(); + try { + fullBuild(); + // TODO the problems layout is changed by patches, hence they are deactivated for now + // expectingOnlySpecificProblemsFor(p1, new Problem[] { + // new Problem("p1", "A cycle was detected in the build path of project: P1", + // p1, -1, -1, CategorizedProblem.CAT_BUILDPATH), + // new Problem("p1", "The project was not built since its build path is incomplete. Cannot find the class file for l.Super. Fix the build path then try building this project", + // p1, -1, -1, CategorizedProblem.CAT_BUILDPATH), + // new Problem("p1", "The type l.Super cannot be resolved. It is indirectly referenced from required .class files", + // xPath, 34, 39, CategorizedProblem.CAT_BUILDPATH), + // }); + // expectingOnlySpecificProblemsFor(p2, new Problem[] { + // new Problem("p2", "A cycle was detected in the build path of project: P2", + // p2, -1, -1, CategorizedProblem.CAT_BUILDPATH), + // new Problem("p2", "The project was not built since its build path is incomplete. Cannot find the class file for l.Super. Fix the build path then try building this project", + // p2, -1, -1, CategorizedProblem.CAT_BUILDPATH), + // new Problem("p2", "The type l.Super cannot be resolved. It is indirectly referenced from required .class files", + // yPath, 34, 39, CategorizedProblem.CAT_BUILDPATH), + // }); + IWorkspaceDescription description = brokenLibProject.getWorkspace().getDescription(); + description.setAutoBuilding(true); + brokenLibProject.getWorkspace().setDescription(description); + brokenLibProject.getWorkspace(). + addResourceChangeListener(listener, IResourceChangeEvent.POST_BUILD); + env.addClass(root1, "p", "X", + "package p;\n" + + "public class X extends l.Sub {\n" + + " q.Y m;\n" + + "}\n" + ); + try { + Thread.sleep(3000); // beware, too low a delay would miss the point + } catch (InterruptedException e) { /* */ } + if (listener.invocationsNb > 1) { + fail("looping in build (" + listener.invocationsNb + " invocations)"); + } + } finally { + brokenLibProject.getWorkspace().removeResourceChangeListener(listener); + brokenLibProject.getWorkspace().getDescription().setAutoBuilding(false); + } + } finally { + JavaCore.setOptions(options); + } + } } #P org.eclipse.jdt.core Index: compiler/org/eclipse/jdt/internal/compiler/lookup/BinaryTypeBinding.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BinaryTypeBinding.java,v retrieving revision 1.95.4.2 diff -u -r1.95.4.2 BinaryTypeBinding.java --- compiler/org/eclipse/jdt/internal/compiler/lookup/BinaryTypeBinding.java 6 Sep 2006 18:11:37 -0000 1.95.4.2 +++ compiler/org/eclipse/jdt/internal/compiler/lookup/BinaryTypeBinding.java 14 Oct 2006 20:22:11 -0000 @@ -144,7 +144,12 @@ return type; } - +/** + * Standard constructor for creating binary type bindings from binary models (classfiles) + * @param packageBinding + * @param binaryType + * @param environment + */ public BinaryTypeBinding(PackageBinding packageBinding, IBinaryType binaryType, LookupEnvironment environment) { this.compoundName = CharOperation.splitOn('/', binaryType.getName()); computeId(); @@ -183,6 +188,29 @@ } } +/** + * Special constructor for constructing proxies of missing binary types (114349) + * @param packageBinding + * @param compoundName + * @param environment + */ +BinaryTypeBinding(PackageBinding packageBinding, char[][] compoundName, LookupEnvironment environment) { + this.compoundName = compoundName; + computeId(); + this.tagBits |= TagBits.IsBinaryBinding; + this.environment = environment; + this.fPackage = packageBinding; + this.fileName = CharOperation.concatWith(compoundName, '/'); + this.sourceName = CharOperation.concatWith(compoundName, '.'); + this.modifiers = ClassFileConstants.AccPublic; + this.superclass = null; + this.superInterfaces = Binding.NO_SUPERINTERFACES; + this.typeVariables = Binding.NO_TYPE_VARIABLES; + this.memberTypes = Binding.NO_MEMBER_TYPES; + this.fields = Binding.NO_FIELDS; + this.methods = Binding.NO_METHODS; +} + public FieldBinding[] availableFields() { if ((this.tagBits & TagBits.AreFieldsComplete) != 0) return fields; @@ -899,9 +927,20 @@ method.modifiers &= ~ExtraCompilerModifiers.AccUnresolved; return method; } + AnnotationBinding[] retrieveAnnotations(Binding binding) { return AnnotationBinding.addStandardAnnotations(super.retrieveAnnotations(binding), binding.getAnnotationTagBits(), this.environment); } + +/** + * Only used to fixup the superclass hierarchy of proxy binary types + * @param missingSuperclass + * @see LookupEnvironment#cacheMissingBinaryType(char[][]) + */ +void setMissingSuperclass(ReferenceBinding missingSuperclass) { + this.superclass = missingSuperclass; +} + SimpleLookupTable storedAnnotations(boolean forceInitialize) { if (forceInitialize && this.storedAnnotations == null) { if (!this.environment.globalOptions.storeAnnotations) @@ -910,6 +949,7 @@ } return this.storedAnnotations; } + /* Answer the receiver's superclass... null if the receiver is Object or an interface. * * NOTE: superclass of a binary type is resolved when needed Index: compiler/org/eclipse/jdt/internal/compiler/lookup/LookupEnvironment.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/LookupEnvironment.java,v retrieving revision 1.72 diff -u -r1.72 LookupEnvironment.java --- compiler/org/eclipse/jdt/internal/compiler/lookup/LookupEnvironment.java 11 May 2006 10:14:34 -0000 1.72 +++ compiler/org/eclipse/jdt/internal/compiler/lookup/LookupEnvironment.java 14 Oct 2006 20:22:13 -0000 @@ -16,6 +16,7 @@ import org.eclipse.jdt.core.compiler.CharOperation; import org.eclipse.jdt.internal.compiler.ClassFilePool; import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration; +import org.eclipse.jdt.internal.compiler.ast.TypeReference; import org.eclipse.jdt.internal.compiler.ast.Wildcard; import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; import org.eclipse.jdt.internal.compiler.env.*; @@ -64,7 +65,8 @@ private SimpleLookupTable uniqueParameterizedGenericMethodBindings; public CompilationUnitDeclaration unitBeingCompleted = null; // only set while completing units - + public TypeReference typeReferenceBeingResolved = null; // only set when resolving certain type references, to help locating problems + private CompilationUnitDeclaration[] units = new CompilationUnitDeclaration[4]; private MethodVerifier verifier; @@ -173,6 +175,35 @@ return createBinaryTypeFrom(binaryType, computePackageFrom(compoundName), needFieldsAndMethods, accessRestriction); return null; // the type already exists & can be retrieved from the cache } + +public BinaryTypeBinding cacheMissingBinaryType(char[][] compoundName) { + PackageBinding packageBinding = getPackage0(compoundName[0]); + if (packageBinding == null || packageBinding == TheNotFoundPackage) { + packageBinding = new PackageBinding(compoundName[0], this); + knownPackages.put(compoundName[0], packageBinding); + } + for (int i = 1, packageLength = compoundName.length - 1; i < packageLength; i++) { + PackageBinding subPackageBinding = packageBinding.getPackage0(compoundName[i]); + if (subPackageBinding == null || subPackageBinding == TheNotFoundPackage) { + char[][] subName = CharOperation.subarray(compoundName, 0, i + 1); + subPackageBinding = new PackageBinding(subName, packageBinding, this); + packageBinding.addPackage(subPackageBinding); + packageBinding = subPackageBinding; + } + } + // create a proxy for the missing BinaryType + BinaryTypeBinding type = new BinaryTypeBinding(packageBinding, compoundName, this); + if (type.id != TypeIds.T_JavaLangObject) { + // make Object be its superclass - it could in turn be missing as well + ReferenceBinding objectType = getType(TypeConstants.JAVA_LANG_OBJECT); + if (objectType == null) { + objectType = cacheMissingBinaryType(TypeConstants.JAVA_LANG_OBJECT); // create a proxy for the missing Object type + } + type.setMissingSuperclass(objectType); + } + packageBinding.addType(type); + return type; +} /* * 1. Connect the type hierarchy for the type bindings created for parsedUnits. * 2. Create the field bindings @@ -859,8 +890,12 @@ ReferenceBinding type = getType(compoundName); if (type != null) return type; - problemReporter.isClassPathCorrect(compoundName, scope == null ? null : scope.referenceCompilationUnit()); - return null; // will not get here since the above error aborts the compilation + ClassScope classScope = scope == null ? null : scope.enclosingClassScope(); + problemReporter.isClassPathCorrect( + compoundName, + scope == null ? this.unitBeingCompleted : scope.referenceCompilationUnit(), + classScope == null ? this.typeReferenceBeingResolved : classScope.superTypeReference); + return cacheMissingBinaryType(compoundName); // create a proxy for the missing BinaryType } /* Answer the top level package named name. * Ask the oracle for the package if its not in the cache. @@ -957,14 +992,15 @@ binding = new UnresolvedReferenceBinding(compoundName, packageBinding); packageBinding.addType(binding); } else if (binding == TheNotFoundType) { - problemReporter.isClassPathCorrect(compoundName, null); - return null; // will not get here since the above error aborts the compilation + problemReporter.isClassPathCorrect(compoundName, this.unitBeingCompleted, this.typeReferenceBeingResolved); + return cacheMissingBinaryType(compoundName); // create a proxy for the missing BinaryType } else if (!isParameterized) { // check raw type, only for resolved types binding = (ReferenceBinding)convertUnresolvedBinaryToRawType(binding); } return binding; } + /* Answer the type corresponding to the name from the binary file. * Does not ask the oracle for the type if its not found in the cache... instead an * unresolved type is returned which must be resolved before used. Index: compiler/org/eclipse/jdt/internal/compiler/lookup/CompilationUnitScope.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/CompilationUnitScope.java,v retrieving revision 1.100.4.1 diff -u -r1.100.4.1 CompilationUnitScope.java --- compiler/org/eclipse/jdt/internal/compiler/lookup/CompilationUnitScope.java 2 Jul 2006 10:11:49 -0000 1.100.4.1 +++ compiler/org/eclipse/jdt/internal/compiler/lookup/CompilationUnitScope.java 14 Oct 2006 20:22:12 -0000 @@ -550,9 +550,12 @@ importBinding = ((PackageBinding) importBinding).getTypeOrPackage(JAVA_LANG[1]); // abort if java.lang cannot be found... - if (importBinding == null || !importBinding.isValidBinding()) - problemReporter().isClassPathCorrect(JAVA_LANG_OBJECT, referenceCompilationUnit()); + if (importBinding == null || !importBinding.isValidBinding()) { + problemReporter().isClassPathCorrect(JAVA_LANG_OBJECT, referenceCompilationUnit(), null); + BinaryTypeBinding missingObject = environment.cacheMissingBinaryType(JAVA_LANG_OBJECT); // create a proxy for the missing BinaryType + importBinding = missingObject.fPackage; + } return environment.defaultImports = new ImportBinding[] {new ImportBinding(JAVA_LANG, true, importBinding, null)}; } // NOT Public API Index: compiler/org/eclipse/jdt/internal/compiler/lookup/UnresolvedReferenceBinding.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/UnresolvedReferenceBinding.java,v retrieving revision 1.26 diff -u -r1.26 UnresolvedReferenceBinding.java --- compiler/org/eclipse/jdt/internal/compiler/lookup/UnresolvedReferenceBinding.java 10 May 2006 18:03:50 -0000 1.26 +++ compiler/org/eclipse/jdt/internal/compiler/lookup/UnresolvedReferenceBinding.java 14 Oct 2006 20:22:13 -0000 @@ -41,12 +41,11 @@ targetType = this.fPackage.getType0(this.compoundName[this.compoundName.length - 1]); if (targetType == this) targetType = environment.askForType(this.compoundName); - if (targetType != null && targetType != this) { // could not resolve any better, error was already reported against it - setResolvedType(targetType, environment); - } else { - environment.problemReporter.isClassPathCorrect(this.compoundName, null); - return null; // will not get here since the above error aborts the compilation + if (targetType == null || targetType == this) { // could not resolve any better, error was already reported against it + environment.problemReporter.isClassPathCorrect(this.compoundName, environment.unitBeingCompleted, environment.typeReferenceBeingResolved); + targetType = environment.cacheMissingBinaryType(this.compoundName); // create a proxy for the missing BinaryType } + setResolvedType(targetType, environment); } if (convertGenericToRawType) { targetType = (ReferenceBinding) environment.convertUnresolvedBinaryToRawType(targetType); Index: compiler/org/eclipse/jdt/internal/compiler/lookup/ClassScope.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ClassScope.java,v retrieving revision 1.137.2.4 diff -u -r1.137.2.4 ClassScope.java --- compiler/org/eclipse/jdt/internal/compiler/lookup/ClassScope.java 6 Oct 2006 09:17:11 -0000 1.137.2.4 +++ compiler/org/eclipse/jdt/internal/compiler/lookup/ClassScope.java 14 Oct 2006 20:22:12 -0000 @@ -1097,19 +1097,23 @@ } private ReferenceBinding findSupertype(TypeReference typeReference) { + LookupEnvironment environment = environment(); try { typeReference.aboutToResolve(this); // allows us to trap completion & selection nodes compilationUnitScope().recordQualifiedReference(typeReference.getTypeName()); this.superTypeReference = typeReference; + environment.typeReferenceBeingResolved = typeReference; ReferenceBinding superType = (ReferenceBinding) typeReference.resolveSuperType(this); - this.superTypeReference = null; return superType; } catch (AbortCompilation e) { SourceTypeBinding sourceType = this.referenceContext.binding; if (sourceType.superInterfaces == null) sourceType.superInterfaces = Binding.NO_SUPERINTERFACES; // be more resilient for hierarchies (144976) e.updateContext(typeReference, referenceCompilationUnit().compilationResult); throw e; - } + } finally { + environment.typeReferenceBeingResolved = null; + this.superTypeReference = null; + } } /* Answer the problem reporter to use for raising new problems. Index: compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java,v retrieving revision 1.311.4.4 diff -u -r1.311.4.4 ProblemReporter.java --- compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java 6 Oct 2006 09:17:11 -0000 1.311.4.4 +++ compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java 14 Oct 2006 20:22:17 -0000 @@ -3387,16 +3387,15 @@ argument.type.sourceStart, argument.sourceEnd); } -public void isClassPathCorrect(char[][] wellKnownTypeName, CompilationUnitDeclaration compUnitDecl) { +public void isClassPathCorrect(char[][] expectedTypeName, CompilationUnitDeclaration compUnitDecl, ASTNode location) { this.referenceContext = compUnitDecl; - String[] arguments = new String[] {CharOperation.toString(wellKnownTypeName)}; + String[] arguments = new String[] {CharOperation.toString(expectedTypeName)}; this.handle( IProblem.IsClassPathCorrect, arguments, arguments, - ProblemSeverities.AbortCompilation | ProblemSeverities.Error | ProblemSeverities.Fatal, - 0, - 0); + location == null ? 0 : location.sourceStart(), + location == null ? 0 : location.sourceEnd()); } private boolean isIdentifier(int token) { return token == TerminalTokens.TokenNameIdentifier; Index: model/org/eclipse/jdt/internal/core/builder/MissingClassFileException.java =================================================================== RCS file: model/org/eclipse/jdt/internal/core/builder/MissingClassFileException.java diff -N model/org/eclipse/jdt/internal/core/builder/MissingClassFileException.java --- model/org/eclipse/jdt/internal/core/builder/MissingClassFileException.java 10 May 2006 18:03:50 -0000 1.8 +++ /dev/null 1 Jan 1970 00:00:00 -0000 @@ -1,25 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2006 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.builder; - -/** - * Exception thrown when the build should be aborted because a referenced - * class file cannot be found. - */ -public class MissingClassFileException extends RuntimeException { - - protected String missingClassFile; - private static final long serialVersionUID = 3060418973806972616L; // backward compatible - -public MissingClassFileException(String missingClassFile) { - this.missingClassFile = missingClassFile; -} -} Index: model/org/eclipse/jdt/internal/core/builder/AbstractImageBuilder.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/AbstractImageBuilder.java,v retrieving revision 1.96 diff -u -r1.96 AbstractImageBuilder.java --- model/org/eclipse/jdt/internal/core/builder/AbstractImageBuilder.java 25 Apr 2006 20:39:49 -0000 1.96 +++ model/org/eclipse/jdt/internal/core/builder/AbstractImageBuilder.java 14 Oct 2006 20:22:18 -0000 @@ -50,6 +50,7 @@ private boolean inCompiler; +protected boolean keepStoringProblemMarkers; protected SimpleSet filesWithAnnotations = null; public static int MAX_AT_ONCE = 2000; // best compromise between space used and speed @@ -84,6 +85,7 @@ this.nameEnvironment = javaBuilder.nameEnvironment; this.sourceLocations = this.nameEnvironment.sourceLocations; this.notifier = javaBuilder.notifier; + this.keepStoringProblemMarkers = true; // may get disabled when missing classfiles are encountered if (buildStarting) { this.newState = newState == null ? new State(javaBuilder) : newState; @@ -545,24 +547,39 @@ */ protected void storeProblemsFor(SourceFile sourceFile, CategorizedProblem[] problems) throws CoreException { if (sourceFile == null || problems == null || problems.length == 0) return; + // once a classpath error is found, ignore all other problems for this project so the user can see the main error + // but still try to compile as many source files as possible to help the case when the base libraries are in source + if (!this.keepStoringProblemMarkers) return; // only want the one error recorded on this source file - String missingClassFile = null; IResource resource = sourceFile.resource; HashSet managedMarkerTypes = JavaModelManager.getJavaModelManager().compilationParticipants.managedMarkerTypes(); for (int i = 0, l = problems.length; i < l; i++) { CategorizedProblem problem = problems[i]; int id = problem.getID(); + + // handle missing classfile situation if (id == IProblem.IsClassPathCorrect) { - JavaBuilder.removeProblemsAndTasksFor(javaBuilder.currentProject); // make this the only problem for this project - String[] args = problem.getArguments(); - missingClassFile = args[0]; + String missingClassfileName = problem.getArguments()[0]; + if (JavaBuilder.DEBUG) + System.out.println(Messages.bind(Messages.build_incompleteClassPath, missingClassfileName)); + boolean isInvalidClasspathError = JavaCore.ERROR.equals(javaBuilder.javaProject.getOption(JavaCore.CORE_INCOMPLETE_CLASSPATH, true)); + // insert extra classpath problem, and make it the only problem for this project (optional) + if (isInvalidClasspathError && JavaCore.ABORT.equals(javaBuilder.javaProject.getOption(JavaCore.CORE_JAVA_BUILD_INVALID_CLASSPATH, true))) { + JavaBuilder.removeProblemsAndTasksFor(javaBuilder.currentProject); // make this the only problem for this project + this.keepStoringProblemMarkers = false; + } + IMarker marker = this.javaBuilder.currentProject.createMarker(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER); + marker.setAttribute(IMarker.MESSAGE, Messages.bind(Messages.build_incompleteClassPath, missingClassfileName)); + marker.setAttribute(IMarker.SEVERITY, isInvalidClasspathError ? IMarker.SEVERITY_ERROR : IMarker.SEVERITY_WARNING); + marker.setAttribute(IJavaModelMarker.CATEGORY_ID, CategorizedProblem.CAT_BUILDPATH); + // if not keeping more markers, still fall through rest of the problem reporting, so that offending IsClassPathCorrect + // problem gets recorded since it may help locating the offending reference } - + String markerType = problem.getMarkerType(); - if (IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER.equals(markerType) - || managedMarkerTypes.contains(markerType)) { + if (IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER.equals(markerType) || managedMarkerTypes.contains(markerType)) { IMarker marker = resource.createMarker(markerType); - + // standard attributes marker.setAttributes( JAVA_PROBLEM_MARKER_ATTRIBUTE_NAMES, @@ -583,9 +600,9 @@ if (extraLength > 0) { marker.setAttributes(extraAttributeNames, problem.getExtraMarkerAttributeValues()); } + + if (!this.keepStoringProblemMarkers) return; // only want the one error recorded on this source file } - if (missingClassFile != null) - throw new MissingClassFileException(missingClassFile); } } Index: model/org/eclipse/jdt/internal/core/builder/JavaBuilder.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/JavaBuilder.java,v retrieving revision 1.122 diff -u -r1.122 JavaBuilder.java --- model/org/eclipse/jdt/internal/core/builder/JavaBuilder.java 6 Apr 2006 19:15:52 -0000 1.122 +++ model/org/eclipse/jdt/internal/core/builder/JavaBuilder.java 14 Oct 2006 20:22:18 -0000 @@ -209,14 +209,6 @@ marker.setAttribute(IMarker.MESSAGE, Messages.bind(Messages.build_inconsistentProject, e.getLocalizedMessage())); marker.setAttribute(IMarker.SEVERITY, IMarker.SEVERITY_ERROR); marker.setAttribute(IJavaModelMarker.CATEGORY_ID, CategorizedProblem.CAT_BUILDPATH); - } catch (MissingClassFileException e) { - // do not log this exception since its thrown to handle aborted compiles because of missing class files - if (DEBUG) - System.out.println(Messages.bind(Messages.build_incompleteClassPath, e.missingClassFile)); - IMarker marker = currentProject.createMarker(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER); - marker.setAttribute(IMarker.MESSAGE, Messages.bind(Messages.build_incompleteClassPath, e.missingClassFile)); - marker.setAttribute(IMarker.SEVERITY, IMarker.SEVERITY_ERROR); - marker.setAttribute(IJavaModelMarker.CATEGORY_ID, CategorizedProblem.CAT_BUILDPATH); } catch (MissingSourceFileException e) { // do not log this exception since its thrown to handle aborted compiles because of missing source files if (DEBUG)