-- Test cases related to classes for the semantic analyzer.

[case testSimpleClass]
class A: pass
x = A
[out]
MypyFile:1(
  ClassDef:1(
    A
    PassStmt:1())
  AssignmentStmt:2(
    NameExpr(x* [__main__.x])
    NameExpr(A [__main__.A])))

[case testMethods]
class A:
  def __init__(self, x):
    y = x
  def f(self):
    y = self
[out]
MypyFile:1(
  ClassDef:1(
    A
    FuncDef:2(
      __init__
      Args(
        Var(self)
        Var(x))
      Block:2(
        AssignmentStmt:3(
          NameExpr(y* [l])
          NameExpr(x [l]))))
    FuncDef:4(
      f
      Args(
        Var(self))
      Block:4(
        AssignmentStmt:5(
          NameExpr(y* [l])
          NameExpr(self [l]))))))

[case testMemberDefinitionInInit]
class A:
  def __init__(self):
    self.x = 1
    self.y = 2
[out]
MypyFile:1(
  ClassDef:1(
    A
    FuncDef:2(
      __init__
      Args(
        Var(self))
      Block:2(
        AssignmentStmt:3(
          MemberExpr:3(
            NameExpr(self [l])
            x*)
          IntExpr(1))
        AssignmentStmt:4(
          MemberExpr:4(
            NameExpr(self [l])
            y*)
          IntExpr(2))))))

[case testMemberAssignmentViaSelfOutsideInit]
class A:
  def f(self):
    self.x = 1
def __init__(self):
  self.y = 1
[out]
MypyFile:1(
  ClassDef:1(
    A
    FuncDef:2(
      f
      Args(
        Var(self))
      Block:2(
        AssignmentStmt:3(
          MemberExpr:3(
            NameExpr(self [l])
            x*)
          IntExpr(1)))))
  FuncDef:4(
    __init__
    Args(
      Var(self))
    Block:4(
      AssignmentStmt:5(
        MemberExpr:5(
          NameExpr(self [l])
          y)
        IntExpr(1)))))

[case testMemberAssignmentNotViaSelf]
class A:
  def __init__(x, self):
    self.y = 1 # not really self
class B:
  def __init__(x):
    self = x
    self.z = 1
[out]
MypyFile:1(
  ClassDef:1(
    A
    FuncDef:2(
      __init__
      Args(
        Var(x)
        Var(self))
      Block:2(
        AssignmentStmt:3(
          MemberExpr:3(
            NameExpr(self [l])
            y)
          IntExpr(1)))))
  ClassDef:4(
    B
    FuncDef:5(
      __init__
      Args(
        Var(x))
      Block:5(
        AssignmentStmt:6(
          NameExpr(self* [l])
          NameExpr(x [l]))
        AssignmentStmt:7(
          MemberExpr:7(
            NameExpr(self [l])
            z)
          IntExpr(1))))))

[case testNonStandardNameForSelfAndInit]
class A:
  def __init__(x):
    x.y = 1
[out]
MypyFile:1(
  ClassDef:1(
    A
    FuncDef:2(
      __init__
      Args(
        Var(x))
      Block:2(
        AssignmentStmt:3(
          MemberExpr:3(
            NameExpr(x [l])
            y*)
          IntExpr(1))))))

[case testAssignmentAfterAttributeInit]
class A:
  def __init__(self):
    self.x = 1
    self.x = 2
[out]
MypyFile:1(
  ClassDef:1(
    A
    FuncDef:2(
      __init__
      Args(
        Var(self))
      Block:2(
        AssignmentStmt:3(
          MemberExpr:3(
            NameExpr(self [l])
            x*)
          IntExpr(1))
        AssignmentStmt:4(
          MemberExpr:4(
            NameExpr(self [l])
            x)
          IntExpr(2))))))

[case testOverloadedMethod]
from typing import overload
class A:
  @overload
  def f(self) -> None: self
  @overload
  def f(self, x: 'A') -> None: self
  def f(self, *args): self
[out]
MypyFile:1(
  ImportFrom:1(typing, [overload])
  ClassDef:2(
    A
    OverloadedFuncDef:3(
      FuncDef:7(
        f
        Args(
          Var(self))
        VarArg(
          Var(args))
        Block:7(
          ExpressionStmt:7(
            NameExpr(self [l]))))
      Overload(def (self: __main__.A), \
               def (self: __main__.A, x: __main__.A))
      Decorator:3(
        Var(f)
        NameExpr(overload [typing.overload])
        FuncDef:4(
          f
          Args(
            Var(self))
          def (self: __main__.A)
          Block:4(
            ExpressionStmt:4(
              NameExpr(self [l])))))
      Decorator:5(
        Var(f)
        NameExpr(overload [typing.overload])
        FuncDef:6(
          f
          Args(
            Var(self)
            Var(x))
          def (self: __main__.A, x: __main__.A)
          Block:6(
            ExpressionStmt:6(
              NameExpr(self [l]))))))))

[case testAttributeWithoutType]
class A:
    a = object
[out]
MypyFile:1(
  ClassDef:1(
    A
    AssignmentStmt:2(
      NameExpr(a* [m])
      NameExpr(object [builtins.object]))))

[case testDataAttributeRefInClassBody]
class A:
    x = 1
    y = x
[out]
MypyFile:1(
  ClassDef:1(
    A
    AssignmentStmt:2(
      NameExpr(x* [m])
      IntExpr(1))
    AssignmentStmt:3(
      NameExpr(y* [m])
      NameExpr(x [__main__.A.x]))))

[case testMethodRefInClassBody]
class A:
    def f(self): pass
    g = f
[out]
MypyFile:1(
  ClassDef:1(
    A
    FuncDef:2(
      f
      Args(
        Var(self))
      Block:2(
        PassStmt:2()))
    AssignmentStmt:3(
      NameExpr(g* [m])
      NameExpr(f [__main__.A.f]))))

[case testIfStatementInClassBody]
class A:
    if A:
        x = 1
    else:
        x = 2
[out]
MypyFile:1(
  ClassDef:1(
    A
    IfStmt:2(
      If(
        NameExpr(A [__main__.A]))
      Then(
        AssignmentStmt:3(
          NameExpr(x* [m])
          IntExpr(1)))
      Else(
        AssignmentStmt:5(
          NameExpr(x [__main__.A.x])
          IntExpr(2))))))

[case testForStatementInClassBody]
class A:
    for x in [1, 2]:
        y = x
[out]
MypyFile:1(
  ClassDef:1(
    A
    ForStmt:2(
      NameExpr(x* [m])
      ListExpr:2(
        IntExpr(1)
        IntExpr(2))
      Block:2(
        AssignmentStmt:3(
          NameExpr(y* [m])
          NameExpr(x [__main__.A.x]))))))

[case testReferenceToClassWithinFunction]
def f():
    class A: pass
    A
[out]
MypyFile:1(
  FuncDef:1(
    f
    Block:1(
      ClassDef:2(
        A
        PassStmt:2())
      ExpressionStmt:3(
        NameExpr(A [__main__.A@2])))))

[case testReferenceToClassWithinClass]
class A:
    class B: pass
    B
[out]
MypyFile:1(
  ClassDef:1(
    A
    ClassDef:2(
      B
      PassStmt:2())
    ExpressionStmt:3(
      NameExpr(B [__main__.A.B]))))

[case testClassWithBaseClassWithinClass]
class A:
    class B: pass
    class C(B): pass
[out]
MypyFile:1(
  ClassDef:1(
    A
    ClassDef:2(
      B
      PassStmt:2())
    ClassDef:3(
      C
      BaseType(
        __main__.A.B)
      PassStmt:3())))

[case testDeclarationReferenceToNestedClass]
def f() -> None:
    class A: pass
    x = None # type: A
[out]
MypyFile:1(
  FuncDef:1(
    f
    def ()
    Block:1(
      ClassDef:2(
        A
        PassStmt:2())
      AssignmentStmt:3(
        NameExpr(x [l])
        NameExpr(None [builtins.None])
        __main__.A@2))))

[case testAccessToLocalInOuterScopeWithinNestedClass]
def f(x):
    class A:
        y = x
        def g(self):
            z = x
[out]
MypyFile:1(
  FuncDef:1(
    f
    Args(
      Var(x))
    Block:1(
      ClassDef:2(
        A
        AssignmentStmt:3(
          NameExpr(y* [m])
          NameExpr(x [l]))
        FuncDef:4(
          g
          Args(
            Var(self))
          Block:4(
            AssignmentStmt:5(
              NameExpr(z* [l])
              NameExpr(x [l]))))))))

[case testQualifiedMetaclass]
import abc
class A(metaclass=abc.ABCMeta): pass
[out]
MypyFile:1(
  Import:1(abc)
  ClassDef:2(
    A
    Metaclass(MemberExpr:2(
      NameExpr(abc)
      ABCMeta [abc.ABCMeta]))
    PassStmt:2()))

[case testStaticMethod]
class A:
  @staticmethod
  def f(z: int) -> str: pass
[builtins fixtures/staticmethod.pyi]
[out]
MypyFile:1(
  ClassDef:1(
    A
    Decorator:2(
      Var(f)
      FuncDef:3(
        f
        Args(
          Var(z))
        def (z: builtins.int) -> builtins.str
        Static
        Block:3(
          PassStmt:3())))))

[case testStaticMethodWithNoArgs]
class A:
  @staticmethod
  def f() -> str: pass
[builtins fixtures/staticmethod.pyi]
[out]
MypyFile:1(
  ClassDef:1(
    A
    Decorator:2(
      Var(f)
      FuncDef:3(
        f
        def () -> builtins.str
        Static
        Block:3(
          PassStmt:3())))))

[case testClassMethod]
class A:
  @classmethod
  def f(cls, z: int) -> str: pass
[builtins fixtures/classmethod.pyi]
[out]
MypyFile:1(
  ClassDef:1(
    A
    Decorator:2(
      Var(f)
      FuncDef:3(
        f
        Args(
          Var(cls)
          Var(z))
        def (cls: def () -> __main__.A, z: builtins.int) -> builtins.str
        Class
        Block:3(
          PassStmt:3())))))

[case testClassMethodWithNoArgs]
class A:
  @classmethod
  def f(cls) -> str: pass
[builtins fixtures/classmethod.pyi]
[out]
MypyFile:1(
  ClassDef:1(
    A
    Decorator:2(
      Var(f)
      FuncDef:3(
        f
        Args(
          Var(cls))
        def (cls: def () -> __main__.A) -> builtins.str
        Class
        Block:3(
          PassStmt:3())))))

[case testProperty]
import typing
class A:
  @property
  def f(self) -> str: pass
[builtins fixtures/property.pyi]
[out]
MypyFile:1(
  Import:1(typing)
  ClassDef:2(
    A
    Decorator:3(
      Var(f)
      FuncDef:4(
        f
        Args(
          Var(self))
        def (self: __main__.A) -> builtins.str
        Property
        Block:4(
          PassStmt:4())))))

[case testClassDecorator]
import typing
@object
class A: pass
[out]
MypyFile:1(
  Import:1(typing)
  ClassDef:2(
    A
    Decorators(
      NameExpr(object [builtins.object]))
    PassStmt:3()))

[case testClassAttributeAsMethodDefaultArgumentValue]
import typing
class A:
    X = 1
    def f(self, x : int = X) -> None: pass
[out]
MypyFile:1(
  Import:1(typing)
  ClassDef:2(
    A
    AssignmentStmt:3(
      NameExpr(X* [m])
      IntExpr(1))
    FuncDef:4(
      f
      Args(
        Var(self)
        default(
          Var(x)
          NameExpr(X [__main__.A.X])))
      def (self: __main__.A, x: builtins.int =)
      Block:4(
        PassStmt:4()))))

[case testInvalidBaseClass]
from typing import Any, Callable
class A(None): pass
class B(Any): pass
class C(Callable[[], int]): pass
[out]
main: error: Invalid base class
main:4: error: Invalid base class

[case testTupleAsBaseClass]
import m
[file m.pyi]
from typing import Tuple
class A(Tuple[int, str]): pass
[builtins fixtures/tuple.pyi]
[out]
MypyFile:1(
  Import:1(m))
MypyFile:1(
  tmp/m.pyi
  ImportFrom:1(typing, [Tuple])
  ClassDef:2(
    A
    TupleType(
      Tuple[builtins.int, builtins.str])
    BaseType(
      builtins.tuple[Any])
    PassStmt:2()))

[case testBaseClassFromIgnoredModule]
import m # type: ignore
class B(m.A):
   pass
[out]
MypyFile:1(
  Import:1(m)
  ClassDef:2(
    B
    FallbackToAny
    BaseType(
      builtins.object)
    PassStmt:3())
  IgnoredLines(1))

[case testBaseClassFromIgnoredModuleUsingImportFrom]
from m import A # type: ignore
class B(A, int):
   pass
[out]
MypyFile:1(
  ImportFrom:1(m, [A])
  ClassDef:2(
    B
    FallbackToAny
    BaseType(
      builtins.int)
    PassStmt:3())
  IgnoredLines(1))

[case testBaseClassWithExplicitAnyType]
from typing import Any
A = 1 # type: Any
class B(A):
   pass
[out]
MypyFile:1(
  ImportFrom:1(typing, [Any])
  AssignmentStmt:2(
    NameExpr(A [__main__.A])
    IntExpr(1)
    Any)
  ClassDef:3(
    B
    FallbackToAny
    BaseType(
      builtins.object)
    PassStmt:4()))
