mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Quickfix for renaming a reference that shadows a built-in name (PY-8788)
This commit is contained in:
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
def <warning descr="Shadows a built-in with the same name">i<caret>d</warning>(x):
|
||||
return x
|
||||
|
||||
|
||||
def f():
|
||||
return id('foo')
|
||||
@@ -0,0 +1,6 @@
|
||||
def a(x):
|
||||
return x
|
||||
|
||||
|
||||
def f():
|
||||
return a('foo')
|
||||
@@ -0,0 +1,3 @@
|
||||
def f(name):
|
||||
<warning descr="Shadows a built-in with the same name">f<caret>ile</warning> = open(name, 'rb')
|
||||
return file.read()
|
||||
@@ -0,0 +1,3 @@
|
||||
def f(name):
|
||||
a = open(name, 'rb')
|
||||
return a.read()
|
||||
@@ -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() {
|
||||
|
||||
Reference in New Issue
Block a user