From 4ce0cd862fe2f62d20df817ece9009c63c7e2c13 Mon Sep 17 00:00:00 2001 From: fitermay Date: Tue, 27 Feb 2018 01:51:42 -0500 Subject: [PATCH] PY-28686: Fix PSI leak in AutoImportQuickFIx --- .../imports/AutoImportQuickFix.java | 3 +- .../imports/ImportCandidateHolder.java | 44 ++++++++++--------- .../imports/ImportFromExistingAction.java | 13 +++++- 3 files changed, 36 insertions(+), 24 deletions(-) diff --git a/python/src/com/jetbrains/python/codeInsight/imports/AutoImportQuickFix.java b/python/src/com/jetbrains/python/codeInsight/imports/AutoImportQuickFix.java index af2f5f8cdaec..58d9ff05fc70 100644 --- a/python/src/com/jetbrains/python/codeInsight/imports/AutoImportQuickFix.java +++ b/python/src/com/jetbrains/python/codeInsight/imports/AutoImportQuickFix.java @@ -217,7 +217,8 @@ public class AutoImportQuickFix extends LocalQuickFixOnPsiElement implements Hig public boolean hasProjectImports() { ProjectFileIndex fileIndex = ProjectFileIndex.SERVICE.getInstance(getStartElement().getProject()); for (ImportCandidateHolder anImport : myImports) { - VirtualFile file = anImport.getFile().getVirtualFile(); + PsiFileSystemItem importFile = anImport.getFile(); + VirtualFile file = importFile != null ? importFile.getVirtualFile() : null; if (file != null && fileIndex.isInContent(file)) { return true; } diff --git a/python/src/com/jetbrains/python/codeInsight/imports/ImportCandidateHolder.java b/python/src/com/jetbrains/python/codeInsight/imports/ImportCandidateHolder.java index f67bd5087c76..f81197ed4c34 100644 --- a/python/src/com/jetbrains/python/codeInsight/imports/ImportCandidateHolder.java +++ b/python/src/com/jetbrains/python/codeInsight/imports/ImportCandidateHolder.java @@ -22,9 +22,7 @@ import com.intellij.openapi.roots.ProjectRootManager; import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiFile; -import com.intellij.psi.PsiFileSystemItem; +import com.intellij.psi.*; import com.intellij.psi.util.QualifiedName; import com.intellij.util.containers.ContainerUtil; import com.jetbrains.python.psi.*; @@ -47,10 +45,10 @@ import java.util.List; */ // visibility is intentionally package-level public class ImportCandidateHolder implements Comparable { - private final PsiElement myImportable; - private final PyImportElement myImportElement; - private final PsiFileSystemItem myFile; - private final QualifiedName myPath; + @NotNull private final SmartPsiElementPointer myImportable; + @Nullable private final SmartPsiElementPointer myImportElement; + @NotNull private final SmartPsiElementPointer myFile; + @Nullable private final QualifiedName myPath; @Nullable private final String myAsName; /** @@ -67,9 +65,10 @@ public class ImportCandidateHolder implements Comparable */ public ImportCandidateHolder(@NotNull PsiElement importable, @NotNull PsiFileSystemItem file, @Nullable PyImportElement importElement, @Nullable QualifiedName path, @Nullable String asName) { - myFile = file; - myImportable = importable; - myImportElement = importElement; + SmartPointerManager pointerManager = SmartPointerManager.getInstance(importable.getProject()); + myFile = pointerManager.createSmartPsiElementPointer(file); + myImportable = pointerManager.createSmartPsiElementPointer(importable); + myImportElement = importElement != null ? pointerManager.createSmartPsiElementPointer(importElement) : null; myPath = path; myAsName = asName; assert importElement != null || path != null; // one of these must be present @@ -79,19 +78,20 @@ public class ImportCandidateHolder implements Comparable @Nullable PyImportElement importElement, @Nullable QualifiedName path) { this(importable, file, importElement, path, null); } - @NotNull + + @Nullable public PsiElement getImportable() { - return myImportable; + return myImportable.getElement(); } @Nullable public PyImportElement getImportElement() { - return myImportElement; + return myImportElement != null ? myImportElement.getElement() : null; } - @NotNull + @Nullable public PsiFileSystemItem getFile() { - return myFile; + return myFile.getElement(); } @Nullable @@ -131,16 +131,18 @@ public class ImportCandidateHolder implements Comparable @NotNull public String getPresentableText(@NotNull String myName) { - final StringBuilder sb = new StringBuilder(getQualifiedName(myName, myPath, myImportElement)); + PyImportElement importElement = getImportElement(); + PsiElement importable = getImportable(); + final StringBuilder sb = new StringBuilder(getQualifiedName(myName, myPath, importElement)); PsiElement parent = null; - if (myImportElement != null) { - parent = myImportElement.getParent(); + if (importElement != null) { + parent = importElement.getParent(); } - if (myImportable instanceof PyFunction) { + if (importable instanceof PyFunction) { sb.append("()"); } - else if (myImportable instanceof PyClass) { - final List supers = ContainerUtil.mapNotNull(((PyClass)myImportable).getSuperClasses(null), + else if (importable instanceof PyClass) { + final List supers = ContainerUtil.mapNotNull(((PyClass)importable).getSuperClasses(null), cls -> PyUtil.isObjectClass(cls) ? null : cls.getName()); if (!supers.isEmpty()) { sb.append("("); diff --git a/python/src/com/jetbrains/python/codeInsight/imports/ImportFromExistingAction.java b/python/src/com/jetbrains/python/codeInsight/imports/ImportFromExistingAction.java index faed081294d8..aa4bb64940c2 100644 --- a/python/src/com/jetbrains/python/codeInsight/imports/ImportFromExistingAction.java +++ b/python/src/com/jetbrains/python/codeInsight/imports/ImportFromExistingAction.java @@ -153,6 +153,9 @@ public class ImportFromExistingAction implements QuestionAction { final PyElementGenerator gen = PyElementGenerator.getInstance(project); final PsiFileSystemItem filesystemAnchor = ObjectUtils.chooseNotNull(as(item.getImportable(), PsiFileSystemItem.class), item.getFile()); + if (filesystemAnchor == null) { + return; + } AddImportHelper.ImportPriority priority = AddImportHelper.getImportPriority(myTarget, filesystemAnchor); PsiFile file = myTarget.getContainingFile(); InjectedLanguageManager manager = InjectedLanguageManager.getInstance(project); @@ -214,9 +217,12 @@ public class ImportFromExistingAction implements QuestionAction { private void doWriteAction(final ImportCandidateHolder item) { PsiElement src = item.getImportable(); + if (src == null) { + return; + } new WriteCommandAction(src.getProject(), PyBundle.message("ACT.CMD.use.import"), myTarget.getContainingFile()) { @Override - protected void run(@NotNull Result result) throws Throwable { + protected void run(@NotNull Result result) { doIt(item); } }.execute(); @@ -259,7 +265,10 @@ public class ImportFromExistingAction implements QuestionAction { clear(); ImportCandidateHolder item = (ImportCandidateHolder)value; - setIcon(item.getImportable().getIcon(0)); + PsiElement importable = ((ImportCandidateHolder)value).getImportable(); + if (importable != null) { + setIcon(importable.getIcon(0)); + } String item_name = item.getPresentableText(myName); append(item_name, SimpleTextAttributes.REGULAR_ATTRIBUTES);