Bug 553269 - Eclipse detects changed ENCODING on opening a project with explicit encoding set After closing and opening a project we do not expect ENCODING flag to be in the resource delta send, but the code does exactly that *if* the project encoding was modified at least once during the current Eclipse session. This problem was introduced in bug 84350. ResourceInfo.incrementCharsetGenerationCount() writes two parts of an int into charsetAndContentId (and ResourceInfo.getCharsetGenerationCount() uses the upper part), but ResourceInfo.writeTo(DataOutput) and ResourceInfo.readFrom(int, DataInput) read/write only the lower part. So every time Container.setDefaultCharset(String, IProgressMonitor) is called (for example after reading .settings/org.eclipse.core.resources.prefs with encoding set), the "current" (in memory) project info differs from saved/loaded project info. Since the "current" project info remains in memory after closing the project, its charsetAndContentId content will be always different compared to the data read back from disk. After Eclipse restart, where *all* the data is loaded from disk, charsetAndContentId will be consistent (it will not have "CharsetGenerationCount" part anymore), and the troubles start again only after someone touches .settings/org.eclipse.core.resources.prefs in some way (either by changing encoding settings via UI or via git/other direct resource operations). Safest way to fix that would be NOT to change the way how the tree is saved to disk (so do NOT save "CharsetGenerationCount" part of ResourceInfo.charsetAndContentId), but instead, clean up this part on closing the project in Project.internalClose(IProgressMonitor), similar what is done via ResourceInfo.clearModificationStamp(). Change-Id: I77cd8c0af2e3283191e185a8683162b77e544f39 Signed-off-by: Andrey Loskutov <loskutov@gmx.de>
diff --git a/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/Project.java b/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/Project.java index 5a61ab9..f907db7 100644 --- a/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/Project.java +++ b/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/Project.java
@@ -627,6 +627,7 @@ info.clear(M_OPEN); info.clearSessionProperties(); info.clearModificationStamp(); + info.clearCharsetGenerationCount(); info.setSyncInfo(null); }
diff --git a/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/ResourceInfo.java b/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/ResourceInfo.java index 1fbd484..f8c2e7a 100644 --- a/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/ResourceInfo.java +++ b/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/ResourceInfo.java
@@ -116,6 +116,10 @@ modStamp = IResource.NULL_STAMP; } + public void clearCharsetGenerationCount() { + charsetAndContentId = getContentId(); + } + public synchronized void clearSessionProperties() { sessionProperties = null; }
diff --git a/tests/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/resources/regression/IResourceTest.java b/tests/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/resources/regression/IResourceTest.java index aa95f69..8e14a6f 100644 --- a/tests/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/resources/regression/IResourceTest.java +++ b/tests/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/resources/regression/IResourceTest.java
@@ -15,16 +15,18 @@ package org.eclipse.core.tests.resources.regression; import java.io.InputStream; +import java.nio.charset.StandardCharsets; import junit.framework.Test; import junit.framework.TestSuite; import org.eclipse.core.filesystem.EFS; import org.eclipse.core.resources.*; import org.eclipse.core.runtime.*; +import org.eclipse.core.tests.resources.ResourceDeltaVerifier; import org.eclipse.core.tests.resources.ResourceTest; public class IResourceTest extends ResourceTest { - private boolean DISABLED = true; + private final boolean DISABLED = true; public static Test suite() { return new TestSuite(IResourceTest.class); @@ -166,7 +168,7 @@ final boolean[] seen = new boolean[] {false}; final boolean[] phantomSeen = new boolean[] {false}; class DeltaVisitor implements IResourceDeltaVisitor { - private boolean[] mySeen; + private final boolean[] mySeen; DeltaVisitor(boolean[] mySeen) { this.mySeen = mySeen; @@ -695,4 +697,41 @@ fail("3.0", e); } } + + /** + * 553269: Eclipse sends unexpected ENCODING change after closing/opening + * project with explicit encoding settings changed in the same session + */ + public void testBug553269() throws Exception { + IWorkspace workspace = getWorkspace(); + IProject project = workspace.getRoot().getProject("MyProject"); + IFolder settingsFolder = project.getFolder(".settings"); + IFile settingsFile = settingsFolder.getFile("org.eclipse.core.resources.prefs"); + project.create(null); + project.open(null); + project.setDefaultCharset(StandardCharsets.UTF_8.name(), null); + + assertTrue("Preferences saved", settingsFile.exists()); + + project.close(null); + + ResourceDeltaVerifier verifier = new ResourceDeltaVerifier(); + workspace.addResourceChangeListener(verifier, IResourceChangeEvent.POST_CHANGE); + // We expect only OPEN change, the original code generated + // IResourceDelta.OPEN | IResourceDelta.ENCODING + verifier.addExpectedChange(project, IResourceDelta.CHANGED, IResourceDelta.OPEN); + + // This is irrelevant for the test but verifier verifies entire delta... + verifier.addExpectedChange(settingsFolder, IResourceDelta.ADDED, 0); + verifier.addExpectedChange(settingsFile, IResourceDelta.ADDED, 0); + verifier.addExpectedChange(project.getFile(".project"), IResourceDelta.ADDED, 0); + + try { + project.open(null); + assertTrue(verifier.getMessage(), verifier.isDeltaValid()); + } finally { + workspace.removeResourceChangeListener(verifier); + project.delete(true, true, null); + } + } }