Reviewed By: dulmarod Differential Revision: D3980883 fbshipit-source-id: 5f030damaster
							parent
							
								
									1713378438
								
							
						
					
					
						commit
						898d956513
					
				@ -0,0 +1,74 @@
 | 
				
			||||
(*
 | 
				
			||||
 * Copyright (c) 2016 - present Facebook, Inc.
 | 
				
			||||
 * All rights reserved.
 | 
				
			||||
 *
 | 
				
			||||
 * This source code is licensed under the BSD style license found in the
 | 
				
			||||
 * LICENSE file in the root directory of this source tree. An additional grant
 | 
				
			||||
 * of patent rights can be found in the PATENTS file in the same directory.
 | 
				
			||||
 *)
 | 
				
			||||
 | 
				
			||||
{
 | 
				
			||||
  open Lexing
 | 
				
			||||
  open Ctl_parser
 | 
				
			||||
 | 
				
			||||
  exception SyntaxError of string
 | 
				
			||||
 | 
				
			||||
  let next_line lexbuf =
 | 
				
			||||
    let pos = lexbuf.lex_curr_p in
 | 
				
			||||
    lexbuf.lex_curr_p <-
 | 
				
			||||
      { pos with pos_bol = lexbuf.lex_curr_pos;
 | 
				
			||||
                pos_lnum = pos.pos_lnum + 1
 | 
				
			||||
      }
 | 
				
			||||
}
 | 
				
			||||
 | 
				
			||||
let comment = "//" [^'\n']*
 | 
				
			||||
let whitespace = [' ' '\t']
 | 
				
			||||
let id = ['a'-'z' 'A'-'Z' '_'] ['a'-'z' 'A'-'Z' '0'-'9' '_']*
 | 
				
			||||
 | 
				
			||||
 | 
				
			||||
rule token = parse
 | 
				
			||||
  | whitespace+ { token lexbuf }
 | 
				
			||||
  | whitespace*("\r")?"\n" { next_line lexbuf; token lexbuf }
 | 
				
			||||
  | comment { token lexbuf }
 | 
				
			||||
  | "holds-until" { EU }
 | 
				
			||||
  | "holds-everywhere-until" { AU }
 | 
				
			||||
  | "holds-eventually" { EF }
 | 
				
			||||
  | "holds-eventually-everywhere" { AF }
 | 
				
			||||
  | "holds-next" { EX }
 | 
				
			||||
  | "holds-every-next" { AX }
 | 
				
			||||
  | "always-holds" { EG }
 | 
				
			||||
  | "always-holds-everywhere" { AG }
 | 
				
			||||
  | "instanceof" { EH }
 | 
				
			||||
  | "with-node" { ET }
 | 
				
			||||
  | "define-checker" { DEFINE_CHECKER }
 | 
				
			||||
  | "set" { SET }
 | 
				
			||||
  | "let" { SET }
 | 
				
			||||
  | "True" { TRUE }
 | 
				
			||||
  | "False" { FALSE }
 | 
				
			||||
  | "{" { LEFT_BRACE }
 | 
				
			||||
  | "}" { RIGHT_BRACE }
 | 
				
			||||
  | "(" { LEFT_PAREN }
 | 
				
			||||
  | ")" { RIGHT_PAREN }
 | 
				
			||||
  | "=" { ASSIGNMENT }
 | 
				
			||||
  | ";" { SEMICOLON }
 | 
				
			||||
  | "," { COMMA }
 | 
				
			||||
  | "AND" { AND }
 | 
				
			||||
  | "OR" { OR }
 | 
				
			||||
  | "NOT" { NOT }
 | 
				
			||||
  | id { IDENTIFIER (Lexing.lexeme lexbuf) }
 | 
				
			||||
  | '"' { read_string (Buffer.create 80) lexbuf }
 | 
				
			||||
  | _ { raise (SyntaxError ("Unexpected char: '" ^ (Lexing.lexeme lexbuf) ^"'")) }
 | 
				
			||||
  | eof { EOF }
 | 
				
			||||
 | 
				
			||||
and read_string buf = parse
 | 
				
			||||
| '"' { STRING (Buffer.contents buf) }
 | 
				
			||||
| '\\' '/' { Buffer.add_char buf '/'; read_string buf lexbuf }
 | 
				
			||||
| '\\' '\\' { Buffer.add_char buf '\\'; read_string buf lexbuf }
 | 
				
			||||
| '\\' 'b' { Buffer.add_char buf '\b'; read_string buf lexbuf }
 | 
				
			||||
| '\\' 'f' { Buffer.add_char buf '\012'; read_string buf lexbuf }
 | 
				
			||||
| '\\' 'n' { Buffer.add_char buf '\n'; read_string buf lexbuf }
 | 
				
			||||
| '\\' 'r' { Buffer.add_char buf '\r'; read_string buf lexbuf }
 | 
				
			||||
| '\\' 't' { Buffer.add_char buf '\t'; read_string buf lexbuf }
 | 
				
			||||
| [^ '"' '\\']+ { Buffer.add_string buf (Lexing.lexeme lexbuf); read_string buf lexbuf }
 | 
				
			||||
| _ { raise (SyntaxError ("Illegal string character: " ^ Lexing.lexeme lexbuf)) }
 | 
				
			||||
| eof { raise (SyntaxError ("String is not terminated")) }
 | 
				
			||||
@ -0,0 +1,108 @@
 | 
				
			||||
/*
 | 
				
			||||
 * Copyright (c) 2016 - present Facebook, Inc.
 | 
				
			||||
 * All rights reserved.
 | 
				
			||||
 *
 | 
				
			||||
 * This source code is licensed under the BSD style license found in the
 | 
				
			||||
 * LICENSE file in the root directory of this source tree. An additional grant
 | 
				
			||||
 * of patent rights can be found in the PATENTS file in the same directory.
 | 
				
			||||
 */
 | 
				
			||||
 | 
				
			||||
%{
 | 
				
			||||
  open Ctl_parser_types
 | 
				
			||||
%}
 | 
				
			||||
 | 
				
			||||
%token EU
 | 
				
			||||
%token AU
 | 
				
			||||
%token EF
 | 
				
			||||
%token AF
 | 
				
			||||
%token EX
 | 
				
			||||
%token AX
 | 
				
			||||
%token EG
 | 
				
			||||
%token AG
 | 
				
			||||
%token EH
 | 
				
			||||
%token ET
 | 
				
			||||
%token DEFINE_CHECKER
 | 
				
			||||
%token SET
 | 
				
			||||
%token LET
 | 
				
			||||
%token TRUE
 | 
				
			||||
%token FALSE
 | 
				
			||||
%token LEFT_BRACE
 | 
				
			||||
%token RIGHT_BRACE
 | 
				
			||||
%token LEFT_PAREN
 | 
				
			||||
%token RIGHT_PAREN
 | 
				
			||||
%token ASSIGNMENT
 | 
				
			||||
%token SEMICOLON
 | 
				
			||||
%token COMMA
 | 
				
			||||
%token AND
 | 
				
			||||
%token OR
 | 
				
			||||
%token NOT
 | 
				
			||||
%token QUOTES
 | 
				
			||||
%token COMMENT
 | 
				
			||||
%token COMMENT_LINE
 | 
				
			||||
%token <string> IDENTIFIER
 | 
				
			||||
%token <string> STRING
 | 
				
			||||
%token EOF
 | 
				
			||||
 | 
				
			||||
%start <Ctl_parser_types.ctl_checker list> checkers_list
 | 
				
			||||
 | 
				
			||||
%%
 | 
				
			||||
checkers_list:
 | 
				
			||||
  | EOF { [] }
 | 
				
			||||
  | checker SEMICOLON checkers_list { $1::$3 }
 | 
				
			||||
  ;
 | 
				
			||||
 | 
				
			||||
checker:
 | 
				
			||||
 DEFINE_CHECKER IDENTIFIER ASSIGNMENT LEFT_BRACE clause_list RIGHT_BRACE
 | 
				
			||||
  { Logging.out "Parsed checker \n"; { name = $2; definitions = $5 } }
 | 
				
			||||
;
 | 
				
			||||
 | 
				
			||||
clause_list:
 | 
				
			||||
 | clause SEMICOLON { [$1] }
 | 
				
			||||
 | clause SEMICOLON clause_list { $1 :: $3 }
 | 
				
			||||
;
 | 
				
			||||
 | 
				
			||||
clause:
 | 
				
			||||
  | SET IDENTIFIER ASSIGNMENT formula
 | 
				
			||||
    { Logging.out "Parsed set clause\n"; CSet ($2, $4) }
 | 
				
			||||
  | SET IDENTIFIER ASSIGNMENT STRING
 | 
				
			||||
    { Logging.out "Parsed desc clause\n"; CDesc ($2, $4) }
 | 
				
			||||
  | LET IDENTIFIER ASSIGNMENT formula
 | 
				
			||||
    { Logging.out "Parsed let clause\n"; CLet ($2, $4) }
 | 
				
			||||
;
 | 
				
			||||
 | 
				
			||||
atomic_formula:
 | 
				
			||||
  | TRUE { Logging.out "Parsed True\n"; CTL.True }
 | 
				
			||||
  | FALSE { Logging.out "Parsed False\n"; CTL.False }
 | 
				
			||||
  | IDENTIFIER LEFT_PAREN params RIGHT_PAREN
 | 
				
			||||
    { Logging.out "Parsed predicate\n"; CTL.Atomic($1, $3) }
 | 
				
			||||
  ;
 | 
				
			||||
 | 
				
			||||
 formula_id:
 | 
				
			||||
  | IDENTIFIER { CTL.Atomic($1,[]) }
 | 
				
			||||
  ;
 | 
				
			||||
 | 
				
			||||
params:
 | 
				
			||||
  | {[]}
 | 
				
			||||
  | IDENTIFIER { [$1] }
 | 
				
			||||
  | IDENTIFIER COMMA params { $1 :: $3 }
 | 
				
			||||
  ;
 | 
				
			||||
 | 
				
			||||
formula:
 | 
				
			||||
  | LEFT_PAREN formula RIGHT_PAREN { $2 }
 | 
				
			||||
  | formula_id { Logging.out "Parsed formula identifier\n"; $1 }
 | 
				
			||||
  | atomic_formula { Logging.out "Parsed atomic formula\n"; $1 }
 | 
				
			||||
  | formula EU formula { Logging.out "Parsed EU\n"; CTL.EU($1, $3) }
 | 
				
			||||
  | formula AU formula { Logging.out "Parsed AU\n"; CTL.AU($1, $3) }
 | 
				
			||||
  | formula EF { Logging.out "Parsed EF\n"; CTL.EF($1) }
 | 
				
			||||
  | formula AF{ Logging.out "Parsed AF\n"; CTL.AF($1) }
 | 
				
			||||
  | formula EX  { Logging.out "Parsed EX\n"; CTL.EX($1) }
 | 
				
			||||
  | formula AX  { Logging.out "Parsed AX\n"; CTL.AX($1) }
 | 
				
			||||
  | formula EG  { Logging.out "Parsed EG\n"; CTL.EG($1) }
 | 
				
			||||
  | formula AG  { Logging.out "Parsed AG\n"; CTL.AG($1) }
 | 
				
			||||
  | formula EH params  { Logging.out "Parsed EH\n"; CTL.EH($3, $1) }
 | 
				
			||||
  | formula AND formula { Logging.out "Parsed AND\n"; CTL.And($1, $3) }
 | 
				
			||||
  | formula OR formula { Logging.out "Parsed OR\n"; CTL.Or($1, $3) }
 | 
				
			||||
  | NOT formula { Logging.out "Parsed NOT\n"; CTL.Not($2)}
 | 
				
			||||
;
 | 
				
			||||
 | 
				
			||||
%%
 | 
				
			||||
@ -0,0 +1,37 @@
 | 
				
			||||
(*
 | 
				
			||||
 * Copyright (c) 2016 - present Facebook, Inc.
 | 
				
			||||
 * All rights reserved.
 | 
				
			||||
 *
 | 
				
			||||
 * This source code is licensed under the BSD style license found in the
 | 
				
			||||
 * LICENSE file in the root directory of this source tree. An additional grant
 | 
				
			||||
 * of patent rights can be found in the PATENTS file in the same directory.
 | 
				
			||||
 *)
 | 
				
			||||
 | 
				
			||||
 | 
				
			||||
(* Types used by the ctl parser *)
 | 
				
			||||
 | 
				
			||||
(* "set" clauses are used for defining mandatory variables that will be used
 | 
				
			||||
   by when reporting issues: eg for defining the condition.
 | 
				
			||||
 | 
				
			||||
   "desc" clauses are used for defining the error message,
 | 
				
			||||
   the suggestion, the severity.
 | 
				
			||||
 | 
				
			||||
   "let" clauses are used to define temporary formulas which are then
 | 
				
			||||
   used to abbreviate the another formula. For example
 | 
				
			||||
 | 
				
			||||
   let f = a And B
 | 
				
			||||
 | 
				
			||||
   set formula  = f OR f
 | 
				
			||||
 | 
				
			||||
   set message = "bla"
 | 
				
			||||
 | 
				
			||||
*)
 | 
				
			||||
type clause =
 | 
				
			||||
  | CLet  of string * CTL.t (* Let clause: let id = definifion;  *)
 | 
				
			||||
  | CSet of string * CTL.t (* Set clause: set id = definition *)
 | 
				
			||||
  | CDesc of string * string (* Description clause eg: set message = "..." *)
 | 
				
			||||
 | 
				
			||||
type ctl_checker = {
 | 
				
			||||
  name : string; (* Checker's name *)
 | 
				
			||||
  definitions : clause list (* A list of let/set definitions *)
 | 
				
			||||
}
 | 
				
			||||
@ -0,0 +1,60 @@
 | 
				
			||||
// Copyright (c) 2016 - present Facebook, Inc.
 | 
				
			||||
// All rights reserved.
 | 
				
			||||
//
 | 
				
			||||
// This source code is licensed under the BSD style license found in the
 | 
				
			||||
// LICENSE file in the root directory of this source tree. An additional grant
 | 
				
			||||
// of patent rights can be found in the PATENTS file in the same directory.
 | 
				
			||||
 | 
				
			||||
// DIRECT_ATOMIC_PROPERTY_ACCESS:
 | 
				
			||||
// a property declared atomic should not be accessed directly via its ivar
 | 
				
			||||
define-checker DIRECT_ATOMIC_PROPERTY_ACCESS = {
 | 
				
			||||
 | 
				
			||||
	set formula =
 | 
				
			||||
		(NOT context_in_synchronized_block())
 | 
				
			||||
		AND NOT is_method_property_accessor_of_ivar()
 | 
				
			||||
		AND NOT is_objc_constructor()
 | 
				
			||||
		AND NOT is_objc_dealloc();
 | 
				
			||||
 | 
				
			||||
  	set message = "Direct access to ivar %s of an atomic property";
 | 
				
			||||
  	set suggestion = "Accessing an ivar of an atomic property makes the property nonatomic";
 | 
				
			||||
	  set severity = "WARNING";
 | 
				
			||||
};
 | 
				
			||||
 | 
				
			||||
// ASSIGN_POINTER_WARNING:
 | 
				
			||||
// a property with a pointer type should not be declared `assign`
 | 
				
			||||
define-checker ASSIGN_POINTER_WARNING = {
 | 
				
			||||
 | 
				
			||||
	 set formula =
 | 
				
			||||
	  	is_assign_property() AND is_property_pointer_type();
 | 
				
			||||
 | 
				
			||||
	 set message = "Property `%s` is a pointer type marked with the `assign` attribute";
 | 
				
			||||
	 set suggestion = "Use a different attribute like `strong` or `weak`.";
 | 
				
			||||
	 set severity = "WARNING";
 | 
				
			||||
};
 | 
				
			||||
 | 
				
			||||
// BAD_POINTER_COMPARISON:
 | 
				
			||||
// Fires whenever a NSNumber is dangerously coerced to a boolean in a comparison
 | 
				
			||||
define-checker BAD_POINTER_COMPARISON = {
 | 
				
			||||
 | 
				
			||||
	let is_binop = is_stmt(BinaryOperator);
 | 
				
			||||
	let is_binop_eq = is_binop_with_kind(EQ);
 | 
				
			||||
	let is_binop_ne = is_binop_with_kind(NE);
 | 
				
			||||
	let is_binop_neq = Or (is_binop_eq, is_binop_ne);
 | 
				
			||||
	let is_unop_lnot = is_unop_with_kind(LNot);
 | 
				
			||||
	let is_implicit_cast_expr = is_stmt(ImplicitCastExpr);
 | 
				
			||||
	let is_expr_with_cleanups = is_stmt(ExprWithCleanups);
 | 
				
			||||
	let is_nsnumber = isa(NSNumber);
 | 
				
			||||
 | 
				
			||||
 	set formula =
 | 
				
			||||
         	(
 | 
				
			||||
					 (NOT is_binop_neq) AND (
 | 
				
			||||
					 is_expr_with_cleanups
 | 
				
			||||
					 OR is_implicit_cast_expr
 | 
				
			||||
					 OR is_binop
 | 
				
			||||
					 OR is_unop_lnot)
 | 
				
			||||
				 	)
 | 
				
			||||
				 	holds-until
 | 
				
			||||
				 	(
 | 
				
			||||
				 	 	is_nsnumber
 | 
				
			||||
				 	);
 | 
				
			||||
};
 | 
				
			||||
					Loading…
					
					
				
		Reference in new issue