added PY-3120 Inspection to replace set built-in function with set literal

This commit is contained in:
Ekaterina Tuzova
2011-03-24 12:51:26 +03:00
parent 6fd64fd9c6
commit 6f3dbf345a
9 changed files with 167 additions and 0 deletions
@@ -81,6 +81,9 @@ QFIX.default.argument=Replace mutable default argument
#RemoveArgumentEqualDefaultQuickFix
QFIX.remove.argument.equal.default=Remove argument equal to default
# ReplaceFunctionWithSetLiteralQuickFix
QFIX.replace.function.set.with.literal=Replace function call with set literal
# Intentions: INTN
INTN.Family.convert.import.unqualify=Convert 'import module' to 'from module import'
INTN.Family.convert.import.qualify=Convert 'from module import' to 'import module'
@@ -381,6 +384,9 @@ INSP.NAME.single.quoted.docstring=Single quoted docstring
# PyMissingConstructorInspection
INSP.NAME.missing.super.constructor=Missed call to constructor of super class
# PySetFunctionToLiteralInspection
INSP.NAME.set.function.to.literal=Function call can be replaced with set literal
# Refactoring
# introduce
refactoring.introduce.name.error=Incorrect name
@@ -0,0 +1,58 @@
package com.jetbrains.python.actions;
import com.intellij.codeInspection.LocalQuickFix;
import com.intellij.codeInspection.ProblemDescriptor;
import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiElement;
import com.jetbrains.python.PyBundle;
import com.jetbrains.python.psi.*;
import org.jetbrains.annotations.NotNull;
/**
* User : catherine
* Quick Fix to replace function call of built-in function "set" with
* set literal if applicable
*/
public class ReplaceFunctionWithSetLiteralQuickFix implements LocalQuickFix {
@Override
@NotNull
public String getName() {
return PyBundle.message("QFIX.replace.function.set.with.literal");
}
@Override
@NotNull
public String getFamilyName() {
return PyBundle.message("INSP.GROUP.python");
}
@Override
public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
PyElementGenerator elementGenerator = PyElementGenerator.getInstance(project);
PsiElement functionCall = descriptor.getPsiElement();
StringBuilder str = new StringBuilder("{");
if (functionCall instanceof PyCallExpression) {
PyExpression[] arguments = ((PyCallExpression)functionCall).getArguments();
if (arguments.length > 0) {
PyExpression argument= arguments[0];
PyElement[] elements = {};
if (argument instanceof PySequenceExpression)
elements = ((PySequenceExpression)argument).getElements();
if (argument instanceof PyParenthesizedExpression) {
PyExpression tuple = ((PyParenthesizedExpression)argument).getContainedExpression();
if (tuple instanceof PyTupleExpression)
elements = ((PyTupleExpression)(tuple)).getElements();
}
for (int i = 0; i != elements.length; ++i) {
PyElement e = elements[i];
str.append(e.getText());
if (i != elements.length-1)
str.append(", ");
}
}
str.append("}");
functionCall.replace(elementGenerator.createFromText(LanguageLevel.forElement(functionCall), PyExpressionStatement.class,
str.toString()).getExpression());
}
}
}
@@ -0,0 +1,78 @@
package com.jetbrains.python.inspections;
import com.intellij.codeInspection.ProblemsHolder;
import com.intellij.openapi.roots.ProjectFileIndex;
import com.intellij.openapi.roots.ProjectRootManager;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiElementVisitor;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiReference;
import com.jetbrains.python.PyBundle;
import com.jetbrains.python.actions.ReplaceFunctionWithSetLiteralQuickFix;
import com.jetbrains.python.psi.*;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull;
/**
* User: catherine
*
* Inspection to find set built-in function and replace it with set literal
* available if the selected language level supports set literals.
*/
public class PySetFunctionToLiteralInspection extends PyInspection {
@Nls
@NotNull
@Override
public String getDisplayName() {
return PyBundle.message("INSP.NAME.set.function.to.literal");
}
@NotNull
@Override
public PsiElementVisitor buildVisitor(@NotNull ProblemsHolder holder, boolean isOnTheFly) {
return new Visitor(holder);
}
private static class Visitor extends PyInspectionVisitor {
public Visitor(final ProblemsHolder holder) {
super(holder);
}
@Override
public void visitPyCallExpression(final PyCallExpression node) {
if (LanguageLevel.forElement(node).supportsSetLiterals()) {
PyExpression callee = node.getCallee();
if (callee != null) {
if (isBuiltinSet(callee)) {
PyExpression[] arguments = node.getArguments();
if (arguments.length == 0 ||(arguments.length == 1) &&
(arguments[0] instanceof PySequenceExpression ||
(arguments[0] instanceof PyParenthesizedExpression &&
((PyParenthesizedExpression)arguments[0]).getContainedExpression() instanceof PyTupleExpression)))
registerProblem(node, "Function call can be replaced with set literal",
new ReplaceFunctionWithSetLiteralQuickFix());
}
}
}
}
private static boolean isBuiltinSet(PyExpression callee) {
ProjectFileIndex ind = ProjectRootManager.getInstance(callee.getProject()).getFileIndex();
PsiReference reference = callee.getReference();
if (reference != null) {
PsiElement resolved = reference.resolve();
if (resolved != null) {
PsiFile file = resolved.getContainingFile();
if (file != null && file.getVirtualFile() != null && ind.isInLibraryClasses(file.getVirtualFile())) {
if (callee.getText().equals("set")) {
return true;
}
}
}
}
return false;
}
}
}
@@ -58,6 +58,7 @@ public class PythonInspectionToolProvider implements InspectionToolProvider {
PySingleQuotedDocstringInspection.class,
PyMissingConstructorInspection.class,
PyArgumentEqualDefaultInspection.class,
PySetFunctionToLiteralInspection.class,
};
}
}
@@ -0,0 +1,11 @@
my_set = <warning descr="Function call can be replaced with set literal">set()</warning>
my_set = <warning descr="Function call can be replaced with set literal">set([1,2,3])</warning>
my_set = <warning descr="Function call can be replaced with set literal">set((1,2,3))</warning>
my_set = set(var)
def set(fake=None):
pass
my_fake_set = set()
my_fake_set = set([1,2,3])
@@ -0,0 +1 @@
my_set = <warning descr="Function call can be replaced with set literal">set([1<caret>,2,3])</warning>
@@ -0,0 +1 @@
my_set = {1, 2, 3}
@@ -240,6 +240,12 @@ public class PyQuickFixTest extends PyLightFixtureTestCase {
PyBundle.message("QFIX.remove.argument.equal.default"), true, true);
}
public void testSetFunctionToLiteral() { //PY-3120
setLanguageLevel(LanguageLevel.PYTHON27);
doInspectionTest("SetFunctionToLiteral.py", PySetFunctionToLiteralInspection.class,
PyBundle.message("QFIX.replace.function.set.with.literal"), true, true);
}
public void testUnnecessaryBackslash() {
String[] testFiles = new String[]{"UnnecessaryBackslash.py"};
myFixture.enableInspections(PyUnnecessaryBackslashInspection.class);
@@ -326,4 +326,9 @@ public class PythonInspectionsTest extends PyLightFixtureTestCase {
public void testPyArgumentEqualDefaultInspection() { //PY-3125
doHighlightingTest(PyArgumentEqualDefaultInspection.class);
}
public void testPySetFunctionToLiteralInspection() { //PY-3120
setLanguageLevel(LanguageLevel.PYTHON27);
doHighlightingTest(PySetFunctionToLiteralInspection.class);
}
}