From 84994a13da6689e03a4ae5590bc9efad9a68602d Mon Sep 17 00:00:00 2001 From: Anton Bragin Date: Tue, 10 Jul 2018 19:39:11 +0300 Subject: [PATCH] PY-30827 PyRenameElementQuickFix fixed to work both with physical and virtual files New implementation extends LocalQuickFixAndIntentionActionOnPsiElement and uses Editor instance provided by super class instead of retrieving it. The clients are updated accordingly. Duplicated code extracted into PyQuickFixUtil. --- .../PyCompatibilityInspection.java | 2 +- .../inspections/PyPep8NamingInspection.java | 4 +- .../PyProtectedMemberInspection.java | 2 +- .../PyRedeclarationInspection.java | 2 +- .../PyShadowingBuiltinsInspection.java | 2 +- .../PyShadowingNamesInspection.java | 2 +- .../quickfix/PyMakePublicQuickFix.java | 10 +--- .../inspections/quickfix/PyQuickFixUtil.java | 11 ++++ .../quickfix/PyRenameElementQuickFix.java | 57 ++++++++++--------- 9 files changed, 52 insertions(+), 40 deletions(-) diff --git a/python/src/com/jetbrains/python/inspections/PyCompatibilityInspection.java b/python/src/com/jetbrains/python/inspections/PyCompatibilityInspection.java index 38fb4182c772..0d1f406aaf17 100644 --- a/python/src/com/jetbrains/python/inspections/PyCompatibilityInspection.java +++ b/python/src/com/jetbrains/python/inspections/PyCompatibilityInspection.java @@ -366,7 +366,7 @@ public class PyCompatibilityInspection extends PyInspection { registerOnFirstMatchingVersion(level -> level.isAtLeast(LanguageLevel.PYTHON37), "'async' and 'await' are keywords in Python 3.7 and newer", nameIdentifier, - new PyRenameElementQuickFix()); + new PyRenameElementQuickFix(nameIdentifierOwner)); } } } diff --git a/python/src/com/jetbrains/python/inspections/PyPep8NamingInspection.java b/python/src/com/jetbrains/python/inspections/PyPep8NamingInspection.java index d3f089d07672..c37a8ac6907b 100644 --- a/python/src/com/jetbrains/python/inspections/PyPep8NamingInspection.java +++ b/python/src/com/jetbrains/python/inspections/PyPep8NamingInspection.java @@ -155,7 +155,7 @@ public class PyPep8NamingInspection extends PyInspection { private void registerAndAddRenameAndIgnoreErrorQuickFixes(@Nullable final PsiElement node, @NotNull final String errorCode) { if (getHolder() != null && getHolder().isOnTheFly()) - registerProblem(node, ERROR_CODES_DESCRIPTION.get(errorCode), new PyRenameElementQuickFix(), new IgnoreErrorFix(errorCode)); + registerProblem(node, ERROR_CODES_DESCRIPTION.get(errorCode), new PyRenameElementQuickFix(node), new IgnoreErrorFix(errorCode)); else registerProblem(node, ERROR_CODES_DESCRIPTION.get(errorCode), new IgnoreErrorFix(errorCode)); } @@ -174,7 +174,7 @@ public class PyPep8NamingInspection extends PyInspection { if (nameNode != null) { final List quickFixes = Lists.newArrayList(); if (getHolder() != null && getHolder().isOnTheFly()) - quickFixes.add(new PyRenameElementQuickFix()); + quickFixes.add(new PyRenameElementQuickFix(nameNode.getPsi())); if (containingClass != null) { quickFixes.add(new IgnoreBaseClassQuickFix(containingClass, myTypeEvalContext)); diff --git a/python/src/com/jetbrains/python/inspections/PyProtectedMemberInspection.java b/python/src/com/jetbrains/python/inspections/PyProtectedMemberInspection.java index efc3609c43bd..83b2bfbb98e2 100644 --- a/python/src/com/jetbrains/python/inspections/PyProtectedMemberInspection.java +++ b/python/src/com/jetbrains/python/inspections/PyProtectedMemberInspection.java @@ -106,7 +106,7 @@ public class PyProtectedMemberInspection extends PyInspection { private void checkReference(@NotNull final PyReferenceExpression node, @NotNull final PyExpression qualifier) { final String name = node.getName(); final List quickFixes = new ArrayList<>(); - quickFixes.add(new PyRenameElementQuickFix()); + quickFixes.add(new PyRenameElementQuickFix(node)); if (name != null && name.startsWith("_") && !name.startsWith("__") && !name.endsWith("__")) { final PsiReference reference = node.getReference(getResolveContext()); diff --git a/python/src/com/jetbrains/python/inspections/PyRedeclarationInspection.java b/python/src/com/jetbrains/python/inspections/PyRedeclarationInspection.java index 04747c166f50..52c0a8eb75b1 100644 --- a/python/src/com/jetbrains/python/inspections/PyRedeclarationInspection.java +++ b/python/src/com/jetbrains/python/inspections/PyRedeclarationInspection.java @@ -156,7 +156,7 @@ public class PyRedeclarationInspection extends PyInspection { if (writeElement != null && readElementRef.get() == null) { final List quickFixes = new ArrayList<>(); if (suggestRename(element, writeElement)) { - quickFixes.add(new PyRenameElementQuickFix()); + quickFixes.add(new PyRenameElementQuickFix(element)); } final PsiElement identifier = element.getNameIdentifier(); registerProblem(identifier != null ? identifier : element, diff --git a/python/src/com/jetbrains/python/inspections/PyShadowingBuiltinsInspection.java b/python/src/com/jetbrains/python/inspections/PyShadowingBuiltinsInspection.java index d44851a5b36d..21662d54f116 100644 --- a/python/src/com/jetbrains/python/inspections/PyShadowingBuiltinsInspection.java +++ b/python/src/com/jetbrains/python/inspections/PyShadowingBuiltinsInspection.java @@ -110,7 +110,7 @@ public class PyShadowingBuiltinsInspection extends PyInspection { final PsiElement identifier = element.getNameIdentifier(); final PsiElement problemElement = identifier != null ? identifier : element; registerProblem(problemElement, String.format("Shadows built-in name '%s'", name), - ProblemHighlightType.WEAK_WARNING, null, new PyRenameElementQuickFix(), new PyIgnoreBuiltinQuickFix(name)); + ProblemHighlightType.WEAK_WARNING, null, new PyRenameElementQuickFix(problemElement), new PyIgnoreBuiltinQuickFix(name)); } } } diff --git a/python/src/com/jetbrains/python/inspections/PyShadowingNamesInspection.java b/python/src/com/jetbrains/python/inspections/PyShadowingNamesInspection.java index b337b3f7b74d..e1f63f380588 100644 --- a/python/src/com/jetbrains/python/inspections/PyShadowingNamesInspection.java +++ b/python/src/com/jetbrains/python/inspections/PyShadowingNamesInspection.java @@ -118,7 +118,7 @@ public class PyShadowingNamesInspection extends PyInspection { return; } registerProblem(problemElement, String.format("Shadows name '%s' from outer scope", name), - ProblemHighlightType.WEAK_WARNING, null, new PyRenameElementQuickFix()); + ProblemHighlightType.WEAK_WARNING, null, new PyRenameElementQuickFix(problemElement)); return; } } diff --git a/python/src/com/jetbrains/python/inspections/quickfix/PyMakePublicQuickFix.java b/python/src/com/jetbrains/python/inspections/quickfix/PyMakePublicQuickFix.java index 64e21614737b..f0050e0accb1 100644 --- a/python/src/com/jetbrains/python/inspections/quickfix/PyMakePublicQuickFix.java +++ b/python/src/com/jetbrains/python/inspections/quickfix/PyMakePublicQuickFix.java @@ -21,10 +21,8 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiReference; import com.intellij.refactoring.rename.RenameProcessor; import com.jetbrains.python.PyBundle; -import com.jetbrains.python.psi.PyReferenceExpression; import com.jetbrains.python.psi.PyTargetExpression; import org.jetbrains.annotations.NotNull; @@ -38,11 +36,9 @@ public class PyMakePublicQuickFix implements LocalQuickFix { @Override public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) { - PsiElement element = descriptor.getPsiElement(); - if (element instanceof PyReferenceExpression) { - final PsiReference reference = element.getReference(); - if (reference == null) return; - element = reference.resolve(); + final PsiElement element = PyQuickFixUtil.dereference(descriptor.getPsiElement()); + if (element == null) { + return; } if (element instanceof PyTargetExpression) { final String name = ((PyTargetExpression)element).getName(); diff --git a/python/src/com/jetbrains/python/inspections/quickfix/PyQuickFixUtil.java b/python/src/com/jetbrains/python/inspections/quickfix/PyQuickFixUtil.java index 3ad435445642..38f65249e30a 100644 --- a/python/src/com/jetbrains/python/inspections/quickfix/PyQuickFixUtil.java +++ b/python/src/com/jetbrains/python/inspections/quickfix/PyQuickFixUtil.java @@ -20,6 +20,8 @@ import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.EditorFactory; import com.intellij.psi.PsiDocumentManager; import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiReference; +import com.jetbrains.python.psi.PyReferenceExpression; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -40,4 +42,13 @@ public class PyQuickFixUtil { } return null; } + + @Nullable + public static PsiElement dereference(PsiElement element) { + if (element instanceof PyReferenceExpression) { + final PsiReference reference = element.getReference(); + return reference != null ? reference.resolve() : null; + } + return element; + } } diff --git a/python/src/com/jetbrains/python/inspections/quickfix/PyRenameElementQuickFix.java b/python/src/com/jetbrains/python/inspections/quickfix/PyRenameElementQuickFix.java index d38ea496aa7d..f3584f73ff63 100644 --- a/python/src/com/jetbrains/python/inspections/quickfix/PyRenameElementQuickFix.java +++ b/python/src/com/jetbrains/python/inspections/quickfix/PyRenameElementQuickFix.java @@ -1,18 +1,13 @@ // Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.jetbrains.python.inspections.quickfix; -import com.intellij.codeInspection.LocalQuickFix; -import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.codeInspection.LocalQuickFixAndIntentionActionOnPsiElement; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.editor.Editor; -import com.intellij.openapi.fileEditor.FileEditorManager; -import com.intellij.openapi.fileEditor.OpenFileDescriptor; import com.intellij.openapi.project.Project; -import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import com.intellij.psi.PsiNameIdentifierOwner; -import com.intellij.psi.PsiReference; import com.intellij.psi.search.LocalSearchScope; import com.intellij.psi.search.PsiSearchHelper; import com.intellij.psi.search.SearchScope; @@ -24,12 +19,18 @@ import com.intellij.refactoring.rename.inplace.VariableInplaceRenamer; import com.jetbrains.python.PyBundle; import com.jetbrains.python.codeInsight.dataflow.scope.ScopeUtil; import com.jetbrains.python.psi.PyNamedParameter; -import com.jetbrains.python.psi.PyReferenceExpression; import com.jetbrains.python.psi.PyTargetExpression; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -public class PyRenameElementQuickFix implements LocalQuickFix { +/** + * @see com.intellij.psi.util.PsiUtilBase#findEditor + */ +public class PyRenameElementQuickFix extends LocalQuickFixAndIntentionActionOnPsiElement { + + public PyRenameElementQuickFix(@Nullable PsiElement element) { + super(element); + } @NotNull @Override @@ -37,31 +38,35 @@ public class PyRenameElementQuickFix implements LocalQuickFix { return PyBundle.message("QFIX.NAME.rename.element"); } + @NotNull @Override - public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) { - PsiElement element = descriptor.getPsiElement(); - if (element instanceof PyReferenceExpression) { - final PsiReference reference = element.getReference(); - if (reference == null) return; - element = reference.resolve(); + public String getText() { + return PyBundle.message("QFIX.NAME.rename.element"); + } + + @Override + public void invoke(@NotNull Project project, + @NotNull PsiFile file, + @Nullable Editor editor, + @NotNull PsiElement startElement, + @NotNull PsiElement endElement) { + final PsiElement element = PyQuickFixUtil.dereference(startElement); + if (element == null) { + return; } final PsiNameIdentifierOwner nameOwner = element instanceof PsiNameIdentifierOwner ? (PsiNameIdentifierOwner)element : PsiTreeUtil.getParentOfType(element, PsiNameIdentifierOwner.class, true); - if (nameOwner != null) { - final VirtualFile virtualFile = nameOwner.getContainingFile().getVirtualFile(); - if (virtualFile != null) { - final Editor editor = FileEditorManager.getInstance(project).openTextEditor(new OpenFileDescriptor(project, virtualFile), true); - if (ApplicationManager.getApplication().isUnitTestMode()) { - renameInUnitTestMode(project, nameOwner, editor); + if (nameOwner != null && editor != null) { + if (ApplicationManager.getApplication().isUnitTestMode()) { + renameInUnitTestMode(project, nameOwner, editor); + } + else { + if (checkLocalScope(element) != null && (nameOwner instanceof PyNamedParameter || nameOwner instanceof PyTargetExpression)) { + new VariableInplaceRenamer(nameOwner, editor).performInplaceRename(); } else { - if (checkLocalScope(element) != null && (nameOwner instanceof PyNamedParameter || nameOwner instanceof PyTargetExpression)) { - new VariableInplaceRenamer(nameOwner, editor).performInplaceRename(); - } - else { - PsiElementRenameHandler.invoke(nameOwner, project, ScopeUtil.getScopeOwner(nameOwner), editor); - } + PsiElementRenameHandler.invoke(nameOwner, project, ScopeUtil.getScopeOwner(nameOwner), editor); } } }