(*
- * Copyright 2010, INRIA, University of Copenhagen
+ * Copyright 2012, INRIA
+ * Julia Lawall, Gilles Muller
+ * Copyright 2010-2011, INRIA, University of Copenhagen
* Julia Lawall, Rene Rydhof Hansen, Gilles Muller, Nicolas Palix
* Copyright 2005-2009, Ecole des Mines de Nantes, University of Copenhagen
* Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller, Nicolas Palix
*)
-(* Yoann Padioleau
- *
- * Copyright (C) 2006, 2007 Ecole des Mines de Nantes
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License (GPL)
- * version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * file license.txt for more details.
- *
- * This file was part of Coccinelle.
- *)
open Common
module F = Control_flow_c
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 *)
}
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
+ (* ------------------------------------------------------------------------*)
+ (* Env *)
+ (* ------------------------------------------------------------------------*)
+
+ (* When env is used in + code, have to strip it more to avoid circular
+ references due to local variable information *)
+
+ let clean_env env =
+ List.map
+ (function (v,vl) ->
+ match vl with
+ | Ast_c.MetaExprVal(e,ml) ->
+ (v,Ast_c.MetaExprVal(Lib_parsing_c.real_al_expr e,ml))
+ | Ast_c.MetaExprListVal(es) ->
+ (v,Ast_c.MetaExprListVal(Lib_parsing_c.real_al_arguments es))
+ | Ast_c.MetaTypeVal(ty) ->
+ (v,Ast_c.MetaTypeVal(Lib_parsing_c.real_al_type ty))
+ | Ast_c.MetaInitVal(i) ->
+ (v,Ast_c.MetaInitVal(Lib_parsing_c.real_al_init i))
+ | Ast_c.MetaInitListVal(is) ->
+ (v,Ast_c.MetaInitListVal(Lib_parsing_c.real_al_inits is))
+ | Ast_c.MetaDeclVal(d) ->
+ (v,Ast_c.MetaDeclVal(Lib_parsing_c.real_al_decl d))
+ | Ast_c.MetaStmtVal(s) ->
+ (v,Ast_c.MetaStmtVal(Lib_parsing_c.real_al_statement s))
+ | _ -> (v,vl))
+ env
+
+
(* ------------------------------------------------------------------------*)
(* Exp *)
(* ------------------------------------------------------------------------*)
| None ->
failwith "weird: dont have position info for the mcodekind"
+ (* these remove constraints, at least those that contain pcre regexps,
+ which cannot be compared (problem in the unparser) *)
+ let strip_anything anything =
+ let donothing r k e = k e in
+ let mcode mc = mc in
+ let ident r k e =
+ let e = k e in
+ match Ast_cocci.unwrap e with
+ Ast_cocci.MetaId(name,constraints,u,i) ->
+ Ast_cocci.rewrap e
+ (Ast_cocci.MetaId(name,Ast_cocci.IdNoConstraint,u,i))
+ | Ast_cocci.MetaFunc(name,constraints,u,i) ->
+ Ast_cocci.rewrap e
+ (Ast_cocci.MetaFunc(name,Ast_cocci.IdNoConstraint,u,i))
+ | Ast_cocci.MetaLocalFunc(name,constraints,u,i) ->
+ Ast_cocci.rewrap e
+ (Ast_cocci.MetaLocalFunc(name,Ast_cocci.IdNoConstraint,u,i))
+ | _ -> e in
+ let expression r k e =
+ let e = k e in
+ match Ast_cocci.unwrap e with
+ Ast_cocci.MetaErr(name,constraints,u,i) ->
+ Ast_cocci.rewrap e
+ (Ast_cocci.MetaErr(name,Ast_cocci.NoConstraint,u,i))
+ | Ast_cocci.MetaExpr(name,constraints,u,ty,form,i) ->
+ Ast_cocci.rewrap e
+ (Ast_cocci.MetaExpr(name,Ast_cocci.NoConstraint,u,ty,form,i))
+ | _ -> e in
+ let fn = Visitor_ast.rebuilder
+ mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode
+ donothing donothing donothing donothing donothing
+ ident expression donothing donothing donothing donothing
+ donothing donothing donothing donothing donothing donothing in
+
+ fn.Visitor_ast.rebuilder_anything anything
+
+ let strip_minus_code = function
+ Ast_cocci.REPLACEMENT(l,c) ->
+ Ast_cocci.REPLACEMENT(List.map (List.map strip_anything) l,c)
+ | Ast_cocci.NOREPLACEMENT -> Ast_cocci.NOREPLACEMENT
+ let strip_context_code = function
+ Ast_cocci.BEFORE(l,c) ->
+ Ast_cocci.BEFORE(List.map (List.map strip_anything) l,c)
+ | Ast_cocci.AFTER(l,c) ->
+ Ast_cocci.AFTER(List.map (List.map strip_anything) l,c)
+ | Ast_cocci.BEFOREAFTER(l1,l2,c) ->
+ Ast_cocci.BEFOREAFTER(List.map (List.map strip_anything) l1,
+ List.map (List.map strip_anything) l2,c)
+ | Ast_cocci.NOTHING -> Ast_cocci.NOTHING
+ let strip_mck_code = function
+ Ast_cocci.MINUS(p,l,a,repl) ->
+ Ast_cocci.MINUS(p,l,a,strip_minus_code repl)
+ | Ast_cocci.CONTEXT(p,ba) -> Ast_cocci.CONTEXT(p,strip_context_code ba)
+ | Ast_cocci.PLUS(c) -> Ast_cocci.PLUS(c)
let tag_with_mck mck ib = fun tin ->
(match mck, Ast_c.pinfo_of_info ib with
| _, Ast_c.AbstractLineTok _ -> raise Impossible
| Ast_cocci.MINUS(_), Ast_c.ExpandedTok _ ->
- failwith ("try to delete an expanded token: " ^ (Ast_c.str_of_info ib))
+ failwith
+ (Printf.sprintf
+ "%s: %d: try to delete an expanded token: %s"
+ (Ast_c.file_of_info ib)
+ (Ast_c.line_of_info ib) (Ast_c.str_of_info ib))
| _ -> ()
);
- let many_count = function
+ let many_context_count = function
Ast_cocci.BEFORE(_,Ast_cocci.MANY) | Ast_cocci.AFTER(_,Ast_cocci.MANY)
| Ast_cocci.BEFOREAFTER(_,_,Ast_cocci.MANY) -> true
| _ -> false in
+ let many_minus_count = function
+ Ast_cocci.REPLACEMENT(_,Ast_cocci.MANY) -> true
+ | _ -> false in
+
(match (oldmcode,mck) with
| (Ast_cocci.CONTEXT(_,Ast_cocci.NOTHING), _) ->
(* nothing there, so take the new stuff *)
Ast_cocci.MINUS (pos,_,adj,any_xxs) ->
Ast_cocci.MINUS (pos,inst,adj,any_xxs)
| mck -> mck in
- cocciinforef := Some (update_inst tin.extra.index mck, [tin.binding])
+ let mck = strip_mck_code (update_inst tin.extra.index mck) in
+ (* clean_env actually only needed if there is an addition
+ not sure the extra efficiency would be worth duplicating the code *)
+ cocciinforef :=
+ Some (mck, [clean_env tin.binding])
| (_, Ast_cocci.CONTEXT(_,Ast_cocci.NOTHING)) ->
(* can this case occur? stay with the old stuff *)
()
- | (Ast_cocci.MINUS(old_pos,old_inst,old_adj,[]),
- Ast_cocci.MINUS(new_pos,new_inst,new_adj,[]))
- when old_pos = new_pos &&
- (List.mem tin.binding oldenvs or !Flag.sgrep_mode2)
+ | (Ast_cocci.MINUS(old_pos,old_inst,old_adj,Ast_cocci.NOREPLACEMENT),
+ Ast_cocci.MINUS(new_pos,new_inst,new_adj,Ast_cocci.NOREPLACEMENT))
+ when old_pos = new_pos
+ (* not sure why the following condition is useful.
+ should be ok to double remove even if the environments are
+ different *)
+ (* &&
+ (List.mem tin.binding oldenvs or !Flag.sgrep_mode2) *)
(* no way to combine adjacency information, just drop one *)
->
cocciinforef := Some
(Ast_cocci.MINUS
- (old_pos,Common.union_set old_inst new_inst,old_adj,[]),
+ (old_pos,Common.union_set old_inst new_inst,old_adj,
+ Ast_cocci.NOREPLACEMENT),
[tin.binding]);
(if !Flag_matcher.show_misc
- then pr2 "already tagged but only removed, so safe")
+ then pr2_once "already tagged but only removed, so safe")
+
+ (* ++ cases *)
+ | (Ast_cocci.MINUS(old_pos,old_inst,old_adj,old_modif),
+ Ast_cocci.MINUS(new_pos,new_inst,new_adj,new_modif))
+ when old_pos = new_pos &&
+ old_modif = strip_minus_code new_modif &&
+ many_minus_count old_modif ->
+
+ cocciinforef :=
+ Some(Ast_cocci.MINUS(old_pos,Common.union_set old_inst new_inst,
+ old_adj,old_modif),
+ (clean_env tin.binding)::oldenvs)
| (Ast_cocci.CONTEXT(old_pos,old_modif),
Ast_cocci.CONTEXT(new_pos,new_modif))
when old_pos = new_pos &&
- old_modif = new_modif && many_count old_modif ->
+ old_modif = strip_context_code new_modif &&
+ many_context_count old_modif ->
(* iteration only allowed on context; no way to replace something
more than once; now no need for iterable; just check a flag *)
cocciinforef :=
- Some(Ast_cocci.CONTEXT(old_pos,old_modif),tin.binding::oldenvs)
+ Some(Ast_cocci.CONTEXT(old_pos,old_modif),
+ (clean_env tin.binding)::oldenvs)
| _ ->
(* coccionly:
(fun ib ->
tag_with_mck (Ast_cocci.MINUS (pos,inst,adj,any_xxs)) ib tin),
(fun ib ->
- tag_with_mck (Ast_cocci.MINUS (pos,inst,adj,[])) ib tin),
+ tag_with_mck
+ (Ast_cocci.MINUS (pos,inst,adj,Ast_cocci.NOREPLACEMENT)) ib tin),
(fun ib ->
- tag_with_mck (Ast_cocci.MINUS (pos,inst,adj,[])) ib tin),
+ tag_with_mck
+ (Ast_cocci.MINUS (pos,inst,adj,Ast_cocci.NOREPLACEMENT)) ib tin),
(fun ib ->
tag_with_mck (Ast_cocci.MINUS (pos,inst,adj,any_xxs)) ib tin)
) expr
let distribute_mck_type (maxpos, minpos) = fun (lop,mop,rop,bop) -> fun x ->
Visitor_c.vk_type_s (mk_bigf (maxpos, minpos) (lop,mop,rop,bop)) x
+ let distribute_mck_decl (maxpos, minpos) = fun (lop,mop,rop,bop) -> fun x ->
+ Visitor_c.vk_decl_s (mk_bigf (maxpos, minpos) (lop,mop,rop,bop)) x
+
+ let distribute_mck_field (maxpos, minpos) = fun (lop,mop,rop,bop) -> fun x ->
+ Visitor_c.vk_struct_field_s (mk_bigf (maxpos, minpos) (lop,mop,rop,bop)) x
+
let distribute_mck_ini (maxpos, minpos) = fun (lop,mop,rop,bop) -> fun x ->
Visitor_c.vk_ini_s (mk_bigf (maxpos, minpos) (lop,mop,rop,bop)) x
+ let distribute_mck_inis (maxpos, minpos) = fun (lop,mop,rop,bop) -> fun x ->
+ Visitor_c.vk_inis_splitted_s (mk_bigf (maxpos, minpos) (lop,mop,rop,bop)) x
+
let distribute_mck_param (maxpos, minpos) = fun (lop,mop,rop,bop) -> fun x ->
Visitor_c.vk_param_s (mk_bigf (maxpos, minpos) (lop,mop,rop,bop)) x
Visitor_c.vk_node_s (mk_bigf (maxpos, minpos) (lop,mop,rop,bop))
x
+ let distribute_mck_enum_fields (maxpos, minpos) =
+ fun (lop,mop,rop,bop) ->fun x ->
+ Visitor_c.vk_enum_fields_splitted_s
+ (mk_bigf (maxpos, minpos) (lop,mop,rop,bop))
+ x
+
let distribute_mck_struct_fields (maxpos, minpos) =
fun (lop,mop,rop,bop) ->fun x ->
Visitor_c.vk_struct_fields_s (mk_bigf (maxpos, minpos) (lop,mop,rop,bop))
let distrf_param = distrf (Lib_parsing_c.ii_of_param, distribute_mck_param)
let distrf_params = distrf (Lib_parsing_c.ii_of_params,distribute_mck_params)
let distrf_ini = distrf (Lib_parsing_c.ii_of_ini,distribute_mck_ini)
+ let distrf_inis = distrf (Lib_parsing_c.ii_of_inis,distribute_mck_inis)
+ let distrf_decl = distrf (Lib_parsing_c.ii_of_decl,distribute_mck_decl)
+ let distrf_field = distrf (Lib_parsing_c.ii_of_field,distribute_mck_field)
let distrf_node = distrf (Lib_parsing_c.ii_of_node,distribute_mck_node)
+ let distrf_enum_fields =
+ distrf (Lib_parsing_c.ii_of_enum_fields, distribute_mck_enum_fields)
let distrf_struct_fields =
distrf (Lib_parsing_c.ii_of_struct_fields, distribute_mck_struct_fields)
let distrf_cst =
Lib_engine.metavars_binding (* inherited bindings *) ->
Lib_engine.numbered_transformation_info -> F.cflow -> F.cflow) =
fun rule_name dropped_isos binding0 xs cflow ->
-
let extra = {
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
let node = acc#nodes#assoc nodei in
if !Flag.show_transinfo
- then pr2 "transform one node";
+ then pr2 (Printf.sprintf "transform one node: %d" nodei);
let tin = {
XTRANS.extra = {extra with index = index};