Skip to content

Commit

Permalink
[annot] Make method names regex
Browse files Browse the repository at this point in the history
Summary: Treat method names as regular expressions to have more flexibility.

Reviewed By: rgrig

Differential Revision: D55746644

fbshipit-source-id: 2ec790bd6866db298af0c778fd95d55379622657
  • Loading branch information
hajduakos authored and facebook-github-bot committed Apr 5, 2024
1 parent 290298e commit 120badc
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 22 deletions.
37 changes: 21 additions & 16 deletions infer/src/checkers/annotationReachability.ml
Original file line number Diff line number Diff line change
Expand Up @@ -42,17 +42,23 @@ let is_allocator tenv pname =
false


type custom_model = {class_name: string; method_name: string; annotation: string}
[@@deriving compare, sexp, of_yojson]
type custom_model = {class_name: string; method_regex: string; annotation: string}
[@@deriving of_yojson]

type custom_models = custom_model list [@@deriving of_yojson]

module CustomModelSet = Set.Make (struct
type t = custom_model [@@deriving compare, sexp]
end)

let parse_custom_models () =
CustomModelSet.of_list (custom_models_of_yojson Config.annotation_reachability_custom_models)
let specs = custom_models_of_yojson Config.annotation_reachability_custom_models in
let process_one_spec models {class_name; method_regex; annotation} =
let method_regex = Str.regexp method_regex in
let add_method = Option.value_map ~default:[method_regex] ~f:(fun ms -> method_regex :: ms) in
let add_class =
Option.value_map ~default:(String.Map.singleton class_name [method_regex]) ~f:(fun cs ->
String.Map.update cs class_name ~f:add_method )
in
String.Map.update models annotation ~f:add_class
in
List.fold specs ~f:process_one_spec ~init:String.Map.empty


let check_attributes check tenv pname =
Expand All @@ -65,13 +71,12 @@ let method_overrides is_annotated tenv pname =


let check_modeled_annotation models annot pname =
let f class_name =
CustomModelSet.mem models
{ class_name= Typ.Name.name class_name
; method_name= Procname.get_method pname
; annotation= annot.Annot.class_name }
in
Option.exists ~f (Procname.get_class_type_name pname)
let method_name = Procname.get_method pname in
Option.both (Procname.get_class_type_name pname) (String.Map.find models annot.Annot.class_name)
|> Option.bind ~f:(fun (class_name, classes) ->
String.Map.find classes (Typ.Name.name class_name) )
|> Option.exists ~f:(fun methods ->
List.exists methods ~f:(fun r -> Str.string_match r method_name 0) )


let method_has_annot annot models tenv pname =
Expand Down Expand Up @@ -408,7 +413,7 @@ module NoAllocationAnnotationSpec = struct
; report=
(fun proc_data annot_map ->
report_src_snk_paths proc_data annot_map [no_allocation_annot] constructor_annot
CustomModelSet.empty ) }
String.Map.empty ) }
end

module ExpensiveAnnotationSpec = struct
Expand Down Expand Up @@ -452,7 +457,7 @@ module ExpensiveAnnotationSpec = struct
(check_expensive_subtyping_rules analysis_data)
tenv proc_name ;
report_src_snk_paths analysis_data astate [performance_critical_annot] expensive_annot
CustomModelSet.empty ) }
String.Map.empty ) }
end

type user_defined_spec =
Expand Down
22 changes: 16 additions & 6 deletions infer/tests/codetoanalyze/java/annotreach/.inferconfig
Original file line number Diff line number Diff line change
Expand Up @@ -31,32 +31,42 @@
[
{
"class_name": "codetoanalyze.java.checkers.CustomAnnotations",
"method_name": "sourceDefinedInConfigOk",
"method_regex": "sourceDefinedInConfigOk",
"annotation": "UserDefinedSource1"
},
{
"class_name": "codetoanalyze.java.checkers.CustomAnnotations",
"method_name": "sinkDefinedInConfig",
"method_regex": "sinkDefinedInConfig",
"annotation": "UserDefinedSink1"
},
{
"class_name": "codetoanalyze.java.checkers.CustomAnnotations",
"method_name": "sourceDefinedInConfigBad",
"method_regex": "sourceDefinedInConfigBad",
"annotation": "UserDefinedSource1"
},
{
"class_name": "codetoanalyze.java.checkers.CustomAnnotations",
"method_name": "sanitizerDefinedInConfig",
"method_regex": "sanitizerDefinedInConfig",
"annotation": "UserDefinedSanitizer"
},
{
"class_name": "codetoanalyze.java.checkers.CustomAnnotations$Base",
"method_name": "sourceDefinedInConfigBad",
"method_regex": "sourceDefinedInConfigBad",
"annotation": "UserDefinedSource1"
},
{
"class_name": "codetoanalyze.java.checkers.CustomAnnotations$Base",
"method_name": "sinkDefinedInConfig",
"method_regex": "sinkDefinedInConfig",
"annotation": "UserDefinedSink1"
},
{
"class_name": "codetoanalyze.java.checkers.CustomAnnotations",
"method_regex": "sourceDefinedInConfig.*WithRegex.*",
"annotation": "UserDefinedSource1"
},
{
"class_name": "codetoanalyze.java.checkers.CustomAnnotations",
"method_regex": "sinkDefinedInConfig.*WithRegex",
"annotation": "UserDefinedSink1"
}
]
Expand Down
16 changes: 16 additions & 0 deletions infer/tests/codetoanalyze/java/annotreach/CustomAnnotations.java
Original file line number Diff line number Diff line change
Expand Up @@ -170,4 +170,20 @@ void sourceDefinedInConfigBad() {
@Override
void sinkDefinedInConfig() {}
}

void sourceDefinedInConfig_1_WithRegexBad() {
sinkDefinedInConfig_1_WithRegex();
}

void sourceDefinedInConfig_2_WithRegexBad() {
sinkDefinedInConfig_2_WithRegex();
}

void sourceDefinedInConfig_3_WithRegexOk() {
safeMethod();
}

void sinkDefinedInConfig_1_WithRegex() {}

void sinkDefinedInConfig_2_WithRegex() {}
}
2 changes: 2 additions & 0 deletions infer/tests/codetoanalyze/java/annotreach/issues.exp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ codetoanalyze/java/annotreach/CustomAnnotations.java, codetoanalyze.java.checker
codetoanalyze/java/annotreach/CustomAnnotations.java, codetoanalyze.java.checkers.CustomAnnotations.sourceDefinedInConfigBad():void, 1, CHECKERS_ANNOTATION_REACHABILITY_ERROR, no_bucket, ERROR, []
codetoanalyze/java/annotreach/CustomAnnotations.java, codetoanalyze.java.checkers.CustomAnnotations$Derived.sourceBad():void, 1, CHECKERS_ANNOTATION_REACHABILITY_ERROR, no_bucket, ERROR, []
codetoanalyze/java/annotreach/CustomAnnotations.java, codetoanalyze.java.checkers.CustomAnnotations$Derived.sourceDefinedInConfigBad():void, 1, CHECKERS_ANNOTATION_REACHABILITY_ERROR, no_bucket, ERROR, []
codetoanalyze/java/annotreach/CustomAnnotations.java, codetoanalyze.java.checkers.CustomAnnotations.sourceDefinedInConfig_1_WithRegexBad():void, 1, CHECKERS_ANNOTATION_REACHABILITY_ERROR, no_bucket, ERROR, []
codetoanalyze/java/annotreach/CustomAnnotations.java, codetoanalyze.java.checkers.CustomAnnotations.sourceDefinedInConfig_2_WithRegexBad():void, 1, CHECKERS_ANNOTATION_REACHABILITY_ERROR, no_bucket, ERROR, []
codetoanalyze/java/annotreach/ExpensiveCallExample.java, codetoanalyze.java.checkers.PerformanceCriticalClass.performanceCriticalMethod1(codetoanalyze.java.checkers.ExpensiveClass):void, 1, CHECKERS_CALLS_EXPENSIVE_METHOD, no_bucket, ERROR, []
codetoanalyze/java/annotreach/ExpensiveCallExample.java, codetoanalyze.java.checkers.PerformanceCriticalClass.performanceCriticalMethod2(codetoanalyze.java.checkers.Other):void, 1, CHECKERS_CALLS_EXPENSIVE_METHOD, no_bucket, ERROR, []
codetoanalyze/java/annotreach/ExpensiveCallExample.java, codetoanalyze.java.checkers.PerformanceCriticalClass.performanceCriticalMethod3(codetoanalyze.java.checkers.Other):void, 1, CHECKERS_CALLS_EXPENSIVE_METHOD, no_bucket, ERROR, []
Expand Down

0 comments on commit 120badc

Please sign in to comment.