source/analysis/annotatedAttribute.ml (186 lines of code) (raw):

(* * Copyright (c) Meta Platforms, Inc. and affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. *) open Core open Ast type read_only = | Refinable of { overridable: bool } | Unrefinable [@@deriving eq, show, compare, sexp] type visibility = | ReadOnly of read_only | ReadWrite [@@deriving eq, show, compare, sexp] type initialized = | OnClass | OnlyOnInstance | NotInitialized [@@deriving eq, show, compare, sexp] type invalid_decorator_reason = | CouldNotResolve | CouldNotResolveArgument of { argument_index: int } | NonCallableDecoratorFactory of Type.t | NonCallableDecorator of Type.t | FactorySignatureSelectionFailed of { reason: SignatureSelectionTypes.reason option; callable: Type.Callable.t; } | ApplicationFailed of { callable: Type.Callable.t; reason: SignatureSelectionTypes.reason option; } [@@deriving eq, show, compare, sexp] type problem = | DifferingDecorators of { offender: Type.t Type.Callable.overload } | InvalidDecorator of { index: int; reason: invalid_decorator_reason; } [@@deriving eq, show, compare, sexp] type 'a t = { payload: 'a; abstract: bool; async_property: bool; class_variable: bool; defined: bool; initialized: initialized; name: Identifier.t; parent: Type.Primitive.t; visibility: visibility; property: bool; undecorated_signature: Type.Callable.t option; problem: problem option; } [@@deriving eq, show, compare, sexp] type instantiated_annotation = { annotation: Type.t; original_annotation: Type.t; uninstantiated_annotation: Type.t option; } [@@deriving eq, show, compare, sexp] type instantiated = instantiated_annotation t [@@deriving eq, show, compare, sexp] let create ~abstract ~annotation ~original_annotation ~async_property ~class_variable ~defined ~initialized ~name ~parent ~visibility ~property ~uninstantiated_annotation ~undecorated_signature ~problem = { payload = { annotation; original_annotation; uninstantiated_annotation }; abstract; async_property; class_variable; defined; initialized; name; parent; visibility; property; undecorated_signature; problem; } let create_uninstantiated ~abstract ~uninstantiated_annotation ~async_property ~class_variable ~defined ~initialized ~name ~parent ~visibility ~property ~undecorated_signature ~problem = { payload = uninstantiated_annotation; abstract; async_property; class_variable; defined; initialized; name; parent; visibility; property; undecorated_signature; problem; } let annotation { payload = { annotation; original_annotation; _ }; async_property; defined; visibility; _ } = let annotation, original = if async_property then let coroutine annotation = Type.coroutine [Single Type.Any; Single Type.Any; Single annotation] in coroutine annotation, coroutine original_annotation else annotation, original_annotation in if defined then let final = match visibility with | ReadOnly _ -> true | ReadWrite -> false in Annotation.create_immutable ~original:(Some original) ~final annotation else (* We need to distinguish between unannotated attributes and non-existent ones - ensure that the annotation is viewed as mutable to distinguish from user-defined globals. *) Annotation.create_mutable annotation let uninstantiated_annotation { payload; _ } = payload let with_uninstantiated_annotation ~uninstantiated_annotation attribute = { attribute with payload = uninstantiated_annotation } let with_undecorated_signature attribute ~undecorated_signature = { attribute with undecorated_signature } let name { name; _ } = name let parent { parent; _ } = parent let parent_name { parent; _ } = let type_name = Type.primitive_name (Type.Primitive parent) in Option.value_exn type_name let parent_prefix attribute = parent_name attribute |> Reference.create |> Reference.last |> fun name -> "_" ^ name let initialized { initialized; _ } = initialized let defined { defined; _ } = defined let class_variable { class_variable; _ } = class_variable let abstract { abstract; _ } = abstract let async_property { async_property; _ } = async_property let static { payload = { uninstantiated_annotation; _ }; _ } = match uninstantiated_annotation with | Some (Type.Parametric { name = "typing.StaticMethod"; _ }) -> true | _ -> false let property { property; _ } = property let visibility { visibility; _ } = visibility let undecorated_signature { undecorated_signature; _ } = undecorated_signature let problem { problem; _ } = problem let is_private ({ name; _ } as attribute) = let parent_prefix = parent_prefix attribute in String.is_prefix ~prefix:(parent_prefix ^ "__") name let public_name ({ name; _ } as attribute) = let parent_prefix = parent_prefix attribute in if is_private attribute then String.drop_prefix name (String.length parent_prefix) else name let is_final { visibility; _ } = match visibility with | ReadOnly (Refinable _) -> true | _ -> false let instantiate attribute ~annotation ~original_annotation ~uninstantiated_annotation = { attribute with payload = { annotation; original_annotation; uninstantiated_annotation } } let with_initialized attribute ~initialized = { attribute with initialized }