mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
PY-85030 When constructing a structural type, make sure attribute qualifiers refer to the original parameter on all paths
We already had protection against reassignment to a parameter name, but it didn't take into account that we also skip conditional branches and loops to collect only definitely accessed attributes of an object, so if reassignments took place under conditions, even in every branch, they didn't prevent us from collecting subsequently accessed attributes. GitOrigin-RevId: d41b8f4c3dbce6643d915923172d32a8e4e6466c
This commit is contained in:
committed by
intellij-monorepo-bot
parent
9c3b187edf
commit
223a91c3ac
@@ -271,6 +271,7 @@ public class PyNamedParameterImpl extends PyBaseElementImpl<PyNamedParameterStub
|
||||
|
||||
final Ref<Boolean> parameterWasReassigned = Ref.create(false);
|
||||
final Ref<Boolean> noneComparison = Ref.create(false);
|
||||
final PyResolveContext resolveContext = PyResolveContext.defaultContext(context);
|
||||
|
||||
if (owner != null && name != null) {
|
||||
owner.accept(new PyRecursiveElementVisitor() {
|
||||
@@ -378,8 +379,10 @@ public class PyNamedParameterImpl extends PyBaseElementImpl<PyNamedParameterStub
|
||||
@Contract("null -> false")
|
||||
private boolean isReferenceToParameter(@Nullable PsiElement element) {
|
||||
if (element == null) return false;
|
||||
final PsiReference reference = element.getReference();
|
||||
return reference != null && reference.isReferenceTo(PyNamedParameterImpl.this);
|
||||
if (!(element instanceof PyReferenceExpression || element instanceof PyTargetExpression)) return false;
|
||||
if (((PyQualifiedExpression)element).isQualified()) return false;
|
||||
List<@Nullable PsiElement> definitions = PyUtil.multiResolveTopPriority(element, resolveContext);
|
||||
return ContainerUtil.all(definitions, e -> e == PyNamedParameterImpl.this);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
def foo(smth, param):
|
||||
if smth:
|
||||
param = ""
|
||||
print(param.<weak_warning descr="Member 'str' of 'Union[{smth}, str]' does not have attribute 'smth'">smth</weak_warning>())
|
||||
print(param.<weak_warning descr="Member 'str' of 'Union[str, Any]' does not have attribute 'smth'">smth</weak_warning>())
|
||||
@@ -4676,6 +4676,17 @@ public class Py3TypeTest extends PyTestCase {
|
||||
""");
|
||||
}
|
||||
|
||||
// PY-85030
|
||||
public void testStructuralTypesAttributeAccessAfterTypeNarrowingAndReassignmentInIf() {
|
||||
doTest("(p: Any) -> None", """
|
||||
def f(p):
|
||||
if isinstance(p, int):
|
||||
p = "foo"
|
||||
x = p.lower()
|
||||
expr = f
|
||||
""");
|
||||
}
|
||||
|
||||
private void doTest(final String expectedType, final String text) {
|
||||
myFixture.configureByText(PythonFileType.INSTANCE, text);
|
||||
final PyExpression expr = myFixture.findElementByText("expr", PyExpression.class);
|
||||
|
||||
@@ -4125,5 +4125,37 @@ public class Py3TypeCheckerInspectionTest extends PyInspectionTestCase {
|
||||
_: C2 = c1
|
||||
""");
|
||||
}
|
||||
|
||||
// PY-85030
|
||||
public void testStructuralTypeAndStrictUnion() {
|
||||
doTestByText("""
|
||||
responses = {
|
||||
100: "abc",
|
||||
}
|
||||
|
||||
def process(status):
|
||||
if isinstance(status, int):
|
||||
status = responses[status]
|
||||
return status.lower().replace(" ", "-")
|
||||
|
||||
def do(arg):
|
||||
title = "abc" if arg else 100
|
||||
return process(title)
|
||||
""");
|
||||
}
|
||||
|
||||
// PY-85030
|
||||
public void testStructuralTypeAndDefiniteReassignmentUnderCondition() {
|
||||
doTestByText("""
|
||||
def f(p):
|
||||
if p:
|
||||
p = "foo"
|
||||
else:
|
||||
p = "bar"
|
||||
return p.lower()
|
||||
|
||||
f(42)
|
||||
""");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user