From 48da570aa05ed4a7362d71e81f080c224d6d5497 Mon Sep 17 00:00:00 2001 From: Dulma Churchill Date: Fri, 29 Nov 2019 02:40:38 -0800 Subject: [PATCH] [AL] Introduce a way of binding the two witnesses of an AND formula Summary: New syntax f1 AND-WITH-WITNESSES f2 : predicate_on_both_witnesses() This is needed for a linter to check that a macro is present, see the test. Reviewed By: skcho Differential Revision: D18735988 fbshipit-source-id: a3be75c5e --- infer/src/al/ALIssues.ml | 49 +++++++++------ infer/src/al/CPredicatesOnTwoNodes.ml | 27 +++++++++ .../al/CPredicatesOnTwoNodes.mli} | 12 ++-- infer/src/al/CTL.ml | 60 +++++++++++++++---- infer/src/al/CTL.mli | 3 +- infer/src/al/CTLTypes.ml | 18 +++++- infer/src/al/CTLTypes.mli | 1 + infer/src/al/ctl_lexer.mll | 2 + infer/src/al/ctl_parser.mly | 5 ++ .../al_definitions/linters_example.al | 24 +++++++- .../linters-for-test-only/cat_macro_example.m | 24 ++++++++ .../objc/linters-for-test-only/issues.exp | 16 ++++- .../linters-for-test-only/sibling_example.m | 29 +++++++++ 13 files changed, 228 insertions(+), 42 deletions(-) create mode 100644 infer/src/al/CPredicatesOnTwoNodes.ml rename infer/{tests/codetoanalyze/objc/linters-for-test-only/al_definitions/sibling_example.m => src/al/CPredicatesOnTwoNodes.mli} (59%) create mode 100644 infer/tests/codetoanalyze/objc/linters-for-test-only/cat_macro_example.m create mode 100644 infer/tests/codetoanalyze/objc/linters-for-test-only/sibling_example.m diff --git a/infer/src/al/ALIssues.ml b/infer/src/al/ALIssues.ml index 1c3f01f80..d683f5baf 100644 --- a/infer/src/al/ALIssues.ml +++ b/infer/src/al/ALIssues.ml @@ -287,6 +287,9 @@ let rec apply_substitution f sub = Not (apply_substitution f1 sub) | And (f1, f2) -> And (apply_substitution f1 sub, apply_substitution f2 sub) + | AndWithWitnesses (f1, f2, (name, ps)) -> + AndWithWitnesses + (apply_substitution f1 sub, apply_substitution f2 sub, (name, sub_list_param ps)) | Or (f1, f2) -> Or (apply_substitution f1 sub, apply_substitution f2 sub) | Implies (f1, f2) -> @@ -323,32 +326,40 @@ let expand_formula phi map_ error_msg_ = in let open CTLTypes in let rec expand acc map error_msg = + let expand_predicate av actual_param = + match av with + | ALVar.Formula_id name -> ( + (* it may be a macro *) + let error_msg' = error_msg ^ " -Expanding formula identifier '" ^ name ^ "'@\n" in + try + match ALVar.FormulaIdMap.find av map with + | true, _, _ -> + fail_with_circular_macro_definition name error_msg' + | false, fparams, f1 -> ( + (* in this case it should be a defined macro *) + match List.zip fparams actual_param with + | Ok sub -> + let f1_sub = apply_substitution f1 sub in + let map' = ALVar.FormulaIdMap.add av (true, fparams, f1) map in + expand f1_sub map' error_msg' + | Unequal_lengths -> + L.(die ExternalError) + "Formula identifier '%s' is not called with the right number of parameters" name + ) + with Caml.Not_found -> acc ) + (* in this case it should be a predicate *) + in match acc with | True | False -> acc - | Atomic ((ALVar.Formula_id name as av), actual_param) -> ( - (* it may be a macro *) - let error_msg' = error_msg ^ " -Expanding formula identifier '" ^ name ^ "'@\n" in - try - match ALVar.FormulaIdMap.find av map with - | true, _, _ -> - fail_with_circular_macro_definition name error_msg' - | false, fparams, f1 -> ( - (* in this case it should be a defined macro *) - match List.zip fparams actual_param with - | Ok sub -> - let f1_sub = apply_substitution f1 sub in - let map' = ALVar.FormulaIdMap.add av (true, fparams, f1) map in - expand f1_sub map' error_msg' - | Unequal_lengths -> - L.(die ExternalError) - "Formula identifier '%s' is not called with the right number of parameters" name ) - with Caml.Not_found -> acc - (* in this case it should be a predicate *) ) + | Atomic (av, actual_param) -> + expand_predicate av actual_param | Not f1 -> Not (expand f1 map error_msg) | And (f1, f2) -> And (expand f1 map error_msg, expand f2 map error_msg) + | AndWithWitnesses (f1, f2, pred) -> + AndWithWitnesses (expand f1 map error_msg, expand f2 map error_msg, pred) | Or (f1, f2) -> Or (expand f1 map error_msg, expand f2 map error_msg) | Implies (f1, f2) -> diff --git a/infer/src/al/CPredicatesOnTwoNodes.ml b/infer/src/al/CPredicatesOnTwoNodes.ml new file mode 100644 index 000000000..bea63a9e6 --- /dev/null +++ b/infer/src/al/CPredicatesOnTwoNodes.ml @@ -0,0 +1,27 @@ +(* + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + *) + +open! IStd + +let decl_name_is_contained_in_name_of_decl (node1 : Ctl_parser_types.ast_node) + (node2 : Ctl_parser_types.ast_node) = + let get_name decl = + match Clang_ast_proj.get_named_decl_tuple decl with + | Some (_, ndi) -> + Some ndi.ni_name + | None -> + None + in + match (node1, node2) with + | Decl decl1, Decl decl2 -> ( + match (get_name decl1, get_name decl2) with + | Some name1, Some name2 -> + String.is_substring name2 ~substring:name1 + | _ -> + false ) + | _ -> + false diff --git a/infer/tests/codetoanalyze/objc/linters-for-test-only/al_definitions/sibling_example.m b/infer/src/al/CPredicatesOnTwoNodes.mli similarity index 59% rename from infer/tests/codetoanalyze/objc/linters-for-test-only/al_definitions/sibling_example.m rename to infer/src/al/CPredicatesOnTwoNodes.mli index 8d9f755c5..2afeb7d02 100644 --- a/infer/tests/codetoanalyze/objc/linters-for-test-only/al_definitions/sibling_example.m +++ b/infer/src/al/CPredicatesOnTwoNodes.mli @@ -1,13 +1,11 @@ -/* +(* * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. - */ -#import + *) -int x; +open! IStd -@interface SiblingExample : NSObject - -@end +val decl_name_is_contained_in_name_of_decl : + Ctl_parser_types.ast_node -> Ctl_parser_types.ast_node -> bool diff --git a/infer/src/al/CTL.ml b/infer/src/al/CTL.ml index 799dca930..cd6a5cd32 100644 --- a/infer/src/al/CTL.ml +++ b/infer/src/al/CTL.ml @@ -513,7 +513,7 @@ let choose_witness_opt witness_opt1 witness_opt2 = (* Evaluation of formulas *) (* evaluate an atomic formula (i.e. a predicate) on a ast node an and a linter context lcxt. That is: an, lcxt |= pred_name(params) *) -let rec eval_Atomic pred_name_ args an lcxt = +let eval_Atomic pred_name_ args an lcxt = let pred_name = ALVar.formula_id_to_string pred_name_ in match (pred_name, args, an) with | "call_class_method", [m], an -> @@ -758,10 +758,44 @@ let rec eval_Atomic pred_name_ args an lcxt = L.(die ExternalError) "Undefined Predicate or wrong set of arguments: '%s'" pred_name -and eval_AND an lcxt f1 f2 = +let eval_Atomic_with_witness pred_name_ args witness1 witness2 _ = + let pred_name = ALVar.formula_id_to_string pred_name_ in + match (pred_name, args) with + | "decl_name_is_contained_in_name_of_decl", [] -> + CPredicatesOnTwoNodes.decl_name_is_contained_in_name_of_decl witness1 witness2 + | _ -> + L.(die ExternalError) "Undefined Predicate or wrong set of arguments: '%s'" pred_name + + +let rec eval_AndWithW an lcxt f1 f2 = match eval_formula f1 an lcxt with | Some witness1 -> ( - match eval_formula f2 an lcxt with + match eval_formula ~keep_witness:true f2 an lcxt with + | Some witness2 -> + Some (witness1, witness2) + | _ -> + None ) + | None (* we short-circuit the AND evaluation *) -> + None + + +and eval_AndWithWitnesses an lcxt f1 f2 pred_name_ args = + match eval_AndWithW an lcxt f1 f2 with + | Some (witness1, witness2) -> ( + try if eval_Atomic_with_witness pred_name_ args witness1 witness2 lcxt then Some an else None + with CFrontend_errors.IncorrectAssumption e -> + let trans_unit_ctx = lcxt.CLintersContext.translation_unit_context in + ClangLogging.log_caught_exception trans_unit_ctx "IncorrectAssumption" e.position + e.source_range e.ast_node ; + None ) + | None -> + None + + +and eval_AND ?keep_witness an lcxt f1 f2 = + match eval_formula ?keep_witness f1 an lcxt with + | Some witness1 -> ( + match eval_formula ?keep_witness f2 an lcxt with | Some witness2 -> Some (choose_one_witness witness1 witness2) | _ -> @@ -806,7 +840,7 @@ and eval_EF phi an lcxt trans = there exists is a child an' of the node an such that (an', lcxt) satifies phi *) -and eval_EX phi an lcxt trans = +and eval_EX ?(keep_witness = false) phi an lcxt trans = let succs = match trans with | Some l -> @@ -818,11 +852,13 @@ and eval_EX phi an lcxt trans = List.fold_left succs ~init:None ~f:(fun acc node -> choose_witness_opt (eval_formula phi node lcxt) acc ) in - match (witness_opt, trans) with - | Some _, Some trans when not (CTLTypes.is_transition_to_successor trans) -> - Some an (* We want to limit the witnesses to the successors of the original node. *) - | _ -> - witness_opt + if keep_witness then witness_opt + else + match (witness_opt, trans) with + | Some _, Some trans when not (CTLTypes.is_transition_to_successor trans) -> + Some an (* We want to limit the witnesses to the successors of the original node. *) + | _ -> + witness_opt (* an, lcxt |= E(phi1 U phi2) evaluated using the equivalence @@ -917,7 +953,7 @@ and eval_InObjCClass an lcxt f1 f2 = (* Formulas are evaluated on a AST node an and a linter context lcxt *) -and eval_formula f an lcxt : Ctl_parser_types.ast_node option = +and eval_formula ?keep_witness f an lcxt : Ctl_parser_types.ast_node option = let open CTLTypes in debug_eval_begin (debug_create_payload an f lcxt) ; let res = @@ -939,6 +975,8 @@ and eval_formula f an lcxt : Ctl_parser_types.ast_node option = match eval_formula f1 an lcxt with Some _ -> None | None -> Some an ) | And (f1, f2) -> eval_AND an lcxt f1 f2 + | AndWithWitnesses (f1, f2, (name, params)) -> + eval_AndWithWitnesses an lcxt f1 f2 name params | Or (f1, f2) -> eval_OR an lcxt f1 f2 | Implies (f1, f2) -> @@ -954,7 +992,7 @@ and eval_formula f an lcxt : Ctl_parser_types.ast_node option = | AG (trans, f1) -> eval_formula (Not (EF (trans, Not f1))) an lcxt | EX (trans, f1) -> - eval_EX f1 an lcxt trans + eval_EX ?keep_witness f1 an lcxt trans | AX (trans, f1) -> eval_formula (Not (EX (trans, Not f1))) an lcxt | EH (cl, phi) -> diff --git a/infer/src/al/CTL.mli b/infer/src/al/CTL.mli index 09d0e6c02..443528a44 100644 --- a/infer/src/al/CTL.mli +++ b/infer/src/al/CTL.mli @@ -48,7 +48,8 @@ type al_file = val print_checker : ctl_checker -> unit val eval_formula : - CTLTypes.t + ?keep_witness:bool + -> CTLTypes.t -> Ctl_parser_types.ast_node -> CLintersContext.context -> Ctl_parser_types.ast_node option diff --git a/infer/src/al/CTLTypes.ml b/infer/src/al/CTLTypes.ml index 695f43db6..dcce61dcd 100644 --- a/infer/src/al/CTLTypes.ml +++ b/infer/src/al/CTLTypes.ml @@ -53,6 +53,7 @@ type t = | Atomic of CPredicates.t | Not of t | And of t * t + | AndWithWitnesses of t * t * CPredicates.t | Or of t * t | Implies of t * t | InNode of ALVar.alexp list * t @@ -73,7 +74,17 @@ let equal = [%compare.equal: t] let has_transition phi = match phi with - | True | False | Atomic _ | Not _ | And _ | Or _ | Implies _ | InNode _ | EH _ | InObjCClass _ -> + | True + | False + | Atomic _ + | Not _ + | And _ + | Or _ + | Implies _ + | InNode _ + | EH _ + | InObjCClass _ + | AndWithWitnesses _ -> false | AX (trans_opt, _) | AF (trans_opt, _) @@ -140,6 +151,11 @@ let rec pp_formula fmt phi = | And (phi1, phi2) -> if full_print then Format.fprintf fmt "(%a AND %a)" pp_formula phi1 pp_formula phi2 else Format.pp_print_string fmt "(... AND ...)" + | AndWithWitnesses (phi1, phi2, p) -> + if full_print then + Format.fprintf fmt "(%a AndWithWitnesses %a : %a)" pp_formula phi1 pp_formula phi2 + CPredicates.pp_predicate p + else Format.pp_print_string fmt "(... AndWithWitnesses ...)" | Or (phi1, phi2) -> if full_print then Format.fprintf fmt "(%a OR %a)" pp_formula phi1 pp_formula phi2 else Format.pp_print_string fmt "(... OR ...)" diff --git a/infer/src/al/CTLTypes.mli b/infer/src/al/CTLTypes.mli index fd9e64ae9..382bcb132 100644 --- a/infer/src/al/CTLTypes.mli +++ b/infer/src/al/CTLTypes.mli @@ -34,6 +34,7 @@ type t = | Atomic of CPredicates.t (** Atomic formula *) | Not of t | And of t * t + | AndWithWitnesses of t * t * CPredicates.t | Or of t * t | Implies of t * t | InNode of ALVar.alexp list * t diff --git a/infer/src/al/ctl_lexer.mll b/infer/src/al/ctl_lexer.mll index b53ee6e2a..fca2eab6d 100644 --- a/infer/src/al/ctl_lexer.mll +++ b/infer/src/al/ctl_lexer.mll @@ -63,10 +63,12 @@ rule token = parse | ")" { RIGHT_PAREN } | "=" { ASSIGNMENT } | ";" { SEMICOLON } + | ":" { COLON } | "," { COMMA } | "[" { LEFT_SQBRACE } | "]" { RIGHT_SQBRACE } | "AND" { AND } + | "AND-WITH-WITNESSES" {AND_WITH_WITNESSES} | "OR" { OR } | "NOT" { NOT } | "IMPLIES" { IMPLIES } diff --git a/infer/src/al/ctl_parser.mly b/infer/src/al/ctl_parser.mly index e21a5fb2b..6fe11a70d 100644 --- a/infer/src/al/ctl_parser.mly +++ b/infer/src/al/ctl_parser.mly @@ -64,9 +64,11 @@ %token ASSIGNMENT %token SEMICOLON %token COMMA +%token COLON %token LEFT_SQBRACE %token RIGHT_SQBRACE %token AND +%token AND_WITH_WITNESSES %token OR %token NOT %token IMPLIES @@ -308,6 +310,9 @@ formula: "\tParsed AX with transition '%a'@\n" CTLTypes.pp_transition $3; CTLTypes.AX ($3, $4)} | formula AND formula { L.(debug Linters Verbose) "\tParsed AND@\n"; CTLTypes.And ($1, $3) } + | formula AND_WITH_WITNESSES formula COLON identifier LEFT_PAREN actual_params RIGHT_PAREN + { L.(debug Linters Verbose) "\tParsed predicate@\n"; + CTLTypes.AndWithWitnesses ($1, $3, (ALVar.Formula_id $5, $7)) } | formula OR formula { L.(debug Linters Verbose) "\tParsed OR@\n"; CTLTypes.Or ($1, $3) } | formula IMPLIES formula { L.(debug Linters Verbose) "\tParsed IMPLIES@\n"; CTLTypes.Implies ($1, $3) } diff --git a/infer/tests/codetoanalyze/objc/linters-for-test-only/al_definitions/linters_example.al b/infer/tests/codetoanalyze/objc/linters-for-test-only/al_definitions/linters_example.al index 14bc94989..8b2097bb4 100644 --- a/infer/tests/codetoanalyze/objc/linters-for-test-only/al_definitions/linters_example.al +++ b/infer/tests/codetoanalyze/objc/linters-for-test-only/al_definitions/linters_example.al @@ -907,8 +907,30 @@ DEFINE-CHECKER CLASS_AND_VAR = { (global_var_exists())); SET report_when = - WHEN var_decl() AND declaration_has_name("SiblingExample") + WHEN (var_decl() AND declaration_has_name("SiblingExample")) HOLDS-IN-NODE ObjCInterfaceDecl; SET message = "Found a global var next to a class"; +}; + +DEFINE-CHECKER CAT_DECL_MACRO = { + + LET is_linkable_var = + is_extern_var() AND + declaration_has_name(REGEXP("Linkable_.*")) AND + has_type("char"); + + LET var_decls = + HOLDS-NEXT WITH-TRANSITION Sibling + (is_node("VarDecl") AND is_linkable_var()); + + SET report_when = + WHEN + NOT ( + is_node("ObjCCategoryDecl") + AND-WITH-WITNESSES var_decls() : decl_name_is_contained_in_name_of_decl() + ) + HOLDS-IN-NODE ObjCCategoryDecl; + + SET message = "A category is defined without the corrsponding macro"; }; \ No newline at end of file diff --git a/infer/tests/codetoanalyze/objc/linters-for-test-only/cat_macro_example.m b/infer/tests/codetoanalyze/objc/linters-for-test-only/cat_macro_example.m new file mode 100644 index 000000000..ee33e3e77 --- /dev/null +++ b/infer/tests/codetoanalyze/objc/linters-for-test-only/cat_macro_example.m @@ -0,0 +1,24 @@ +/* + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ +#import + +int x; + +@interface SiblingExample + +@end + +#define LINK_REQUIRE(NAME) \ + extern char Linkable_##NAME; \ + extern const void* const OS_WEAK OS_CONCAT(Link_, NAME); \ + OS_USED const void* const OS_WEAK OS_CONCAT(Link_, NAME) = &Linkable_##NAME; + +LINK_REQUIRE(SiblingExample_Cat2); +@interface SiblingExample (Cat2) +- (void)foo:(int)themeProvider; + +@end diff --git a/infer/tests/codetoanalyze/objc/linters-for-test-only/issues.exp b/infer/tests/codetoanalyze/objc/linters-for-test-only/issues.exp index a0269aa7f..c5d2e5b86 100644 --- a/infer/tests/codetoanalyze/objc/linters-for-test-only/issues.exp +++ b/infer/tests/codetoanalyze/objc/linters-for-test-only/issues.exp @@ -16,10 +16,12 @@ codetoanalyze/objc/linters-for-test-only/CallingAMethodWithSelf.m, CallingAMetho codetoanalyze/objc/linters-for-test-only/CallingAMethodWithSelf.m, CallingAMethodWithSelfBase::testView, 15, TEST_VAR_TYPE_CHECK, no_bucket, WARNING, [] codetoanalyze/objc/linters-for-test-only/GenericTestClass.m, Linters_dummy_method, 12, TEST_IF_IS_PROTOCOL_NAMED, no_bucket, WARNING, [] codetoanalyze/objc/linters-for-test-only/GenericTestClass.m, Linters_dummy_method, 19, TEST_IF_IS_CLASS_NAMED, no_bucket, WARNING, [] +codetoanalyze/objc/linters-for-test-only/GenericTestClass.m, Linters_dummy_method, 29, CAT_DECL_MACRO, no_bucket, WARNING, [] codetoanalyze/objc/linters-for-test-only/GenericTestClass.m, Linters_dummy_method, 29, TEST_IF_IS_CATEGORY_INTERFACE_ON_CLASS_NAMED, no_bucket, WARNING, [] codetoanalyze/objc/linters-for-test-only/GenericTestClass.m, Linters_dummy_method, 29, TEST_IF_IS_CATEGORY_ON_CLASS_NAMED, no_bucket, WARNING, [] codetoanalyze/objc/linters-for-test-only/GenericTestClass.m, Linters_dummy_method, 35, TEST_IF_IS_CLASS_NAMED, no_bucket, WARNING, [] codetoanalyze/objc/linters-for-test-only/GenericTestClass.m, Linters_dummy_method, 35, TEST_IF_IS_IMPLEMENTATION_NAMED, no_bucket, WARNING, [] +codetoanalyze/objc/linters-for-test-only/GenericTestClass.m, Linters_dummy_method, 76, CAT_DECL_MACRO, no_bucket, WARNING, [] codetoanalyze/objc/linters-for-test-only/GenericTestClass.m, Linters_dummy_method, 76, TEST_IF_IS_CATEGORY_INTERFACE_NAMED, no_bucket, WARNING, [] codetoanalyze/objc/linters-for-test-only/GenericTestClass.m, Linters_dummy_method, 76, TEST_IF_IS_CATEGORY_INTERFACE_ON_CLASS_NAMED, no_bucket, WARNING, [] codetoanalyze/objc/linters-for-test-only/GenericTestClass.m, Linters_dummy_method, 76, TEST_IF_IS_CATEGORY_NAMED, no_bucket, WARNING, [] @@ -28,6 +30,7 @@ codetoanalyze/objc/linters-for-test-only/GenericTestClass.m, Linters_dummy_metho codetoanalyze/objc/linters-for-test-only/GenericTestClass.m, Linters_dummy_method, 82, TEST_IF_IS_CATEGORY_IMPLEMENTATION_ON_CLASS_NAMED, no_bucket, WARNING, [] codetoanalyze/objc/linters-for-test-only/GenericTestClass.m, Linters_dummy_method, 82, TEST_IF_IS_CATEGORY_NAMED, no_bucket, WARNING, [] codetoanalyze/objc/linters-for-test-only/GenericTestClass.m, Linters_dummy_method, 82, TEST_IF_IS_CATEGORY_ON_CLASS_NAMED, no_bucket, WARNING, [] +codetoanalyze/objc/linters-for-test-only/GenericTestClass.m, Linters_dummy_method, 183, CAT_DECL_MACRO, no_bucket, WARNING, [] codetoanalyze/objc/linters-for-test-only/GenericTestClass.m, Linters_dummy_method, 183, TEST_IF_IS_CATEGORY_INTERFACE_ON_SUBCLASS_OF, no_bucket, WARNING, [] codetoanalyze/objc/linters-for-test-only/GenericTestClass.m, Linters_dummy_method, 183, TEST_IF_IS_CATEGORY_ON_SUBCLASS_OF, no_bucket, WARNING, [] codetoanalyze/objc/linters-for-test-only/GenericTestClass.m, Linters_dummy_method, 189, TEST_IF_IS_CATEGORY_IMPLEMENTATION_ON_SUBCLASS_OF, no_bucket, WARNING, [] @@ -227,8 +230,10 @@ codetoanalyze/objc/linters-for-test-only/PrivateInstanceMethod.m, UselessClass:: codetoanalyze/objc/linters-for-test-only/PrivateInstanceMethod.m, UselessClass::b, 11, TEST_RETURN_METHOD, no_bucket, WARNING, [] codetoanalyze/objc/linters-for-test-only/PrivateInstanceMethod.m, UselessClass::b, 18, TEST_IS_METHOD_EXPOSED, no_bucket, WARNING, [] codetoanalyze/objc/linters-for-test-only/PrivateInstanceMethod.m, UselessClass::b, 18, TEST_RETURN_METHOD, no_bucket, WARNING, [] -codetoanalyze/objc/linters-for-test-only/al_definitions/sibling_example.m, Linters_dummy_method, 9, TEST_VAR_TYPE_CHECK, no_bucket, WARNING, [] -codetoanalyze/objc/linters-for-test-only/al_definitions/sibling_example.m, Linters_dummy_method, 11, CLASS_AND_VAR, no_bucket, WARNING, [] +codetoanalyze/objc/linters-for-test-only/cat_macro_example.m, Linters_dummy_method, 9, TEST_VAR_TYPE_CHECK, no_bucket, WARNING, [] +codetoanalyze/objc/linters-for-test-only/cat_macro_example.m, Linters_dummy_method, 11, CLASS_AND_VAR, no_bucket, WARNING, [] +codetoanalyze/objc/linters-for-test-only/cat_macro_example.m, Linters_dummy_method, 20, CONST_NAMING, no_bucket, WARNING, [] +codetoanalyze/objc/linters-for-test-only/cat_macro_example.m, SiblingExample::foo, 22, TEST_PARAM_TYPE_CHECK2, no_bucket, WARNING, [] codetoanalyze/objc/linters-for-test-only/const.m, Linters_dummy_method, 7, CONST_NAMING, no_bucket, WARNING, [] codetoanalyze/objc/linters-for-test-only/const.m, Linters_dummy_method, 7, TEST_VAR_TYPE_CHECK, no_bucket, WARNING, [] codetoanalyze/objc/linters-for-test-only/const.m, Linters_dummy_method, 8, CONST_NAMING, no_bucket, WARNING, [] @@ -274,6 +279,13 @@ codetoanalyze/objc/linters-for-test-only/protocols.m, Linters_dummy_method, 12, codetoanalyze/objc/linters-for-test-only/protocols.m, Linters_dummy_method, 15, TEST_PROTOCOL_DEF_INHERITANCE, no_bucket, WARNING, [] codetoanalyze/objc/linters-for-test-only/sel.m, fooButtonComponent::newWithAction, 10, TEST_INSTANCE_TYPE, no_bucket, WARNING, [] codetoanalyze/objc/linters-for-test-only/sel.m, fooButtonComponent::newWithAction, 10, TEST_PARAMETER_SEL_TYPE, no_bucket, WARNING, [] +codetoanalyze/objc/linters-for-test-only/sibling_example.m, Linters_dummy_method, 9, TEST_VAR_TYPE_CHECK, no_bucket, WARNING, [] +codetoanalyze/objc/linters-for-test-only/sibling_example.m, Linters_dummy_method, 11, CLASS_AND_VAR, no_bucket, WARNING, [] +codetoanalyze/objc/linters-for-test-only/sibling_example.m, Linters_dummy_method, 20, CAT_DECL_MACRO, no_bucket, WARNING, [] +codetoanalyze/objc/linters-for-test-only/sibling_example.m, Linters_dummy_method, 25, CONST_NAMING, no_bucket, WARNING, [] +codetoanalyze/objc/linters-for-test-only/sibling_example.m, Linters_dummy_method, 26, CAT_DECL_MACRO, no_bucket, WARNING, [] +codetoanalyze/objc/linters-for-test-only/sibling_example.m, SiblingExample::foo, 21, TEST_PARAM_TYPE_CHECK2, no_bucket, WARNING, [] +codetoanalyze/objc/linters-for-test-only/sibling_example.m, SiblingExample::foo, 27, TEST_PARAM_TYPE_CHECK2, no_bucket, WARNING, [] codetoanalyze/objc/linters-for-test-only/subclassing.m, A::foo, 11, TEST_PARAM_TYPE_CHECK2, no_bucket, WARNING, [] codetoanalyze/objc/linters-for-test-only/subclassing.m, A::foo, 11, TEST_RETURN_METHOD, no_bucket, WARNING, [] codetoanalyze/objc/linters-for-test-only/subclassing.m, A::foo, 17, TEST_IS_METHOD_EXPOSED, no_bucket, WARNING, [] diff --git a/infer/tests/codetoanalyze/objc/linters-for-test-only/sibling_example.m b/infer/tests/codetoanalyze/objc/linters-for-test-only/sibling_example.m new file mode 100644 index 000000000..d6d65dbd6 --- /dev/null +++ b/infer/tests/codetoanalyze/objc/linters-for-test-only/sibling_example.m @@ -0,0 +1,29 @@ +/* + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ +#import + +int x; + +@interface SiblingExample + +@end + +#define LINK_REQUIRE(NAME) \ + extern char Linkable_##NAME; \ + extern const void* const OS_WEAK OS_CONCAT(Link_, NAME); \ + OS_USED const void* const OS_WEAK OS_CONCAT(Link_, NAME) = &Linkable_##NAME; + +@interface SiblingExample (Cat1) +- (void)foo:(int)themeProvider; + +@end + +LINK_REQUIRE(SiblingExampl); +@interface SiblingExample (Cat2) +- (void)foo:(int)themeProvider; + +@end