diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ClasspathTests.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ClasspathTests.java index 4166cb2..27c6864 100644 --- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ClasspathTests.java +++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ClasspathTests.java @@ -249,6 +249,7 @@ suite.addTest(new ClasspathTests("testInvalidClasspath2")); suite.addTest(new ClasspathTests("testInvalidExternalClassFolder")); suite.addTest(new ClasspathTests("testInvalidExternalJar")); + suite.addTest(new ClasspathTests("testTransitionFromInvalidToValidJar")); suite.addTest(new ClasspathTests("testInvalidInternalJar1")); suite.addTest(new ClasspathTests("testInvalidInternalJar2")); suite.addTest(new ClasspathTests("testInvalidSourceFolder")); @@ -334,6 +335,7 @@ suite.addTest(new ClasspathTests("testBug321170")); suite.addTest(new ClasspathTests("testBug229042")); suite.addTest(new ClasspathTests("testBug274737")); + suite.addTest(new ClasspathTests("testBug357425")); return suite; } public void setUpSuite() throws Exception { @@ -4201,6 +4203,41 @@ } } /* + * Ensures that validateClasspathEntry() sees a transition from an invalid/missing jar to a valid jar. + */ +public void testTransitionFromInvalidToValidJar() throws CoreException, IOException { + String transitioningJarName = "transitioningJar.jar"; + String transitioningJar = getExternalPath() + transitioningJarName; + String nonExistingJar = getExternalPath() + "nonExisting.jar"; + IClasspathEntry transitioningEntry = JavaCore.newLibraryEntry(new Path(transitioningJar), null, null); + IClasspathEntry nonExistingEntry = JavaCore.newLibraryEntry(new Path(nonExistingJar), null, null); + + try { + IJavaProject proj = createJavaProject("P", new String[] {}, new String[] {transitioningJar, nonExistingJar}, "bin"); + + IJavaModelStatus status1 = ClasspathEntry.validateClasspathEntry(proj, transitioningEntry, false, false); + IJavaModelStatus status2 = ClasspathEntry.validateClasspathEntry(proj, nonExistingEntry, false, false); + assertFalse("Non-existing jar should be invalid", status1.isOK()); + assertFalse("Non-existing jar should be invalid", status2.isOK()); + + Util.createJar( + new String[0], + new String[] { + "META-INF/MANIFEST.MF", + "Manifest-Version: 1.0\n" + }, + transitioningJar, + JavaCore.VERSION_1_4); + status1 = ClasspathEntry.validateClasspathEntry(proj, transitioningEntry, false, false); + status2 = ClasspathEntry.validateClasspathEntry(proj, nonExistingEntry, false, false); + assertTrue("Existing jar should be valid", status1.isOK()); + assertFalse("Non-existing jar should be invalid", status2.isOK()); + } finally { + deleteExternalResource(transitioningJarName); + deleteProject("P"); + } +} +/* * Ensures that a non existing internal jar cannot be put on the classpath. */ public void testInvalidInternalJar1() throws CoreException { @@ -7190,4 +7227,46 @@ } } +/* + * Ensures that the correct delta is reported when changing the Class-Path: clause + * of an external jar from not containing a chained jar to containing a chained jar. + * (regression test for https://bugs.eclipse.org/bugs/show_bug.cgi?id=357425) + */ +public void testBug357425() throws Exception { + try { + IJavaProject p = createJavaProject("P"); + addExternalLibrary(p, getExternalResourcePath("lib357425_a.jar"), new String[0], + new String[] { + "META-INF/MANIFEST.MF", + "Manifest-Version: 1.0\n" + }, + JavaCore.VERSION_1_4); + refreshExternalArchives(p); + + startDeltas(); + org.eclipse.jdt.core.tests.util.Util.createJar(new String[0], + new String[] { + "META-INF/MANIFEST.MF", + "Manifest-Version: 1.0\n" + + "Class-Path: lib357425_b.jar\n", + }, + getExternalResourcePath("lib357425_a.jar"), + JavaCore.VERSION_1_4); + createExternalFile("lib357425_b.jar", ""); + + refreshExternalArchives(p); + assertDeltas( + "Unexpected delta", + "P[*]: {CHILDREN | RESOLVED CLASSPATH CHANGED}\n" + + " "+ getExternalPath() + "lib357425_a.jar[*]: {CONTENT | REORDERED | ARCHIVE CONTENT CHANGED}\n" + + " "+ getExternalPath() + "lib357425_b.jar[+]: {}" + ); + } finally { + stopDeltas(); + deleteProject("P"); + deleteExternalResource("lib357425_a.jar"); + deleteExternalResource("lib357425_b.jar"); + } +} + } diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClasspathEntry.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClasspathEntry.java index d8086ff..6b9aeae 100644 --- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClasspathEntry.java +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClasspathEntry.java @@ -7,6 +7,7 @@ * * Contributors: * IBM Corporation - initial API and implementation + * Terry Parker - DeltaProcessor misses state changes in archive files, see https://bugs.eclipse.org/bugs/show_bug.cgi?id=357425 *******************************************************************************/ package org.eclipse.jdt.internal.core; @@ -1827,6 +1828,9 @@ * @return a java model status describing the problem related to this classpath entry if any, a status object with code IStatus.OK if the entry is fine */ public static IJavaModelStatus validateClasspathEntry(IJavaProject project, IClasspathEntry entry, boolean checkSourceAttachment, boolean referredByContainer){ + if (entry.getEntryKind() == IClasspathEntry.CPE_LIBRARY) { + JavaModelManager.getJavaModelManager().removeFromInvalidArchiveCache(entry.getPath()); + } IJavaModelStatus status = validateClasspathEntry(project, entry, null, checkSourceAttachment, referredByContainer); // https://bugs.eclipse.org/bugs/show_bug.cgi?id=171136 and https://bugs.eclipse.org/bugs/show_bug.cgi?id=300136 // Ignore class path errors from optional entries. diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/DeltaProcessor.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/DeltaProcessor.java index f7a0c1c..126fcc9 100644 --- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/DeltaProcessor.java +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/DeltaProcessor.java @@ -8,6 +8,7 @@ * Contributors: * IBM Corporation - initial API and implementation * Terry Parker - DeltaProcessor exhibits O(N^2) behavior, see https://bugs.eclipse.org/bugs/show_bug.cgi?id=354332 + * Terry Parker - DeltaProcessor misses state changes in archive files, see https://bugs.eclipse.org/bugs/show_bug.cgi?id=357425 *******************************************************************************/ package org.eclipse.jdt.internal.core; @@ -954,7 +955,7 @@ // project does not exist -> ignore continue; } - boolean hasChainedJar = false; + boolean deltaContainsModifiedJar = false; for (int j = 0; j < entries.length; j++){ if (entries[j].getEntryKind() == IClasspathEntry.CPE_LIBRARY) { IPath entryPath = entries[j].getPath(); @@ -1024,7 +1025,7 @@ System.out.println("- External JAR ADDED, affecting root: "+root.getElementName()); //$NON-NLS-1$ } elementAdded(root, null, null); - hasChainedJar |= !this.manager.isNonChainingJar(entryPath); + deltaContainsModifiedJar = true; this.state.addClasspathValidation(javaProject); // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=185733 hasDelta = true; } else if (status == EXTERNAL_JAR_CHANGED) { @@ -1033,7 +1034,7 @@ System.out.println("- External JAR CHANGED, affecting root: "+root.getElementName()); //$NON-NLS-1$ } contentChanged(root); - hasChainedJar |= !this.manager.isNonChainingJar(entryPath); + deltaContainsModifiedJar = true; hasDelta = true; } else if (status == EXTERNAL_JAR_REMOVED) { PackageFragmentRoot root = (PackageFragmentRoot) javaProject.getPackageFragmentRoot(entryPath.toString()); @@ -1041,7 +1042,7 @@ System.out.println("- External JAR REMOVED, affecting root: "+root.getElementName()); //$NON-NLS-1$ } elementRemoved(root, null, null); - hasChainedJar |= !this.manager.isNonChainingJar(entryPath); + deltaContainsModifiedJar = true; this.state.addClasspathValidation(javaProject); // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=185733 hasDelta = true; } @@ -1049,7 +1050,7 @@ } } - if (hasChainedJar) { + if (deltaContainsModifiedJar) { javaProject.resetResolvedClasspath(); } } diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModelManager.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModelManager.java index cdead40..8a18b61 100644 --- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModelManager.java +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModelManager.java @@ -11,6 +11,7 @@ * before its contents * (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=102422) * Stephan Herrmann - Contribution for Bug 346010 - [model] strange initialization dependency in OptionTests + * Terry Parker - DeltaProcessor misses state changes in archive files, see https://bugs.eclipse.org/bugs/show_bug.cgi?id=357425 *******************************************************************************/ package org.eclipse.jdt.internal.core; @@ -3086,6 +3087,12 @@ return this.invalidArchives != null && this.invalidArchives.contains(path); } + public void removeFromInvalidArchiveCache(IPath path) { + if (this.invalidArchives != null) { + this.invalidArchives.remove(path); + } + } + public void setClasspathBeingResolved(IJavaProject project, boolean classpathIsResolved) { if (classpathIsResolved) { getClasspathBeingResolved().add(project);