From 14bdb823c02342f001b27140252ff5474a3e8ef1 Mon Sep 17 00:00:00 2001 From: Ilya Kazakevich Date: Sat, 18 Jan 2014 00:41:29 +0400 Subject: [PATCH] PY-3569 Inspection to warn if a loop variable is assigned inside the loop --- ...ssignmentToForLoopParameterInspection.html | 13 ---------- ...gnmentToLoopOrWithParameterInspection.html | 21 ++++++++++++++++ python/src/META-INF/python-core.xml | 2 +- .../com/jetbrains/python/PyBundle.properties | 4 ++-- ...nmentToLoopOrWithParameterInspection.java} | 24 ++++++++++--------- .../simpleReassignment.py | 3 --- .../tupleAssignment.py | 3 --- .../tupleDeclaration.py | 3 --- .../twoLoops.py | 4 ---- .../good.py | 0 .../simpleReassignment.py | 3 +++ .../tupleAssignment.py | 3 +++ .../tupleDeclaration.py | 3 +++ .../twoLoops.py | 4 ++++ .../withStatement.py | 3 +++ ...tToLoopOrWithParameterInspectionTest.java} | 7 ++++-- 16 files changed, 58 insertions(+), 42 deletions(-) delete mode 100644 python/resources/inspectionDescriptions/PyAssignmentToForLoopParameterInspection.html create mode 100644 python/resources/inspectionDescriptions/PyAssignmentToLoopOrWithParameterInspection.html rename python/src/com/jetbrains/python/inspections/{PyAssignmentToForLoopParameterInspection.java => PyAssignmentToLoopOrWithParameterInspection.java} (80%) delete mode 100644 python/testData/inspections/PyAssignmentToForLoopParameterInspection/simpleReassignment.py delete mode 100644 python/testData/inspections/PyAssignmentToForLoopParameterInspection/tupleAssignment.py delete mode 100644 python/testData/inspections/PyAssignmentToForLoopParameterInspection/tupleDeclaration.py delete mode 100644 python/testData/inspections/PyAssignmentToForLoopParameterInspection/twoLoops.py rename python/testData/inspections/{PyAssignmentToForLoopParameterInspection => PyAssignmentToLoopOrWithParameterInspection}/good.py (100%) create mode 100644 python/testData/inspections/PyAssignmentToLoopOrWithParameterInspection/simpleReassignment.py create mode 100644 python/testData/inspections/PyAssignmentToLoopOrWithParameterInspection/tupleAssignment.py create mode 100644 python/testData/inspections/PyAssignmentToLoopOrWithParameterInspection/tupleDeclaration.py create mode 100644 python/testData/inspections/PyAssignmentToLoopOrWithParameterInspection/twoLoops.py create mode 100644 python/testData/inspections/PyAssignmentToLoopOrWithParameterInspection/withStatement.py rename python/testSrc/com/jetbrains/python/inspections/{PyAssignmentToForLoopParameterInspectionTest.java => PyAssignmentToLoopOrWithParameterInspectionTest.java} (85%) diff --git a/python/resources/inspectionDescriptions/PyAssignmentToForLoopParameterInspection.html b/python/resources/inspectionDescriptions/PyAssignmentToForLoopParameterInspection.html deleted file mode 100644 index 5944aee07d3c..000000000000 --- a/python/resources/inspectionDescriptions/PyAssignmentToForLoopParameterInspection.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - This inspection checks for cases when loop variable is redeclared inside of loop. - -
-    for i in xrange(5):
-      for i in xrange(20, 25):
-          print("Inner", i)
-      print("Outer", i)
-  
- - diff --git a/python/resources/inspectionDescriptions/PyAssignmentToLoopOrWithParameterInspection.html b/python/resources/inspectionDescriptions/PyAssignmentToLoopOrWithParameterInspection.html new file mode 100644 index 000000000000..08a234cec60f --- /dev/null +++ b/python/resources/inspectionDescriptions/PyAssignmentToLoopOrWithParameterInspection.html @@ -0,0 +1,21 @@ + + + + This inspection checks for cases when loop variable is redeclared inside of loop: + +
+    for i in xrange(5):
+      for i in xrange(20, 25):
+          print("Inner", i)
+      print("Outer", i)
+  
+ + It also warns you if variable declared in with statement is redeclared inside of statement body: + +
+    with open("file") as f:
+      f.read()
+      f = open("another file")
+  
+ + diff --git a/python/src/META-INF/python-core.xml b/python/src/META-INF/python-core.xml index 424f0f79a19b..742db29c76fd 100644 --- a/python/src/META-INF/python-core.xml +++ b/python/src/META-INF/python-core.xml @@ -329,7 +329,7 @@ - + diff --git a/python/src/com/jetbrains/python/PyBundle.properties b/python/src/com/jetbrains/python/PyBundle.properties index f780607189a9..47f4a736797b 100644 --- a/python/src/com/jetbrains/python/PyBundle.properties +++ b/python/src/com/jetbrains/python/PyBundle.properties @@ -511,8 +511,8 @@ INSP.none.function.assignment=Function ''{0}'' doesn''t return anything INSP.NAME.global.undefined=Global variable is undefined at the module level INSP.NAME.global.$0.undefined=Global variable ''{0}'' is undefined at the module level -#PyAssignmentToForLoopParameterInspection -INSP.NAME.assignment.to.for.loop.parameter.display.name=Assignment to 'for' loop parameter +#PyAssignmentToLoopOrWithParameterInspection +INSP.NAME.assignment.to.loop.or.with.parameter.display.name=Assignment to 'for' loop or 'with' statement parameter # Refactoring # introduce diff --git a/python/src/com/jetbrains/python/inspections/PyAssignmentToForLoopParameterInspection.java b/python/src/com/jetbrains/python/inspections/PyAssignmentToLoopOrWithParameterInspection.java similarity index 80% rename from python/src/com/jetbrains/python/inspections/PyAssignmentToForLoopParameterInspection.java rename to python/src/com/jetbrains/python/inspections/PyAssignmentToLoopOrWithParameterInspection.java index fcfb364e338f..1e501a8224b0 100644 --- a/python/src/com/jetbrains/python/inspections/PyAssignmentToForLoopParameterInspection.java +++ b/python/src/com/jetbrains/python/inspections/PyAssignmentToLoopOrWithParameterInspection.java @@ -19,10 +19,11 @@ import com.intellij.codeInspection.LocalInspectionToolSession; import com.intellij.codeInspection.ProblemsHolder; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiElementVisitor; -import com.intellij.psi.PsiFile; +import com.intellij.psi.util.PsiTreeUtil; import com.jetbrains.python.PyBundle; import com.jetbrains.python.psi.PyForPart; import com.jetbrains.python.psi.PyTargetExpression; +import com.jetbrains.python.psi.PyWithStatement; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -34,12 +35,18 @@ import org.jetbrains.annotations.Nullable; * for i in range(1, 10): * i = "new value" * + * and + *
+ * with open("file") as f:
+ *  f.read()
+ *  f = open("another file")
+ * 
* * @author link */ -public class PyAssignmentToForLoopParameterInspection extends PyInspection { +public class PyAssignmentToLoopOrWithParameterInspection extends PyInspection { - private static final String MESSAGE = PyBundle.message("INSP.NAME.assignment.to.for.loop.parameter.display.name"); + private static final String MESSAGE = PyBundle.message("INSP.NAME.assignment.to.loop.or.with.parameter.display.name"); @NotNull @Override @@ -73,14 +80,9 @@ public class PyAssignmentToForLoopParameterInspection extends PyInspection { return; //We are checking first time declaration } - //Find "for" between predecessors until we tree root - PsiElement element = variableFirstTimeDeclaration; - while (!(element instanceof PsiFile) && element != null) { - if (element instanceof PyForPart) { - registerProblem(node, MESSAGE); - return; - } - element = element.getParent(); + //Check if variable declared in "for" or "with" statement + if (PsiTreeUtil.getNonStrictParentOfType(variableFirstTimeDeclaration, PyForPart.class, PyWithStatement.class) != null) { + registerProblem(node, MESSAGE); } } } diff --git a/python/testData/inspections/PyAssignmentToForLoopParameterInspection/simpleReassignment.py b/python/testData/inspections/PyAssignmentToForLoopParameterInspection/simpleReassignment.py deleted file mode 100644 index 130176454320..000000000000 --- a/python/testData/inspections/PyAssignmentToForLoopParameterInspection/simpleReassignment.py +++ /dev/null @@ -1,3 +0,0 @@ -for i in range(1, 2): - print(i) - i = 12 \ No newline at end of file diff --git a/python/testData/inspections/PyAssignmentToForLoopParameterInspection/tupleAssignment.py b/python/testData/inspections/PyAssignmentToForLoopParameterInspection/tupleAssignment.py deleted file mode 100644 index 07281c7c9784..000000000000 --- a/python/testData/inspections/PyAssignmentToForLoopParameterInspection/tupleAssignment.py +++ /dev/null @@ -1,3 +0,0 @@ -for i in [1, 2, 3]: - print(i) - (i, f) = (1, 2) \ No newline at end of file diff --git a/python/testData/inspections/PyAssignmentToForLoopParameterInspection/tupleDeclaration.py b/python/testData/inspections/PyAssignmentToForLoopParameterInspection/tupleDeclaration.py deleted file mode 100644 index 52905d42e134..000000000000 --- a/python/testData/inspections/PyAssignmentToForLoopParameterInspection/tupleDeclaration.py +++ /dev/null @@ -1,3 +0,0 @@ -for (k, v) in {"K": "V"}.items(): - print(k) - k = "12" \ No newline at end of file diff --git a/python/testData/inspections/PyAssignmentToForLoopParameterInspection/twoLoops.py b/python/testData/inspections/PyAssignmentToForLoopParameterInspection/twoLoops.py deleted file mode 100644 index c39f58244512..000000000000 --- a/python/testData/inspections/PyAssignmentToForLoopParameterInspection/twoLoops.py +++ /dev/null @@ -1,4 +0,0 @@ -for i in range(5): - for i in range(20, 25): - print("Inner", i) - print("Outer", i) \ No newline at end of file diff --git a/python/testData/inspections/PyAssignmentToForLoopParameterInspection/good.py b/python/testData/inspections/PyAssignmentToLoopOrWithParameterInspection/good.py similarity index 100% rename from python/testData/inspections/PyAssignmentToForLoopParameterInspection/good.py rename to python/testData/inspections/PyAssignmentToLoopOrWithParameterInspection/good.py diff --git a/python/testData/inspections/PyAssignmentToLoopOrWithParameterInspection/simpleReassignment.py b/python/testData/inspections/PyAssignmentToLoopOrWithParameterInspection/simpleReassignment.py new file mode 100644 index 000000000000..bff004fdc4f5 --- /dev/null +++ b/python/testData/inspections/PyAssignmentToLoopOrWithParameterInspection/simpleReassignment.py @@ -0,0 +1,3 @@ +for i in range(1, 2): + print(i) + i = 12 \ No newline at end of file diff --git a/python/testData/inspections/PyAssignmentToLoopOrWithParameterInspection/tupleAssignment.py b/python/testData/inspections/PyAssignmentToLoopOrWithParameterInspection/tupleAssignment.py new file mode 100644 index 000000000000..0606522ae69c --- /dev/null +++ b/python/testData/inspections/PyAssignmentToLoopOrWithParameterInspection/tupleAssignment.py @@ -0,0 +1,3 @@ +for i in [1, 2, 3]: + print(i) + (i, f) = (1, 2) \ No newline at end of file diff --git a/python/testData/inspections/PyAssignmentToLoopOrWithParameterInspection/tupleDeclaration.py b/python/testData/inspections/PyAssignmentToLoopOrWithParameterInspection/tupleDeclaration.py new file mode 100644 index 000000000000..1469eb81a36d --- /dev/null +++ b/python/testData/inspections/PyAssignmentToLoopOrWithParameterInspection/tupleDeclaration.py @@ -0,0 +1,3 @@ +for (k, v) in {"K": "V"}.items(): + print(k) + k = "12" \ No newline at end of file diff --git a/python/testData/inspections/PyAssignmentToLoopOrWithParameterInspection/twoLoops.py b/python/testData/inspections/PyAssignmentToLoopOrWithParameterInspection/twoLoops.py new file mode 100644 index 000000000000..d26a791db081 --- /dev/null +++ b/python/testData/inspections/PyAssignmentToLoopOrWithParameterInspection/twoLoops.py @@ -0,0 +1,4 @@ +for i in range(5): + for i in range(20, 25): + print("Inner", i) + print("Outer", i) \ No newline at end of file diff --git a/python/testData/inspections/PyAssignmentToLoopOrWithParameterInspection/withStatement.py b/python/testData/inspections/PyAssignmentToLoopOrWithParameterInspection/withStatement.py new file mode 100644 index 000000000000..e642026ba896 --- /dev/null +++ b/python/testData/inspections/PyAssignmentToLoopOrWithParameterInspection/withStatement.py @@ -0,0 +1,3 @@ +with open("file") as f: + f.read() + f = open("another file") \ No newline at end of file diff --git a/python/testSrc/com/jetbrains/python/inspections/PyAssignmentToForLoopParameterInspectionTest.java b/python/testSrc/com/jetbrains/python/inspections/PyAssignmentToLoopOrWithParameterInspectionTest.java similarity index 85% rename from python/testSrc/com/jetbrains/python/inspections/PyAssignmentToForLoopParameterInspectionTest.java rename to python/testSrc/com/jetbrains/python/inspections/PyAssignmentToLoopOrWithParameterInspectionTest.java index 9231a3d3a55b..621e2a10fb77 100644 --- a/python/testSrc/com/jetbrains/python/inspections/PyAssignmentToForLoopParameterInspectionTest.java +++ b/python/testSrc/com/jetbrains/python/inspections/PyAssignmentToLoopOrWithParameterInspectionTest.java @@ -21,7 +21,7 @@ import org.jetbrains.annotations.NotNull; /** * @author link */ -public class PyAssignmentToForLoopParameterInspectionTest extends PyInspectionTestCase { +public class PyAssignmentToLoopOrWithParameterInspectionTest extends PyInspectionTestCase { public void testGood() { doTest(); @@ -42,12 +42,15 @@ public class PyAssignmentToForLoopParameterInspectionTest extends PyInspectionTe public void testTwoLoops() { doTest(); } + public void testWithStatement() { + doTest(); + } @NotNull @Override protected Class getInspectionClass() { - return PyAssignmentToForLoopParameterInspection.class; + return PyAssignmentToLoopOrWithParameterInspection.class; } @Override