Fixed NPE's in resourceless source modules
Change-Id: I3f2b8e65d0596528763e8ab6a61923db2846b589
Signed-off-by: Vasili Gulevich <vasili.gulevich@xored.com>
diff --git a/core/plugins/org.eclipse.dltk.core/model/org/eclipse/dltk/internal/core/AbstractSourceModule.java b/core/plugins/org.eclipse.dltk.core/model/org/eclipse/dltk/internal/core/AbstractSourceModule.java
index c7f997e..178e0f4 100644
--- a/core/plugins/org.eclipse.dltk.core/model/org/eclipse/dltk/internal/core/AbstractSourceModule.java
+++ b/core/plugins/org.eclipse.dltk.core/model/org/eclipse/dltk/internal/core/AbstractSourceModule.java
@@ -16,7 +16,6 @@
import java.util.List;
import java.util.Map;
-import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
@@ -548,17 +547,9 @@
printNode(printer);
printer.flush();
}
- // update timestamp (might be IResource.NULL_STAMP if original does
- // not exist)
- if (underlyingResource == null) {
- underlyingResource = getResource();
- }
- // underlying resource is null in the case of a working copy out of
- // workspace
- if (underlyingResource != null) {
- moduleInfo.timestamp = ((IFile) underlyingResource)
- .getModificationStamp();
- }
+ moduleInfo.timestamp = underlyingResource != null
+ ? underlyingResource.getLocalTimeStamp()
+ : getOriginTimestamp();
// We need to update children contents using model providers
// Call for extra model providers
final IDLTKLanguageToolkit toolkit = DLTKLanguageManager
@@ -624,7 +615,7 @@
// create buffer
final BufferManager bufManager = getBufferManager();
final boolean isWorkingCopy = isWorkingCopy();
- IBuffer buffer = isWorkingCopy ? this.owner.createBuffer(this)
+ IBuffer buffer = isWorkingCopy ? createBuffer()
: BufferManager.createBuffer(this);
if (buffer == null) {
return null;
@@ -689,6 +680,10 @@
return buffer;
}
+ protected IBuffer createBuffer() {
+ return this.owner.createBuffer(this);
+ }
+
@Override
protected void openParent(Object childInfo, HashMap newElements,
IProgressMonitor pm) throws ModelException {
@@ -789,4 +784,8 @@
public ISourceRange getNameRange() throws ModelException {
return null;
}
+
+ protected long getOriginTimestamp() {
+ return IResource.NULL_STAMP;
+ }
}
diff --git a/core/plugins/org.eclipse.dltk.core/model/org/eclipse/dltk/internal/core/BecomeWorkingCopyOperation.java b/core/plugins/org.eclipse.dltk.core/model/org/eclipse/dltk/internal/core/BecomeWorkingCopyOperation.java
index 9e6f5d5..b438430 100644
--- a/core/plugins/org.eclipse.dltk.core/model/org/eclipse/dltk/internal/core/BecomeWorkingCopyOperation.java
+++ b/core/plugins/org.eclipse.dltk.core/model/org/eclipse/dltk/internal/core/BecomeWorkingCopyOperation.java
@@ -5,10 +5,11 @@
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
-
+
*******************************************************************************/
package org.eclipse.dltk.internal.core;
+import org.eclipse.core.resources.IResource;
import org.eclipse.dltk.core.IModelElement;
import org.eclipse.dltk.core.IModelElementDelta;
import org.eclipse.dltk.core.IProblemRequestor;
@@ -51,16 +52,19 @@
delta.added(workingCopy);
addDelta(delta);
} else {
- if (workingCopy.getResource().isAccessible()) {
+ IResource resource = workingCopy.getResource();
+ if (resource != null && resource.isAccessible()) {
// report a F_PRIMARY_WORKING_COPY change delta for a primary
// working copy
- ModelElementDelta delta = new ModelElementDelta(this.getModel());
+ ModelElementDelta delta = new ModelElementDelta(
+ this.getModel());
delta.changed(workingCopy,
IModelElementDelta.F_PRIMARY_WORKING_COPY);
addDelta(delta);
} else {
// report an ADDED delta
- ModelElementDelta delta = new ModelElementDelta(this.getModel());
+ ModelElementDelta delta = new ModelElementDelta(
+ this.getModel());
delta.added(workingCopy,
IModelElementDelta.F_PRIMARY_WORKING_COPY);
addDelta(delta);
diff --git a/core/plugins/org.eclipse.dltk.core/model/org/eclipse/dltk/internal/core/DiscardWorkingCopyOperation.java b/core/plugins/org.eclipse.dltk.core/model/org/eclipse/dltk/internal/core/DiscardWorkingCopyOperation.java
index 6b93781..7dbfcda 100644
--- a/core/plugins/org.eclipse.dltk.core/model/org/eclipse/dltk/internal/core/DiscardWorkingCopyOperation.java
+++ b/core/plugins/org.eclipse.dltk.core/model/org/eclipse/dltk/internal/core/DiscardWorkingCopyOperation.java
@@ -8,9 +8,10 @@
*******************************************************************************/
package org.eclipse.dltk.internal.core;
-import org.eclipse.dltk.core.IScriptProject;
+import org.eclipse.core.resources.IResource;
import org.eclipse.dltk.core.IModelElement;
import org.eclipse.dltk.core.IModelElementDelta;
+import org.eclipse.dltk.core.IScriptProject;
import org.eclipse.dltk.core.ModelException;
/**
@@ -37,12 +38,14 @@
}
if (!workingCopy.isPrimary()) {
// report removedscriptdelta for a non-primary working copy
- ModelElementDelta delta = new ModelElementDelta(this.getModel());
+ ModelElementDelta delta = new ModelElementDelta(
+ this.getModel());
delta.removed(workingCopy);
addDelta(delta);
removeReconcileDelta(workingCopy);
} else {
- if (workingCopy.getResource().isAccessible()) {
+ IResource resource = workingCopy.getResource();
+ if (resource != null && resource.isAccessible()) {
// report a F_PRIMARY_WORKING_COPY change delta for a
// primary working copy
ModelElementDelta delta = new ModelElementDelta(this
diff --git a/core/plugins/org.eclipse.dltk.core/model/org/eclipse/dltk/internal/core/SourceModule.java b/core/plugins/org.eclipse.dltk.core/model/org/eclipse/dltk/internal/core/SourceModule.java
index b375a25..44e748c 100644
--- a/core/plugins/org.eclipse.dltk.core/model/org/eclipse/dltk/internal/core/SourceModule.java
+++ b/core/plugins/org.eclipse.dltk.core/model/org/eclipse/dltk/internal/core/SourceModule.java
@@ -203,8 +203,18 @@
return false;
}
- return ((SourceModuleElementInfo) info).timestamp != getResource()
- .getModificationStamp();
+ return ((SourceModuleElementInfo) info).timestamp != getOriginTimestamp();
+ }
+
+ /**
+ * Last modification stamp of underlying resource.
+ *
+ * @return modification stamp of underlying resource, IResource.NULL_STAMP
+ * if deleted
+ */
+ @Override
+ protected long getOriginTimestamp() {
+ return getResource().getModificationStamp();
}
@Override
@@ -392,8 +402,7 @@
protected void updateTimeStamp(SourceModule original)
throws ModelException {
// XXX: should be an interface method
- long timeStamp = ((IFile) original.getResource())
- .getModificationStamp();
+ long timeStamp = original.getOriginTimestamp();
if (timeStamp == IResource.NULL_STAMP) {
throw new ModelException(
new ModelStatus(IModelStatusConstants.INVALID_RESOURCE));
diff --git a/core/plugins/org.eclipse.dltk.ui/src/org/eclipse/dltk/ui/ProblemsLabelDecorator.java b/core/plugins/org.eclipse.dltk.ui/src/org/eclipse/dltk/ui/ProblemsLabelDecorator.java
index 906c23f..fccde2c 100644
--- a/core/plugins/org.eclipse.dltk.ui/src/org/eclipse/dltk/ui/ProblemsLabelDecorator.java
+++ b/core/plugins/org.eclipse.dltk.ui/src/org/eclipse/dltk/ui/ProblemsLabelDecorator.java
@@ -275,11 +275,13 @@
private IAnnotationModel isInScriptAnnotationModel(ISourceModule original) {
if (original.isWorkingCopy()) {
if (original instanceof SourceModule) {
- FileEditorInput editorInput = new FileEditorInput(
- (IFile) original.getResource());
- return DLTKUIPlugin.getDefault()
- .getSourceModuleDocumentProvider()
- .getAnnotationModel(editorInput);
+ IFile file = (IFile) original.getResource();
+ if (file != null) {
+ FileEditorInput editorInput = new FileEditorInput(file);
+ return DLTKUIPlugin.getDefault()
+ .getSourceModuleDocumentProvider()
+ .getAnnotationModel(editorInput);
+ }
} else if (original instanceof IExternalSourceModule) {
ExternalStorageEditorInput editorInput = new ExternalStorageEditorInput(
(IExternalSourceModule) original);
diff --git a/core/tests/org.eclipse.dltk.core.tests/src/org/eclipse/dltk/core/tests/model/WorkingCopyTests.java b/core/tests/org.eclipse.dltk.core.tests/src/org/eclipse/dltk/core/tests/model/WorkingCopyTests.java
index 1f7d61c..55d259f 100644
--- a/core/tests/org.eclipse.dltk.core.tests/src/org/eclipse/dltk/core/tests/model/WorkingCopyTests.java
+++ b/core/tests/org.eclipse.dltk.core.tests/src/org/eclipse/dltk/core/tests/model/WorkingCopyTests.java
@@ -8,25 +8,40 @@
*******************************************************************************/
package org.eclipse.dltk.core.tests.model;
-import junit.framework.Test;
+import java.util.HashMap;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.OperationCanceledException;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.dltk.compiler.problem.IProblem;
import org.eclipse.dltk.core.IBuffer;
import org.eclipse.dltk.core.IModelElement;
+import org.eclipse.dltk.core.IProblemRequestor;
+import org.eclipse.dltk.core.IScriptProject;
import org.eclipse.dltk.core.ISourceModule;
import org.eclipse.dltk.core.ModelException;
import org.eclipse.dltk.core.WorkingCopyOwner;
+import org.eclipse.dltk.internal.core.BufferManager;
+import org.eclipse.dltk.internal.core.DefaultWorkingCopyOwner;
+import org.eclipse.dltk.internal.core.ModelElement;
+import org.eclipse.dltk.internal.core.SourceModule;
import org.eclipse.team.core.RepositoryProvider;
+import org.junit.Assert;
+import junit.framework.Test;
public class WorkingCopyTests extends ModifyingResourceTests {
- private static final String[] TEST_NATURE = new String[] { "org.eclipse.dltk.core.tests.testnature" };
- ISourceModule cu = null;
- ISourceModule copy = null;
+ private static final String[] TEST_NATURE = new String[] {
+ "org.eclipse.dltk.core.tests.testnature" };
+ private ISourceModule cu = null;
+ private ISourceModule copy = null;
+ private IScriptProject scriptProject = null;
+
public class TestWorkingCopyOwner extends WorkingCopyOwner {
@Override
public IBuffer createBuffer(ISourceModule workingCopy) {
@@ -46,16 +61,20 @@
protected void setUp() throws Exception {
super.setUp();
try {
-
- this.createScriptProject("P", TEST_NATURE,new String[] {
- "src"
- } );
+
+ this.scriptProject = this.createScriptProject("P", TEST_NATURE,
+ new String[] { "src" });
this.createFolder("P/src/x/y");
- this.createFile("P/src/x/y/A.txt", "package x.y;\n" + "import java.io.File;\n" + "public class A {\n"
- + " public class Inner {\n" + " public class InnerInner {\n" + " }\n" + " int innerField;\n"
- + " void innerMethod() {\n" + " }\n" + " }\n" + " static String FIELD;\n" + " {\n"
- + " FIELD = File.pathSeparator;\n" + " }\n" + " int field1;\n" + " boolean field2;\n" + " public void foo() {\n"
- + " }\n" + "}");
+ this.createFile("P/src/x/y/A.txt",
+ "package x.y;\n" + "import java.io.File;\n"
+ + "public class A {\n" + " public class Inner {\n"
+ + " public class InnerInner {\n" + " }\n"
+ + " int innerField;\n"
+ + " void innerMethod() {\n" + " }\n" + " }\n"
+ + " static String FIELD;\n" + " {\n"
+ + " FIELD = File.pathSeparator;\n" + " }\n"
+ + " int field1;\n" + " boolean field2;\n"
+ + " public void foo() {\n" + " }\n" + "}");
this.cu = this.getSourceModule("P/src/x/y/A.txt");
this.copy = cu.getWorkingCopy(null);
} catch (CoreException e) {
@@ -78,7 +97,8 @@
* delta after method copy-rename)
*/
public void testCancelMakeConsistent() throws ModelException {
- String newContents = "package x.y;\n" + "public class A {\n" + " public void bar() {\n" + " }\n" + "}";
+ String newContents = "package x.y;\n" + "public class A {\n"
+ + " public void bar() {\n" + " }\n" + "}";
this.copy.getBuffer().setContents(newContents);
NullProgressMonitor monitor = new NullProgressMonitor();
monitor.setCanceled(true);
@@ -93,12 +113,15 @@
/**
*/
public void testChangeContent() throws CoreException {
- String newContents = "package x.y;\n" + "public class A {\n" + " public void bar() {\n" + " }\n" + "}";
+ String newContents = "package x.y;\n" + "public class A {\n"
+ + " public void bar() {\n" + " }\n" + "}";
this.copy.getBuffer().setContents(newContents);
this.copy.reconcile(false, null, null);
- assertSourceEquals("Unexpected working copy contents", newContents, this.copy.getBuffer().getContents());
+ assertSourceEquals("Unexpected working copy contents", newContents,
+ this.copy.getBuffer().getContents());
this.copy.commitWorkingCopy(true, null);
- assertSourceEquals("Unexpected original cu contents", newContents, this.cu.getBuffer().getContents());
+ assertSourceEquals("Unexpected original cu contents", newContents,
+ this.cu.getBuffer().getContents());
}
/*
@@ -118,8 +141,10 @@
} finally {
setReadOnly(resource, readOnlyFlag);
}
- assertTrue("Should have complained about modifying a read-only unit:", didComplain);
- assertTrue("ReadOnly buffer got modified:", !this.cu.getBuffer().getContents().equals("invalid"));
+ assertTrue("Should have complained about modifying a read-only unit:",
+ didComplain);
+ assertTrue("ReadOnly buffer got modified:",
+ !this.cu.getBuffer().getContents().equals("invalid"));
}
/*
@@ -127,7 +152,8 @@
* cu if a pessimistic repository provider allows it.
*/
public void testChangeContentOfReadOnlyCU2() throws CoreException {
- String newContents = "package x.y;\n" + "public class A {\n" + " public void bar() {\n" + " }\n" + "}";
+ String newContents = "package x.y;\n" + "public class A {\n"
+ + " public void bar() {\n" + " }\n" + "}";
IResource resource = this.cu.getUnderlyingResource();
IProject project = resource.getProject();
boolean readOnlyFlag = isReadOnly(resource);
@@ -137,19 +163,114 @@
setReadOnly(resource, true);
this.copy.getBuffer().setContents(newContents);
this.copy.commitWorkingCopy(true, null);
- assertSourceEquals("Unexpected original cu contents", newContents, this.cu.getBuffer().getContents());
+ assertSourceEquals("Unexpected original cu contents", newContents,
+ this.cu.getBuffer().getContents());
} finally {
TestPessimisticProvider.markWritableOnSave = false;
RepositoryProvider.unmap(project);
setReadOnly(resource, readOnlyFlag);
}
}
+
/**
* Ensures that the primary cu can be retrieved.
*/
public void testGetPrimaryCU() {
- IModelElement primary= this.copy.getPrimaryElement();
- assertTrue("Element is not a cu", primary instanceof ISourceModule && !((ISourceModule)primary).isWorkingCopy());
+ IModelElement primary = this.copy.getPrimaryElement();
+ assertTrue("Element is not a cu", primary instanceof ISourceModule
+ && !((ISourceModule) primary).isWorkingCopy());
assertTrue("Element should exist", primary.exists());
- }
+ }
+
+ private static final class NonResourceSourceModule extends SourceModule {
+ private long originStamp = IResource.NULL_STAMP;
+
+ public NonResourceSourceModule(ModelElement parent,
+ WorkingCopyOwner owner, String name) {
+ super(parent, name, owner);
+ }
+
+ @Override
+ public boolean isReadOnly() {
+ return false;
+ }
+
+ @Override
+ protected IBuffer createBuffer() {
+ return BufferManager.createBuffer(this);
+ }
+
+ @Override
+ protected char[] getBufferContent() throws ModelException {
+ return new char[0];
+ }
+
+ @Override
+ protected void openParent(Object childInfo, HashMap newElements,
+ IProgressMonitor pm) throws ModelException {
+ }
+
+ @Override
+ protected IStatus validateSourceModule(IResource resource) {
+ return Status.OK_STATUS;
+ }
+
+ @Override
+ public IResource getResource() {
+ return null;
+ }
+
+ @Override
+ protected String getNatureId() {
+ return "test_nature";
+ }
+
+ @Override
+ protected long getOriginTimestamp() {
+ return originStamp;
+ }
+ }
+
+ private static final IProblemRequestor DUMMY_REQUESTOR = new IProblemRequestor() {
+
+ @Override
+ public boolean isActive() {
+ return true;
+ }
+
+ @Override
+ public void endReporting() {
+ }
+
+ @Override
+ public void beginReporting() {
+ }
+
+ @Override
+ public void acceptProblem(IProblem problem) {
+ }
+ };
+
+ public void testResourceLessSourceWorkingCopy() throws ModelException {
+ NonResourceSourceModule subject = new NonResourceSourceModule(
+ (ModelElement) scriptProject, DefaultWorkingCopyOwner.PRIMARY,
+ "test.py");
+ Assert.assertFalse(subject.hasResourceChanged());
+ subject.becomeWorkingCopy(DUMMY_REQUESTOR, new NullProgressMonitor());
+ Assert.assertFalse(subject.hasResourceChanged());
+ subject.discardWorkingCopy();
+ }
+
+ public void testResourceLessTimestamps() throws ModelException {
+ NonResourceSourceModule subject = new NonResourceSourceModule(
+ (ModelElement) scriptProject, DefaultWorkingCopyOwner.PRIMARY,
+ "test.py");
+ subject.originStamp = 2;
+ Assert.assertFalse(subject.hasResourceChanged());
+ subject.becomeWorkingCopy(DUMMY_REQUESTOR, new NullProgressMonitor());
+ Assert.assertFalse(subject.hasResourceChanged());
+ subject.originStamp = 3;
+ Assert.assertTrue(subject.hasResourceChanged());
+ subject.discardWorkingCopy();
+ }
}