From a26719d401a24fdc56fd9f737d2ebd7b8d2821b6 Mon Sep 17 00:00:00 2001 From: peter Date: Mon, 14 Sep 2015 12:40:29 +0200 Subject: [PATCH] assert that just created smart pointers can always be restored correctly + handle corner cases of empty-ranged PSI --- .../SmartPsiElementPointersTest.java | 2 +- .../impl/smartPointers/SelfElementInfo.java | 3 +++ .../SmartPsiElementPointerImpl.java | 22 +++++++++++++++++++ 3 files changed, 26 insertions(+), 1 deletion(-) diff --git a/java/java-tests/testSrc/com/intellij/psi/impl/smartPointers/SmartPsiElementPointersTest.java b/java/java-tests/testSrc/com/intellij/psi/impl/smartPointers/SmartPsiElementPointersTest.java index 2500bcd902ec..3086308c76bf 100644 --- a/java/java-tests/testSrc/com/intellij/psi/impl/smartPointers/SmartPsiElementPointersTest.java +++ b/java/java-tests/testSrc/com/intellij/psi/impl/smartPointers/SmartPsiElementPointersTest.java @@ -207,7 +207,7 @@ public class SmartPsiElementPointersTest extends CodeInsightTestCase { PsiDocumentManager.getInstance(myProject).commitAllDocuments(); PlatformTestUtil.tryGcSoftlyReachableObjects(); - assertNull(pointer.getElement()); + assertEquals(myFile.getFirstChild(), pointer.getElement()); } public void testChangeInPsi() { diff --git a/platform/core-impl/src/com/intellij/psi/impl/smartPointers/SelfElementInfo.java b/platform/core-impl/src/com/intellij/psi/impl/smartPointers/SelfElementInfo.java index ae006572c383..e35b6a491022 100644 --- a/platform/core-impl/src/com/intellij/psi/impl/smartPointers/SelfElementInfo.java +++ b/platform/core-impl/src/com/intellij/psi/impl/smartPointers/SelfElementInfo.java @@ -132,6 +132,9 @@ public class SelfElementInfo extends SmartPointerElementInfo { @NotNull Class type, @NotNull Language language) { PsiElement anchor = file.getViewProvider().findElementAt(syncStartOffset, language); + if (anchor == null && syncStartOffset == file.getTextLength()) { + anchor = PsiTreeUtil.getDeepestLast(file.getViewProvider().getPsi(language).getLastChild()); + } if (anchor == null) return null; PsiElement result = findParent(syncStartOffset, syncEndOffset, type, anchor); diff --git a/platform/core-impl/src/com/intellij/psi/impl/smartPointers/SmartPsiElementPointerImpl.java b/platform/core-impl/src/com/intellij/psi/impl/smartPointers/SmartPsiElementPointerImpl.java index 34c74a318882..0ccc5fd5deac 100644 --- a/platform/core-impl/src/com/intellij/psi/impl/smartPointers/SmartPsiElementPointerImpl.java +++ b/platform/core-impl/src/com/intellij/psi/impl/smartPointers/SmartPsiElementPointerImpl.java @@ -19,6 +19,7 @@ package com.intellij.psi.impl.smartPointers; import com.intellij.lang.LanguageUtil; import com.intellij.lang.injection.InjectedLanguageManager; import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Document; import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.project.Project; @@ -30,6 +31,8 @@ import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.*; import com.intellij.psi.impl.FreeThreadedFileViewProvider; import com.intellij.psi.impl.PsiManagerEx; +import com.intellij.psi.impl.source.tree.ForeignLeafPsiElement; +import com.intellij.psi.util.PsiTreeUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -38,6 +41,8 @@ import java.lang.ref.SoftReference; import java.lang.ref.WeakReference; class SmartPsiElementPointerImpl implements SmartPointerEx { + private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.smartPointers.SmartPsiElementPointerImpl"); + private Reference myElement; private final SmartPointerElementInfo myElementInfo; private final Class myElementClass; @@ -138,6 +143,18 @@ class SmartPsiElementPointerImpl implements SmartPointerEx private static SmartPointerElementInfo createElementInfo(@NotNull Project project, @NotNull E element, PsiFile containingFile) { + SmartPointerElementInfo elementInfo = doCreateElementInfo(project, element, containingFile); + if (ApplicationManager.getApplication().isUnitTestMode() && !element.equals(elementInfo.restoreElement())) { + // likely cause: PSI having isPhysical==true, but which can't be restored by containing file and range. To fix, make isPhysical return false + LOG.error("Cannot restore " + element + " of " + element.getClass() + " from " + elementInfo); + } + return elementInfo; + } + + @NotNull + private static SmartPointerElementInfo doCreateElementInfo(@NotNull Project project, + @NotNull E element, + PsiFile containingFile) { if (element instanceof PsiDirectory) { return new DirElementInfo((PsiDirectory)element); } @@ -177,6 +194,11 @@ class SmartPsiElementPointerImpl implements SmartPointerEx if (elementRange == null) { return new HardElementInfo(project, element); } + if (elementRange.isEmpty() && PsiTreeUtil.findChildOfType(element, ForeignLeafPsiElement.class) != null) { + // PSI built on C-style macro expansions. It has empty ranges, no text, but complicated structure. It can't be reliably + // restored by just one offset in a file, so hold it on a hard reference + return new HardElementInfo(project, element); + } ProperTextRange proper = ProperTextRange.create(elementRange); return new SelfElementInfo(project, proper, element.getClass(), containingFile, LanguageUtil.getRootLanguage(element), false);