Coccinelle release 1.0.0-rc4
authorCoccinelle <cocci@diku.dk>
Tue, 5 Jul 2011 18:01:21 +0000 (20:01 +0200)
committerRene Rydhof Hansen <rrh@cs.aau.dk>
Tue, 5 Jul 2011 18:01:21 +0000 (20:01 +0200)
** Language:
- Addition of initializer list metavariables.  Thanks to Michael Stefaniuc
  for noticing the need for them.
- Allow multiple position variables per token
- ++ can now be associated with - code
- Allow /* */ comments as smpl comments, not only as + code
- Add support for && (label addresses)
- local idexpression metavariable no longer matches static local x
- Consider using to be a comment in C++ code.  Patch submitted by Jani Monoses.

** Features:
- Preserve spacing before // comments when not at the beginning of a line
- Adjusted parsing of endif to put it after jump code
- Improve warning message when using -use_cache
- More helpful initial value for exported variables in python
- Support - on expression nests
- Better handling of the case of a matched declaration that should only
  be replaced by other top level things.
- Allow a semantic patch beginning and ending with braces to match the
  complete body of a function if the braces are not removed and if nothing
  is added before the first brace or after the last one.
- Add -cache_prefix option, to specify where to put cached files.
- Allow module_init(foo); to match module_init(foo) (or likewise for any
  declarer), when no transformation is specified on the semicolon.
- Add Coccilib.exit() for ocaml code and cocci.exit() for python code,
  to abort the treatment of the current file.

** Bugfix:
- Corrected parsing of script strings delimited by a single quote.  Thanks
  to Eugeniy Meshcheryakov for reporting the problem.
- Improved indentation of added ifdefs.
- Allow added comments and #ifdefs to precede other added code.  Thanks to
  Jani Monoses for noticing the problem.
- Corrected failure to due missing ocamlfind. Thanks to Derek M. Jones for
  reporting the problem.
- Allow fake nodes to be - in the allminus case, to drop tokens related to
  a function definition or forward declaration but before the first code
  mentioned in the semantic patch.
- Drop __init etc when deleting a whole function.
- Cause appropriate newlines to be preserved when multiple matches (trees)
  contain adjacent modifications derived from the same SmPL code.
- check_meta takes into account fresh identifier seed information.
- Types for worth-trying optimization should not be followed by space
- Improved filtering of result of matching atomic patterns
- Drop positions before creating function prototype rules
- Adjust position of { introduced by adding multiple statements in a
  single-statement position
- Drop newline after function call ( when all arguments on that line are
  eliminated
- Accept removal of a single declaration, replaced by arbitrary,
  non-declaration code
- smpl_spacing takes into account newlines, indentation
- Improved prevention of transformations on toplevel { ... } from causing
  changes outside function boundaries; also outside ifs, whiles, etc.
  Changes are still allowed on { ... } present for other reasons.
- Fix bug in include_match that caused everything to halt when all matches
  were discarded

53 files changed:
changes.txt
cocci.ml
commons/common.ml
commons/common.mli
docs/Coccilib.3cocci
docs/manual/cocci-python.txt
docs/manual/cocci_syntax.tex
docs/manual/main_grammar.pdf
docs/manual/manual.pdf
docs/manual/options.pdf
docs/manual/spatch_options.tex
engine/asttoctl2.ml
engine/cocci_vs_c.ml
engine/cocci_vs_c.mli
engine/ctlcocci_integration.ml
engine/ctltotex.ml
engine/lib_engine.ml
engine/pattern_c.ml
engine/pretty_print_engine.ml
engine/transformation_c.ml
globals/config.ml.in
main.ml
ocaml/coccilib.ml
ocaml/coccilib.mli
ocaml/run_ocamlcocci.ml
parsing_c/ast_c.ml
parsing_c/control_flow_c_build.ml
parsing_c/flag_parsing_c.ml
parsing_c/lexer_c.mll
parsing_c/parse_c.ml
parsing_c/parser_c.mly
parsing_c/pretty_print_c.ml
parsing_c/visitor_c.ml
python/no_pycocci.ml
python/pycocci.mli
python/yes_pycocci.ml
tests/SCORE_expected.sexp
tests/SCORE_expected_orig.sexp
tests/exitc.c [new file with mode: 0644]
tests/exitc.cocci [new file with mode: 0644]
tests/exitc.res [new file with mode: 0644]
tests/exitp.c [new file with mode: 0644]
tests/exitp.cocci [new file with mode: 0644]
tests/exitp.res [new file with mode: 0644]
tests/incpos.c [new file with mode: 0644]
tests/incpos.cocci [new file with mode: 0644]
tests/incpos.res [new file with mode: 0644]
tests/incpos1.c [new file with mode: 0644]
tests/incpos1.cocci [new file with mode: 0644]
tests/incpos1.res [new file with mode: 0644]
tests/smallfn.c [new file with mode: 0644]
tests/smallfn.cocci [new file with mode: 0644]
tests/smallfn.res [new file with mode: 0644]

index 6ed8ca9..13419aa 100644 (file)
@@ -23,6 +23,7 @@
 - Allow /* */ comments as smpl comments, not only as + code
 - Add support for && (label addresses)
 - local idexpression metavariable no longer matches static local x
+- Consider using to be a comment in C++ code.  Patch submitted by Jani Monoses.
 
 ** Features:
 - Preserve spacing before // comments when not at the beginning of a line
 - Support - on expression nests
 - Better handling of the case of a matched declaration that should only
   be replaced by other top level things.
+- Allow a semantic patch beginning and ending with braces to match the
+  complete body of a function if the braces are not removed and if nothing
+  is added before the first brace or after the last one.
+- Add -cache_prefix option, to specify where to put cached files.
+- Allow module_init(foo); to match module_init(foo) (or likewise for any
+  declarer), when no transformation is specified on the semicolon.
+- Add Coccilib.exit() for ocaml code and cocci.exit() for python code,
+  to abort the treatment of the current file.
 
 ** Bugfix:
 - Corrected parsing of script strings delimited by a single quote.  Thanks
 - Accept removal of a single declaration, replaced by arbitrary,
   non-declaration code
 - smpl_spacing takes into account newlines, indentation
+- Improved prevention of transformations on toplevel { ... } from causing
+  changes outside function boundaries; also outside ifs, whiles, etc.
+  Changes are still allowed on { ... } present for other reasons.
+- Fix bug in include_match that caused everything to halt when all matches
+  were discarded
 
 * 0.2.5
 ** Language:
index ef8c893..82be548 100644 (file)
--- a/cocci.ml
+++ b/cocci.ml
@@ -1249,6 +1249,8 @@ let contains_binding e (_,(r,m),_) =
     true
   with Not_found -> false
 
+exception Exited
+
 let python_application mv ve script_vars r =
   let mv =
     List.map
@@ -1264,7 +1266,9 @@ let python_application mv ve script_vars r =
     Pycocci.construct_variables mv ve;
     Pycocci.construct_script_variables script_vars;
     let _ = Pycocci.pyrun_simplestring (local_python_code ^r.script_code) in
-    if !Pycocci.inc_match
+    if !Pycocci.exited
+    then raise Exited
+    else if !Pycocci.inc_match
     then Some (Pycocci.retrieve_script_variables script_vars)
     else None
   with Pycocci.Pycocciexception ->
@@ -1276,7 +1280,9 @@ let ocaml_application mv ve script_vars r =
     let script_vals =
       Run_ocamlcocci.run mv ve script_vars
        r.scr_rule_info.rulename r.script_code in
-    if !Coccilib.inc_match
+    if !Coccilib.exited
+    then raise Exited
+    else if !Coccilib.inc_match
     then Some script_vals
     else None
   with e -> (pr2 ("Failure in " ^ r.scr_rule_info.rulename); raise e)
@@ -1676,6 +1682,8 @@ let rec bigloop2 rs (ccs: file_info list) =
   let ccs = ref ccs in
   let rules_that_have_ever_matched = ref [] in
 
+  (try
+
   (* looping over the rules *)
   rs +> List.iter (fun r ->
     match r with
@@ -1723,10 +1731,13 @@ let rec bigloop2 rs (ccs: file_info list) =
        then
          Common.push2 r.scr_rule_info.rulename rules_that_have_ever_matched);
 
-        es := newes (*(if newes = [] then init_es else newes)*);
+       (* just newes can't work, because if one does include_match false
+           on everything that binds a variable, then nothing is left *)
+        es := (*newes*) (if newes = [] then init_es else newes)
     | CocciRuleCocciInfo r ->
        apply_cocci_rule r rules_that_have_ever_matched
-         es ccs);
+         es ccs)
+  with Exited -> ());
 
   if !Flag.sgrep_mode2
   then begin
index a622cee..0be087e 100644 (file)
@@ -3335,19 +3335,38 @@ let cache_computation ?verbose ?use_cache a b c =
 
 
 let cache_computation_robust2
- file ext_cache
dest_dir file ext_cache
  (need_no_changed_files, need_no_changed_variables) ext_depend
  f =
-  if not (Sys.file_exists file)
-  then failwith ("can't find: "  ^ file);
-
-  let file_cache = (file ^ ext_cache) in
-  let dependencies_cache = (file ^ ext_depend) in
+  (if not (Sys.file_exists file)
+  then failwith ("can't find: "  ^ file));
 
+  let (file_cache,dependencies_cache) =
+    let file_cache = (file ^ ext_cache) in
+    let dependencies_cache = (file ^ ext_depend) in
+    match dest_dir with
+      None -> (file_cache, dependencies_cache)
+    | Some dir ->
+       let file_cache =
+         Filename.concat dir
+           (if String.get file_cache 0 =*= '/'
+           then String.sub file_cache 1 ((String.length file_cache) - 1)
+           else file_cache) in
+       let dependencies_cache =
+         Filename.concat dir
+           (if String.get dependencies_cache 0 =*= '/'
+           then
+             String.sub dependencies_cache 1
+               ((String.length dependencies_cache) - 1)
+           else dependencies_cache) in
+       let _ = Sys.command
+           (Printf.sprintf "mkdir -p %s" (Filename.dirname file_cache)) in
+       (file_cache,dependencies_cache) in
+  
   let dependencies =
     (* could do md5sum too *)
     ((file::need_no_changed_files) +> List.map (fun f -> f, filemtime f),
-    need_no_changed_variables)
+     need_no_changed_variables)
   in
 
   if Sys.file_exists dependencies_cache &&
@@ -3363,7 +3382,11 @@ let cache_computation_robust2
 
 let cache_computation_robust a b c d e =
   profile_code "Common.cache_computation_robust" (fun () ->
-    cache_computation_robust2 a b c d e)
+    cache_computation_robust2 None a b c d e)
+
+let cache_computation_robust_in_dir a b c d e f =
+  profile_code "Common.cache_computation_robust" (fun () ->
+    cache_computation_robust2 a b c d e f)
 
 
 
index 723977b..8d56e01 100644 (file)
@@ -439,6 +439,14 @@ val cache_computation_robust :
   (unit -> 'a) ->
   'a
 
+val cache_computation_robust_in_dir :
+  string option (* destination directory *) -> filename ->
+  string (* extension for marshalled object *) ->
+  (filename list * 'x) ->
+  string (* extension for marshalled dependencies *) ->
+  (unit -> 'a) ->
+  'a
+
 
 
 val once : ('a -> unit) -> ('a -> unit)
index 7e5956d..5ed518b 100644 (file)
@@ -143,13 +143,12 @@ the argument is false, discard this environment.  By default, the
 environment is retained.
 .sp
 
-.I val inc_match 
+.I val exit
 : 
-.B bool ref
+.B unit -> unit
 .sp
-True if the environment with respect to which the
-ocaml script code is being executed is to be retained for use in
-subsequent rules, and false otherwise.
+If called, aborts the treatment of the current file.  All previous changes
+take effect.
 .sp
 
 .I val dir
index 08ca830..45b5b1d 100644 (file)
@@ -23,9 +23,22 @@ Here cocci is the interface class for interfacting with Coccinelle's OCaml core.
 Controlling environments
 ------------------------
 
-The python script will be called for each environment generated by Coccinelle with matches to the previous rules. By default, the python script drops each environment unless otherwise is indicated in the script using cocci.include_match(True).
-
-As a short-cut for registering information that "belongs together", the Output class also provides a register_match method that may be overridden in derived classes. This method can be called like: cocci.register_match(True, [(x, 'Array size'), (y, 'Array index size')]). Here the True is automatically passed on to include_match (so one could use False in order to drop the environment, but still print information). In the GTK frontend, this will result in the "Array index size" information being shown as a child node to the "Array size".
+The python script will be called for each environment generated by
+Coccinelle with matches to the previous rules. By default, the python
+script keeps each environment unless otherwise is indicated in the script
+using cocci.include_match(False).
+
+As a short-cut for registering information that "belongs together", the
+Output class also provides a register_match method that may be overridden
+in derived classes. This method can be called like:
+cocci.register_match(True, [(x, 'Array size'), (y, 'Array index
+size')]). Here the True is automatically passed on to include_match (so one
+could use False in order to drop the environment, but still print
+information). In the GTK frontend, this will result in the "Array index
+size" information being shown as a child node to the "Array size".
+
+cocci.exit() simply aborts the treatment of the current file.  Previously
+made changes do take effect.
 
 Output methods for the python scripts
 -------------------------------------
index 9c7e01d..307d1b5 100644 (file)
@@ -126,6 +126,11 @@ behavior.  Using \NT{disable-iso} with the given name disables this behavior.
   not have to be specified in the SmPL code, but may be present in the C code.
 \item \KW{value\_format}: Integers in various formats, e.g., 1 and 0x1, are
   considered to be equivalent in the matching process.
+\item \KW{optional\_declarer\_semicolon}: Some declarers (top-level terms
+  that look like function calls but serve to declare some variable) don't
+  require a semicolon.  This isomorphism allows a SmPL declarer with a semicolon
+  to match such a C declarer, if no transformation is specified on the SmPL
+  semicolon.
 \item \KW{comm\_assoc}: An expression of the form \NT{exp} \NT{bin\_op}
   \KW{...}, where \NT{bin\_op} is commutative and associative, is
   considered to match any top-level sequence of \NT{bin\_op} operators
index 6561629..5b8a6ae 100644 (file)
Binary files a/docs/manual/main_grammar.pdf and b/docs/manual/main_grammar.pdf differ
index 19cfa01..2bb3cbf 100644 (file)
Binary files a/docs/manual/manual.pdf and b/docs/manual/manual.pdf differ
index a8d4eb4..beb5abc 100644 (file)
Binary files a/docs/manual/options.pdf and b/docs/manual/options.pdf differ
index ae7d1ac..93f38d2 100644 (file)
@@ -256,8 +256,11 @@ is none, the constant is assumed to be a signed integer.  If there is only
   patch/match run faster, at the cost of not finding matches that wrap
   around loops.}
 
-\developer{-use\_cache} Use preparsed versions of the C files that are
-stored in a cache.
+\developer{-use\_cache}{Use preparsed versions of the C files that are
+stored in a cache.}
+
+\developer{-cache\_prefix}{Specify the directory in which to store 
+preparsed versions of the C files.  This sets {-use\_cache}}
 
 \developer{-debug\_cpp, -debug\_lexer, -debug\_etdt,
   -debug\_typedef}{Various options for debugging the C parser.}
index b5abb46..2f856b0 100644 (file)
@@ -167,6 +167,7 @@ let predmaker guard pred label = CTL.Pred pred
 let aftpred     = predmaker false (Lib_engine.After,       CTL.Control)
 let retpred     = predmaker false (Lib_engine.Return,      CTL.Control)
 let funpred     = predmaker false (Lib_engine.FunHeader,   CTL.Control)
+let unsbrpred   = predmaker false (Lib_engine.UnsafeBrace, CTL.Control)
 let toppred     = predmaker false (Lib_engine.Top,         CTL.Control)
 let exitpred    = predmaker false (Lib_engine.ErrorExit,   CTL.Control)
 let endpred     = predmaker false (Lib_engine.Exit,        CTL.Control)
@@ -374,6 +375,8 @@ than dots or a nest. *)
 
 type after = After of formula | Guard of formula | Tail | End | VeryEnd
 
+type top = Top | NotTop
+
 let a2n = function After x -> Guard x | a -> a
 
 let print_ctl x =
@@ -997,7 +1000,7 @@ let ifthen ifheader branch ((afvs,_,_,_) as aft) after
     (* no point to put a label on truepred etc; it is local to this construct
        so it must have the same label *)
     make_seq guard
-      [truepred None; recurse branch Tail new_quantified new_mquantified
+      [truepred None; recurse branch NotTop Tail new_quantified new_mquantified
          (Some (lv,used)) llabel slabel guard] in
   let after_pred = aftpred None in
   let or_cases after_branch =
@@ -1072,7 +1075,7 @@ let ifthenelse ifheader branch1 els branch2 ((afvs,_,_,_) as aft) after
   let used = ref false in
   let true_branch =
     make_seq guard
-      [truepred None; recurse branch1 Tail new_quantified new_mquantified
+      [truepred None; recurse branch1 NotTop Tail new_quantified new_mquantified
          (Some (lv,used)) llabel slabel guard] in
   let false_branch =
     make_seq guard
@@ -1080,7 +1083,7 @@ let ifthenelse ifheader branch1 els branch2 ((afvs,_,_,_) as aft) after
        quantify guard
          (Common.minus_set (Ast.get_fvs els) new_quantified)
          (header_match None guard els);
-       recurse branch2 Tail new_quantified new_mquantified
+       recurse branch2 NotTop Tail new_quantified new_mquantified
          (Some (lv,used)) llabel slabel guard] in
   let after_pred = aftpred None in
   let or_cases after_branch =
@@ -1123,7 +1126,7 @@ let forwhile header body ((afvs,_,_,_) as aft) after
     let body =
       make_seq guard
        [inlooppred None;
-         recurse body Tail new_quantified new_mquantified
+         recurse body NotTop Tail new_quantified new_mquantified
            (Some (lv,used)) (Some (lv,used)) None guard] in
     let after_pred = loopfallpred None in
     let or_cases after_branch = ctl_or body after_branch in
@@ -1610,7 +1613,7 @@ and whencond_false e label guard quantified =
 (* --------------------------------------------------------------------- *)
 (* the main translation loop *)
 
-let rec statement_list stmt_list after quantified minus_quantified
+let rec statement_list stmt_list top after quantified minus_quantified
     label llabel slabel dots_before guard =
   let isdots x =
     (* include Disj to be on the safe side *)
@@ -1619,11 +1622,12 @@ let rec statement_list stmt_list after quantified minus_quantified
   let compute_label l e db = if db or isdots e then l else None in
   match Ast.unwrap stmt_list with
     Ast.DOTS(x) ->
-      let rec loop quantified minus_quantified dots_before label llabel slabel
+      let rec loop top quantified minus_quantified dots_before
+         label llabel slabel
          = function
          ([],_,_) -> (match after with After f -> f | _ -> CTL.True)
        | ([e],_,_) ->
-           statement e after quantified minus_quantified
+           statement e top after quantified minus_quantified
              (compute_label label e dots_before)
              llabel slabel guard
        | (e::sl,fv::fvs,mfv::mfvs) ->
@@ -1636,7 +1640,7 @@ let rec statement_list stmt_list after quantified minus_quantified
            let new_mquantified =
              Common.union_set munqshared minus_quantified in
            quantify guard unqshared
-             (statement e
+             (statement e top
                 (After
                    (let (label1,llabel1,slabel1) =
                      match Ast.unwrap e with
@@ -1645,13 +1649,13 @@ let rec statement_list stmt_list after quantified minus_quantified
                            Ast.Goto _ -> (None,None,None)
                          | _ -> (label,llabel,slabel))
                      | _ -> (label,llabel,slabel) in
-                   loop new_quantified new_mquantified (isdots e)
+                   loop NotTop new_quantified new_mquantified (isdots e)
                      label1 llabel1 slabel1
                      (sl,fvs,mfvs)))
                 new_quantified new_mquantified
                 (compute_label label e dots_before) llabel slabel guard)
        | _ -> failwith "not possible" in
-      loop quantified minus_quantified dots_before
+      loop top quantified minus_quantified dots_before
        label llabel slabel
        (x,List.map Ast.get_fvs x,List.map Ast.get_mfvs x)
   | Ast.CIRCLES(x) -> failwith "not supported"
@@ -1659,7 +1663,7 @@ let rec statement_list stmt_list after quantified minus_quantified
 
 (* llabel is the label of the enclosing loop and slabel is the label of the
    enclosing switch *)
-and statement stmt after quantified minus_quantified
+and statement stmt top after quantified minus_quantified
     label llabel slabel guard =
   let ctl_au     = ctl_au CTL.NONSTRICT in
   let ctl_ax     = ctl_ax CTL.NONSTRICT in
@@ -1849,7 +1853,7 @@ and statement stmt after quantified minus_quantified
                  (ctl_or
                     (if !exists = Exists then CTL.False else (aftpred label))
                     (quantify guard b2fvs
-                       (statement_list body
+                       (statement_list body NotTop
                           (After (make_seq_after end_brace after))
                           new_quantified2 new_mquantified2
                           (Some (lv,ref true))
@@ -1890,7 +1894,7 @@ and statement stmt after quantified minus_quantified
                (make_match empty_rbrace)
                (ctl_ax (* skip the destination label *)
                   (quantify guard b2fvs
-                     (statement_list body End
+                     (statement_list body NotTop End
                         new_quantified2 new_mquantified2 None llabel slabel
                         true guard)))] in
        let pattern3 =
@@ -1908,7 +1912,7 @@ and statement stmt after quantified minus_quantified
                            (* want AF even for sgrep *)
                            (CTL.AF(CTL.FORWARD,CTL.STRICT,end_brace))))
                      (quantify guard b2fvs
-                        (statement_list body Tail
+                        (statement_list body NotTop Tail
                            new_quantified2 new_mquantified2
                            None(*no label because past the goto*)
                            llabel slabel false guard))])) in
@@ -1930,12 +1934,17 @@ and statement stmt after quantified minus_quantified
   | Ast.Disj(stmt_dots_list) -> (* list shouldn't be empty *)
       (*ctl_and        seems pointless, disjuncts see label too
        (label_pred_maker label)*)
-       (List.fold_left ctl_seqor CTL.False
-          (List.map
-             (function sl ->
-               statement_list sl after quantified minus_quantified label
-                 llabel slabel true guard)
-             stmt_dots_list))
+      let subformulas =
+       List.map
+         (function sl ->
+           statement_list sl top after quantified minus_quantified label
+             llabel slabel true guard)
+         stmt_dots_list in
+      let safe_subformulas =
+       match top with
+         Top -> List.map2 protect_top_level stmt_dots_list subformulas
+       | NotTop -> subformulas in
+      List.fold_left ctl_seqor CTL.False safe_subformulas
 
   | Ast.Nest(starter,stmt_dots,ender,whencode,multi,bef,aft) ->
       (* label in recursive call is None because label check is already
@@ -1961,17 +1970,20 @@ and statement stmt after quantified minus_quantified
 
       quantify guard bfvs
        (let dots_pattern =
-         statement_list stmt_dots (a2n after) new_quantified minus_quantified
+         statement_list stmt_dots top (a2n after)
+           new_quantified minus_quantified
            label(*None*) llabel slabel true guard in
        dots_and_nests multi
          (Some dots_pattern) whencode bef aft dot_code after label
          (process_bef_aft new_quantified minus_quantified
             label(*None*) llabel slabel true)
-         (function x ->
-           statement_list x Tail new_quantified minus_quantified label(*None*)
+         (function x -> (* for when code *)
+           statement_list x NotTop Tail
+             new_quantified minus_quantified label(*None*)
              llabel slabel true true)
-         (function x ->
-           statement x Tail new_quantified minus_quantified label(*None*)
+         (function x -> (* for when code *)
+           statement x NotTop Tail
+             new_quantified minus_quantified label(*None*)
              llabel slabel true)
          guard quantified
          (function x -> Ast.set_fvs [] (Ast.rewrap stmt x)))
@@ -1987,10 +1999,11 @@ and statement stmt after quantified minus_quantified
       dots_and_nests false None whencodes bef aft dot_code after label
        (process_bef_aft quantified minus_quantified None llabel slabel true)
        (function x ->
-         statement_list x Tail quantified minus_quantified
+         statement_list x NotTop Tail quantified minus_quantified
            None llabel slabel true true)
        (function x ->
-         statement x Tail quantified minus_quantified None llabel slabel true)
+         statement x NotTop Tail quantified minus_quantified
+           None llabel slabel true)
        guard quantified
        (function x -> Ast.set_fvs [] (Ast.rewrap stmt x))
 
@@ -2100,7 +2113,7 @@ and statement stmt after quantified minus_quantified
        then (CTL.True,CTL.False)
        else
        let res =
-         statement_list decls Tail
+         statement_list decls NotTop Tail
            new2_quantified new2_mquantified (Some (lv,used)) llabel None
            false(*?*) guard in
        (res,res) in
@@ -2129,7 +2142,7 @@ and statement stmt after quantified minus_quantified
                  let new3_quantified = union b1fvs new2_quantified in
                  let new3_mquantified = union mb1fvs new2_mquantified in
                  let body =
-                   statement_list body Tail
+                   statement_list body NotTop Tail
                      new3_quantified new3_mquantified (Some (lv,used)) llabel
                      (Some (lv,used)) false(*?*) guard in
                  quantify guard b1fvs (make_seq [case_header; body])
@@ -2236,7 +2249,7 @@ and statement stmt after quantified minus_quantified
                Some
                  (CTL.AndAny
                     (CTL.FORWARD,guard_to_strict guard,start_brace,
-                     statement_list stmt_dots
+                     statement_list stmt_dots NotTop
                 (* discards match on right brace, but don't need it *)
                        (Guard (make_seq_after end_brace after))
                        new_quantified3 new_mquantified3
@@ -2273,7 +2286,8 @@ and statement stmt after quantified minus_quantified
                                                 Ast.WhenAlways(s) -> prev
                                               | Ast.WhenNot(sl) ->
                                                   let x =
-                                                    statement_list sl Tail
+                                                    statement_list sl
+                                                      NotTop Tail
                                                       new_quantified3
                                                       new_mquantified3
                                                       label llabel slabel
@@ -2291,7 +2305,7 @@ and statement stmt after quantified minus_quantified
                                          function
                                              Ast.WhenAlways(s) ->
                                                let x =
-                                                 statement s Tail
+                                                 statement s NotTop Tail
                                                    new_quantified3
                                                    new_mquantified3
                                                    label llabel slabel true in
@@ -2342,7 +2356,7 @@ and statement stmt after quantified minus_quantified
            make_seq
              [start_brace;
                quantify guard b3fvs
-                 (statement_list body
+                 (statement_list body NotTop
                     (After (make_seq_after end_brace after))
                     new_quantified3 new_mquantified3 None llabel slabel
                     false guard)] in
@@ -2361,7 +2375,7 @@ and statement stmt after quantified minus_quantified
        | _ -> failwith "not possible" in
       let define_header = quantify guard hfvs (make_match header) in
       let body_code =
-       statement_list body after
+       statement_list body NotTop after
          (Common.union_set bfvs quantified)
          (Common.union_set mbfvs minus_quantified)
          None llabel slabel true guard in
@@ -2383,7 +2397,7 @@ and do_between_dots stmt term after quantified minus_quantified
       Ast.AddingBetweenDots (brace_term,n)
     | Ast.DroppingBetweenDots (brace_term,n) ->
        let match_brace =
-         statement brace_term after quantified minus_quantified
+         statement brace_term NotTop after quantified minus_quantified
            label llabel slabel guard in
        let v = Printf.sprintf "_r_%d" n in
        let case1 = ctl_and CTL.NONSTRICT (CTL.Ref v) match_brace in
@@ -2405,11 +2419,64 @@ and process_bef_aft quantified minus_quantified label llabel slabel guard =
       quantify true (get_unquantified quantified [n])
        (ctl_and s (make_raw_match None guard re) paren_pred)
   | Ast.Other s ->
-      statement s Tail quantified minus_quantified label llabel slabel guard
+      statement s NotTop Tail quantified minus_quantified
+       label llabel slabel guard
   | Ast.Other_dots d ->
-      statement_list d Tail quantified minus_quantified
+      statement_list d NotTop Tail quantified minus_quantified
        label llabel slabel true guard
 
+and protect_top_level stmt_dots formula =
+  let starts_with_dots =
+    match Ast.undots stmt_dots with
+      d::ds ->
+       (match Ast.unwrap d with
+         Ast.Dots(_,_,_,_) | Ast.Circles(_,_,_,_)
+       | Ast.Stars(_,_,_,_) -> true
+       | _ -> false)
+    | _ -> false in
+  let starts_with_non_context_brace =
+    (* None = No danger
+       Some false = OK except on function braces
+       Some true = Never OK *)
+    match Ast.undots stmt_dots with
+      d::ds ->
+       (match Ast.unwrap d with
+         Ast.Seq(before,body,after) ->
+           let beforemc =
+             match Ast.unwrap before with
+               Ast.SeqStart(obr) -> Ast.get_mcodekind obr
+             | _ -> failwith "bad seq" in
+           let aftermc =
+             match Ast.unwrap after with
+               Ast.SeqEnd(cbr) -> Ast.get_mcodekind cbr
+             | _ -> failwith "bad seq"in
+           (match (beforemc,aftermc) with
+              (* safe cases *)
+             (Ast.CONTEXT(_,(Ast.NOTHING|Ast.AFTER _)),
+              Ast.CONTEXT(_,(Ast.NOTHING|Ast.BEFORE _))) -> None
+           | (Ast.MINUS(_,_,_,Ast.NOREPLACEMENT),
+              Ast.MINUS(_,_,_,Ast.NOREPLACEMENT))
+             when List.length (Ast.undots body) = 1 -> Some false (*ok on if*)
+             (* unsafe, can't be allowed to match fn top *)
+           | _ -> Some true)
+       | _ -> None)
+    | _ -> None in
+  if starts_with_dots
+  then (* EX because there is a loop on enter/top *)
+    ctl_and CTL.NONSTRICT (toppred None) (ctl_ex formula)
+  else
+    match starts_with_non_context_brace with
+      None -> formula
+    | Some false ->
+       ctl_and CTL.NONSTRICT
+         (ctl_not(CTL.EX(CTL.BACKWARD,funpred None)))
+         formula
+    | Some true ->
+       ctl_and CTL.NONSTRICT
+         (ctl_not(CTL.EX(CTL.BACKWARD,unsbrpred None)))
+         formula
+
+
 (* --------------------------------------------------------------------- *)
 (* cleanup: convert AX to EX for pdots.
 Concretely: AX(A[...] & E[...]) becomes AX(A[...]) & EX(E[...])
@@ -2480,41 +2547,17 @@ let top_level name ((ua,pos),fua) (fuas,t) =
        let unopt = elim_opt.V.rebuilder_statement stmt in
        let unopt = preprocess_dots_e unopt in
        let formula =
-         cleanup(statement unopt VeryEnd quantified [] None None None false) in
+         cleanup
+           (statement unopt Top VeryEnd quantified [] None None None false) in
        ((function x -> NONDECL x), formula)
     | Ast.CODE(stmt_dots) ->
        let unopt = elim_opt.V.rebuilder_statement_dots stmt_dots in
        let unopt = preprocess_dots unopt in
-       let starts_with_dots =
-         match Ast.undots stmt_dots with
-           d::ds ->
-             (match Ast.unwrap d with
-               Ast.Dots(_,_,_,_) | Ast.Circles(_,_,_,_)
-             | Ast.Stars(_,_,_,_) -> true
-             | _ -> false)
-         | _ -> false in
-       let starts_with_brace =
-         match Ast.undots stmt_dots with
-           d::ds ->
-             (match Ast.unwrap d with
-               Ast.Seq(_) -> true
-             | _ -> false)
-         | _ -> false in
-       let res =
-         statement_list unopt VeryEnd quantified [] None None None
-           false false in
        let formula =
-         cleanup
-           (if starts_with_dots
-           then
-         (* EX because there is a loop on enter/top *)
-             ctl_and CTL.NONSTRICT (toppred None) (ctl_ex res)
-           else if starts_with_brace
-           then
-             ctl_and CTL.NONSTRICT
-               (ctl_not(CTL.EX(CTL.BACKWARD,(funpred None)))) res
-           else res) in
-       ((function x -> CODE x), formula)
+         statement_list unopt Top VeryEnd quantified [] None None None
+           false false in
+       let clean_formula = cleanup (protect_top_level stmt_dots formula) in
+       ((function x -> CODE x), clean_formula)
     | Ast.ERRORWORDS(exps) -> failwith "not supported errorwords" in
   wrap (quantify false quantified formula)
 
index a5e297c..ba77dbc 100644 (file)
@@ -691,7 +691,9 @@ module type PARAM =
 
     val optional_storage_flag : (bool -> tin -> 'x tout) -> (tin -> 'x tout)
     val optional_qualifier_flag : (bool -> tin -> 'x tout) -> (tin -> 'x tout)
-    val value_format_flag: (bool -> tin -> 'x tout) -> (tin -> 'x tout)
+    val value_format_flag : (bool -> tin -> 'x tout) -> (tin -> 'x tout)
+    val optional_declarer_semicolon_flag :
+       (bool -> tin -> 'x tout) -> (tin -> 'x tout)
 
   end
 
@@ -1774,7 +1776,7 @@ and (declaration: (A.mcodekind * bool * A.declaration,B.declaration) matcher) =
         error ii
          "More than one variable in the declaration, and so it cannot be transformed.  Check that there is no transformation on the type or the ;"
 
-  | A.MacroDecl (sa,lpa,eas,rpa,enda), B.MacroDecl ((sb,ebs),ii) ->
+  | A.MacroDecl (sa,lpa,eas,rpa,enda), B.MacroDecl ((sb,ebs,true),ii) ->
       let (iisb, lpb, rpb, iiendb, iifakestart, iistob) =
         (match ii with
         | iisb::lpb::rpb::iiendb::iifakestart::iisto ->
@@ -1797,10 +1799,41 @@ and (declaration: (A.mcodekind * bool * A.declaration,B.declaration) matcher) =
           return (
             (mckstart, allminus,
             (A.MacroDecl (sa,lpa,eas,rpa,enda)) +> A.rewrap decla),
-            (B.MacroDecl ((sb,ebs),
+            (B.MacroDecl ((sb,ebs,true),
                          [iisb;lpb;rpb;iiendb;iifakestart] ++ iistob))
           ))))))))
 
+  | A.MacroDecl (sa,lpa,eas,rpa,enda), B.MacroDecl ((sb,ebs,false),ii) ->
+      X.optional_declarer_semicolon_flag (fun optional_declarer_semicolon ->
+      match mcodekind enda, optional_declarer_semicolon with
+       A.CONTEXT (_,A.NOTHING), true ->
+         let (iisb, lpb, rpb, iifakestart, iistob) =
+            (match ii with
+            | iisb::lpb::rpb::iifakestart::iisto ->
+               (iisb,lpb,rpb,iifakestart,iisto)
+            | _ -> raise Impossible) in
+         (if allminus
+         then minusize_list iistob
+         else return ((), iistob)) >>=
+         (fun () iistob ->
+
+           X.tokenf_mck mckstart iifakestart >>=
+           (fun mckstart iifakestart ->
+             ident DontKnow sa (sb, iisb) >>= (fun sa (sb, iisb) ->
+             tokenf lpa lpb >>= (fun lpa lpb ->
+             tokenf rpa rpb >>= (fun rpa rpb ->
+             arguments (seqstyle eas) (A.undots eas) ebs >>=
+               (fun easundots ebs ->
+                 let eas = redots eas easundots in
+
+                 return (
+                 (mckstart, allminus,
+                  (A.MacroDecl (sa,lpa,eas,rpa,enda)) +> A.rewrap decla),
+                 (B.MacroDecl ((sb,ebs,false),
+                               [iisb;lpb;rpb;iifakestart] ++ iistob))
+                 )))))))
+      | _ -> fail)
+
   | _, (B.MacroDecl _ |B.DeclList _) ->      fail
 
 
@@ -4131,8 +4164,9 @@ let rec (rule_elem_node: (A.rule_elem, Control_flow_c.node) matcher) =
   (* todo?: print a warning at least ? *)
   | _, F.CaseRange _
   | _, F.Asm _
-  | _, F.MacroTop _
     -> fail2()
+  | _, F.MacroTop _
+    -> Printf.printf "have macrotop\n"; fail2()
 
   | _, (F.IfdefEndif _|F.IfdefElse _|F.IfdefHeader _)
     -> fail2 ()
@@ -4155,4 +4189,3 @@ let rec (rule_elem_node: (A.rule_elem, Control_flow_c.node) matcher) =
 
   )
 end
-
index f5ff82e..cf0f53c 100644 (file)
@@ -201,7 +201,8 @@ module type PARAM =
     val optional_storage_flag : (bool -> tin -> 'x tout) -> (tin -> 'x tout)
     val optional_qualifier_flag : (bool -> tin -> 'x tout) -> (tin -> 'x tout)
     val value_format_flag: (bool -> tin -> 'x tout) -> (tin -> 'x tout)
-
+    val optional_declarer_semicolon_flag :
+       (bool -> tin -> 'x tout) -> (tin -> 'x tout)
 
   end
 
index fbb0680..65ed6a9 100644 (file)
@@ -143,6 +143,15 @@ let (labels_for_ctl: string list (* dropped isos *) ->
       | Lib_engine.ErrorExit,   F.ErrorExit -> [nodei, (p,[])]
       |        Lib_engine.Goto,        F.Goto(_,_,_) -> [nodei, (p,[])]
 
+      | Lib_engine.UnsafeBrace, node ->
+         (* cases where it it not safe to put something on the outer side
+            of braces *)
+         (match node with
+           F.FunHeader _ | F.DoHeader _ | F.TrueNode _ | F.Else _
+         | F.InLoopNode _ (* while, for *) | F.SwitchHeader _ ->
+             [nodei, (p,[])]
+         | _ -> [])
+
       | Lib_engine.InLoop , _ -> []
       | Lib_engine.TrueBranch , _ -> []
       | Lib_engine.FalseBranch, _ -> []
index b9308be..13ec0ac 100644 (file)
@@ -269,6 +269,7 @@ let pred2c = function
   | Lib_engine.LoopFallThrough -> ("\\msf{LoopFallThrough}",15)
   | Lib_engine.Return -> ("\\msf{Return}",6)
   | Lib_engine.FunHeader -> ("\\msf{FunHeader}",9)
+  | Lib_engine.UnsafeBrace -> ("\\msf{UnsafeBrace}",11)
   | Lib_engine.Top -> ("\\msf{Top}",3)
   | Lib_engine.Exit -> ("\\msf{Exit}",4)
   | Lib_engine.ErrorExit -> ("\\msf{ErrorExit}",9)
index 7db4a94..5919dc9 100644 (file)
@@ -34,7 +34,7 @@ type predicate =
   | After (* pointer to the code after an if or while *)
   | FallThrough | LoopFallThrough
   | Return (* any exit from the current function *)
-  | FunHeader | Top | Exit | ErrorExit | Goto
+  | FunHeader | UnsafeBrace | Top | Exit | ErrorExit | Goto
   | Paren of Ast_cocci.meta_name
   | Match of Ast_cocci.rule_elem
   | Label of Ast_cocci.meta_name
index 122717b..bf874c9 100644 (file)
@@ -34,6 +34,7 @@ type xinfo = {
   optional_storage_iso : bool;
   optional_qualifier_iso : bool;
   value_format_iso : bool;
+  optional_declarer_semicolon_iso : bool;
 }
 
 module XMATCH = struct
@@ -536,6 +537,9 @@ module XMATCH = struct
   let value_format_flag f = fun tin ->
     f (tin.extra.value_format_iso) tin
 
+  let optional_declarer_semicolon_flag f = fun tin ->
+    f (tin.extra.optional_declarer_semicolon_iso) tin
+
   (* ------------------------------------------------------------------------*)
   (* Tokens *)
   (* ------------------------------------------------------------------------*)
@@ -566,6 +570,8 @@ let match_re_node2 dropped_isos a b binding0 =
       optional_storage_iso   = not(List.mem "optional_storage"   dropped_isos);
       optional_qualifier_iso = not(List.mem "optional_qualifier" dropped_isos);
       value_format_iso       = not(List.mem "value_format"       dropped_isos);
+      optional_declarer_semicolon_iso =
+        not(List.mem "optional_declarer_semicolon"   dropped_isos);
     };
     XMATCH.binding = [];
     XMATCH.binding0 = binding0;
index a1b5d37..6c964c9 100644 (file)
@@ -107,6 +107,7 @@ let rec pp_predicate = function
   | FallThrough -> pp "FallThrough"
   | LoopFallThrough -> pp "LoopFallThrough"
   | Return -> pp "Return"
+  | UnsafeBrace -> pp "UnsafeBrace"
   | FunHeader -> pp "FunHeader"
   | Top -> pp "Top"
   | ErrorExit -> pp "ErrorExit"
index 6270e73..631673c 100644 (file)
@@ -35,6 +35,7 @@ type xinfo = {
   optional_storage_iso : bool;
   optional_qualifier_iso : bool;
   value_format_iso : bool;
+  optional_declarer_semicolon_iso : bool;
   current_rule_name : string; (* used for errors *)
   index : int list (* witness tree indices *)
 }
@@ -103,6 +104,9 @@ module XTRANS = struct
   let value_format_flag f = fun tin ->
     f (tin.extra.value_format_iso) tin
 
+  let optional_declarer_semicolon_flag f = fun tin ->
+    f (tin.extra.optional_declarer_semicolon_iso) tin
+
   let mode = Cocci_vs_c.TransformMode
 
   (* ------------------------------------------------------------------------*)
@@ -608,6 +612,8 @@ let (transform2: string (* rule name *) -> string list (* dropped_isos *) ->
      optional_storage_iso   = not(List.mem "optional_storage" dropped_isos);
      optional_qualifier_iso = not(List.mem "optional_qualifier" dropped_isos);
      value_format_iso = not(List.mem "value_format" dropped_isos);
+     optional_declarer_semicolon_iso =
+       not(List.mem "optional_declarer_semicolon"   dropped_isos);
      current_rule_name = rule_name;
      index = [];
    } in
index c254ac2..b80e672 100644 (file)
@@ -1,4 +1,4 @@
-let version = "1.0.0-rc3"
+let version = "1.0.0-rc4"
 
 let path =
   try (Sys.getenv "COCCINELLE_HOME")
diff --git a/main.ml b/main.ml
index 81cacc7..e56383c 100644 (file)
--- a/main.ml
+++ b/main.ml
@@ -345,7 +345,7 @@ let short_options = [
     "  guess what";
 
   "-date",   Arg.Unit (fun () ->
-    pr2 "version: $Date: 2011/03/14 21:16:17 $";
+    pr2 "version: $Date: 2011/06/23 11:11:16 $";
     raise (Common.UnixExit 0)
     ),
   "   guess what";
@@ -614,6 +614,11 @@ let other_options = [
   [
     "-use_cache", Arg.Set Flag_parsing_c.use_cache,
     "   use .ast_raw pre-parsed cached C file";
+    "-cache_prefix",
+    Arg.String (function s ->
+      Flag_parsing_c.cache_prefix := Some s;
+      Flag_parsing_c.use_cache := true),
+    "   directory of cached ASTs, sets -use_cache";
     (* could use Flag_parsing_c.options_pad instead *)
   ];
 
@@ -872,7 +877,7 @@ let main_action xs =
                  groups +> List.map (function Kbuild.Group xs -> xs)
                    )
           in
-         
+
          let infiles =
            match (!distrib_index,!distrib_max) with
              (None,None) -> infiles
@@ -940,7 +945,8 @@ let main_action xs =
              (cocci_infos,res)) in
          let outfiles = List.concat outfiles in
          (match Iteration.get_pending_instance() with
-           None -> (x,xs,cocci_infos,outfiles)
+           None ->
+             (x,xs,cocci_infos,outfiles)
          | Some (files,virt_rules,virt_ids) ->
              if outfiles = [] or outfiles = [] or not !FC.show_diff
              then
index 19e2e98..8b09fbf 100644 (file)
@@ -31,4 +31,6 @@ let fcts : (string, param_type list -> string ref list -> unit) Hashtbl.t =
 
 let inc_match = ref true
 let include_match x = inc_match := x
+let exited = ref true
+let exit _ = exited := true
 let dir () = !Flag.dir
index 7f3c10d..c79d8ef 100644 (file)
@@ -29,4 +29,6 @@ val fcts : (string, param_type list -> string ref list -> unit) Hashtbl.t
 
 val inc_match : bool ref
 val include_match : bool -> unit
+val exited : bool ref
+val exit : unit -> unit
 val dir : unit -> string
index 2c57cc9..ce5fa89 100644 (file)
@@ -66,6 +66,7 @@ let run mv ve script_vars name code =
 
   (* call the function *)
   Coccilib.include_match true;
+  Coccilib.exited := false;
   let fn =
     try Hashtbl.find Coccilib.fcts name
     with Not_found -> failwith (Printf.sprintf "%s not found" name) in
index a1e9760..450b5a9 100644 (file)
@@ -515,7 +515,8 @@ and statement = statementbis wrap3
 and declaration =
   | DeclList of onedecl wrap2 (* , *) list wrap (* ; fakestart sto *)
   (* cppext: *)
-  | MacroDecl of (string * argument wrap2 list) wrap (* fakestart *)
+    (* bool is true if there is a ; at the end *)
+  | MacroDecl of (string * argument wrap2 list * bool) wrap (* fakestart *)
 
      and onedecl =
        { v_namei: (name * v_init) option;
index b346791..a706003 100644 (file)
@@ -350,6 +350,8 @@ let rec (aux_statement: (nodei option * xinfo) -> statement -> nodei option) =
             let endi = !g#add_node endnode in
            if xi.compound_caller = Statement
            then
+             (* Problem! This edge is only created if the block does not
+                have return on all execution paths. *)
              (let afteri = !g +> add_node AfterNode lbl "[after]" in
              !g#add_arc ((newi, afteri), Direct);
              !g#add_arc ((afteri, endi), Direct));
index 8852ffa..9a6114d 100644 (file)
@@ -193,6 +193,7 @@ let diff_lines = ref (None : string option) (* number of lines of context *)
 
 (* for parse_c *)
 let use_cache = ref false
+let cache_prefix = ref (None : string option)
 
 let cmdline_flags_other () =
   [
index 0d88443..12f42d5 100644 (file)
@@ -171,7 +171,8 @@ let keyword_table = Common.hash_of_list [
 
 let cpp_keyword_table = Common.hash_of_list [
   "new",   (fun ii -> Tnew ii);
-  "delete",(fun ii -> Tdelete ii) ]
+  "delete",(fun ii -> Tdelete ii);
+  "using", (fun ii -> TComment ii) ]
 
 let error_radix s =
   ("numeric " ^ s ^ " constant contains digits beyond the radix:")
index 5bfe014..c47afda 100644 (file)
@@ -1080,7 +1080,8 @@ let parse_cache file =
     (* could add some of the flags of flag_parsing_c.ml *)
     []
   in
-  Common.cache_computation_robust
+  Common.cache_computation_robust_in_dir
+    !Flag_parsing_c.cache_prefix
     file ".ast_raw"
     (need_no_changed_files, need_no_changed_variables) ".depend_raw"
     (fun () -> parse_print_error_heuristic None None file)
index 54e22c3..e0e1831 100644 (file)
@@ -1339,13 +1339,13 @@ decl2:
 
  | TMacroDecl TOPar argument_list TCPar TPtVirg
      { function _ ->
-       MacroDecl ((fst $1, $3), [snd $1;$2;$4;$5;fakeInfo()]) }
+       MacroDecl ((fst $1, $3, true), [snd $1;$2;$4;$5;fakeInfo()]) }
  | Tstatic TMacroDecl TOPar argument_list TCPar TPtVirg
      { function _ ->
-       MacroDecl ((fst $2, $4), [snd $2;$3;$5;$6;fakeInfo();$1]) }
+       MacroDecl ((fst $2, $4, true), [snd $2;$3;$5;$6;fakeInfo();$1]) }
  | Tstatic TMacroDeclConst TMacroDecl TOPar argument_list TCPar TPtVirg
      { function _ ->
-       MacroDecl ((fst $3, $5), [snd $3;$4;$6;$7;fakeInfo();$1;$2])}
+       MacroDecl ((fst $3, $5, true), [snd $3;$4;$6;$7;fakeInfo();$1;$2])}
 
 
 /*(*-----------------------------------------------------------------------*)*/
@@ -1849,13 +1849,13 @@ cpp_other:
     *)*/
  | identifier TOPar argument_list TCPar TPtVirg
      {
-       Declaration (MacroDecl ((fst $1, $3), [snd $1;$2;$4;$5;fakeInfo()]))
+       Declaration(MacroDecl((fst $1, $3, true), [snd $1;$2;$4;$5;fakeInfo()]))
        (* old: MacroTop (fst $1, $3,    [snd $1;$2;$4;$5])  *)
      }
 
  /*(* TCParEOL to fix the end-of-stream bug of ocamlyacc *)*/
  | identifier TOPar argument_list TCParEOL
-     { MacroTop (fst $1, $3,    [snd $1;$2;$4;fakeInfo()]) }
+     { Declaration (MacroDecl ((fst $1, $3, false), [snd $1;$2;$4;fakeInfo()])) }
 
   /*(* ex: EXPORT_NO_SYMBOLS; *)*/
  | identifier TPtVirg { EmptyDef [snd $1;$2] }
index a1bbcc1..8029f09 100644 (file)
@@ -899,7 +899,7 @@ let mk_pretty_printers
 
        pr_elem iivirg;
 
-    | MacroDecl ((s, es), iis::lp::rp::iiend::ifakestart::iisto) ->
+    | MacroDecl ((s, es, true), iis::lp::rp::iiend::ifakestart::iisto) ->
        pr_elem ifakestart;
        iisto +> List.iter pr_elem; (* static and const *)
        pr_elem iis;
@@ -913,6 +913,19 @@ let mk_pretty_printers
        pr_elem rp;
        pr_elem iiend;
 
+    | MacroDecl ((s, es, false), iis::lp::rp::ifakestart::iisto) ->
+       pr_elem ifakestart;
+       iisto +> List.iter pr_elem; (* static and const *)
+       pr_elem iis;
+       pr_elem lp;
+       es +> List.iter (fun (e, opt) ->
+          assert (List.length opt <= 1);
+          opt +> List.iter pr_elem;
+          pp_argument e;
+       );
+
+       pr_elem rp;
+
     | (DeclList (_, _) | (MacroDecl _)) -> raise Impossible
 
 
index 9d6d761..ca8841f 100644 (file)
@@ -498,7 +498,7 @@ and vk_decl = fun bigf d ->
         iif ii;
         vk_onedecl bigf x;
       );
-    | MacroDecl ((s, args),ii) ->
+    | MacroDecl ((s, args, ptvg),ii) ->
         iif ii;
         vk_argument_list bigf args;
   in f (k, bigf) d
@@ -1291,11 +1291,11 @@ and vk_decl_s = fun bigf d ->
     match decl with
     | DeclList (xs, ii) ->
         DeclList (List.map aux xs,   iif ii)
-    | MacroDecl ((s, args),ii) ->
+    | MacroDecl ((s, args, ptvg),ii) ->
         MacroDecl
           ((s,
-           args +> List.map (fun (e,ii) -> vk_argument_s bigf e, iif ii)
-           ),
+           args +> List.map (fun (e,ii) -> vk_argument_s bigf e, iif ii),
+           ptvg),
           iif ii)
 
 
index 793ed33..7f3f485 100644 (file)
@@ -62,9 +62,12 @@ let pycocci_instantiate_class fqn args = failwith "no python"
 (* end python interaction *)
 
 let inc_match = ref false
+let exited = ref false
 
 let include_match v = failwith "no python"
 
+let sp_exit _ = failwith "no python"
+
 let build_method (mname, camlfunc, args) pymodule classx classdict =
   failwith "no python"
 
index f0778bd..6c2b0c6 100644 (file)
@@ -29,6 +29,7 @@ val construct_variables :
 val construct_script_variables : Ast_cocci.meta_name list -> unit
 val pyrun_simplestring : string -> int
 val inc_match : bool ref
+val exited : bool ref
 val retrieve_script_variables : Ast_cocci.meta_name list -> string list
 exception Pycocciexception 
 val set_coccifile : string -> unit
index 6c01be9..39e0468 100644 (file)
@@ -115,6 +115,7 @@ let pycocci_instantiate_class fqn args =
 (* end python interaction *)
 
 let inc_match = ref true
+let exited = ref false
 
 let include_match v =
   let truth = pyobject_istrue (pytuple_getitem (v, 1)) in
@@ -122,6 +123,10 @@ let include_match v =
   inc_match := truth != 0;
   _pycocci_none ()
 
+let sp_exit _ =
+  exited := true;
+  _pycocci_none ()
+
 let build_method (mname, camlfunc, args) pymodule classx classdict =
   let cmx = pymethod_new(pywrap_closure camlfunc, args, classx) in
   let v = pydict_setitemstring(classdict, mname, cmx) in
@@ -186,7 +191,8 @@ let pycocci_init () =
   coccinelle_module := pymodule_new "coccinelle";
   let mx = !coccinelle_module in
   let (cd, cx) = build_class "Cocci" (!Flag.pyoutput)
-      [("include_match", include_match, (pynull()));
+      [("exit", sp_exit, (pynull()));
+       ("include_match", include_match, (pynull()));
        ("has_env_binding", has_environment_binding, (pynull()))] mx in
   pyoutputinstance := cx;
   pyoutputdict := cd;
@@ -206,12 +212,13 @@ let added_variables = ref []
 let build_classes env =
   let _ = pycocci_init () in
   inc_match := true;
+  exited := false;
   the_environment := env;
   let mx = !coccinelle_module in
   let dict = pymodule_getdict mx in
   List.iter
     (function
-       "include_match" | "has_env_binding" -> ()
+       "include_match" | "has_env_binding" | "exit" -> ()
       | name ->
          let v = pydict_delitemstring(dict,name) in
          check_int_return_value v)
index 7a6e0dd..e23d249 100644 (file)
  (double_lines.res Ok) (double_switch.res Ok) (doublepos.res Ok)
  (doubleswitch.res Ok) (doundo.res Ok) (dowhile.res Ok) (dropf.res Ok)
  (dropparam.res Ok) (eb1.res Ok) (edots.res Ok) (edots_ver1.res Ok)
- (empty.res Ok) (end_commas.res Ok) (endif.res Ok) (enum.res Ok) (exp.res Ok)
- (expnest.res Ok) (expopt.res Ok) (expopt2.res Ok) (expopt3.res Ok)
- (expopt3_ver1.res Ok) (expopt3_ver2.res Ok) (fields.res Ok)
+ (empty.res Ok) (end_commas.res Ok) (endif.res Ok) (enum.res Ok)
+ (exitc.res Ok) (exitp.res (Pb "PROBLEM\n   exn = Failure(\"no python\")\n"))
+ (exp.res Ok) (expnest.res Ok) (expopt.res Ok) (expopt2.res Ok)
+ (expopt3.res Ok) (expopt3_ver1.res Ok) (expopt3_ver2.res Ok) (fields.res Ok)
  (fieldsmin.res Ok) (find_long.res Ok) (fix_flow_need.res Ok)
  (fn_todo.res Ok) (fnptr.res Ok) (fnret.res Ok) (fnty.res Ok) (four.res Ok)
  (foura.res Ok) (fp.res Ok) (fsh.res Ok) (fun.res Ok)
   (Pb
    "INCORRECT:diff token: x VS 12\nFile \"tests/incdir.c\", line 4, column 6,  charpos = 46\n    around = 'x', whole content =   foo(x);\nFile \"tests/incdir.res\", line 4, column 6,  charpos = 46\n    around = '12', whole content =   foo(12);\n\n    diff (result(<) vs expected_result(>)) = \n    @@ -1,5 +1,5 @@\n     #include \"sub/incdir2.c\"\n     \n     int main () {\n    -  foo(x);\n    +  foo(12);\n     }\n"))
  (incl.res Ok) (inclifdef.res Ok) (include.res Ok)
- (incompatible_value.res Ok) (inherited.res Ok) (inherited_ver1.res Ok)
- (inhmet.res Ok) (inhpos.res Ok) (initializer.res Ok)
- (initializer_many_fields.res Ok) (inline.res Ok) (insdef.res Ok)
- (isococci.res Ok) (isotest.res Ok) (isotest2.res Ok) (iterator.res Ok)
+ (incompatible_value.res Ok)
+ (incpos.res (Pb "PROBLEM\n   exn = Failure(\"no python\")\n"))
+ (incpos1.res (Pb "PROBLEM\n   exn = Failure(\"no python\")\n"))
+ (inherited.res Ok) (inherited_ver1.res Ok) (inhmet.res Ok) (inhpos.res Ok)
+ (initializer.res Ok) (initializer_many_fields.res Ok) (inline.res Ok)
+ (insdef.res Ok) (isococci.res Ok) (isotest.res Ok) (isotest2.res Ok)
+ (iterator.res Ok)
  (jloop1.res
   (Pb
    "PROBLEM\n   exn = Failure(\"minus: parse error: \\n = File \\\"tests/jloop1.cocci\\\", line 10, column 3,  charpos = 129\\n    around = '...>', whole content =    ...>\\n\")\n"))
    "INCORRECT:diff token: init_MUTEX VS mutex_init\nFile \"tests/serio.c\", line 7, column 1,  charpos = 130\n    around = 'init_MUTEX', whole content = \tinit_MUTEX(&serio->drv_sem);\nFile \"tests/serio.res\", line 7, column 1,  charpos = 130\n    around = 'mutex_init', whole content = \tmutex_init(&serio->new_lock);\n\n    diff (result(<) vs expected_result(>)) = \n    @@ -4,5 +4,5 @@\n     \n     static void serio_init_port(struct serio *serio)\n     {\n    -\tinit_MUTEX(&serio->drv_sem);\n    +\tmutex_init(&serio->new_lock);\n     }\n"))
  (shared_brace.res Ok) (signed.res Ok) (sis.res Ok) (sizeof.res Ok)
  (sizeof_julia.res Ok) (sizeptr.res Ok) (sizestar.res Ok) (skip.res Ok)
- (sp.res Ok) (spaces.res Ok) (spacing.res Ok) (spl.res Ok) (static.res Ok)
- (stm1.res Ok) (stm10.res Ok) (stm10_ver1.res Ok) (stm2.res Ok) (stm3.res Ok)
- (stm4.res Ok) (stm5.res Ok) (stm6.res Ok) (stm7.res Ok) (stm8.res Ok)
- (stmt.res Ok) (str_init.res Ok) (strangeorder.res Ok) (strid.res Ok)
- (strid2.res Ok) (string.res Ok) (struct.res Ok) (struct_metavar.res Ok)
- (struct_typedef.res Ok) (structfoo.res Ok) (substruct.res Ok) (sw.res Ok)
- (switch.res Ok) (switchdecl.res Ok) (td.res Ok) (tern.res Ok) (test0.res Ok)
- (test1.res Ok) (test10.res Ok) (test10_ver1.res Ok) (test11.res Ok)
- (test11_ver1.res Ok) (test12.res Ok) (test2.res Ok) (test3.res Ok)
- (test4.res Ok) (test5.res Ok) (test5_ver1.res Ok) (test6.res Ok)
- (test7.res Ok) (test8.res Ok) (test9.res Ok) (test_s.res Ok)
- (test_unsigned_meta.res Ok) (three_types.res Ok) (threea.res Ok)
- (top.res Ok) (topdec.res Ok) (topdec_ver1.res Ok) (topdec_ver2.res Ok)
- (toplevel_macrostmt.res Ok) (toplevel_struct.res Ok) (tup.res Ok)
- (twoproto.res Ok) (ty.res Ok) (ty1.res Ok) (ty_tyexp.res Ok) (tydisj.res Ok)
- (tyex.res Ok) (type.res Ok) (type1.res Ok) (type_annotated.res Ok)
- (type_ver1.res Ok)
+ (smallfn.res Ok) (sp.res Ok) (spaces.res Ok) (spacing.res Ok) (spl.res Ok)
+ (static.res Ok) (stm1.res Ok) (stm10.res Ok) (stm10_ver1.res Ok)
+ (stm2.res Ok) (stm3.res Ok) (stm4.res Ok) (stm5.res Ok) (stm6.res Ok)
+ (stm7.res Ok) (stm8.res Ok) (stmt.res Ok) (str_init.res Ok)
+ (strangeorder.res Ok) (strid.res Ok) (strid2.res Ok) (string.res Ok)
+ (struct.res Ok) (struct_metavar.res Ok) (struct_typedef.res Ok)
+ (structfoo.res Ok) (substruct.res Ok) (sw.res Ok) (switch.res Ok)
+ (switchdecl.res Ok) (td.res Ok) (tern.res Ok) (test0.res Ok) (test1.res Ok)
+ (test10.res Ok) (test10_ver1.res Ok) (test11.res Ok) (test11_ver1.res Ok)
+ (test12.res Ok) (test2.res Ok) (test3.res Ok) (test4.res Ok) (test5.res Ok)
+ (test5_ver1.res Ok) (test6.res Ok) (test7.res Ok) (test8.res Ok)
+ (test9.res Ok) (test_s.res Ok) (test_unsigned_meta.res Ok)
+ (three_types.res Ok) (threea.res Ok) (top.res Ok) (topdec.res Ok)
+ (topdec_ver1.res Ok) (topdec_ver2.res Ok) (toplevel_macrostmt.res Ok)
+ (toplevel_struct.res Ok) (tup.res Ok) (twoproto.res Ok) (ty.res Ok)
+ (ty1.res Ok) (ty_tyexp.res Ok) (tydisj.res Ok) (tyex.res Ok) (type.res Ok)
+ (type1.res Ok) (type_annotated.res Ok) (type_ver1.res Ok)
  (type_ver2.res
   (Pb
    "INCORRECT:PB parsing only in generated-file\n    diff (result(<) vs expected_result(>)) = \n    @@ -1,5 +1,5 @@\n     int foo() {\n    -  int[10] *x;\n    +  int *x[10];\n       return 0;\n     }\n     \n"))
index 07f0d75..95c8d2f 100644 (file)
  (double_lines.res Ok) (double_switch.res Ok) (doublepos.res Ok)
  (doubleswitch.res Ok) (doundo.res Ok) (dowhile.res Ok) (dropf.res Ok)
  (dropparam.res Ok) (eb1.res Ok) (edots.res Ok) (edots_ver1.res Ok)
- (empty.res Ok) (end_commas.res Ok) (endif.res Ok) (enum.res Ok) (exp.res Ok)
- (expnest.res Ok) (expopt.res Ok) (expopt2.res Ok) (expopt3.res Ok)
- (expopt3_ver1.res Ok) (expopt3_ver2.res Ok) (fields.res Ok)
+ (empty.res Ok) (end_commas.res Ok) (endif.res Ok) (enum.res Ok)
+ (exitc.res Ok) (exitp.res (Pb "PROBLEM\n   exn = Failure(\"no python\")\n"))
+ (exp.res Ok) (expnest.res Ok) (expopt.res Ok) (expopt2.res Ok)
+ (expopt3.res Ok) (expopt3_ver1.res Ok) (expopt3_ver2.res Ok) (fields.res Ok)
  (fieldsmin.res Ok) (find_long.res Ok) (fix_flow_need.res Ok)
  (fn_todo.res Ok) (fnptr.res Ok) (fnret.res Ok) (fnty.res Ok) (four.res Ok)
  (foura.res Ok) (fp.res Ok) (fsh.res Ok) (fun.res Ok)
   (Pb
    "INCORRECT:diff token: x VS 12\nFile \"tests/incdir.c\", line 4, column 6,  charpos = 46\n    around = 'x', whole content =   foo(x);\nFile \"tests/incdir.res\", line 4, column 6,  charpos = 46\n    around = '12', whole content =   foo(12);\n\n    diff (result(<) vs expected_result(>)) = \n    @@ -1,5 +1,5 @@\n     #include \"sub/incdir2.c\"\n     \n     int main () {\n    -  foo(x);\n    +  foo(12);\n     }\n"))
  (incl.res Ok) (inclifdef.res Ok) (include.res Ok)
- (incompatible_value.res Ok) (inherited.res Ok) (inherited_ver1.res Ok)
- (inhmet.res Ok) (inhpos.res Ok) (initializer.res Ok)
- (initializer_many_fields.res Ok) (inline.res Ok) (insdef.res Ok)
- (isococci.res Ok) (isotest.res Ok) (isotest2.res Ok) (iterator.res Ok)
+ (incompatible_value.res Ok)
+ (incpos.res (Pb "PROBLEM\n   exn = Failure(\"no python\")\n"))
+ (incpos1.res (Pb "PROBLEM\n   exn = Failure(\"no python\")\n"))
+ (inherited.res Ok) (inherited_ver1.res Ok) (inhmet.res Ok) (inhpos.res Ok)
+ (initializer.res Ok) (initializer_many_fields.res Ok) (inline.res Ok)
+ (insdef.res Ok) (isococci.res Ok) (isotest.res Ok) (isotest2.res Ok)
+ (iterator.res Ok)
  (jloop1.res
   (Pb
    "PROBLEM\n   exn = Failure(\"minus: parse error: \\n = File \\\"tests/jloop1.cocci\\\", line 10, column 3,  charpos = 129\\n    around = '...>', whole content =    ...>\\n\")\n"))
    "INCORRECT:diff token: init_MUTEX VS mutex_init\nFile \"tests/serio.c\", line 7, column 1,  charpos = 130\n    around = 'init_MUTEX', whole content = \tinit_MUTEX(&serio->drv_sem);\nFile \"tests/serio.res\", line 7, column 1,  charpos = 130\n    around = 'mutex_init', whole content = \tmutex_init(&serio->new_lock);\n\n    diff (result(<) vs expected_result(>)) = \n    @@ -4,5 +4,5 @@\n     \n     static void serio_init_port(struct serio *serio)\n     {\n    -\tinit_MUTEX(&serio->drv_sem);\n    +\tmutex_init(&serio->new_lock);\n     }\n"))
  (shared_brace.res Ok) (signed.res Ok) (sis.res Ok) (sizeof.res Ok)
  (sizeof_julia.res Ok) (sizeptr.res Ok) (sizestar.res Ok) (skip.res Ok)
- (sp.res Ok) (spaces.res Ok) (spacing.res Ok) (spl.res Ok) (static.res Ok)
- (stm1.res (Pb "PROBLEM\n   exn = Failure(\"no python\")\n")) (stm10.res Ok)
- (stm10_ver1.res Ok) (stm2.res Ok) (stm3.res Ok) (stm4.res Ok) (stm5.res Ok)
- (stm6.res Ok) (stm7.res (Pb "PROBLEM\n   exn = Failure(\"no python\")\n"))
- (stm8.res Ok) (stmt.res Ok) (str_init.res Ok) (strangeorder.res Ok)
- (strid.res Ok) (strid2.res Ok) (string.res Ok) (struct.res Ok)
- (struct_metavar.res Ok) (struct_typedef.res Ok) (structfoo.res Ok)
- (substruct.res Ok) (sw.res Ok) (switch.res Ok) (switchdecl.res Ok)
- (td.res Ok) (tern.res Ok) (test0.res Ok) (test1.res Ok) (test10.res Ok)
- (test10_ver1.res Ok) (test11.res Ok) (test11_ver1.res Ok) (test12.res Ok)
- (test2.res Ok) (test3.res Ok) (test4.res Ok) (test5.res Ok)
- (test5_ver1.res Ok) (test6.res Ok) (test7.res Ok) (test8.res Ok)
- (test9.res Ok) (test_s.res Ok) (test_unsigned_meta.res Ok)
- (three_types.res Ok) (threea.res Ok) (top.res Ok) (topdec.res Ok)
- (topdec_ver1.res Ok) (topdec_ver2.res Ok) (toplevel_macrostmt.res Ok)
- (toplevel_struct.res Ok) (tup.res Ok) (twoproto.res Ok) (ty.res Ok)
- (ty1.res Ok) (ty_tyexp.res Ok) (tydisj.res Ok) (tyex.res Ok) (type.res Ok)
- (type1.res Ok) (type_annotated.res Ok) (type_ver1.res Ok)
+ (smallfn.res Ok) (sp.res Ok) (spaces.res Ok) (spacing.res Ok) (spl.res Ok)
+ (static.res Ok) (stm1.res (Pb "PROBLEM\n   exn = Failure(\"no python\")\n"))
+ (stm10.res Ok) (stm10_ver1.res Ok) (stm2.res Ok) (stm3.res Ok) (stm4.res Ok)
+ (stm5.res Ok) (stm6.res Ok)
+ (stm7.res (Pb "PROBLEM\n   exn = Failure(\"no python\")\n")) (stm8.res Ok)
+ (stmt.res Ok) (str_init.res Ok) (strangeorder.res Ok) (strid.res Ok)
+ (strid2.res Ok) (string.res Ok) (struct.res Ok) (struct_metavar.res Ok)
+ (struct_typedef.res Ok) (structfoo.res Ok) (substruct.res Ok) (sw.res Ok)
+ (switch.res Ok) (switchdecl.res Ok) (td.res Ok) (tern.res Ok) (test0.res Ok)
+ (test1.res Ok) (test10.res Ok) (test10_ver1.res Ok) (test11.res Ok)
+ (test11_ver1.res Ok) (test12.res Ok) (test2.res Ok) (test3.res Ok)
+ (test4.res Ok) (test5.res Ok) (test5_ver1.res Ok) (test6.res Ok)
+ (test7.res Ok) (test8.res Ok) (test9.res Ok) (test_s.res Ok)
+ (test_unsigned_meta.res Ok) (three_types.res Ok) (threea.res Ok)
+ (top.res Ok) (topdec.res Ok) (topdec_ver1.res Ok) (topdec_ver2.res Ok)
+ (toplevel_macrostmt.res Ok) (toplevel_struct.res Ok) (tup.res Ok)
+ (twoproto.res Ok) (ty.res Ok) (ty1.res Ok) (ty_tyexp.res Ok) (tydisj.res Ok)
+ (tyex.res Ok) (type.res Ok) (type1.res Ok) (type_annotated.res Ok)
+ (type_ver1.res Ok)
  (type_ver2.res
   (Pb
    "INCORRECT:PB parsing only in generated-file\n    diff (result(<) vs expected_result(>)) = \n    @@ -1,5 +1,5 @@\n     int foo() {\n    -  int[10] *x;\n    +  int *x[10];\n       return 0;\n     }\n     \n"))
diff --git a/tests/exitc.c b/tests/exitc.c
new file mode 100644 (file)
index 0000000..06b89c3
--- /dev/null
@@ -0,0 +1,6 @@
+int main () {
+  f(a1);
+  f(a2);
+  f(done);
+  f(a4);
+}
diff --git a/tests/exitc.cocci b/tests/exitc.cocci
new file mode 100644 (file)
index 0000000..dba50cd
--- /dev/null
@@ -0,0 +1,21 @@
+@r@
+identifier x;
+@@
+
+-f(x);
++g(x);
+
+@script:ocaml@
+x << r.x;
+@@
+
+if x = "done" then
+  Coccilib.exit()
+
+@@
+identifier x;
+@@
+
+g(x
++ ,y
+ );
diff --git a/tests/exitc.res b/tests/exitc.res
new file mode 100644 (file)
index 0000000..7e7ade8
--- /dev/null
@@ -0,0 +1,6 @@
+int main () {
+  g(a1);
+  g(a2);
+  g(done);
+  g(a4);
+}
diff --git a/tests/exitp.c b/tests/exitp.c
new file mode 100644 (file)
index 0000000..06b89c3
--- /dev/null
@@ -0,0 +1,6 @@
+int main () {
+  f(a1);
+  f(a2);
+  f(done);
+  f(a4);
+}
diff --git a/tests/exitp.cocci b/tests/exitp.cocci
new file mode 100644 (file)
index 0000000..542f11f
--- /dev/null
@@ -0,0 +1,21 @@
+@r@
+identifier x;
+@@
+
+-f(x);
++g(x);
+
+@script:python@
+x << r.x;
+@@
+
+if ("%s" % x) == "done":
+  cocci.exit()
+
+@@
+identifier x;
+@@
+
+g(x
++ ,y
+ );
diff --git a/tests/exitp.res b/tests/exitp.res
new file mode 100644 (file)
index 0000000..7e7ade8
--- /dev/null
@@ -0,0 +1,6 @@
+int main () {
+  g(a1);
+  g(a2);
+  g(done);
+  g(a4);
+}
diff --git a/tests/incpos.c b/tests/incpos.c
new file mode 100644 (file)
index 0000000..531d878
--- /dev/null
@@ -0,0 +1,5 @@
+#include <one>
+#include "two"
+#include <three>
+#include "four"
+#include <five>
diff --git a/tests/incpos.cocci b/tests/incpos.cocci
new file mode 100644 (file)
index 0000000..c7f8d76
--- /dev/null
@@ -0,0 +1,55 @@
+@initialize:python@
+
+first = 0
+second = 0
+
+@first_hdr@
+position p;
+@@
+
+#include <...>@p
+
+@script:python@
+p << first_hdr.p;
+@@
+
+if first == 0:
+   print "keeping first hdr %s" % (p[0].line)
+   first = int(p[0].line)
+else:
+   print "dropping first hdr"
+   cocci.include_match(False)
+
+@second_hdr@
+position p;
+@@
+
+#include "..."@p
+
+@script:python@
+p << second_hdr.p;
+@@
+
+if int(p[0].line) > first and first != 0:
+   print "dropping second hdr"
+   cocci.include_match(False)
+else:
+   if second == 0:
+      print "keeping second hdr %s because of %d" % (p[0].line,first)
+      second = int(p[0].line)
+   else:
+      print "dropping second hdr"
+      cocci.include_match(False)
+
+@done@
+position second_hdr.p;
+@@
+
++#include <foo.h>
+#include "..."@p
+
+@depends on never done@
+@@
+
++#include <foo.h>
+#include <...>
diff --git a/tests/incpos.res b/tests/incpos.res
new file mode 100644 (file)
index 0000000..2a057cd
--- /dev/null
@@ -0,0 +1,6 @@
+#include <foo.h>
+#include <one>
+#include "two"
+#include <three>
+#include "four"
+#include <five>
diff --git a/tests/incpos1.c b/tests/incpos1.c
new file mode 100644 (file)
index 0000000..7580e12
--- /dev/null
@@ -0,0 +1,4 @@
+#include "two"
+#include <three>
+#include "four"
+#include <five>
diff --git a/tests/incpos1.cocci b/tests/incpos1.cocci
new file mode 100644 (file)
index 0000000..c7f8d76
--- /dev/null
@@ -0,0 +1,55 @@
+@initialize:python@
+
+first = 0
+second = 0
+
+@first_hdr@
+position p;
+@@
+
+#include <...>@p
+
+@script:python@
+p << first_hdr.p;
+@@
+
+if first == 0:
+   print "keeping first hdr %s" % (p[0].line)
+   first = int(p[0].line)
+else:
+   print "dropping first hdr"
+   cocci.include_match(False)
+
+@second_hdr@
+position p;
+@@
+
+#include "..."@p
+
+@script:python@
+p << second_hdr.p;
+@@
+
+if int(p[0].line) > first and first != 0:
+   print "dropping second hdr"
+   cocci.include_match(False)
+else:
+   if second == 0:
+      print "keeping second hdr %s because of %d" % (p[0].line,first)
+      second = int(p[0].line)
+   else:
+      print "dropping second hdr"
+      cocci.include_match(False)
+
+@done@
+position second_hdr.p;
+@@
+
++#include <foo.h>
+#include "..."@p
+
+@depends on never done@
+@@
+
++#include <foo.h>
+#include <...>
diff --git a/tests/incpos1.res b/tests/incpos1.res
new file mode 100644 (file)
index 0000000..fb8b046
--- /dev/null
@@ -0,0 +1,5 @@
+#include <foo.h>
+#include "two"
+#include <three>
+#include "four"
+#include <five>
diff --git a/tests/smallfn.c b/tests/smallfn.c
new file mode 100644 (file)
index 0000000..201e37b
--- /dev/null
@@ -0,0 +1,30 @@
+int main () {
+  if (y) {
+    one();
+  }
+  else {
+    two();
+  }
+ while (y) {
+    one();
+  }
+ do {
+    one();
+ } while(y);
+ switch (y) {
+ case 12:one();
+ case 27:two();
+  }
+{
+    one();
+  }
+}
+
+int main () {
+  if (y) {
+    one();
+  }
+  else {
+    two();
+      }
+}
diff --git a/tests/smallfn.cocci b/tests/smallfn.cocci
new file mode 100644 (file)
index 0000000..42a44ab
--- /dev/null
@@ -0,0 +1,8 @@
+@@
+statement S;
+@@
+
+ {
+ S
+ }
++foo();
diff --git a/tests/smallfn.res b/tests/smallfn.res
new file mode 100644 (file)
index 0000000..fccb7a0
--- /dev/null
@@ -0,0 +1,65 @@
+int main () {
+  if (y) { 
+  {
+    one();
+    foo();
+  }
+  foo();
+}
+  else {
+  {
+    two();
+    foo();
+  }
+  foo();
+}
+foo();
+ while (y) { 
+ {
+    one();
+    foo();
+  }
+  foo();
+}
+foo();
+ {
+ do {
+    one();
+    foo();
+ }
+ foo(); while(y);
+ foo();
+}
+ switch (y) {
+ case 12:
+ foo();one();
+ foo();
+ case 27:
+ foo();two();
+ foo();
+  }
+  foo();
+{
+    one();
+    foo();
+  }
+  foo();
+}
+
+int main () {
+  if (y) { 
+  {
+    one();
+    foo();
+  }
+  foo();
+}
+  else {
+  {
+    two();
+    foo();
+      }
+      foo();
+}
+foo();
+}