Release coccinelle-0.1.5
[bpt/coccinelle.git] / cocci.ml
index 9953d1e..1c1c45a 100644 (file)
--- a/cocci.ml
+++ b/cocci.ml
@@ -1,5 +1,5 @@
 (*
-* Copyright 2005-2008, Ecole des Mines de Nantes, University of Copenhagen
+* Copyright 2005-2009, Ecole des Mines de Nantes, University of Copenhagen
 * Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller
 * This file is part of Coccinelle.
 * 
@@ -46,11 +46,15 @@ let cprogram_of_file file =
 
 let cprogram_of_file_cached file = 
   let (program2, _stat) = Parse_c.parse_cache file in
-  program2
-
+  if !Flag_cocci.ifdef_to_if
+  then 
+    program2 +> Parse_c.with_program2 (fun asts -> 
+      Cpp_ast_c.cpp_ifdef_statementize asts
+    )
+  else program2
 
 let cfile_of_program program2_with_ppmethod outf = 
-  Unparse_c2.pp_program program2_with_ppmethod outf
+  Unparse_c.pp_program program2_with_ppmethod outf
 
 (* for memoization, contains only one entry, the one for the SP *)
 let _hparse = Hashtbl.create 101
@@ -224,12 +228,12 @@ let show_or_not_ctl_tex a b  =
     
 let show_or_not_rule_name ast rulenb =
   if !Flag_cocci.show_ctl_text or !Flag.show_trying or
-    !Flag_cocci.show_transinfo or !Flag_cocci.show_binding_in_out
+    !Flag.show_transinfo or !Flag_cocci.show_binding_in_out
   then
     begin
       let name =
        match ast with
-         Ast_cocci.CocciRule (nm, (deps, drops, exists), x, _) -> nm
+         Ast_cocci.CocciRule (nm, (deps, drops, exists), x, _, _) -> nm
        | _ -> i_to_s rulenb in
       Common.pr_xxxxxxxxxxxxxxxxx ();
       pr (name ^ " = ");
@@ -238,7 +242,7 @@ let show_or_not_rule_name ast rulenb =
 
 let show_or_not_scr_rule_name rulenb =
   if !Flag_cocci.show_ctl_text or !Flag.show_trying or
-    !Flag_cocci.show_transinfo or !Flag_cocci.show_binding_in_out
+    !Flag.show_transinfo or !Flag_cocci.show_binding_in_out
   then
     begin
       let name = i_to_s rulenb in
@@ -272,24 +276,35 @@ let show_or_not_ctl_text a b c =
 
 
 (* running information *)
+let get_celem celem : string = 
+  match celem with 
+      Ast_c.Definition ({Ast_c.f_name = funcs;},_) -> funcs
+    | Ast_c.Declaration
+       (Ast_c.DeclList ([{Ast_c.v_namei = Some ((s, _),_);}, _], _)) -> s
+    | _ -> ""
 
 let show_or_not_celem2 prelude celem = 
-  if !Flag.show_trying then 
+  let (tag,trying) =
   (match celem with 
-  | Ast_c.Definition ((funcs,_,_,_c),_) -> 
-      pr2 (prelude ^ " function: " ^ funcs);
+  | Ast_c.Definition ({Ast_c.f_name = funcs;},_) -> 
+      Flag.current_element := funcs;
+      (" function: ",funcs)
   | Ast_c.Declaration
-      (Ast_c.DeclList ([(Some ((s, _),_), typ, sto, _local), _], _)) ->
-      pr2 (prelude ^ " variable " ^ s);
-  | _ -> 
-      pr2 (prelude ^ " something else");
-  )
+      (Ast_c.DeclList ([{Ast_c.v_namei = Some ((s, _),_);}, _], _)) ->
+      Flag.current_element := s;
+      (" variable ",s);
+  | _ ->
+      Flag.current_element := "something_else";
+      (" ","something else");
+  ) in
+  if !Flag.show_trying then pr2 (prelude ^ tag ^ trying)
+  
 let show_or_not_celem a b  = 
   Common.profile_code "show_xxx" (fun () -> show_or_not_celem2 a b)
 
 
 let show_or_not_trans_info2 trans_info = 
-  if !Flag_cocci.show_transinfo then begin
+  if !Flag.show_transinfo then begin
     if null trans_info then pr2 "transformation info is empty"
     else begin
       pr2 "transformation info returned:";
@@ -404,7 +419,6 @@ let sp_contain_typed_metavar_z toplevel_list_list =
   let combiner = 
     Visitor_ast.combiner bind option_default
       mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode
-      mcode
       donothing donothing donothing donothing
       donothing expression donothing donothing donothing donothing donothing
       donothing donothing donothing donothing donothing 
@@ -420,11 +434,13 @@ let sp_contain_typed_metavar rules =
     (List.map
        (function x ->
         match x with
-          Ast_cocci.CocciRule (a,b,c,d) -> (a,b,c)
+          Ast_cocci.CocciRule (a,b,c,d,_) -> (a,b,c)
         | _ -> failwith "error in filter")
     (List.filter
        (function x ->
-        match x with Ast_cocci.CocciRule _ -> true | _ -> false)
+        match x with
+          Ast_cocci.CocciRule (a,b,c,d,Ast_cocci.Normal) -> true
+        | _ -> false)
        rules))
 
 
@@ -437,31 +453,37 @@ let sp_contain_typed_metavar rules =
  * serio.c is related we think to #include <linux/serio.h> 
  *)
 
-let includes_to_parse xs = 
-  if !Flag_cocci.no_includes
-  then []
-  else
-    xs +> List.map (fun (file, cs) -> 
-      let dir = Common.dirname file in
-      
-      cs +> Common.map_filter (fun (c,_info_item) -> 
-       match c with
-       | Ast_c.Include ((x,ii),info_h_pos)  -> 
-            (match x with
+let (includes_to_parse:
+       (Common.filename * Parse_c.program2) list ->
+        Flag_cocci.include_options -> 'a) = fun xs choose_includes ->
+  match choose_includes with
+    Flag_cocci.I_UNSPECIFIED -> failwith "not possible"
+  | Flag_cocci.I_NO_INCLUDES -> []
+  | x ->
+      let all_includes = x = Flag_cocci.I_ALL_INCLUDES in
+      xs +> List.map (fun (file, cs) -> 
+       let dir = Common.dirname file in
+       
+       cs +> Common.map_filter (fun (c,_info_item) -> 
+         match c with
+         | Ast_c.CppTop
+             (Ast_c.Include
+                {Ast_c.i_include = ((x,ii)); i_rel_pos = info_h_pos;})  -> 
+           (match x with
             | Ast_c.Local xs -> 
                let f = Filename.concat dir (Common.join "/" xs) in
              (* for our tests, all the files are flat in the current dir *)
                if not (Sys.file_exists f) && !Flag_cocci.relax_include_path
                then
                  let attempt2 = Filename.concat dir (Common.last xs) in
-                 if not (Sys.file_exists f) && !Flag_cocci.all_includes
+                 if not (Sys.file_exists f) && all_includes
                  then Some (Filename.concat !Flag_cocci.include_path 
                                (Common.join "/" xs))
                  else Some attempt2
                else Some f
-                   
+
             | Ast_c.NonLocal xs -> 
-               if !Flag_cocci.all_includes ||
+               if all_includes ||
                Common.fileprefix (Common.last xs) = Common.fileprefix file
                then 
                   Some (Filename.concat !Flag_cocci.include_path 
@@ -469,11 +491,9 @@ let includes_to_parse xs =
                else None
             | Ast_c.Wierd _ -> None
                  )
-       | _ -> None
-             )
-       )
-      +> List.concat
-      +> Common.uniq
+         | _ -> None))
+       +> List.concat
+       +> Common.uniq
       
 let rec interpret_dependencies local global = function
     Ast_cocci.Dep s      -> List.mem s local
@@ -494,36 +514,40 @@ let rec interpret_dependencies local global = function
       (interpret_dependencies local global s2)
   | Ast_cocci.NoDep -> true
        
-let rec print_dependencies local global =
-  let seen = ref [] in
-  let rec loop = function
-      Ast_cocci.Dep s | Ast_cocci.AntiDep s ->
-       if not (List.mem s !seen)
-       then
-         begin
-           if List.mem s local
-           then pr2 (s^" satisfied")
-           else pr2 (s^" not satisfied");
-           seen := s :: !seen
-         end 
-    | Ast_cocci.EverDep s | Ast_cocci.NeverDep s ->
-       if not (List.mem s !seen)
-       then
-         begin
-           if List.mem s global
-           then pr2 (s^" satisfied")
-           else pr2 (s^" not satisfied");
-           seen := s :: !seen
-         end
-    | Ast_cocci.AndDep(s1,s2) ->
-       print_dependencies local global s1;
-       print_dependencies local global s2
-    | Ast_cocci.OrDep(s1,s2)  ->
-       print_dependencies local global s1;
-       print_dependencies local global s2
-    | Ast_cocci.NoDep -> () in
-  loop
-    
+let rec print_dependencies str local global dep =
+  if !Flag_cocci.show_dependencies
+  then
+    begin
+      pr2 str;
+      let seen = ref [] in
+      let rec loop = function
+         Ast_cocci.Dep s | Ast_cocci.AntiDep s ->
+           if not (List.mem s !seen)
+           then
+             begin
+               if List.mem s local
+               then pr2 (s^" satisfied")
+               else pr2 (s^" not satisfied");
+               seen := s :: !seen
+             end 
+       | Ast_cocci.EverDep s | Ast_cocci.NeverDep s ->
+           if not (List.mem s !seen)
+           then
+             begin
+               if List.mem s global
+               then pr2 (s^" satisfied")
+               else pr2 (s^" not satisfied");
+               seen := s :: !seen
+             end
+       | Ast_cocci.AndDep(s1,s2) ->
+           loop s1;
+           loop s2
+       | Ast_cocci.OrDep(s1,s2)  ->
+           loop s1;
+           loop s2
+       | Ast_cocci.NoDep -> () in
+      loop dep
+    end
     
     
     
@@ -563,7 +587,9 @@ let compute_new_prefixes xs =
 let rec update_include_rel_pos cs =
   let only_include = cs +> Common.map_filter (fun c -> 
     match c with 
-    | Ast_c.Include ((x,_),(aref, inifdef)) ->
+    | Ast_c.CppTop (Ast_c.Include {Ast_c.i_include = ((x,_));
+                     i_rel_pos = aref;
+                     i_is_in_ifdef = inifdef}) ->
         (match x with
         | Ast_c.Wierd _ -> None
         | _ -> 
@@ -633,6 +659,7 @@ type toplevel_cocci_info_script_rule = {
 
 type toplevel_cocci_info_cocci_rule = {
   ctl: Lib_engine.ctlcocci * (CCI.pred list list);
+  metavars: Ast_cocci.metavar list;
   ast_rule: Ast_cocci.rule;
   isexp: bool; (* true if + code is an exp, only for Flag.make_hrule *)
 
@@ -648,6 +675,7 @@ type toplevel_cocci_info_cocci_rule = {
   positions: Ast_cocci.meta_name list;
 
   ruleid: int;
+  ruletype: Ast_cocci.ruletype;
 
   was_matched: bool ref;
 }
@@ -672,26 +700,48 @@ let g_contain_typedmetavar = ref false
 let last_env_toplevel_c_info xs =
   (Common.last xs).env_typing_after
 
-let concat_headers_and_c ccs = 
-  (List.concat (ccs +> List.map (fun x -> x.asts)))
+let concat_headers_and_c (ccs: file_info list) 
+    : (toplevel_c_info * string) list = 
+  (List.concat (ccs +> List.map (fun x -> 
+                                  x.asts +> List.map (fun x' ->
+                                                        (x', x.fname)))))
 
 let for_unparser xs = 
   xs +> List.map (fun x -> 
-    (x.ast_c, (x.fullstring, x.tokens_c)), Unparse_c2.PPviastr
+    (x.ast_c, (x.fullstring, x.tokens_c)), Unparse_c.PPviastr
   )
 
+let gen_pdf_graph () =
+  (Ctl_engine.get_graph_files ()) +> List.iter (fun outfile -> 
+  Printf.printf "Generation of %s%!" outfile;
+  let filename_stack = Ctl_engine.get_graph_comp_files outfile in
+  List.iter (fun filename ->
+    ignore (Unix.system ("dot " ^ filename ^ " -Tpdf  -o " ^ filename ^ ".pdf;"))
+           ) filename_stack;
+  let (head,tail) = (List.hd filename_stack, List.tl filename_stack) in
+    ignore(Unix.system ("cp " ^ head ^ ".pdf " ^ outfile ^ ".pdf;"));
+    tail +> List.iter (fun filename ->
+      ignore(Unix.system ("mv " ^ outfile ^ ".pdf /tmp/tmp.pdf;"));
+      ignore(Unix.system ("pdftk " ^ filename ^ ".pdf /tmp/tmp.pdf cat output " ^ outfile ^ ".pdf"));
+             );
+    ignore(Unix.system ("rm /tmp/tmp.pdf;"));
+    List.iter (fun filename ->
+       ignore (Unix.system ("rm " ^ filename ^ " " ^ filename ^ ".pdf;"))
+           ) filename_stack;
+  Printf.printf " - Done\n")
+
+
 (* --------------------------------------------------------------------- *)
 let prepare_cocci ctls free_var_lists negated_pos_lists
-    used_after_lists positions_list astcocci = 
+    used_after_lists positions_list metavars astcocci = 
 
   let gathered = Common.index_list_1
-      (zip (zip (zip (zip (zip ctls astcocci) free_var_lists)
+      (zip (zip (zip (zip (zip (zip ctls metavars) astcocci) free_var_lists)
                   negated_pos_lists) used_after_lists) positions_list)
   in
   gathered +> List.map 
-    (fun ((((((ctl_toplevel_list,ast),free_var_list),negated_pos_list),
-          used_after_list),
-          positions_list),rulenb) -> 
+    (fun (((((((ctl_toplevel_list,metavars),ast),free_var_list),
+            negated_pos_list),used_after_list),positions_list),rulenb) -> 
       
       let is_script_rule r =
         match r with Ast_cocci.ScriptRule _ -> true | _ -> false in
@@ -711,10 +761,11 @@ let prepare_cocci ctls free_var_lists negated_pos_lists
           }
           in ScriptRuleCocciInfo r
       | Ast_cocci.CocciRule
-         (rulename,(dependencies,dropped_isos,z),restast,isexp) ->
+         (rulename,(dependencies,dropped_isos,z),restast,isexp,ruletype) ->
           CocciRuleCocciInfo (
           {
             ctl = List.hd ctl_toplevel_list;
+            metavars = metavars;
             ast_rule = ast;
            isexp = List.hd isexp;
             rulename = rulename;
@@ -725,6 +776,7 @@ let prepare_cocci ctls free_var_lists negated_pos_lists
             used_after = List.hd used_after_list;
             positions = List.hd positions_list;
             ruleid = rulenb;
+           ruletype = ruletype;
             was_matched = ref false;
           })
     )
@@ -735,7 +787,7 @@ let prepare_cocci ctls free_var_lists negated_pos_lists
 let build_info_program cprogram env = 
   let (cs, parseinfos) = Common.unzip cprogram in
   let (cs, envs) =
-    Common.unzip (TAC.annotate_program env !g_contain_typedmetavar cs) in
+    Common.unzip (TAC.annotate_program env (*!g_contain_typedmetavar*) cs) in
 
   zip (zip cs parseinfos) envs +> List.map (fun ((c, parseinfo), (enva,envb))->
     let (fullstr, tokens) = parseinfo in
@@ -777,27 +829,21 @@ let rebuild_info_program cs file isexp =
   cs +> List.map (fun c ->
     if !(c.was_modified)
     then
-      (match !Flag.make_hrule with
-       Some dir ->
-         Unparse_hrule.pp_program (c.ast_c, (c.fullstring, c.tokens_c))
-           dir file isexp;
-         []
-      |        None ->
-         let file = Common.new_temp_file "cocci_small_output" ".c" in
-         cfile_of_program 
-            [(c.ast_c, (c.fullstring, c.tokens_c)), Unparse_c2.PPnormal] 
-            file;
+      let file = Common.new_temp_file "cocci_small_output" ".c" in
+      cfile_of_program 
+        [(c.ast_c, (c.fullstring, c.tokens_c)), Unparse_c.PPnormal] 
+        file;
          
-          (* Common.command2 ("cat " ^ file); *)
-         let cprogram = cprogram_of_file file in
-         let xs = build_info_program cprogram c.env_typing_before in
+      (* Common.command2 ("cat " ^ file); *)
+      let cprogram = cprogram_of_file file in
+      let xs = build_info_program cprogram c.env_typing_before in
          
-          (* TODO: assert env has not changed,
-           * if yes then must also reparse what follows even if not modified.
-           * Do that only if contain_typedmetavar of course, so good opti.
-          *)
-          (* Common.list_init xs *) (* get rid of the FinalDef *)
-         xs)
+      (* TODO: assert env has not changed,
+      * if yes then must also reparse what follows even if not modified.
+      * Do that only if contain_typedmetavar of course, so good opti.
+      *)
+      (* Common.list_init xs *) (* get rid of the FinalDef *)
+      xs
     else [c]
   ) +> List.concat
 
@@ -818,9 +864,9 @@ let rebuild_info_c_and_headers ccs isexp =
 
 
 
-let prepare_c files = 
+let prepare_c files choose_includes : file_info list 
   let cprograms = List.map cprogram_of_file_cached files in
-  let includes = includes_to_parse (zip files cprograms) in
+  let includes = includes_to_parse (zip files cprograms) choose_includes in
 
   (* todo?: may not be good to first have all the headers and then all the c *)
   let all = 
@@ -829,7 +875,7 @@ let prepare_c files =
     ((zip files cprograms) +> List.map (fun (file, asts) -> Left (file, asts)))
   in
 
-  let env = ref TAC.initial_env in
+  let env = ref !TAC.initial_env in
 
   let ccs = all +> Common.map_filter (fun x -> 
     match x with 
@@ -931,20 +977,15 @@ let rec apply_python_rule r cache newes e rules_that_have_matched
           !rules_that_have_ever_matched r.scr_dependencies)
   then
     begin
-      if !Flag.show_misc
-      then
-       begin
-         pr2 ("dependencies for script not satisfied:");
-         print_dependencies rules_that_have_matched
-           !rules_that_have_ever_matched r.scr_dependencies;
-         show_or_not_binding "in environment" e
-       end;
+      print_dependencies "dependencies for script not satisfied:"
+       rules_that_have_matched
+       !rules_that_have_ever_matched r.scr_dependencies;
+      show_or_not_binding "in environment" e;
       (cache, (e, rules_that_have_matched)::newes)
     end
   else
     begin
       let (_, mv, _) = r.scr_ast_rule in
-      show_or_not_binding "in" e;
       if List.for_all (Pycocci.contains_binding e) mv
       then
        begin
@@ -958,6 +999,10 @@ let rec apply_python_rule r cache newes e rules_that_have_matched
            then cache
            else
              begin
+               print_dependencies "dependencies for script satisfied:"
+                 rules_that_have_matched
+                 !rules_that_have_ever_matched r.scr_dependencies;
+               show_or_not_binding "in" e;
                Pycocci.build_classes (List.map (function (x,y) -> x) e);
                Pycocci.construct_variables mv e;
                let _ = Pycocci.pyrun_simplestring
@@ -967,13 +1012,13 @@ let rec apply_python_rule r cache newes e rules_that_have_matched
                relevant_bindings :: cache
              end in
          if !Pycocci.inc_match
-         then (new_cache, (e, rules_that_have_matched)::newes)
+         then (new_cache, merge_env [(e, rules_that_have_matched)] newes)
          else (new_cache, newes)
        end
-      else (cache, (e, rules_that_have_matched)::newes)
+      else (cache, merge_env [(e, rules_that_have_matched)] newes)
     end
 
-and apply_cocci_rule r rules_that_have_ever_matched es ccs =
+and apply_cocci_rule r rules_that_have_ever_matched es (ccs:file_info list ref) =
   Common.profile_code r.rulename (fun () -> 
     show_or_not_rule_name r.ast_rule r.ruleid;
     show_or_not_ctl_text r.ctl r.ast_rule r.ruleid;
@@ -990,50 +1035,57 @@ and apply_cocci_rule r rules_that_have_ever_matched es ccs =
                     !rules_that_have_ever_matched r.dependencies)
            then
              begin
-               if !Flag.show_misc
-               then
-                 begin
-                   pr2
-                     ("dependencies for rule "^r.rulename^" not satisfied:");
-                   print_dependencies rules_that_have_matched
-                     !rules_that_have_ever_matched r.dependencies;
-                   show_or_not_binding "in environment" e
-                 end;
+               print_dependencies
+                 ("dependencies for rule "^r.rulename^" not satisfied:")
+                 rules_that_have_matched
+                 !rules_that_have_ever_matched r.dependencies;
+               show_or_not_binding "in environment" e;
                (cache,
-                Common.union_set newes
+                merge_env
                   [(e +> List.filter (fun (s,v) -> List.mem s r.used_after),
-                    rules_that_have_matched)])
+                    rules_that_have_matched)]
+                  newes)
              end
            else
              let new_bindings =
                try List.assoc relevant_bindings cache
                with
                  Not_found ->
-                   begin
-                     show_or_not_binding "in" e;
-                     show_or_not_binding "relevant in" relevant_bindings;
+                   print_dependencies
+                     ("dependencies for rule "^r.rulename^" satisfied:")
+                     rules_that_have_matched
+                     !rules_that_have_ever_matched r.dependencies;
+                   show_or_not_binding "in" e;
+                   show_or_not_binding "relevant in" relevant_bindings;
 
-                     let children_e = ref [] in
+                   (* applying the rule *)
+                   (match r.ruletype with
+                     Ast_cocci.Normal ->
+                       let children_e = ref [] in
       
                       (* looping over the functions and toplevel elements in
                         .c and .h *)
-                     concat_headers_and_c !ccs +> List.iter (fun c -> 
-                       if c.flow <> None 
-                       then
-                        (* does also some side effects on c and r *)
-                         let processed =
-                           process_a_ctl_a_env_a_toplevel r relevant_bindings
-                             c in
-                         match processed with
-                         | None -> ()
-                         | Some newbindings -> 
-                             newbindings +> List.iter (fun newbinding -> 
-                               children_e :=
-                                 Common.insert_set newbinding !children_e)
-                               ); (* end iter cs *)
-
-                     !children_e
-                   end in
+                       concat_headers_and_c !ccs +> List.iter (fun (c,f) -> 
+                         if c.flow <> None 
+                         then
+                          (* does also some side effects on c and r *)
+                           let processed =
+                             process_a_ctl_a_env_a_toplevel r
+                               relevant_bindings c f in
+                           match processed with
+                           | None -> ()
+                           | Some newbindings -> 
+                               newbindings +> List.iter (fun newbinding -> 
+                                 children_e :=
+                                   Common.insert_set newbinding !children_e)
+                                 ); (* end iter cs *)
+
+                       !children_e
+                   | Ast_cocci.Generated ->
+                       process_a_generated_a_env_a_toplevel r
+                         relevant_bindings !ccs;
+                       []) in
+
              let old_bindings_to_keep =
                Common.nub
                  (e +> List.filter (fun (s,v) -> List.mem s r.used_after)) in
@@ -1067,12 +1119,13 @@ and apply_cocci_rule r rules_that_have_ever_matched es ccs =
                              not (List.mem s old_variables)))) in
                  List.map
                    (function new_binding_to_add ->
-                     (Common.union_set
-                        old_bindings_to_keep new_binding_to_add,
+                     (List.sort compare
+                        (Common.union_set
+                           old_bindings_to_keep new_binding_to_add),
                       r.rulename::rules_that_have_matched))
                    new_bindings_to_add in
              ((relevant_bindings,new_bindings)::cache,
-              Common.union_set new_e newes))
+              merge_env new_e newes))
        ([],[]) reorganized_env in (* end iter es *)
     if !(r.was_matched)
     then Common.push2 r.rulename rules_that_have_ever_matched;
@@ -1084,7 +1137,18 @@ and apply_cocci_rule r rules_that_have_ever_matched es ccs =
     then ccs := rebuild_info_c_and_headers !ccs r.isexp
   )
 
-and bigloop2 rs ccs = 
+and merge_env new_e old_e =
+  List.fold_left
+    (function old_e ->
+      function (e,rules) as elem ->
+       let (same,diff) = List.partition (function (e1,_) -> e = e1) old_e in
+       match same with
+         [] -> elem :: old_e
+       | [(_,old_rules)] -> (e,Common.union_set rules old_rules) :: diff
+       | _ -> failwith "duplicate environment entries")
+    old_e new_e
+
+and bigloop2 rs (ccs: file_info list) = 
   let es = ref [(Ast_c.emptyMetavarsBinding,[])] in
   let ccs = ref ccs in
   let rules_that_have_ever_matched = ref [] in
@@ -1117,7 +1181,7 @@ and bigloop2 rs ccs =
                    apply_python_rule r cache newes e rules_that_have_matched
                      rules_that_have_ever_matched
                | "test" ->
-                   concat_headers_and_c !ccs +> List.iter (fun c -> 
+                   concat_headers_and_c !ccs +> List.iter (fun (c,_) -> 
                      if c.flow <> None 
                      then
                        Printf.printf "Flow: %s\r\nFlow!\r\n%!" c.fullstring);
@@ -1234,10 +1298,11 @@ and bigloop a b =
 
 
 (* does side effects on C ast and on Cocci info rule *)
-and process_a_ctl_a_env_a_toplevel2 r e c = 
+and process_a_ctl_a_env_a_toplevel2 r e c 
  indent_do (fun () -> 
   show_or_not_celem "trying" c.ast_c;
-  let (trans_info, returned_any_states, newbindings) = 
+  Flag.currentfile := Some (f ^ ":" ^get_celem c.ast_c);
+  let (trans_info, returned_any_states, inherited_bindings, newbindings) = 
     Common.save_excursion Flag_ctl.loop_in_src_code (fun () -> 
       Flag_ctl.loop_in_src_code := !Flag_ctl.loop_in_src_code||c.contain_loop;
       
@@ -1267,18 +1332,42 @@ and process_a_ctl_a_env_a_toplevel2 r e c =
          * trasformation au fichier concerne. *)
 
         (* modify ast via side effect *)
-        ignore(Transformation3.transform r.rulename r.dropped_isos
-                  trans_info (Common.some c.flow));
+        ignore(Transformation_c.transform r.rulename r.dropped_isos
+                  inherited_bindings trans_info (Common.some c.flow));
       with Timeout -> raise Timeout | UnixExit i -> raise (UnixExit i)
     end;
 
-    Some newbindings
+    Some (List.map (function x -> x@inherited_bindings) newbindings)
   end
  )
    
-and process_a_ctl_a_env_a_toplevel  a b c = 
+and process_a_ctl_a_env_a_toplevel  a b c f
   Common.profile_code "process_a_ctl_a_env_a_toplevel" 
-    (fun () -> process_a_ctl_a_env_a_toplevel2 a b c)
+    (fun () -> process_a_ctl_a_env_a_toplevel2 a b c f)
+
+and process_a_generated_a_env_a_toplevel2 r env = function
+    [cfile] ->
+      let free_vars =
+       List.filter
+         (function
+             (rule,_) when rule = r.rulename -> false
+           | (_,"ARGS") -> false
+           | _ -> true)
+         r.free_vars in
+      let env_domain = List.map (function (nm,vl) -> nm) env in
+      let metavars =
+       List.filter
+         (function md ->
+           let (rl,_) = Ast_cocci.get_meta_name md in
+           rl = r.rulename)
+         r.metavars in
+      if Common.include_set free_vars env_domain
+      then Unparse_hrule.pp_rule metavars r.ast_rule env cfile.full_fname
+  | _ -> failwith "multiple files not supported"
+   
+and process_a_generated_a_env_a_toplevel rule env ccs = 
+  Common.profile_code "process_a_ctl_a_env_a_toplevel" 
+    (fun () -> process_a_generated_a_env_a_toplevel2 rule env ccs)
    
 
 
@@ -1302,13 +1391,13 @@ let full_engine2 (coccifile, isofile) cfiles =
   in
 
   (* useful opti when use -dir *)
-  let (astcocci,free_var_lists,negated_pos_lists,used_after_lists,
+  let (metavars,astcocci,free_var_lists,negated_pos_lists,used_after_lists,
        positions_lists,toks,_) = 
       sp_of_file coccifile isofile
   in
   let ctls = 
     Common.memoized _hctl (coccifile, isofile) (fun () -> 
-      ctls_of_ast  astcocci used_after_lists positions_lists)
+      ctls_of_ast astcocci used_after_lists positions_lists)
   in
 
   let contain_typedmetavar = sp_contain_typed_metavar astcocci in
@@ -1329,10 +1418,19 @@ let full_engine2 (coccifile, isofile) cfiles =
 
     check_macro_in_sp_and_adjust toks;
 
+    
+
     let cocci_infos =
       prepare_cocci ctls free_var_lists negated_pos_lists
-       used_after_lists positions_lists astcocci in
-    let c_infos  = prepare_c cfiles in
+       used_after_lists positions_lists metavars astcocci in
+    let choose_includes =
+      match !Flag_cocci.include_options with
+       Flag_cocci.I_UNSPECIFIED ->
+         if contain_typedmetavar
+         then Flag_cocci.I_NORMAL_INCLUDES
+         else Flag_cocci.I_NO_INCLUDES
+      |        x -> x in
+    let c_infos  = prepare_c cfiles choose_includes in
 
     show_or_not_ctl_tex astcocci ctls;
 
@@ -1341,6 +1439,7 @@ let full_engine2 (coccifile, isofile) cfiles =
 
     if !Flag.show_misc then Common.pr_xxxxxxxxxxxxxxxxx ();
     if !Flag.show_misc then pr "Finished";
+    if !Flag_ctl.graphical_trace then gen_pdf_graph ();
     if !Flag.show_misc then Common.pr_xxxxxxxxxxxxxxxxx();
 
     c_infos' +> List.map (fun c_or_h ->