PY-36889 Type check assignments to class/instance attributes outside of class bodies

Previously, PyTypingTypeProvider.getReferenceType returned a type from a class attribute
type hint only for assignment to instance attribute located inside a class definition.

In other words, here we inferred the expected type from the annotation
and reported incompatible types in assignment:

```python
class C:
    attr: int

    def m(self):
        self.attr = "foo"
```
but in the following we didn't:

```python
class C:
    attr: int

inst = C()
inst.attr = "foo"
```

Now we try to resolve any qualified target expression to a class
or instance attribute and then infer the type from the corresponding
annotation.


(cherry picked from commit 086dbb678a8cd89cfe332bf801631568fb6c3a4d)

IJ-MR-147382

GitOrigin-RevId: 4e3f71baa598d4caf684d0aeab23d1a9a688b94d
This commit is contained in:
Mikhail Golubev
2024-10-21 14:33:50 +03:00
committed by intellij-monorepo-bot
parent 24284fe20f
commit 99a6645e5d
3 changed files with 72 additions and 6 deletions

View File

@@ -358,6 +358,46 @@ public class Py3TypeCheckerInspectionTest extends PyInspectionTestCase {
doTest();
}
// PY-36889
public void testInstanceAndClassAttributeAssignment() {
doTestByText("""
from typing import ClassVar
class ClassAnnotations:
attr: int
class_attr: ClassVar[int]
ClassAnnotations().attr = <warning descr="Expected type 'int', got 'str' instead">"foo"</warning>
ClassAnnotations.class_attr = <warning descr="Expected type 'int', got 'str' instead">"foo"</warning>
class ClassAnnotationInstanceAssignment:
attr: int
def __init__(self, x):
self.attr = x
ClassAnnotationInstanceAssignment(42).attr = <warning descr="Expected type 'int', got 'str' instead">"foo"</warning>
class InstanceAnnotationAndAssignment:
def __init__(self):
self.attr: int = 42
InstanceAnnotationAndAssignment().attr = <warning descr="Expected type 'int', got 'str' instead">"foo"</warning>
""");
}
// PY-36889
public void testDataclassInstanceAssignment() {
doTestByText("""
from dataclasses import dataclass
@dataclass
class C:
attr: int
C().attr = <warning descr="Expected type 'int', got 'str' instead">"foo"</warning>
""");
}
// PY-24832
public void testNoTypeMismatchInAssignmentWithoutTypeAnnotation() {
doTest();