From eab613365f0335e7d516b950f039caf88c8ef6ff Mon Sep 17 00:00:00 2001 From: Andrey Vlasovskikh Date: Thu, 14 Feb 2013 18:01:32 +0400 Subject: [PATCH] Quickfix for renaming a reference that shadows a built-in name (PY-8788) --- .../PyShadowingBuiltinsInspection.java | 64 ++++++++++++++++++- .../RenameFunctionShadowingBuiltins.py | 6 ++ .../RenameFunctionShadowingBuiltins_after.py | 6 ++ .../inspections/RenameShadowingBuiltins.py | 3 + .../RenameShadowingBuiltins_after.py | 3 + .../com/jetbrains/python/PyQuickFixTest.java | 13 ++++ 6 files changed, 94 insertions(+), 1 deletion(-) create mode 100644 python/testData/inspections/RenameFunctionShadowingBuiltins.py create mode 100644 python/testData/inspections/RenameFunctionShadowingBuiltins_after.py create mode 100644 python/testData/inspections/RenameShadowingBuiltins.py create mode 100644 python/testData/inspections/RenameShadowingBuiltins_after.py diff --git a/python/src/com/jetbrains/python/inspections/PyShadowingBuiltinsInspection.java b/python/src/com/jetbrains/python/inspections/PyShadowingBuiltinsInspection.java index 3c81974adacf..64c3ff48a5c3 100644 --- a/python/src/com/jetbrains/python/inspections/PyShadowingBuiltinsInspection.java +++ b/python/src/com/jetbrains/python/inspections/PyShadowingBuiltinsInspection.java @@ -1,10 +1,24 @@ package com.jetbrains.python.inspections; import com.intellij.codeInspection.LocalInspectionToolSession; +import com.intellij.codeInspection.LocalQuickFix; +import com.intellij.codeInspection.ProblemDescriptor; import com.intellij.codeInspection.ProblemsHolder; +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.PsiElementVisitor; import com.intellij.psi.PsiNameIdentifierOwner; +import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.refactoring.rename.PsiElementRenameHandler; +import com.intellij.refactoring.rename.RenameProcessor; +import com.intellij.refactoring.rename.RenamePsiElementProcessor; +import com.intellij.refactoring.rename.inplace.VariableInplaceRenamer; +import com.jetbrains.python.codeInsight.dataflow.scope.ScopeUtil; import com.jetbrains.python.psi.*; import com.jetbrains.python.psi.impl.PyBuiltinCache; import org.jetbrains.annotations.NotNull; @@ -62,7 +76,55 @@ public class PyShadowingBuiltinsInspection extends PyInspection { final PsiElement builtin = builtinCache.getByName(name); if (builtin != null && !PyUtil.inSameFile(builtin, element)) { final PsiElement identifier = element.getNameIdentifier(); - registerProblem(identifier != null ? identifier : element, "Shadows a built-in with the same name"); + registerProblem(identifier != null ? identifier : element, "Shadows a built-in with the same name", + new PyRenameElementQuickFix()); + } + } + } + + private static class PyRenameElementQuickFix implements LocalQuickFix { + @NotNull + @Override + public String getName() { + return "Rename element"; + } + + @NotNull + @Override + public String getFamilyName() { + return "Rename element"; + } + + @Override + public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) { + final PsiElement element = descriptor.getPsiElement(); + 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); + } + else { + if (nameOwner instanceof PyNamedParameter || nameOwner instanceof PyTargetExpression) { + new VariableInplaceRenamer(nameOwner, editor).performInplaceRename(); + } + else { + PsiElementRenameHandler.invoke(nameOwner, project, ScopeUtil.getScopeOwner(nameOwner), editor); + } + } + } + } + } + + private static void renameInUnitTestMode(@NotNull Project project, @NotNull PsiNameIdentifierOwner nameOwner, + @Nullable Editor editor) { + final PsiElement substitution = RenamePsiElementProcessor.forElement(nameOwner).substituteElementToRename(nameOwner, editor); + if (substitution != null) { + new RenameProcessor(project, substitution, "a", false, false).run(); } } } diff --git a/python/testData/inspections/RenameFunctionShadowingBuiltins.py b/python/testData/inspections/RenameFunctionShadowingBuiltins.py new file mode 100644 index 000000000000..ed54b1c887d9 --- /dev/null +++ b/python/testData/inspections/RenameFunctionShadowingBuiltins.py @@ -0,0 +1,6 @@ +def id(x): + return x + + +def f(): + return id('foo') diff --git a/python/testData/inspections/RenameFunctionShadowingBuiltins_after.py b/python/testData/inspections/RenameFunctionShadowingBuiltins_after.py new file mode 100644 index 000000000000..57ac3e896508 --- /dev/null +++ b/python/testData/inspections/RenameFunctionShadowingBuiltins_after.py @@ -0,0 +1,6 @@ +def a(x): + return x + + +def f(): + return a('foo') diff --git a/python/testData/inspections/RenameShadowingBuiltins.py b/python/testData/inspections/RenameShadowingBuiltins.py new file mode 100644 index 000000000000..f22217991759 --- /dev/null +++ b/python/testData/inspections/RenameShadowingBuiltins.py @@ -0,0 +1,3 @@ +def f(name): + file = open(name, 'rb') + return file.read() diff --git a/python/testData/inspections/RenameShadowingBuiltins_after.py b/python/testData/inspections/RenameShadowingBuiltins_after.py new file mode 100644 index 000000000000..4f8354971055 --- /dev/null +++ b/python/testData/inspections/RenameShadowingBuiltins_after.py @@ -0,0 +1,3 @@ +def f(name): + a = open(name, 'rb') + return a.read() diff --git a/python/testSrc/com/jetbrains/python/PyQuickFixTest.java b/python/testSrc/com/jetbrains/python/PyQuickFixTest.java index 84b60a170548..4a7aba094c2b 100644 --- a/python/testSrc/com/jetbrains/python/PyQuickFixTest.java +++ b/python/testSrc/com/jetbrains/python/PyQuickFixTest.java @@ -424,6 +424,19 @@ public class PyQuickFixTest extends PyTestCase { myFixture.checkResultByFile(graftBeforeExt(testFiles[0], "_after")); } + // PY-8788 + public void testRenameShadowingBuiltins() { + doInspectionTest("RenameShadowingBuiltins.py", PyShadowingBuiltinsInspection.class, + "Rename element", true, true); + } + + // PY-8788 + public void testRenameFunctionShadowingBuiltins() { + doInspectionTest("RenameFunctionShadowingBuiltins.py", PyShadowingBuiltinsInspection.class, + "Rename element", true, true); + + } + @Override @NonNls protected String getTestDataPath() {