diff --git a/infer/src/concurrency/RacerDFileAnalysis.ml b/infer/src/concurrency/RacerDFileAnalysis.ml index beb672f56..7a4344a6c 100644 --- a/infer/src/concurrency/RacerDFileAnalysis.ml +++ b/infer/src/concurrency/RacerDFileAnalysis.ml @@ -29,9 +29,9 @@ let get_reporting_explanation_java ~nullsafe report_kind tenv pname thread = "@\n Reporting because current method is annotated %a or overrides an annotated method." MF.pp_monospaced "@ThreadSafe") else - match FbThreadSafety.get_fbthreadsafe_class_annot pname tenv with - | Some (qual, annot) -> - Some (FbThreadSafety.message_fbthreadsafe_class qual annot) + match RacerDModels.get_litho_explanation tenv pname with + | Some _ as expl_opt -> + expl_opt | None -> ( match get_current_class_and_threadsafe_superclasses tenv pname with | Some (current_class, (thread_safe_class :: _ as thread_safe_annotated_classes)) -> diff --git a/infer/src/concurrency/RacerDModels.ml b/infer/src/concurrency/RacerDModels.ml index 4f5a0bb89..0be755fd1 100644 --- a/infer/src/concurrency/RacerDModels.ml +++ b/infer/src/concurrency/RacerDModels.ml @@ -573,3 +573,59 @@ let is_synchronized_container callee_pname (access_exp : HilExp.AccessExpression let is_initializer tenv proc_name = Procname.is_constructor proc_name || FbThreadSafety.is_custom_init tenv proc_name + + +let get_current_class_and_superclasses_satisfying_attr_check check tenv pname = + match pname with + | Procname.Java java_pname -> + let current_class = Procname.Java.get_class_type_name java_pname in + let satisfying_classes = + PatternMatch.Java.find_superclasses_with_attributes check tenv current_class + in + Some (current_class, satisfying_classes) + | _ -> + None + + +module Litho = struct + let component_annots = ["MountSpec"; "LayoutSpec"] + + let section_annots = ["DiffSectionSpec"; "GroupSectionSpec"] + + let spec_annots = List.append component_annots section_annots + + let get_class_annot pname tenv = + let helper annot = + let is_annotated ia = Annotations.ia_ends_with ia annot in + match get_current_class_and_superclasses_satisfying_attr_check is_annotated tenv pname with + | Some (current_class, (_ :: _ as classes)) -> + if List.mem ~equal:Typ.Name.equal classes current_class then Some ("current ", annot) + else Some ("a super", annot) + | _ -> + None + in + List.find_map ~f:helper spec_annots + + + (* "ann" is typically a suffix of an annotation, so if ann is "LayoutSpec" the developer would have + written "@LayoutSpec". qualifier is " this " or "a super", the latter corresponding to + superclass. *) + let message (qualifier, ann) = + let mes1 = + if List.mem ~equal:String.equal component_annots ann then + "Litho components are required to be thread safe because of multi-threaded layout." + else if List.mem ~equal:String.equal section_annots ann then + "Sections are required to be thread safe because changesets are calculated in the \ + background." + else (*should not get here*) + "" + in + (* This "round the houses" way of doing things, where developer writes annotation with @, we pass + around annotation without @, then add it back here, is just because we use ia_ends_with and it + is not worth adding stuff to annotations.ml to make the code here simpler *) + Format.asprintf "@\n %s Reporting because %sclass is annotated %a" mes1 qualifier + MarkupFormatter.pp_monospaced ("@" ^ ann) +end + +let get_litho_explanation tenv pname = + Litho.get_class_annot pname tenv |> Option.map ~f:Litho.message diff --git a/infer/src/concurrency/RacerDModels.mli b/infer/src/concurrency/RacerDModels.mli index cb9820269..fde76f52c 100644 --- a/infer/src/concurrency/RacerDModels.mli +++ b/infer/src/concurrency/RacerDModels.mli @@ -60,3 +60,6 @@ val is_synchronized_container_constructor : Tenv.t -> Procname.t -> HilExp.t lis val is_converter_to_synchronized_container : Tenv.t -> Procname.t -> HilExp.t list -> bool (** is the given [procname] a method that wraps a container into a thread-safe wrapper? *) + +val get_litho_explanation : Tenv.t -> Procname.t -> string option +(** Get report explanation specific to Litho class methods, if applicable *) diff --git a/infer/src/opensource/FbThreadSafety.ml b/infer/src/opensource/FbThreadSafety.ml index 7e5e7af10..b64508641 100644 --- a/infer/src/opensource/FbThreadSafety.ml +++ b/infer/src/opensource/FbThreadSafety.ml @@ -8,7 +8,3 @@ let is_custom_init _ _ = false let is_logging_method _ = false - -let get_fbthreadsafe_class_annot _ _ = None - -let message_fbthreadsafe_class _ _ = "" diff --git a/infer/src/opensource/FbThreadSafety.mli b/infer/src/opensource/FbThreadSafety.mli index cf35766ec..7ee117695 100644 --- a/infer/src/opensource/FbThreadSafety.mli +++ b/infer/src/opensource/FbThreadSafety.mli @@ -8,7 +8,3 @@ val is_custom_init : 'tenv_t -> 'procname_t -> bool val is_logging_method : 'procname_t -> bool - -val get_fbthreadsafe_class_annot : 'procname_t -> 'tenv_t -> (string * string) option - -val message_fbthreadsafe_class : string -> string -> string