From 7cef8ae3b503b609dd4cd0ebe545c41b00f9c9bd Mon Sep 17 00:00:00 2001 From: Dino Distefano Date: Fri, 7 Apr 2017 06:58:05 -0700 Subject: [PATCH] Making AL distinguish class methods from instance methods Reviewed By: dulmarod Differential Revision: D4826401 fbshipit-source-id: 97c2570 --- infer/lib/linter_rules/linters.al | 42 +++++------ infer/src/clang/ALVar.ml | 2 + infer/src/clang/ALVar.mli | 1 + infer/src/clang/cFrontend_checkers_main.ml | 7 +- infer/src/clang/cFrontend_errors.ml | 6 +- infer/src/clang/cPredicates.ml | 55 ++++++++++---- infer/src/clang/cPredicates.mli | 4 ++ infer/src/clang/cTL.ml | 10 ++- infer/src/clang/ctl_lexer.mll | 1 + infer/src/clang/ctl_parser.mly | 72 +++++++++++-------- infer/src/clang/ctl_parser_types.ml | 2 + .../objc/linters-for-test-only/issues.exp | 1 + .../linters-for-test-only/linters_example.al | 28 +++++--- 13 files changed, 151 insertions(+), 80 deletions(-) diff --git a/infer/lib/linter_rules/linters.al b/infer/lib/linter_rules/linters.al index 7711d9c42..38ec963ec 100644 --- a/infer/lib/linter_rules/linters.al +++ b/infer/lib/linter_rules/linters.al @@ -40,14 +40,14 @@ DEFINE-CHECKER ASSIGN_POINTER_WARNING = { // Fires whenever a NSNumber is dangerously coerced to a boolean in a comparison DEFINE-CHECKER BAD_POINTER_COMPARISON = { - LET is_binop = is_node(BinaryOperator); - LET is_binop_eq = is_binop_with_kind(EQ); - LET is_binop_ne = is_binop_with_kind(NE); + LET is_binop = is_node("BinaryOperator"); + LET is_binop_eq = is_binop_with_kind("EQ"); + LET is_binop_ne = is_binop_with_kind("NE"); LET is_binop_neq = is_binop_eq OR is_binop_ne; - LET is_unop_lnot = is_unop_with_kind(LNot); - LET is_implicit_cast_expr = is_node(ImplicitCastExpr); - LET is_expr_with_cleanups = is_node(ExprWithCleanups); - LET is_nsnumber = isa(NSNumber); + LET is_unop_lnot = is_unop_with_kind("LNot"); + LET is_implicit_cast_expr = is_node("ImplicitCastExpr"); + LET is_expr_with_cleanups = is_node("ExprWithCleanups"); + LET is_nsnumber = isa("NSNumber"); LET eu =( (NOT is_binop_neq) @@ -81,10 +81,10 @@ DEFINE-CHECKER BAD_POINTER_COMPARISON = { DEFINE-CHECKER REGISTERED_OBSERVER_BEING_DEALLOCATED = { LET exists_method_calling_addObserver = - call_method_strict(addObserver:selector:name:object:) HOLDS-EVENTUALLY; + call_method_strict("addObserver:selector:name:object:") HOLDS-EVENTUALLY; LET exists_method_calling_addObserverForName = - call_method_strict(addObserverForName:object:queue:usingBlock:) HOLDS-EVENTUALLY; + call_method_strict("addObserverForName:object:queue:usingBlock:") HOLDS-EVENTUALLY; LET add_observer = exists_method_calling_addObserver OR exists_method_calling_addObserverForName; @@ -95,10 +95,10 @@ DEFINE-CHECKER REGISTERED_OBSERVER_BEING_DEALLOCATED = { HOLDS-EVENTUALLY; LET exists_method_calling_removeObserver = - call_method_strict(removeObserver:) HOLDS-EVENTUALLY; + call_method_strict("removeObserver:") HOLDS-EVENTUALLY; LET exists_method_calling_removeObserverName = - call_method_strict(removeObserver:name:object:) HOLDS-EVENTUALLY; + call_method_strict("removeObserver:name:object:") HOLDS-EVENTUALLY; LET remove_observer = exists_method_calling_removeObserver OR exists_method_calling_removeObserverName; @@ -137,9 +137,11 @@ DEFINE-CHECKER REGISTERED_OBSERVER_BEING_DEALLOCATED = { DEFINE-CHECKER STRONG_DELEGATE_WARNING = { - LET name_contains_delegate = property_name_contains_word(delegate); - LET name_does_not_contain_delegates = NOT property_name_contains_word(delegates); - LET name_does_not_contains_queue = NOT property_name_contains_word(queue); + LET name_contains_delegate = property_name_contains_word(REGEXP("[dD]elegate")); + LET name_does_not_contain_delegates = + NOT property_name_contains_word(REGEXP("[dD]elegates")); + LET name_does_not_contains_queue = + NOT property_name_contains_word(REGEXP("[qQ]ueue")); SET report_when = WHEN @@ -157,11 +159,11 @@ DEFINE-CHECKER GLOBAL_VARIABLE_INITIALIZED_WITH_FUNCTION_OR_METHOD_CALL = { is_objc_extension() AND is_global_var() AND (NOT is_const_var()); LET makes_an_expensive_call = - (is_node(CallExpr) AND NOT call_function_named(CGPointMake)) - OR is_node(CXXTemporaryObjectExpr) - OR is_node(CXXMemberCallExpr) - OR is_node(CXXOperatorCallExpr) - OR is_node(ObjCMessageExpr); + (is_node("CallExpr") AND NOT call_function_named("CGPointMake")) + OR is_node("CXXTemporaryObjectExpr") + OR is_node("CXXMemberCallExpr") + OR is_node("CXXOperatorCallExpr") + OR is_node("ObjCMessageExpr"); LET is_initialized_with_expensive_call = IN-NODE VarDecl WITH-TRANSITION InitExpr @@ -183,7 +185,7 @@ DEFINE-CHECKER GLOBAL_VARIABLE_INITIALIZED_WITH_FUNCTION_OR_METHOD_CALL = { DEFINE-CHECKER CXX_REFERENCE_CAPTURED_IN_OBJC_BLOCK = { SET report_when = WHEN - ((is_node(BlockDecl) AND captures_cxx_references()) + ((is_node("BlockDecl") AND captures_cxx_references()) HOLDS-NEXT) HOLDS-IN-NODE BlockExpr; diff --git a/infer/src/clang/ALVar.ml b/infer/src/clang/ALVar.ml index 9b54e4f80..987bdb610 100644 --- a/infer/src/clang/ALVar.ml +++ b/infer/src/clang/ALVar.ml @@ -20,6 +20,7 @@ type formula_id = Formula_id of string[@@deriving compare] type alexp = | Const of string + | Regexp of string | Var of string | FId of formula_id [@@deriving compare] @@ -35,6 +36,7 @@ let formula_id_to_string fid = let alexp_to_string e = match e with | Const s + | Regexp s | Var s | FId (Formula_id s) -> s diff --git a/infer/src/clang/ALVar.mli b/infer/src/clang/ALVar.mli index c3140ecbe..283c107a0 100644 --- a/infer/src/clang/ALVar.mli +++ b/infer/src/clang/ALVar.mli @@ -19,6 +19,7 @@ type formula_id = Formula_id of string type alexp = | Const of string + | Regexp of string | Var of string | FId of formula_id diff --git a/infer/src/clang/cFrontend_checkers_main.ml b/infer/src/clang/cFrontend_checkers_main.ml index f2ad1d45e..f93162cee 100644 --- a/infer/src/clang/cFrontend_checkers_main.ml +++ b/infer/src/clang/cFrontend_checkers_main.ml @@ -11,8 +11,6 @@ open! IStd open Lexing open Ctl_lexer -exception ALParsingException of string - let parse_al_file fname channel : CTL.al_file option = let pos_str lexbuf = let pos = lexbuf.lex_curr_p in @@ -20,9 +18,12 @@ let parse_al_file fname channel : CTL.al_file option = (string_of_int (pos.pos_cnum - pos.pos_bol + 1)) in let parse_with_error lexbuf = try Some (Ctl_parser.al_file token lexbuf) with + | Ctl_parser_types.ALParsingException s -> + raise (Ctl_parser_types.ALParsingException + (s ^ " at " ^ (pos_str lexbuf))) | SyntaxError _ | Ctl_parser.Error -> - raise (ALParsingException ( "SYNTAX ERROR at " ^ (pos_str lexbuf))) in + raise (Ctl_parser_types.ALParsingException ( "SYNTAX ERROR at " ^ (pos_str lexbuf))) in let lexbuf = Lexing.from_channel channel in lexbuf.lex_curr_p <- { lexbuf.lex_curr_p with pos_fname = fname }; parse_with_error lexbuf diff --git a/infer/src/clang/cFrontend_errors.ml b/infer/src/clang/cFrontend_errors.ml index af857e490..e74fddfce 100644 --- a/infer/src/clang/cFrontend_errors.ml +++ b/infer/src/clang/cFrontend_errors.ml @@ -145,10 +145,12 @@ let check_def_well_expanded vars expanded_formula = let open CTL in let check_const c = match c with + | ALVar.Regexp c | ALVar.Const c when List.mem vars (ALVar.Var c) -> - failwith ("[ERROR]: Const '" ^ c ^ + failwith ("[ERROR]: Const/Regexp '" ^ c ^ "' is used as formal parameter of some LET definition.") - | ALVar.Const _ -> () + | ALVar.Const _ + | ALVar.Regexp _ -> () | ALVar.Var v | ALVar.FId (Formula_id v) -> failwith ("[ERROR]: Variable '" ^ v ^ diff --git a/infer/src/clang/cPredicates.ml b/infer/src/clang/cPredicates.ml index f9fac8e91..b63617965 100644 --- a/infer/src/clang/cPredicates.ml +++ b/infer/src/clang/cPredicates.ml @@ -56,14 +56,13 @@ let captured_variables_cxx_ref an = List.fold ~f:capture_var_is_cxx_ref ~init:[] bdi.bdi_captured_variables | _ -> [] - - - type t = ALVar.formula_id * ALVar.alexp list(* (name, [param1,...,paramK]) *) -(* true if and only if string contained occurs in container *) -let str_contains container contained = - let rexp = Str.regexp_string_case_fold contained in +(* true if and only if a substring of container matches the regular + expression defined by contained +*) +let str_match_regex container contained = + let rexp = Str.regexp contained in try Str.search_forward rexp container 0 >= 0 with Not_found -> false @@ -88,7 +87,7 @@ let is_objc_interface_named_strict an expected_name = (* is an objc interface with name expected_name *) let is_objc_interface_named an expected_name = - _is_objc_interface_named (str_contains) an expected_name + _is_objc_interface_named (str_match_regex) an expected_name let _is_object_of_class_named comp receiver cname = let open Clang_ast_t in @@ -121,9 +120,35 @@ let call_method_strict an m = (* an |= call_method(m) where we check is the name contains m *) let call_method an m = - _call_method (str_contains) an m + _call_method (str_match_regex) an m + +let is_receiver_kind_class comp omei cname = + let open Clang_ast_t in + match omei.omei_receiver_kind with + | `Class ptr -> + (match CAst_utils.get_desugared_type ptr with + | Some ObjCInterfaceType (_, ptr) -> + (match CAst_utils.get_decl ptr with + | Some ObjCInterfaceDecl (_, ndi, _, _, _) -> + comp ndi.ni_name cname + | _ -> false) + | _ -> false) + | _ -> false let _call_class_method comp an cname mname = + match an with + | Ctl_parser_types.Stmt (Clang_ast_t.ObjCMessageExpr (_, _, _, omei)) -> + is_receiver_kind_class comp omei cname && + comp omei.omei_selector mname + | _ -> false + +let call_class_method_strict an cname mname = + _call_class_method (String.equal) an cname mname + +let call_class_method an cname mname = + _call_class_method (str_match_regex) an cname mname + +let _call_instance_method comp an cname mname = match an with | Ctl_parser_types.Stmt (Clang_ast_t.ObjCMessageExpr (_, receiver :: _, _, omei)) -> is_object_of_class_named receiver cname && @@ -133,20 +158,20 @@ let _call_class_method comp an cname mname = (* an is a node calling method mname of class cname. The equality is strict. *) -let call_class_method_strict an cname mname = - _call_class_method (String.equal) an cname mname +let call_instance_method_strict an cname mname = + _call_instance_method (String.equal) an cname mname (* an is a node calling method whose name contains mname of a class whose name contains cname. *) -let call_class_method an cname mname = - _call_class_method (str_contains) an cname mname +let call_instance_method an cname mname = + _call_instance_method (str_match_regex) an cname mname let property_name_contains_word word an = match an with | Ctl_parser_types.Decl decl -> (match Clang_ast_proj.get_named_decl_tuple decl with - | Some (_, n) -> str_contains n.Clang_ast_t.ni_name word + | Some (_, n) -> str_match_regex n.Clang_ast_t.ni_name word | _ -> false) | _ -> false @@ -309,7 +334,7 @@ let _declaration_has_name comp an name = (* an is a declaration whose name contains a regexp defined by re *) let declaration_has_name an re = - _declaration_has_name (str_contains) an re + _declaration_has_name (str_match_regex) an re (* an is a declaration called precisely name *) let declaration_has_name_strict an name = @@ -323,7 +348,7 @@ let _is_class comp an re = | _ -> false let is_class an re = - _is_class (str_contains) an re + _is_class (str_match_regex) an re let is_class_strict an name = _is_class (String.equal) an name diff --git a/infer/src/clang/cPredicates.mli b/infer/src/clang/cPredicates.mli index 4ef229caa..d53773440 100644 --- a/infer/src/clang/cPredicates.mli +++ b/infer/src/clang/cPredicates.mli @@ -21,6 +21,10 @@ val call_class_method : Ctl_parser_types.ast_node -> string -> string -> bool val call_class_method_strict : Ctl_parser_types.ast_node -> string -> string -> bool +val call_instance_method : Ctl_parser_types.ast_node -> string -> string -> bool + +val call_instance_method_strict : Ctl_parser_types.ast_node -> string -> string -> bool + val is_objc_interface_named_strict : Ctl_parser_types.ast_node -> string -> bool val is_objc_interface_named : Ctl_parser_types.ast_node -> string -> bool diff --git a/infer/src/clang/cTL.ml b/infer/src/clang/cTL.ml index 58847c99c..865bd810c 100644 --- a/infer/src/clang/cTL.ml +++ b/infer/src/clang/cTL.ml @@ -576,9 +576,14 @@ let rec eval_Atomic _pred_name _args an lcxt = match pred_name, args, an with | "call_method", [m], an -> CPredicates.call_method an m | "call_method_strict", [m], an -> CPredicates.call_method_strict an m - | "call_class_method", [c; m], an -> CPredicates.call_class_method an c m + | "call_class_method", [c; m], an -> + CPredicates.call_class_method an c m | "call_class_method_strict", [c; m], an -> CPredicates.call_class_method_strict an c m + | "call_instance_method", [c; m], an -> + CPredicates.call_instance_method an c m + | "call_instance_method_strict", [c; m], an -> + CPredicates.call_instance_method_strict an c m | "is_objc_interface_named", [name], an -> CPredicates.is_objc_interface_named an name | "is_objc_interface_named_strict", [name], an -> @@ -617,7 +622,8 @@ let rec eval_Atomic _pred_name _args an lcxt = | "within_responds_to_selector_block", [], an -> CPredicates.within_responds_to_selector_block lcxt an | _ -> failwith - ("ERROR: Undefined Predicate or wrong set of arguments: " ^ pred_name) + ("\nERROR: Undefined Predicate or wrong set of arguments: '" + ^ pred_name ^ "'\n") (* an, lcxt |= EF phi <=> an, lcxt |= phi or exists an' in Successors(st): an', lcxt |= EF phi diff --git a/infer/src/clang/ctl_lexer.mll b/infer/src/clang/ctl_lexer.mll index 3e8f996d9..46f3ad9d8 100644 --- a/infer/src/clang/ctl_lexer.mll +++ b/infer/src/clang/ctl_lexer.mll @@ -65,6 +65,7 @@ rule token = parse | "OR" { OR } | "NOT" { NOT } | "IMPLIES" { IMPLIES } + | "REGEXP" { REGEXP } | id { IDENTIFIER (Lexing.lexeme lexbuf) } | file_id { FILE_IDENTIFIER (Lexing.lexeme lexbuf) } | '"' { read_string (Buffer.create 80) lexbuf } diff --git a/infer/src/clang/ctl_parser.mly b/infer/src/clang/ctl_parser.mly index 74b15d26f..4cbc4522d 100644 --- a/infer/src/clang/ctl_parser.mly +++ b/infer/src/clang/ctl_parser.mly @@ -8,14 +8,22 @@ */ %{ + let formal_params : (ALVar.t list) ref = ref [] let is_not_infer_reserved_id id = if Str.string_match (Str.regexp_string Ctl_parser_types.infer_prefix) id 0 then - failwith - ("ERROR: " ^ id ^ " contains __infer_ctl_ that is a reserved keyword " - ^ "which cannot be used in identifiers.") - else id + raise (Ctl_parser_types.ALParsingException + ("ERROR: " ^ id ^ " contains __infer_ctl_ that is a reserved keyword " + ^ "which cannot be used in identifiers:")) + else () + + let is_defined_identifier id = + if (List.mem (ALVar.Var id) !formal_params) then + Logging.out "\tParsed exp '%s' as variable" id + else + raise (Ctl_parser_types.ALParsingException + ("ERROR: Variable '" ^ id ^ "' is undefined")) %} @@ -53,6 +61,7 @@ %token OR %token NOT %token IMPLIES +%token REGEXP %token IDENTIFIER %token FILE_IDENTIFIER %token STRING @@ -73,6 +82,11 @@ var_list: | identifier COMMA var_list { ALVar.Var($1) :: $3 } ; +node_list: + | identifier { [ALVar.Const $1] } + | identifier COMMA node_list { ALVar.Const($1) :: $3 } +; + formal_params: | var_list { formal_params := $1; $1} @@ -85,12 +99,13 @@ al_file: import_files: | { [] } | HASHIMPORT LESS_THAN file_identifier GREATER_THAN import_files - { $3 :: $5 } + { Logging.out "Parsed import clauses...\n\n"; $3 :: $5 } ; global_macros: | { [] } - | GLOBAL_MACROS LEFT_BRACE let_clause_list RIGHT_BRACE SEMICOLON { $3 } + | GLOBAL_MACROS LEFT_BRACE let_clause_list RIGHT_BRACE SEMICOLON + { Logging.out "Parsed global macro definitions...\n\n"; $3 } ; checkers_list: @@ -101,7 +116,7 @@ checkers_list: checker: DEFINE_CHECKER identifier ASSIGNMENT LEFT_BRACE clause_list RIGHT_BRACE { - Logging.out "\nParsed checker definition"; + Logging.out "\nParsed checker definition\n"; let c = { CTL.name = $2; CTL.definitions = $5 } in CTL.print_checker c; c @@ -168,20 +183,8 @@ atomic_formula: actual_params: | {[]} - | identifier { if (List.mem (ALVar.Var $1) !formal_params) then - (Logging.out "\tParsed exp '%s' as variable \n" $1; - [ALVar.Var $1]) - else - (Logging.out "\tParsed exp '%s' as constant \n" $1; - [ALVar.Const $1]) - } - | identifier COMMA actual_params { - (if (List.mem (ALVar.Var $1) !formal_params) then - (Logging.out "\tParsed exp '%s' as variable \n" $1; - ALVar.Var $1) - else (Logging.out "\tParsed exp '%s' as constant \n" $1; - ALVar.Const $1) - ) :: $3 } + | alexp { [$1] } + | alexp COMMA actual_params { $1 :: $3 } ; transition_label: @@ -212,13 +215,13 @@ formula: | formula AX { Logging.out "\tParsed AX\n"; CTL.AX ($1) } | formula EG { Logging.out "\tParsed EG\n"; CTL.EG (None, $1) } | formula AG { Logging.out "\tParsed AG\n"; CTL.AG ($1) } - | formula EH actual_params { Logging.out "\tParsed EH\n"; CTL.EH ($3, $1) } + | formula EH node_list { Logging.out "\tParsed EH\n"; CTL.EH ($3, $1) } | formula EF { Logging.out "\tParsed EF\n"; CTL.EF (None, $1) } - | WHEN formula HOLDS_IN_NODE actual_params + | WHEN formula HOLDS_IN_NODE node_list { Logging.out "\tParsed InNode\n"; CTL.InNode ($4, $2)} - | ET actual_params WITH_TRANSITION transition_label formula_EF + | ET node_list WITH_TRANSITION transition_label formula_EF { Logging.out "\tParsed ET\n"; CTL.ET ($2, $4, $5)} - | ETX actual_params WITH_TRANSITION transition_label formula_EF + | ETX node_list WITH_TRANSITION transition_label formula_EF { Logging.out "\tParsed ETX\n"; CTL.ETX ($2, $4, $5)} | EX WITH_TRANSITION transition_label formula_with_paren { Logging.out "\tParsed EX\n"; CTL.EX ($3, $4)} @@ -228,11 +231,24 @@ formula: | NOT formula { Logging.out "\tParsed NOT\n"; CTL.Not ($2) } ; -identifier: - | IDENTIFIER { is_not_infer_reserved_id $1 } + +alexp: + | STRING { is_not_infer_reserved_id $1; + Logging.out "\tParsed string constant '%s' \n" $1; + ALVar.Const $1 } + | REGEXP LEFT_PAREN STRING RIGHT_PAREN + { Logging.out "\tParsed regular expression '%s' \n" $3; + ALVar.Regexp $3 } + | identifier { is_defined_identifier $1; ALVar.Var $1 } ; + identifier: + | IDENTIFIER { is_not_infer_reserved_id $1; + Logging.out "\tParsed identifier '%s' \n" $1; $1 } + ; + file_identifier: - | FILE_IDENTIFIER { is_not_infer_reserved_id $1 } + | FILE_IDENTIFIER { is_not_infer_reserved_id $1; + Logging.out "\tParsed file identifier '%s' \n" $1; $1 } ; %% diff --git a/infer/src/clang/ctl_parser_types.ml b/infer/src/clang/ctl_parser_types.ml index cef4792f3..fbb988830 100644 --- a/infer/src/clang/ctl_parser_types.ml +++ b/infer/src/clang/ctl_parser_types.ml @@ -24,3 +24,5 @@ let message_const = "message" let suggestion_const = "suggestion" let severity_const = "severity" let mode_const = "mode" + +exception ALParsingException of string 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 e80e37df4..1c2461d65 100644 --- a/infer/tests/codetoanalyze/objc/linters-for-test-only/issues.exp +++ b/infer/tests/codetoanalyze/objc/linters-for-test-only/issues.exp @@ -1,3 +1,4 @@ +codetoanalyze/objc/linters-for-test-only/subclassing.m, B_bar, 35, TEST_ALL_METHODS, [] codetoanalyze/objc/linters-for-test-only/subclassing.m, B_bar, 36, MACRO_TEST1, [] codetoanalyze/objc/linters-for-test-only/subclassing.m, B_bar, 36, MACRO_TEST2, [] codetoanalyze/objc/linters-for-test-only/subclassing.m, B_bar, 36, MACRO_TEST3, [] diff --git a/infer/tests/codetoanalyze/objc/linters-for-test-only/linters_example.al b/infer/tests/codetoanalyze/objc/linters-for-test-only/linters_example.al index 1d2e9804f..b307f609c 100644 --- a/infer/tests/codetoanalyze/objc/linters-for-test-only/linters_example.al +++ b/infer/tests/codetoanalyze/objc/linters-for-test-only/linters_example.al @@ -3,7 +3,7 @@ GLOBAL-MACROS { LET global_is_subclass_of(x) = - is_class(x) HOLDS-IN-SOME-SUPERCLASS-OF ObjCInterfaceDecl; + is_class(x) HOLDS-IN-SOME-SUPERCLASS-OF ObjCInterfaceDecl; }; @@ -12,7 +12,7 @@ GLOBAL-MACROS { DEFINE-CHECKER SUBCLASSING_TEST_EXAMPLE = { SET report_when = - is_class(A) HOLDS-IN-SOME-SUPERCLASS-OF ObjCInterfaceDecl; + is_class("A") HOLDS-IN-SOME-SUPERCLASS-OF ObjCInterfaceDecl; SET message = "This is subclassing A. Class A should not be subclassed."; @@ -22,7 +22,7 @@ DEFINE-CHECKER MACRO_TEST1 = { LET call_two_methods(x,y) = call_method(x) OR call_method(y); - SET report_when = call_two_methods(foo, bar); + SET report_when = call_two_methods("foo", "bar"); SET message = "Error message here"; @@ -31,9 +31,9 @@ DEFINE-CHECKER MACRO_TEST1 = { // Test reverse parameter of macro DEFINE-CHECKER MACRO_TEST2 = { - LET my_macro_to_call_method_of_class(x,y) = call_class_method(y,x); + LET my_macro_to_call_method_of_class(x,y) = call_instance_method(y,x); - SET report_when = my_macro_to_call_method_of_class(foo, A); + SET report_when = my_macro_to_call_method_of_class("foo", "A"); SET message = "Error message here"; @@ -42,11 +42,11 @@ DEFINE-CHECKER MACRO_TEST2 = { // Test macro call macro DEFINE-CHECKER MACRO_TEST3 = { - LET my_macro_to_call_method_of_class(x,y) = call_class_method(y,x); + LET my_macro_to_call_method_of_class(x,y) = call_instance_method(y,x); LET call_my_macro(t,v) = my_macro_to_call_method_of_class(t,v); - SET report_when = call_my_macro(foo, A); + SET report_when = call_my_macro("foo", "A"); SET message = "Error message here"; @@ -57,7 +57,7 @@ DEFINE-CHECKER LOCAL_MACRO_SUBCLASS = { LET is_subclass_of(x) = is_class(x) HOLDS-IN-SOME-SUPERCLASS-OF ObjCInterfaceDecl; - SET report_when = is_subclass_of(A); + SET report_when = is_subclass_of("A"); SET message = "This is subclassing A. Class A should not be subclassed."; @@ -65,7 +65,7 @@ DEFINE-CHECKER LOCAL_MACRO_SUBCLASS = { DEFINE-CHECKER GLOBAL_MACRO_SUBCLASS = { - SET report_when = global_is_subclass_of(A); + SET report_when = global_is_subclass_of("A"); SET message = "This is subclassing A. Class A should not be subclassed."; @@ -73,8 +73,16 @@ DEFINE-CHECKER GLOBAL_MACRO_SUBCLASS = { DEFINE-CHECKER IMPORTED_MACRO_SUBCLASS = { - SET report_when = imported_is_subclass_of(A); + SET report_when = imported_is_subclass_of("A"); SET message = "This is subclassing A. Class A should not be subclassed."; }; + +DEFINE-CHECKER TEST_ALL_METHODS = { + + SET report_when = call_class_method(REGEXP(".*"), REGEXP(".*")); + + SET message = "Method call..."; + +};