diff --git a/python/src/com/jetbrains/python/inspections/PyAssignmentToLoopOrWithParameterInspection.java b/python/src/com/jetbrains/python/inspections/PyAssignmentToLoopOrWithParameterInspection.java index a4a3c35b5580..bbe1e9a960ef 100644 --- a/python/src/com/jetbrains/python/inspections/PyAssignmentToLoopOrWithParameterInspection.java +++ b/python/src/com/jetbrains/python/inspections/PyAssignmentToLoopOrWithParameterInspection.java @@ -1,21 +1,6 @@ -/* - * Copyright 2000-2014 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2000-2017 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; -import com.google.common.collect.Lists; import com.intellij.codeInspection.LocalInspectionToolSession; import com.intellij.codeInspection.ProblemsHolder; import com.intellij.openapi.util.Condition; @@ -23,12 +8,15 @@ import com.intellij.psi.PsiElement; import com.intellij.psi.PsiElementVisitor; import com.intellij.psi.PsiReference; import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.util.containers.ContainerUtil; import com.jetbrains.python.PyBundle; +import com.jetbrains.python.PyNames; import com.jetbrains.python.codeInsight.controlflow.ScopeOwner; import com.jetbrains.python.psi.*; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -51,7 +39,6 @@ public class PyAssignmentToLoopOrWithParameterInspection extends PyInspection { return NAME; } - @NotNull @Override public PsiElementVisitor buildVisitor(@NotNull final ProblemsHolder holder, @@ -80,7 +67,7 @@ public class PyAssignmentToLoopOrWithParameterInspection extends PyInspection { * that declares one of names, declared in this statement */ private void checkNotReDeclaringUpperLoopOrStatement(@NotNull final PsiElement statement) { - for (final PsiElement declaredVar : getNamedElementsOfForAndWithStatements(statement)) { + for (PyExpression declaredVar : getNamedElementsOfForAndWithStatements(statement)) { final Filter filter = new Filter(handleSubscriptionsAndResolveSafely(declaredVar)); final PsiElement firstParent = PsiTreeUtil.findFirstParent(statement, true, filter); if ((firstParent != null) && isRequiredStatement(firstParent)) { @@ -132,8 +119,8 @@ public class PyAssignmentToLoopOrWithParameterInspection extends PyInspection { if (!isRequiredStatement(psiElement)) { return false; //Parent has wrong type, skip } - final List varsDeclaredInStatement = getNamedElementsOfForAndWithStatements(psiElement); - for (final PsiElement varDeclaredInStatement : varsDeclaredInStatement) { + final List varsDeclaredInStatement = getNamedElementsOfForAndWithStatements(psiElement); + for (PyExpression varDeclaredInStatement : varsDeclaredInStatement) { //For each variable, declared by this parent take first declaration and open subscription list if any final PsiReference reference = handleSubscriptionsAndResolveSafely(varDeclaredInStatement).getReference(); if ((reference != null) && reference.isReferenceTo(myNode)) { @@ -151,13 +138,12 @@ public class PyAssignmentToLoopOrWithParameterInspection extends PyInspection { * @param element element to open and resolve * @return opened and resolved element */ - private static PsiElement handleSubscriptionsAndResolveSafely(PsiElement element) { - assert element != null; + @NotNull + private static PsiElement handleSubscriptionsAndResolveSafely(@NotNull PyExpression element) { if (element instanceof PySubscriptionExpression) { element = ((PySubscriptionExpression)element).getRootOperand(); } - element = PyUtil.resolveToTheTop(element); - return element; + return PyUtil.resolveToTheTop(element); } /** @@ -171,28 +157,34 @@ public class PyAssignmentToLoopOrWithParameterInspection extends PyInspection { return (element instanceof PyWithStatement) || (element instanceof PyForStatement); } - private static List getNamedElementsOfForAndWithStatements(@NotNull PsiElement element) { - final List expressions; + @NotNull + private static List getNamedElementsOfForAndWithStatements(@NotNull PsiElement element) { if (element instanceof PyForStatement) { - final PyForStatement forStmt = (PyForStatement)element; - final PyExpression tgt = forStmt.getForPart().getTarget(); - expressions = Lists.newArrayList(); - expressions.addAll(PyUtil.flattenedParensAndStars(tgt)); + final PyForStatement forStatement = (PyForStatement)element; + final PyExpression target = forStatement.getForPart().getTarget(); + + return dropUnderscores(PyUtil.flattenedParensAndStars(target)); } else if (element instanceof PyWithStatement) { - final PyWithStatement withStmt = (PyWithStatement)element; - expressions = Lists.newArrayList(); - final PyWithItem[] items = PsiTreeUtil.getChildrenOfType(withStmt, PyWithItem.class); - if (items != null) { - for (PyWithItem item : items) { - PyExpression targetExpression = item.getTarget(); - expressions.addAll(PyUtil.flattenedParensAndTuples(targetExpression)); + final PyWithStatement withStatement = (PyWithStatement)element; + final List result = new ArrayList<>(); + + for (PyWithItem item : withStatement.getWithItems()) { + final PyExpression target = item.getTarget(); + if (target != null) { + result.addAll(PyUtil.flattenedParensAndTuples(target)); } } + + return dropUnderscores(result); } - else { - expressions = Collections.emptyList(); - } - return expressions; + + return Collections.emptyList(); + } + + @NotNull + private static List dropUnderscores(@NotNull List expressions) { + return ContainerUtil.filter(expressions, + expression -> !PyNames.UNDERSCORE.equals(expression.getText())); } } diff --git a/python/testData/inspections/PyAssignmentToLoopOrWithParameterInspection/redeclaredUnderscore.py b/python/testData/inspections/PyAssignmentToLoopOrWithParameterInspection/redeclaredUnderscore.py new file mode 100644 index 000000000000..4474fe8e2417 --- /dev/null +++ b/python/testData/inspections/PyAssignmentToLoopOrWithParameterInspection/redeclaredUnderscore.py @@ -0,0 +1,3 @@ +for _ in []: + for _ in []: + print("ok") \ No newline at end of file diff --git a/python/testSrc/com/jetbrains/python/inspections/PyAssignmentToLoopOrWithParameterInspectionTest.java b/python/testSrc/com/jetbrains/python/inspections/PyAssignmentToLoopOrWithParameterInspectionTest.java index fcd391b2d0a5..44d2da4cd98d 100644 --- a/python/testSrc/com/jetbrains/python/inspections/PyAssignmentToLoopOrWithParameterInspectionTest.java +++ b/python/testSrc/com/jetbrains/python/inspections/PyAssignmentToLoopOrWithParameterInspectionTest.java @@ -1,18 +1,4 @@ -/* - * Copyright 2000-2014 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2000-2017 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; import com.jetbrains.python.fixtures.PyInspectionTestCase; @@ -31,6 +17,11 @@ public class PyAssignmentToLoopOrWithParameterInspectionTest extends PyInspectio doTest(); } + // PY-26137 + public void testRedeclaredUnderscore() { + doTest(); + } + @NotNull @Override protected Class getInspectionClass() {