mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
PY-82699 Type parameter is not shadowed by a local variable
GitOrigin-RevId: 973100ef1aae3e5ebd55c514e13565eae8f7985e
This commit is contained in:
committed by
intellij-monorepo-bot
parent
9cffac56b3
commit
572dffa91e
+3
@@ -1050,6 +1050,9 @@ public class PyControlFlowBuilder extends PyRecursiveElementVisitor {
|
||||
myBuilder.addNodeAndCheckPending(instruction);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitPyTypeParameterList(@NotNull PyTypeParameterList node) { }
|
||||
|
||||
private void visitCondition(@NotNull PyExpression expression, @NotNull Instruction trueNode, @NotNull Instruction falseNode) {
|
||||
TrueFalseNodes prevTrueFalseNodes = myTrueFalseNodes;
|
||||
myTrueFalseNodes = new TrueFalseNodes(trueNode, falseNode);
|
||||
|
||||
+4
@@ -114,6 +114,10 @@ public final class PyUnboundLocalVariableInspection extends PyInspection {
|
||||
}
|
||||
final PsiPolyVariantReference ref = node.getReference(getResolveContext());
|
||||
final PsiElement resolved = ref.resolve();
|
||||
// type parameter list is not included in CFG
|
||||
if (resolved instanceof PyTypeParameter) {
|
||||
return;
|
||||
}
|
||||
final boolean isBuiltin = PyBuiltinCache.getInstance(node).isBuiltin(resolved);
|
||||
if (owner instanceof PyClass) {
|
||||
if (isBuiltin || ScopeUtil.getDeclarationScopeOwner(owner, name) != null) {
|
||||
|
||||
+8
-1
@@ -97,8 +97,15 @@ public final class PyUnusedLocalInspectionVisitor extends PyInspectionVisitor {
|
||||
}
|
||||
|
||||
private void collectAllWrites(ScopeOwner owner) {
|
||||
final Instruction[] instructions = ControlFlowCache.getControlFlow(owner).getInstructions();
|
||||
Set<PsiElement> scopeWrites = new HashSet<>();
|
||||
// type parameter list is not included in CFG
|
||||
if (owner instanceof PyTypeParameterListOwner typeParameterListOwner) {
|
||||
PyTypeParameterList typeParameterList = typeParameterListOwner.getTypeParameterList();
|
||||
if (typeParameterList != null) {
|
||||
scopeWrites.addAll(typeParameterList.getTypeParameters());
|
||||
}
|
||||
}
|
||||
final Instruction[] instructions = ControlFlowCache.getControlFlow(owner).getInstructions();
|
||||
for (Instruction instruction : instructions) {
|
||||
final PsiElement element = instruction.getElement();
|
||||
if (element instanceof PyFunction && owner instanceof PyFunction) {
|
||||
|
||||
+4
-1
@@ -236,7 +236,10 @@ public class PyReferenceImpl implements PsiReferenceEx, PsiPolyVariantReference
|
||||
final ScopeOwner resolvedOwner = processor.getOwner();
|
||||
|
||||
final Collection<PsiElement> resolvedElements = processor.getElements();
|
||||
if (resolvedOwner != null && !resolvedElements.isEmpty() && !ControlFlowCache.getScope(resolvedOwner).isGlobal(referencedName)) {
|
||||
if (resolvedOwner != null &&
|
||||
!processor.isTypeParameterScope() &&
|
||||
!resolvedElements.isEmpty() &&
|
||||
!ControlFlowCache.getScope(resolvedOwner).isGlobal(referencedName)) {
|
||||
if (resolvedOwner == referenceOwner && referenceAnchor != null) {
|
||||
final List<Instruction> instructions = getLatestDefinitions(referencedName, resolvedOwner, referenceAnchor);
|
||||
// TODO: Use the results from the processor as a cache for resolving to latest defs
|
||||
|
||||
@@ -8,10 +8,7 @@ import com.intellij.psi.ResolveState;
|
||||
import com.intellij.psi.scope.PsiScopeProcessor;
|
||||
import com.jetbrains.python.codeInsight.controlflow.ScopeOwner;
|
||||
import com.jetbrains.python.codeInsight.dataflow.scope.ScopeUtil;
|
||||
import com.jetbrains.python.psi.PyFromImportStatement;
|
||||
import com.jetbrains.python.psi.PyImportElement;
|
||||
import com.jetbrains.python.psi.PyImportedNameDefiner;
|
||||
import com.jetbrains.python.psi.PyUtil;
|
||||
import com.jetbrains.python.psi.*;
|
||||
import com.jetbrains.python.psi.impl.ResolveResultList;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -27,6 +24,7 @@ public class PyResolveProcessor implements PsiScopeProcessor {
|
||||
private final @NotNull Map<PsiElement, PyImportedNameDefiner> myResults = Maps.newLinkedHashMap();
|
||||
private final @NotNull Map<PsiElement, PyImportedNameDefiner> myImplicitlyImportedResults = Maps.newLinkedHashMap();
|
||||
protected @Nullable ScopeOwner myOwner;
|
||||
private boolean myTypeParameterScope;
|
||||
|
||||
public PyResolveProcessor(@NotNull String name) {
|
||||
this(name, false);
|
||||
@@ -79,6 +77,10 @@ public class PyResolveProcessor implements PsiScopeProcessor {
|
||||
return myOwner;
|
||||
}
|
||||
|
||||
public boolean isTypeParameterScope() {
|
||||
return myTypeParameterScope;
|
||||
}
|
||||
|
||||
private @NotNull List<RatedResolveResult> resolveInImportedNameDefiner(@NotNull PyImportedNameDefiner definer) {
|
||||
if (myLocalResolve) {
|
||||
final PyImportElement importElement = PyUtil.as(definer, PyImportElement.class);
|
||||
@@ -96,8 +98,9 @@ public class PyResolveProcessor implements PsiScopeProcessor {
|
||||
final ScopeOwner owner = ScopeUtil.getScopeOwner(definer != null ? definer : element);
|
||||
if (myOwner == null) {
|
||||
myOwner = owner;
|
||||
myTypeParameterScope = element instanceof PyTypeParameter;
|
||||
}
|
||||
final boolean sameScope = owner == myOwner;
|
||||
final boolean sameScope = owner == myOwner && (element instanceof PyTypeParameter) == myTypeParameterScope;
|
||||
if (sameScope) {
|
||||
addResult(element, definer);
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package com.jetbrains.python.psi.resolve;
|
||||
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
@@ -117,7 +118,10 @@ public final class PyResolveUtil {
|
||||
else {
|
||||
namedElements = scope.getNamedElements();
|
||||
}
|
||||
for (PsiElement element : ContainerUtil.concat(namedElements, scope.getImportedNameDefiners())) {
|
||||
Iterable<PsiElement> elements = Iterables.concat(Iterables.filter(namedElements, t -> !(t instanceof PyTypeParameter)),
|
||||
scope.getImportedNameDefiners(),
|
||||
Iterables.filter(namedElements, PyTypeParameter.class));
|
||||
for (PsiElement element : elements) {
|
||||
if (isClassLevelDefinitionInvisibleToReference(element, scopeOwner, originalScopeOwner)) continue;
|
||||
if (!processor.execute(element, ResolveState.initial())) {
|
||||
return;
|
||||
|
||||
-12
@@ -1,12 +0,0 @@
|
||||
0(1) element: null
|
||||
1(2) element: PyTypeParameter
|
||||
2(3) WRITE ACCESS: T
|
||||
3(4) element: PySubscriptionExpression
|
||||
4(5) READ ACCESS: list
|
||||
5(6) READ ACCESS: T
|
||||
6(7) WRITE ACCESS: x
|
||||
7(8) READ ACCESS: T
|
||||
8(9) element: PyReturnStatement
|
||||
9(10) element: PySubscriptionExpression
|
||||
10(11) READ ACCESS: x
|
||||
11() element: null
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
0(1) element: null
|
||||
1(2) element: PySubscriptionExpression
|
||||
2(3) READ ACCESS: list
|
||||
3(4) READ ACCESS: T
|
||||
4(5) WRITE ACCESS: x
|
||||
5(6) READ ACCESS: T
|
||||
6(7) element: PyReturnStatement
|
||||
7(8) element: PySubscriptionExpression
|
||||
8(9) READ ACCESS: x
|
||||
9() element: null
|
||||
+5
-11
@@ -1,12 +1,6 @@
|
||||
0(1) element: null
|
||||
1(2) element: PyTypeParameter
|
||||
2(3) WRITE ACCESS: T
|
||||
3(4) READ ACCESS: str
|
||||
4(5) element: PyTypeParameter
|
||||
5(6) WRITE ACCESS: U
|
||||
6(7) READ ACCESS: int
|
||||
7(8) element: PySubscriptionExpression
|
||||
8(9) READ ACCESS: Union
|
||||
9(10) READ ACCESS: T
|
||||
10(11) READ ACCESS: U
|
||||
11() element: null
|
||||
1(2) element: PySubscriptionExpression
|
||||
2(3) READ ACCESS: Union
|
||||
3(4) READ ACCESS: T
|
||||
4(5) READ ACCESS: U
|
||||
5() element: null
|
||||
@@ -1,10 +1,6 @@
|
||||
0(1) element: null
|
||||
1(2) element: PyTypeParameter
|
||||
2(3) WRITE ACCESS: T
|
||||
3(4) element: PyTypeParameter
|
||||
4(5) WRITE ACCESS: U
|
||||
5(6) element: PySubscriptionExpression
|
||||
6(7) READ ACCESS: BaseClass
|
||||
7(8) READ ACCESS: T
|
||||
8(9) element: PyPassStatement
|
||||
9() element: null
|
||||
1(2) element: PySubscriptionExpression
|
||||
2(3) READ ACCESS: BaseClass
|
||||
3(4) READ ACCESS: T
|
||||
4(5) element: PyPassStatement
|
||||
5() element: null
|
||||
@@ -1,11 +1,7 @@
|
||||
0(1) element: null
|
||||
1(2) element: PyTypeParameter
|
||||
2(3) WRITE ACCESS: T
|
||||
3(4) element: PyTypeParameter
|
||||
4(5) WRITE ACCESS: U
|
||||
5(6) READ ACCESS: T
|
||||
6(7) WRITE ACCESS: a
|
||||
7(8) READ ACCESS: U
|
||||
8(9) WRITE ACCESS: b
|
||||
9(10) element: PyPassStatement
|
||||
10() element: null
|
||||
1(2) READ ACCESS: T
|
||||
2(3) WRITE ACCESS: a
|
||||
3(4) READ ACCESS: U
|
||||
4(5) WRITE ACCESS: b
|
||||
5(6) element: PyPassStatement
|
||||
6() element: null
|
||||
@@ -0,0 +1,6 @@
|
||||
def outer[T]():
|
||||
def inner():
|
||||
print(T)
|
||||
# <ref>
|
||||
|
||||
T = -1
|
||||
@@ -0,0 +1,4 @@
|
||||
def f[T]():
|
||||
print(T)
|
||||
# <ref>
|
||||
T = 1
|
||||
@@ -895,6 +895,16 @@ public class Py3ResolveTest extends PyResolveTestCase {
|
||||
assertResolvesToItself();
|
||||
}
|
||||
|
||||
// PY-82699
|
||||
public void testTypeParameterRebindToLocalVariableInEnclosingScope() {
|
||||
assertResolvesTo(PyTargetExpression.class, "T");
|
||||
}
|
||||
|
||||
// PY-82699
|
||||
public void testTypeParameterRebindToLocalVariableInSameScope() {
|
||||
assertUnresolved();
|
||||
}
|
||||
|
||||
private void assertResolvesToItself() {
|
||||
PsiElement resolved = doResolve();
|
||||
PsiReference reference = PyResolveTestCase.findReferenceByMarker(myFixture.getFile());
|
||||
|
||||
@@ -3933,6 +3933,17 @@ public class Py3TypeTest extends PyTestCase {
|
||||
""");
|
||||
}
|
||||
|
||||
// PY-82699
|
||||
public void testTypeParameterRebind() {
|
||||
doTest("int", """
|
||||
def outer[T]() -> None:
|
||||
def inner() -> None:
|
||||
expr = T
|
||||
|
||||
T = -1
|
||||
""");
|
||||
}
|
||||
|
||||
private void doTest(final String expectedType, final String text) {
|
||||
myFixture.configureByText(PythonFileType.INSTANCE, text);
|
||||
final PyExpression expr = myFixture.findElementByText("expr", PyExpression.class);
|
||||
|
||||
@@ -578,8 +578,8 @@ public class PyControlFlowBuilderTest extends LightMarkedTestCase {
|
||||
doTest();
|
||||
}
|
||||
|
||||
// PY-61877
|
||||
public void testNewStyleGenericFunctionAnnotationsAreIncludedInItsGraph() {
|
||||
// PY-61877 PY-82699
|
||||
public void testNewStyleGenericFunctionAnnotationsAreNotIncludedInItsGraph() {
|
||||
doTestFirstStatement();
|
||||
}
|
||||
|
||||
|
||||
+12
@@ -464,4 +464,16 @@ public class Py3UnresolvedReferencesInspectionTest extends PyInspectionTestCase
|
||||
);
|
||||
}
|
||||
|
||||
// PY-82699
|
||||
public void testTypeParameterRebind() {
|
||||
doTestByText("""
|
||||
def outer1[T]() -> None:
|
||||
print(<error descr="Unresolved reference 'T'">T</error>)
|
||||
T = 1
|
||||
|
||||
def outer2[T]() -> None:
|
||||
print(T)
|
||||
""");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user