Making AL distinguish class methods from instance methods

Reviewed By: dulmarod

Differential Revision: D4826401

fbshipit-source-id: 97c2570
master
Dino Distefano 8 years ago committed by Facebook Github Bot
parent 6b9a37f5cd
commit 7cef8ae3b5

@ -40,14 +40,14 @@ DEFINE-CHECKER ASSIGN_POINTER_WARNING = {
// Fires whenever a NSNumber is dangerously coerced to a boolean in a comparison // Fires whenever a NSNumber is dangerously coerced to a boolean in a comparison
DEFINE-CHECKER BAD_POINTER_COMPARISON = { DEFINE-CHECKER BAD_POINTER_COMPARISON = {
LET is_binop = is_node(BinaryOperator); LET is_binop = is_node("BinaryOperator");
LET is_binop_eq = is_binop_with_kind(EQ); LET is_binop_eq = is_binop_with_kind("EQ");
LET is_binop_ne = is_binop_with_kind(NE); LET is_binop_ne = is_binop_with_kind("NE");
LET is_binop_neq = is_binop_eq OR is_binop_ne; LET is_binop_neq = is_binop_eq OR is_binop_ne;
LET is_unop_lnot = is_unop_with_kind(LNot); LET is_unop_lnot = is_unop_with_kind("LNot");
LET is_implicit_cast_expr = is_node(ImplicitCastExpr); LET is_implicit_cast_expr = is_node("ImplicitCastExpr");
LET is_expr_with_cleanups = is_node(ExprWithCleanups); LET is_expr_with_cleanups = is_node("ExprWithCleanups");
LET is_nsnumber = isa(NSNumber); LET is_nsnumber = isa("NSNumber");
LET eu =( LET eu =(
(NOT is_binop_neq) (NOT is_binop_neq)
@ -81,10 +81,10 @@ DEFINE-CHECKER BAD_POINTER_COMPARISON = {
DEFINE-CHECKER REGISTERED_OBSERVER_BEING_DEALLOCATED = { DEFINE-CHECKER REGISTERED_OBSERVER_BEING_DEALLOCATED = {
LET exists_method_calling_addObserver = 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 = 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 = LET add_observer =
exists_method_calling_addObserver OR exists_method_calling_addObserverForName; exists_method_calling_addObserver OR exists_method_calling_addObserverForName;
@ -95,10 +95,10 @@ DEFINE-CHECKER REGISTERED_OBSERVER_BEING_DEALLOCATED = {
HOLDS-EVENTUALLY; HOLDS-EVENTUALLY;
LET exists_method_calling_removeObserver = LET exists_method_calling_removeObserver =
call_method_strict(removeObserver:) HOLDS-EVENTUALLY; call_method_strict("removeObserver:") HOLDS-EVENTUALLY;
LET exists_method_calling_removeObserverName = LET exists_method_calling_removeObserverName =
call_method_strict(removeObserver:name:object:) HOLDS-EVENTUALLY; call_method_strict("removeObserver:name:object:") HOLDS-EVENTUALLY;
LET remove_observer = LET remove_observer =
exists_method_calling_removeObserver OR exists_method_calling_removeObserverName; exists_method_calling_removeObserver OR exists_method_calling_removeObserverName;
@ -137,9 +137,11 @@ DEFINE-CHECKER REGISTERED_OBSERVER_BEING_DEALLOCATED = {
DEFINE-CHECKER STRONG_DELEGATE_WARNING = { DEFINE-CHECKER STRONG_DELEGATE_WARNING = {
LET name_contains_delegate = property_name_contains_word(delegate); LET name_contains_delegate = property_name_contains_word(REGEXP("[dD]elegate"));
LET name_does_not_contain_delegates = NOT property_name_contains_word(delegates); LET name_does_not_contain_delegates =
LET name_does_not_contains_queue = NOT property_name_contains_word(queue); 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 = SET report_when =
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()); is_objc_extension() AND is_global_var() AND (NOT is_const_var());
LET makes_an_expensive_call = LET makes_an_expensive_call =
(is_node(CallExpr) AND NOT call_function_named(CGPointMake)) (is_node("CallExpr") AND NOT call_function_named("CGPointMake"))
OR is_node(CXXTemporaryObjectExpr) OR is_node("CXXTemporaryObjectExpr")
OR is_node(CXXMemberCallExpr) OR is_node("CXXMemberCallExpr")
OR is_node(CXXOperatorCallExpr) OR is_node("CXXOperatorCallExpr")
OR is_node(ObjCMessageExpr); OR is_node("ObjCMessageExpr");
LET is_initialized_with_expensive_call = LET is_initialized_with_expensive_call =
IN-NODE VarDecl WITH-TRANSITION InitExpr 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 = { DEFINE-CHECKER CXX_REFERENCE_CAPTURED_IN_OBJC_BLOCK = {
SET report_when = SET report_when =
WHEN WHEN
((is_node(BlockDecl) AND captures_cxx_references()) ((is_node("BlockDecl") AND captures_cxx_references())
HOLDS-NEXT) HOLDS-NEXT)
HOLDS-IN-NODE BlockExpr; HOLDS-IN-NODE BlockExpr;

@ -20,6 +20,7 @@ type formula_id = Formula_id of string[@@deriving compare]
type alexp = type alexp =
| Const of string | Const of string
| Regexp of string
| Var of string | Var of string
| FId of formula_id | FId of formula_id
[@@deriving compare] [@@deriving compare]
@ -35,6 +36,7 @@ let formula_id_to_string fid =
let alexp_to_string e = let alexp_to_string e =
match e with match e with
| Const s | Const s
| Regexp s
| Var s | Var s
| FId (Formula_id s) -> s | FId (Formula_id s) -> s

@ -19,6 +19,7 @@ type formula_id = Formula_id of string
type alexp = type alexp =
| Const of string | Const of string
| Regexp of string
| Var of string | Var of string
| FId of formula_id | FId of formula_id

@ -11,8 +11,6 @@ open! IStd
open Lexing open Lexing
open Ctl_lexer open Ctl_lexer
exception ALParsingException of string
let parse_al_file fname channel : CTL.al_file option = let parse_al_file fname channel : CTL.al_file option =
let pos_str lexbuf = let pos_str lexbuf =
let pos = lexbuf.lex_curr_p in 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 (string_of_int (pos.pos_cnum - pos.pos_bol + 1)) in
let parse_with_error lexbuf = let parse_with_error lexbuf =
try Some (Ctl_parser.al_file token lexbuf) with 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 _ | SyntaxError _
| Ctl_parser.Error -> | 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 let lexbuf = Lexing.from_channel channel in
lexbuf.lex_curr_p <- { lexbuf.lex_curr_p with pos_fname = fname }; lexbuf.lex_curr_p <- { lexbuf.lex_curr_p with pos_fname = fname };
parse_with_error lexbuf parse_with_error lexbuf

@ -145,10 +145,12 @@ let check_def_well_expanded vars expanded_formula =
let open CTL in let open CTL in
let check_const c = let check_const c =
match c with match c with
| ALVar.Regexp c
| ALVar.Const c when List.mem vars (ALVar.Var 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.") "' is used as formal parameter of some LET definition.")
| ALVar.Const _ -> () | ALVar.Const _
| ALVar.Regexp _ -> ()
| ALVar.Var v | ALVar.Var v
| ALVar.FId (Formula_id v) -> | ALVar.FId (Formula_id v) ->
failwith ("[ERROR]: Variable '" ^ v ^ failwith ("[ERROR]: Variable '" ^ v ^

@ -56,14 +56,13 @@ let captured_variables_cxx_ref an =
List.fold ~f:capture_var_is_cxx_ref ~init:[] bdi.bdi_captured_variables List.fold ~f:capture_var_is_cxx_ref ~init:[] bdi.bdi_captured_variables
| _ -> [] | _ -> []
type t = ALVar.formula_id * ALVar.alexp list(* (name, [param1,...,paramK]) *) type t = ALVar.formula_id * ALVar.alexp list(* (name, [param1,...,paramK]) *)
(* true if and only if string contained occurs in container *) (* true if and only if a substring of container matches the regular
let str_contains container contained = expression defined by contained
let rexp = Str.regexp_string_case_fold contained in *)
let str_match_regex container contained =
let rexp = Str.regexp contained in
try try
Str.search_forward rexp container 0 >= 0 Str.search_forward rexp container 0 >= 0
with Not_found -> false 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 *) (* is an objc interface with name expected_name *)
let is_objc_interface_named an 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 _is_object_of_class_named comp receiver cname =
let open Clang_ast_t in 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 *) (* an |= call_method(m) where we check is the name contains m *)
let call_method an 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 = 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 match an with
| Ctl_parser_types.Stmt (Clang_ast_t.ObjCMessageExpr (_, receiver :: _, _, omei)) -> | Ctl_parser_types.Stmt (Clang_ast_t.ObjCMessageExpr (_, receiver :: _, _, omei)) ->
is_object_of_class_named receiver cname && 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. (* an is a node calling method mname of class cname.
The equality is strict. The equality is strict.
*) *)
let call_class_method_strict an cname mname = let call_instance_method_strict an cname mname =
_call_class_method (String.equal) an cname mname _call_instance_method (String.equal) an cname mname
(* an is a node calling method whose name contains mname of a (* an is a node calling method whose name contains mname of a
class whose name contains cname. class whose name contains cname.
*) *)
let call_class_method an cname mname = let call_instance_method an cname mname =
_call_class_method (str_contains) an cname mname _call_instance_method (str_match_regex) an cname mname
let property_name_contains_word word an = let property_name_contains_word word an =
match an with match an with
| Ctl_parser_types.Decl decl -> | Ctl_parser_types.Decl decl ->
(match Clang_ast_proj.get_named_decl_tuple decl with (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)
| _ -> 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 *) (* an is a declaration whose name contains a regexp defined by re *)
let declaration_has_name an 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 *) (* an is a declaration called precisely name *)
let declaration_has_name_strict an name = let declaration_has_name_strict an name =
@ -323,7 +348,7 @@ let _is_class comp an re =
| _ -> false | _ -> false
let is_class an re = let is_class an re =
_is_class (str_contains) an re _is_class (str_match_regex) an re
let is_class_strict an name = let is_class_strict an name =
_is_class (String.equal) an name _is_class (String.equal) an name

@ -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_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_strict : Ctl_parser_types.ast_node -> string -> bool
val is_objc_interface_named : Ctl_parser_types.ast_node -> string -> bool val is_objc_interface_named : Ctl_parser_types.ast_node -> string -> bool

@ -576,9 +576,14 @@ let rec eval_Atomic _pred_name _args an lcxt =
match pred_name, args, an with match pred_name, args, an with
| "call_method", [m], an -> CPredicates.call_method an m | "call_method", [m], an -> CPredicates.call_method an m
| "call_method_strict", [m], an -> CPredicates.call_method_strict 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 -> | "call_class_method_strict", [c; m], an ->
CPredicates.call_class_method_strict an c m 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 -> | "is_objc_interface_named", [name], an ->
CPredicates.is_objc_interface_named an name CPredicates.is_objc_interface_named an name
| "is_objc_interface_named_strict", [name], an -> | "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 -> | "within_responds_to_selector_block", [], an ->
CPredicates.within_responds_to_selector_block lcxt an CPredicates.within_responds_to_selector_block lcxt an
| _ -> failwith | _ -> 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 |= EF phi <=>
an, lcxt |= phi or exists an' in Successors(st): an', lcxt |= EF phi an, lcxt |= phi or exists an' in Successors(st): an', lcxt |= EF phi

@ -65,6 +65,7 @@ rule token = parse
| "OR" { OR } | "OR" { OR }
| "NOT" { NOT } | "NOT" { NOT }
| "IMPLIES" { IMPLIES } | "IMPLIES" { IMPLIES }
| "REGEXP" { REGEXP }
| id { IDENTIFIER (Lexing.lexeme lexbuf) } | id { IDENTIFIER (Lexing.lexeme lexbuf) }
| file_id { FILE_IDENTIFIER (Lexing.lexeme lexbuf) } | file_id { FILE_IDENTIFIER (Lexing.lexeme lexbuf) }
| '"' { read_string (Buffer.create 80) lexbuf } | '"' { read_string (Buffer.create 80) lexbuf }

@ -8,14 +8,22 @@
*/ */
%{ %{
let formal_params : (ALVar.t list) ref = ref [] let formal_params : (ALVar.t list) ref = ref []
let is_not_infer_reserved_id id = let is_not_infer_reserved_id id =
if Str.string_match (Str.regexp_string Ctl_parser_types.infer_prefix) id 0 then if Str.string_match (Str.regexp_string Ctl_parser_types.infer_prefix) id 0 then
failwith raise (Ctl_parser_types.ALParsingException
("ERROR: " ^ id ^ " contains __infer_ctl_ that is a reserved keyword " ("ERROR: " ^ id ^ " contains __infer_ctl_ that is a reserved keyword "
^ "which cannot be used in identifiers.") ^ "which cannot be used in identifiers:"))
else id 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 OR
%token NOT %token NOT
%token IMPLIES %token IMPLIES
%token REGEXP
%token <string> IDENTIFIER %token <string> IDENTIFIER
%token <string> FILE_IDENTIFIER %token <string> FILE_IDENTIFIER
%token <string> STRING %token <string> STRING
@ -73,6 +82,11 @@ var_list:
| identifier COMMA var_list { ALVar.Var($1) :: $3 } | identifier COMMA var_list { ALVar.Var($1) :: $3 }
; ;
node_list:
| identifier { [ALVar.Const $1] }
| identifier COMMA node_list { ALVar.Const($1) :: $3 }
;
formal_params: formal_params:
| var_list { formal_params := $1; $1} | var_list { formal_params := $1; $1}
@ -85,12 +99,13 @@ al_file:
import_files: import_files:
| { [] } | { [] }
| HASHIMPORT LESS_THAN file_identifier GREATER_THAN 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:
| { [] } | { [] }
| 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: checkers_list:
@ -101,7 +116,7 @@ checkers_list:
checker: checker:
DEFINE_CHECKER identifier ASSIGNMENT LEFT_BRACE clause_list RIGHT_BRACE 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 let c = { CTL.name = $2; CTL.definitions = $5 } in
CTL.print_checker c; CTL.print_checker c;
c c
@ -168,20 +183,8 @@ atomic_formula:
actual_params: actual_params:
| {[]} | {[]}
| identifier { if (List.mem (ALVar.Var $1) !formal_params) then | alexp { [$1] }
(Logging.out "\tParsed exp '%s' as variable \n" $1; | alexp COMMA actual_params { $1 :: $3 }
[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 }
; ;
transition_label: transition_label:
@ -212,13 +215,13 @@ formula:
| formula AX { Logging.out "\tParsed AX\n"; CTL.AX ($1) } | formula AX { Logging.out "\tParsed AX\n"; CTL.AX ($1) }
| formula EG { Logging.out "\tParsed EG\n"; CTL.EG (None, $1) } | formula EG { Logging.out "\tParsed EG\n"; CTL.EG (None, $1) }
| formula AG { Logging.out "\tParsed AG\n"; CTL.AG ($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) } | 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)} { 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)} { 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)} { Logging.out "\tParsed ETX\n"; CTL.ETX ($2, $4, $5)}
| EX WITH_TRANSITION transition_label formula_with_paren | EX WITH_TRANSITION transition_label formula_with_paren
{ Logging.out "\tParsed EX\n"; CTL.EX ($3, $4)} { Logging.out "\tParsed EX\n"; CTL.EX ($3, $4)}
@ -228,11 +231,24 @@ formula:
| NOT formula { Logging.out "\tParsed NOT\n"; CTL.Not ($2) } | 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:
| 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 }
; ;
%% %%

@ -24,3 +24,5 @@ let message_const = "message"
let suggestion_const = "suggestion" let suggestion_const = "suggestion"
let severity_const = "severity" let severity_const = "severity"
let mode_const = "mode" let mode_const = "mode"
exception ALParsingException of string

@ -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_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_TEST2, []
codetoanalyze/objc/linters-for-test-only/subclassing.m, B_bar, 36, MACRO_TEST3, [] codetoanalyze/objc/linters-for-test-only/subclassing.m, B_bar, 36, MACRO_TEST3, []

@ -3,7 +3,7 @@
GLOBAL-MACROS { GLOBAL-MACROS {
LET global_is_subclass_of(x) = 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 = { DEFINE-CHECKER SUBCLASSING_TEST_EXAMPLE = {
SET report_when = 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."; 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); 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"; SET message = "Error message here";
@ -31,9 +31,9 @@ DEFINE-CHECKER MACRO_TEST1 = {
// Test reverse parameter of macro // Test reverse parameter of macro
DEFINE-CHECKER MACRO_TEST2 = { 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"; SET message = "Error message here";
@ -42,11 +42,11 @@ DEFINE-CHECKER MACRO_TEST2 = {
// Test macro call macro // Test macro call macro
DEFINE-CHECKER MACRO_TEST3 = { 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); 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"; SET message = "Error message here";
@ -57,7 +57,7 @@ DEFINE-CHECKER LOCAL_MACRO_SUBCLASS = {
LET is_subclass_of(x) = LET is_subclass_of(x) =
is_class(x) HOLDS-IN-SOME-SUPERCLASS-OF ObjCInterfaceDecl; 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."; 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 = { 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."; 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 = { 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."; 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...";
};

Loading…
Cancel
Save