let psi file become invalid when its original file is invalid

because otherwise clients call getOriginalFile and end up with invalid PSI
This commit is contained in:
peter
2017-07-07 08:00:22 +02:00
parent beade7a802
commit f3e5fe2095
3 changed files with 38 additions and 4 deletions
@@ -16,6 +16,7 @@
package com.intellij.java.psi;
import com.intellij.lang.java.JavaLanguage;
import com.intellij.openapi.application.WriteAction;
import com.intellij.openapi.application.ex.PathManagerEx;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.io.IoTestUtil;
@@ -461,4 +462,23 @@ public class ClsPsiTest extends LightIdeaTestCase {
LeakHunter.checkLeak(dbl, ClassElement.class, element -> element.getPsi().getUserData(ClsElementImpl.COMPILED_ELEMENT) == dbl);
assertFalse(hash1 == ((ClsClassImpl)dbl).getMirror().hashCode());
}
public void testMirrorBecomesInvalidTogetherWithCls() throws IOException {
File testFile = IoTestUtil.createTestFile("TestClass.class");
File file1 = new File(PathManagerEx.getTestDataPath() + TEST_DATA_PATH + "/1_TestClass.class");
FileUtil.copy(file1, testFile);
VirtualFile copyVFile = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(testFile);
ClsFileImpl clsFile = (ClsFileImpl)PsiManager.getInstance(getProject()).findFile(copyVFile);
PsiElement mirror = clsFile.getMirror();
assertTrue(clsFile.isValid());
assertTrue(mirror.isValid());
WriteAction.run(() -> copyVFile.delete(this));
assertFalse(clsFile.isValid());
assertFalse(mirror.isValid());
assertTrue(PsiInvalidElementAccessException.findOutInvalidationReason(mirror)
.contains(PsiInvalidElementAccessException.findOutInvalidationReason(clsFile)));
}
}
@@ -107,7 +107,12 @@ public class PsiInvalidElementAccessException extends RuntimeException implement
@Nullable
private static Object getPsiInvalidationTrace(@NotNull PsiElement element) {
Object trace = getInvalidationTrace(element);
return trace != null || element instanceof PsiFile ? trace : findInvalidationTrace(element.getNode());
if (trace != null) return trace;
if (element instanceof PsiFile) {
return getInvalidationTrace(((PsiFile)element).getOriginalFile());
}
return findInvalidationTrace(element.getNode());
}
private static String getMessageWithReason(@NotNull PsiElement element,
@@ -120,7 +125,7 @@ public class PsiInvalidElementAccessException extends RuntimeException implement
trace != null ? "see attachment" :
"no info";
try {
reason += " because: " + reason(element);
reason += " because: " + findOutInvalidationReason(element);
}
catch (PsiInvalidElementAccessException ignore) {
}
@@ -161,7 +166,7 @@ public class PsiInvalidElementAccessException extends RuntimeException implement
@NonNls
@NotNull
private static String reason(@NotNull PsiElement root) {
public static String findOutInvalidationReason(@NotNull PsiElement root) {
if (root == PsiUtilCore.NULL_PSI_ELEMENT) return "NULL_PSI_ELEMENT";
PsiElement element = root instanceof PsiFile ? root : root.getParent();
@@ -170,6 +175,7 @@ public class PsiInvalidElementAccessException extends RuntimeException implement
if (root instanceof StubBasedPsiElement) {
StubElement stub = ((StubBasedPsiElement)root).getStub();
while (stub != null) {
//noinspection StringConcatenationInLoop
m += "\n each stub=" + stub;
if (stub instanceof PsiFileStub) {
m += "; fileStub.psi=" + stub.getPsi() + "; reason=" + ((PsiFileStub)stub).getInvalidationReason();
@@ -190,10 +196,15 @@ public class PsiInvalidElementAccessException extends RuntimeException implement
if (!provider.isPhysical()) {
PsiElement context = file.getContext();
if (context != null && !context.isValid()) {
return "invalid context: " + reason(context);
return "invalid context: " + findOutInvalidationReason(context);
}
}
PsiFile original = file.getOriginalFile();
if (original != file && !original.isValid()) {
return "invalid original: " + findOutInvalidationReason(original);
}
PsiManager manager = file.getManager();
if (manager.getProject().isDisposed()) return "project is disposed";
@@ -162,6 +162,9 @@ public abstract class PsiFileImpl extends ElementBase implements PsiFileEx, PsiF
// but some VFS listeners receive the same events before that and ask PsiFile.isValid
return false;
}
if (myOriginalFile != null && !myOriginalFile.isValid()) {
return false;
}
return !myInvalidated;
}