Ignore underscores in PyAssignmentToLoopOrWithParameterInspection

PY-26137 fixed.
This commit is contained in:
Semyon Proshev
2017-10-09 18:43:39 +03:00
parent 5b19bb7b45
commit 627a2ef4a8
3 changed files with 42 additions and 56 deletions
@@ -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<PyElement> varsDeclaredInStatement = getNamedElementsOfForAndWithStatements(psiElement);
for (final PsiElement varDeclaredInStatement : varsDeclaredInStatement) {
final List<PyExpression> 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<PyElement> getNamedElementsOfForAndWithStatements(@NotNull PsiElement element) {
final List<PyElement> expressions;
@NotNull
private static List<PyExpression> 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<PyExpression> 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<PyExpression> dropUnderscores(@NotNull List<PyExpression> expressions) {
return ContainerUtil.filter(expressions,
expression -> !PyNames.UNDERSCORE.equals(expression.getText()));
}
}
@@ -0,0 +1,3 @@
for _ in []:
for _ in []:
print("ok")
@@ -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<? extends PyInspection> getInspectionClass() {