X-Git-Url: http://git.hcoop.net/bpt/coccinelle.git/blobdiff_plain/951c78018cc91c58699aef95c0ccc20f34065162..abad11c5570b7b9bbae5ff92b3050cf68fe3fd14:/parsing_cocci/context_neg.ml diff --git a/parsing_cocci/context_neg.ml b/parsing_cocci/context_neg.ml index 8b0065a..26cb99f 100644 --- a/parsing_cocci/context_neg.ml +++ b/parsing_cocci/context_neg.ml @@ -1,4 +1,8 @@ (* + * 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 * This file is part of Coccinelle. @@ -20,6 +24,7 @@ *) +# 0 "./context_neg.ml" (* Detects subtrees that are all minus/plus and nodes that are "binding context nodes". The latter is a node whose structure and immediate tokens are the same in the minus and plus trees, and such that for every child, @@ -52,12 +57,14 @@ let set_mcodekind x mcodekind = | Ast0.DeclTag(d) -> Ast0.set_mcodekind d mcodekind | Ast0.InitTag(d) -> Ast0.set_mcodekind d mcodekind | Ast0.StmtTag(d) -> Ast0.set_mcodekind d mcodekind + | Ast0.ForInfoTag(d) -> Ast0.set_mcodekind d mcodekind | Ast0.CaseLineTag(d) -> Ast0.set_mcodekind d mcodekind | Ast0.TopTag(d) -> Ast0.set_mcodekind d mcodekind | Ast0.IsoWhenTag(_) -> failwith "only within iso phase" | Ast0.IsoWhenTTag(_) -> failwith "only within iso phase" | Ast0.IsoWhenFTag(_) -> failwith "only within iso phase" - | Ast0.MetaPosTag(p) -> failwith "metapostag only within iso phase" + | Ast0.MetaPosTag(p) -> failwith "invisible at this stage" + | Ast0.HiddenVarTag(p) -> failwith "hiddenvar only within iso phase" let set_index x index = match x with @@ -76,12 +83,14 @@ let set_index x index = | Ast0.InitTag(d) -> Ast0.set_index d index | Ast0.DeclTag(d) -> Ast0.set_index d index | Ast0.StmtTag(d) -> Ast0.set_index d index + | Ast0.ForInfoTag(d) -> Ast0.set_index d index | Ast0.CaseLineTag(d) -> Ast0.set_index d index | Ast0.TopTag(d) -> Ast0.set_index d index | Ast0.IsoWhenTag(_) -> failwith "only within iso phase" | Ast0.IsoWhenTTag(_) -> failwith "only within iso phase" | Ast0.IsoWhenFTag(_) -> failwith "only within iso phase" - | Ast0.MetaPosTag(p) -> failwith "metapostag only within iso phase" + | Ast0.MetaPosTag(p) -> failwith "invisible at this stage" + | Ast0.HiddenVarTag(p) -> failwith "hiddenvar only within iso phase" let get_index = function Ast0.DotsExprTag(d) -> Index.expression_dots d @@ -99,12 +108,14 @@ let get_index = function | Ast0.InitTag(d) -> Index.initialiser d | Ast0.DeclTag(d) -> Index.declaration d | Ast0.StmtTag(d) -> Index.statement d + | Ast0.ForInfoTag(d) -> Index.forinfo d | Ast0.CaseLineTag(d) -> Index.case_line d | Ast0.TopTag(d) -> Index.top_level d | Ast0.IsoWhenTag(_) -> failwith "only within iso phase" | Ast0.IsoWhenTTag(_) -> failwith "only within iso phase" | Ast0.IsoWhenFTag(_) -> failwith "only within iso phase" - | Ast0.MetaPosTag(p) -> failwith "metapostag only within iso phase" + | Ast0.MetaPosTag(p) -> failwith "invisible at this stage" + | Ast0.HiddenVarTag(p) -> failwith "hiddenvar only within iso phase" (* --------------------------------------------------------------------- *) (* Collect the line numbers of the plus code. This is used for disjunctions. @@ -148,7 +159,7 @@ let collect_plus_lines top = mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode donothing donothing donothing donothing donothing donothing donothing donothing donothing donothing donothing donothing donothing - donothing donothing in + donothing donothing donothing in fn.VT0.combiner_rec_top_level top (* --------------------------------------------------------------------- *) @@ -328,6 +339,13 @@ let classify is_minus all_marked table code = (* no whencode in plus tree so have to drop it *) (* need special cases for dots, nests, and disjs *) + let ident r k e = + compute_result Ast0.ident e + (match Ast0.unwrap e with + Ast0.DisjId(starter,id_list,_,ender) -> + disj_cases e starter id_list r.VT0.combiner_rec_ident ender + | _ -> k e) in + let expression r k e = compute_result Ast0.expr e (match Ast0.unwrap e with @@ -345,6 +363,7 @@ let classify is_minus all_marked table code = (* not clear why we have the next two cases, since DisjDecl and DisjType shouldn't have been constructed yet, as they only come from isos *) + (* actually, DisjDecl now allowed in source struct decls *) let declaration r k e = compute_result Ast0.decl e (match Ast0.unwrap e with @@ -414,18 +433,19 @@ let classify is_minus all_marked table code = | Ast0.Stars(dots,whencode) -> k (Ast0.rewrap s (Ast0.Stars(dots,[]))) | Ast0.Disj(starter,statement_dots_list,_,ender) -> - disj_cases s starter statement_dots_list r.VT0.combiner_rec_statement_dots + disj_cases s starter statement_dots_list + r.VT0.combiner_rec_statement_dots ender (* cases for everything with extra mcode *) | Ast0.FunDecl((info,bef),_,_,_,_,_,_,_,_) | Ast0.Decl((info,bef),_) -> bind (nc_mcode ((),(),info,bef,(),-1)) (k s) - | Ast0.IfThen(_,_,_,_,_,(info,aft)) - | Ast0.IfThenElse(_,_,_,_,_,_,_,(info,aft)) - | Ast0.Iterator(_,_,_,_,_,(info,aft)) - | Ast0.While(_,_,_,_,_,(info,aft)) - | Ast0.For(_,_,_,_,_,_,_,_,_,(info,aft)) -> - bind (k s) (nc_mcode ((),(),info,aft,(),-1)) + | Ast0.IfThen(_,_,_,_,_,(info,aft,adj)) + | Ast0.IfThenElse(_,_,_,_,_,_,_,(info,aft,adj)) + | Ast0.Iterator(_,_,_,_,_,(info,aft,adj)) + | Ast0.While(_,_,_,_,_,(info,aft,adj)) + | Ast0.For(_,_,_,_,_,_,_,_,(info,aft,adj)) -> + bind (k s) (nc_mcode ((),(),info,aft,(),adj)) | _ -> k s ) in @@ -438,8 +458,8 @@ let classify is_minus all_marked table code = (do_nothing Ast0.dotsExpr) (do_nothing Ast0.dotsInit) (do_nothing Ast0.dotsParam) (do_nothing Ast0.dotsStmt) (do_nothing Ast0.dotsDecl) (do_nothing Ast0.dotsCase) - (do_nothing Ast0.ident) expression typeC initialiser param declaration - statement case_line (do_top Ast0.top) in + ident expression typeC initialiser param declaration + statement (do_nothing Ast0.forinfo) case_line (do_top Ast0.top) in combiner.VT0.combiner_rec_top_level code (* --------------------------------------------------------------------- *) @@ -467,12 +487,17 @@ let dots fn d1 d2 = let rec equal_ident i1 i2 = match (Ast0.unwrap i1,Ast0.unwrap i2) with (Ast0.Id(name1),Ast0.Id(name2)) -> equal_mcode name1 name2 - | (Ast0.MetaId(name1,_,_),Ast0.MetaId(name2,_,_)) -> + | (Ast0.MetaId(name1,_,_,_),Ast0.MetaId(name2,_,_,_)) -> equal_mcode name1 name2 | (Ast0.MetaFunc(name1,_,_),Ast0.MetaFunc(name2,_,_)) -> equal_mcode name1 name2 | (Ast0.MetaLocalFunc(name1,_,_),Ast0.MetaLocalFunc(name2,_,_)) -> equal_mcode name1 name2 + | (Ast0.DisjId(starter1,_,mids1,ender1), + Ast0.DisjId(starter2,_,mids2,ender2)) -> + equal_mcode starter1 starter2 && + List.for_all2 equal_mcode mids1 mids2 && + equal_mcode ender1 ender2 | (Ast0.OptIdent(_),Ast0.OptIdent(_)) -> true | (Ast0.UniqueIdent(_),Ast0.UniqueIdent(_)) -> true | _ -> false @@ -485,6 +510,8 @@ let rec equal_expression e1 e2 = equal_mcode lp1 lp2 && equal_mcode rp1 rp2 | (Ast0.Assignment(_,op1,_,_),Ast0.Assignment(_,op2,_,_)) -> equal_mcode op1 op2 + | (Ast0.Sequence(_,op1,_),Ast0.Sequence(_,op2,_)) -> + equal_mcode op1 op2 | (Ast0.CondExpr(_,why1,_,colon1,_),Ast0.CondExpr(_,why2,_,colon2,_)) -> equal_mcode why1 why2 && equal_mcode colon1 colon2 | (Ast0.Postfix(_,op1),Ast0.Postfix(_,op2)) -> equal_mcode op1 op2 @@ -506,6 +533,8 @@ let rec equal_expression e1 e2 = | (Ast0.SizeOfType(szf1,lp1,_,rp1),Ast0.SizeOfType(szf2,lp2,_,rp2)) -> equal_mcode szf1 szf2 && equal_mcode lp1 lp2 && equal_mcode rp1 rp2 | (Ast0.TypeExp(_),Ast0.TypeExp(_)) -> true + | (Ast0.Constructor(lp1,_,rp1,_),Ast0.Constructor(lp2,_,rp2,_)) -> + equal_mcode lp1 lp2 && equal_mcode rp1 rp2 | (Ast0.MetaErr(name1,_,_),Ast0.MetaErr(name2,_,_)) | (Ast0.MetaExpr(name1,_,_,_,_),Ast0.MetaExpr(name2,_,_,_,_)) | (Ast0.MetaExprList(name1,_,_),Ast0.MetaExprList(name2,_,_)) -> @@ -539,6 +568,8 @@ let rec equal_typeC t1 t2 = equal_mcode lb1 lb2 && equal_mcode rb1 rb2 | (Ast0.EnumName(kind1,_),Ast0.EnumName(kind2,_)) -> equal_mcode kind1 kind2 + | (Ast0.EnumDef(_,lb1,_,rb1),Ast0.EnumDef(_,lb2,_,rb2)) -> + equal_mcode lb1 lb2 && equal_mcode rb1 rb2 | (Ast0.StructUnionName(kind1,_),Ast0.StructUnionName(kind2,_)) -> equal_mcode kind1 kind2 | (Ast0.FunctionType(ty1,lp1,p1,rp1),Ast0.FunctionType(ty2,lp2,p2,rp2)) -> @@ -560,18 +591,29 @@ let rec equal_typeC t1 t2 = let equal_declaration d1 d2 = match (Ast0.unwrap d1,Ast0.unwrap d2) with - (Ast0.Init(stg1,_,_,eq1,_,sem1),Ast0.Init(stg2,_,_,eq2,_,sem2)) -> + (Ast0.MetaDecl(name1,_),Ast0.MetaDecl(name2,_)) + | (Ast0.MetaField(name1,_),Ast0.MetaField(name2,_)) + | (Ast0.MetaFieldList(name1,_,_),Ast0.MetaFieldList(name2,_,_)) -> + equal_mcode name1 name2 + | (Ast0.Init(stg1,_,_,eq1,_,sem1),Ast0.Init(stg2,_,_,eq2,_,sem2)) -> equal_option stg1 stg2 && equal_mcode eq1 eq2 && equal_mcode sem1 sem2 | (Ast0.UnInit(stg1,_,_,sem1),Ast0.UnInit(stg2,_,_,sem2)) -> equal_option stg1 stg2 && equal_mcode sem1 sem2 - | (Ast0.MacroDecl(nm1,lp1,_,rp1,sem1),Ast0.MacroDecl(nm2,lp2,_,rp2,sem2)) -> + | (Ast0.MacroDecl(nm1,lp1,_,rp1,sem1),Ast0.MacroDecl(nm2,lp2,_,rp2,sem2))-> equal_mcode lp1 lp2 && equal_mcode rp1 rp2 && equal_mcode sem1 sem2 + | (Ast0.MacroDeclInit(nm1,lp1,_,rp1,eq1,_,sem1), + Ast0.MacroDeclInit(nm2,lp2,_,rp2,eq2,_,sem2))-> + equal_mcode lp1 lp2 && equal_mcode rp1 rp2 && equal_mcode eq1 eq2 + && equal_mcode sem1 sem2 | (Ast0.TyDecl(_,sem1),Ast0.TyDecl(_,sem2)) -> equal_mcode sem1 sem2 | (Ast0.Ddots(dots1,_),Ast0.Ddots(dots2,_)) -> equal_mcode dots1 dots2 | (Ast0.OptDecl(_),Ast0.OptDecl(_)) -> true | (Ast0.UniqueDecl(_),Ast0.UniqueDecl(_)) -> true - | (Ast0.DisjDecl _,_) | (_,Ast0.DisjDecl _) -> - failwith "DisjDecl not expected here" + | (Ast0.DisjDecl(starter1,_,mids1,ender1), + Ast0.DisjDecl(starter2,_,mids2,ender2)) -> + equal_mcode starter1 starter2 && + List.for_all2 equal_mcode mids1 mids2 && + equal_mcode ender1 ender2 | _ -> false let equal_designator d1 d2 = @@ -590,8 +632,12 @@ let equal_initialiser i1 i2 = match (Ast0.unwrap i1,Ast0.unwrap i2) with (Ast0.MetaInit(name1,_),Ast0.MetaInit(name2,_)) -> equal_mcode name1 name2 + | (Ast0.MetaInitList(name1,_,_),Ast0.MetaInitList(name2,_,_)) -> + equal_mcode name1 name2 | (Ast0.InitExpr(_),Ast0.InitExpr(_)) -> true - | (Ast0.InitList(lb1,_,rb1),Ast0.InitList(lb2,_,rb2)) -> + | (Ast0.InitList(lb1,_,rb1,o1),Ast0.InitList(lb2,_,rb2,o2)) -> + (* can't compare orderedness, because this can differ between - + and + code *) (equal_mcode lb1 lb2) && (equal_mcode rb1 rb2) | (Ast0.InitGccExt(designators1,eq1,_), Ast0.InitGccExt(designators2,eq2,_)) -> @@ -643,10 +689,16 @@ let rec equal_statement s1 s2 = | (Ast0.Do(d1,_,whl1,lp1,_,rp1,sem1),Ast0.Do(d2,_,whl2,lp2,_,rp2,sem2)) -> equal_mcode whl1 whl2 && equal_mcode d1 d2 && equal_mcode lp1 lp2 && equal_mcode rp1 rp2 && equal_mcode sem1 sem2 - | (Ast0.For(fr1,lp1,_,sem11,_,sem21,_,rp1,_,_), - Ast0.For(fr2,lp2,_,sem12,_,sem22,_,rp2,_,_)) -> + | (Ast0.For(fr1,lp1,first1,_,sem21,_,rp1,_,_), + Ast0.For(fr2,lp2,first2,_,sem22,_,rp2,_,_)) -> + let first = + match (Ast0.unwrap first1,Ast0.unwrap first2) with + (Ast0.ForExp(_,sem1),Ast0.ForExp(_,sem2)) -> + equal_mcode sem1 sem2 + | (Ast0.ForDecl _,Ast0.ForDecl _) -> true + | _ -> false in equal_mcode fr1 fr2 && equal_mcode lp1 lp2 && - equal_mcode sem11 sem12 && equal_mcode sem21 sem22 && + first && equal_mcode sem21 sem22 && equal_mcode rp1 rp2 | (Ast0.Iterator(nm1,lp1,_,rp1,_,_),Ast0.Iterator(nm2,lp2,_,rp2,_,_)) -> equal_mcode lp1 lp2 && equal_mcode rp1 rp2 @@ -685,6 +737,8 @@ let rec equal_statement s1 s2 = | (Ast0.Stars(d1,_),Ast0.Stars(d2,_)) -> equal_mcode d1 d2 | (Ast0.Include(inc1,name1),Ast0.Include(inc2,name2)) -> equal_mcode inc1 inc2 && equal_mcode name1 name2 + | (Ast0.Undef(def1,_),Ast0.Undef(def2,_)) -> + equal_mcode def1 def2 | (Ast0.Define(def1,_,_,_),Ast0.Define(def2,_,_,_)) -> equal_mcode def1 def2 | (Ast0.OptStm(_),Ast0.OptStm(_)) -> true @@ -715,7 +769,7 @@ let equal_case_line c1 c2 = let rec equal_top_level t1 t2 = match (Ast0.unwrap t1,Ast0.unwrap t2) with - (Ast0.DECL(_),Ast0.DECL(_)) -> true + (Ast0.NONDECL(_),Ast0.NONDECL(_)) -> true | (Ast0.FILEINFO(old_file1,new_file1),Ast0.FILEINFO(old_file2,new_file2)) -> equal_mcode old_file1 old_file2 && equal_mcode new_file1 new_file2 | (Ast0.CODE(_),Ast0.CODE(_)) -> true @@ -779,7 +833,7 @@ let contextify_all = mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode do_nothing do_nothing do_nothing do_nothing do_nothing do_nothing do_nothing do_nothing do_nothing do_nothing do_nothing do_nothing - do_nothing do_nothing do_nothing + do_nothing do_nothing do_nothing do_nothing let contextify_whencode = let bind x y = () in @@ -835,10 +889,11 @@ let plus_table = let iscode t = match Ast0.unwrap t with - Ast0.DECL(_) -> true + Ast0.NONDECL(_) -> true | Ast0.FILEINFO(_) -> true | Ast0.ERRORWORDS(_) -> false | Ast0.CODE(_) -> true + | Ast0.TOPCODE(_) | Ast0.OTHER(_) -> failwith "unexpected top level code" (* ------------------------------------------------------------------- *) @@ -852,7 +907,7 @@ let concat = function [] -> [] | x::rest -> (match Ast0.unwrap x with - Ast0.DECL(s) -> let stms = loop rest in s::stms + Ast0.NONDECL(s) -> let stms = loop rest in s::stms | Ast0.CODE(ss) -> let stms = loop rest in (match Ast0.unwrap ss with @@ -933,14 +988,17 @@ let rec is_toplevel s = Ast0.Decl(_,e) -> true | Ast0.FunDecl(_,_,_,_,_,_,_,_,_) -> true | Ast0.Disj(_,stmts,_,_) -> isall is_toplevel stmts - | Ast0.ExprStatement(fc,_) -> + | Ast0.ExprStatement(Some fc,_) -> (match Ast0.unwrap fc with Ast0.FunCall(_,_,_,_) -> true | _ -> false) | Ast0.Include(_,_) -> true + | Ast0.Undef(_,_) -> true | Ast0.Define(_,_,_,_) -> true | _ -> false +(* consider code and topcode to be the same; difference handled +in top_level.ml *) let check_compatible m p = let fail _ = failwith @@ -948,17 +1006,21 @@ let check_compatible m p = "incompatible minus and plus code starting on lines %d and %d" (Ast0.get_line m) (Ast0.get_line p)) in match (Ast0.unwrap m, Ast0.unwrap p) with - (Ast0.DECL(decl1),Ast0.DECL(decl2)) -> + (Ast0.NONDECL(decl1),Ast0.NONDECL(decl2)) -> if not (is_decl decl1 && is_decl decl2) then fail() - | (Ast0.DECL(decl1),Ast0.CODE(code2)) -> + | (Ast0.NONDECL(decl1),Ast0.CODE(code2)) -> + (* This is probably the only important case. We don't want to + replace top-level declarations by arbitrary code. *) let v1 = is_decl decl1 in let v2 = List.for_all is_toplevel (Ast0.undots code2) in - if !Flag.make_hrule = None && v1 && not v2 then fail() - | (Ast0.CODE(code1),Ast0.DECL(decl2)) -> + if !Flag.make_hrule = None && v1 && not v2 + then fail() + | (Ast0.CODE(code1),Ast0.NONDECL(decl2)) -> let v1 = List.for_all is_toplevel (Ast0.undots code1) in let v2 = is_decl decl2 in - if v1 && not v2 then fail() + if v1 && not v2 + then fail() | (Ast0.CODE(code1),Ast0.CODE(code2)) -> let v1 = isonly is_init code1 in let v2a = isonly is_init code2 in @@ -976,11 +1038,29 @@ let check_compatible m p = testers; let v1 = isonly is_fndecl code1 in let v2 = List.for_all is_toplevel (Ast0.undots code2) in - if !Flag.make_hrule = None && v1 && not v2 then fail() + if !Flag.make_hrule = None && v1 && not v2 + then fail() | (Ast0.FILEINFO(_,_),Ast0.FILEINFO(_,_)) -> () | (Ast0.OTHER(_),Ast0.OTHER(_)) -> () | _ -> fail() +(* can't just remove expressions or types, not sure if all cases are needed. *) +let check_complete m = + match Ast0.unwrap m with + Ast0.NONDECL(code) -> + if is_exp code or is_ty code + then + failwith + (Printf.sprintf "invalid minus starting on line %d" + (Ast0.get_line m)) + | Ast0.CODE(code) -> + if isonly is_exp code or isonly is_ty code + then + failwith + (Printf.sprintf "invalid minus starting on line %d" + (Ast0.get_line m)) + | _ -> () + (* ------------------------------------------------------------------- *) (* returns a list of corresponding minus and plus trees *) @@ -994,12 +1074,14 @@ let context_neg minus plus = | ([],l) -> failwith (Printf.sprintf "%d plus things remaining" (List.length l)) | (minus,[]) -> + List.iter check_complete minus; plus_lines := []; let _ = List.map (function m -> classify true - (function _ -> Ast0.MINUS(ref([],Ast0.default_token_info))) + (function _ -> + Ast0.MINUS(ref(Ast.NOREPLACEMENT,Ast0.default_token_info))) minus_table m) minus in [] @@ -1025,7 +1107,8 @@ let context_neg minus plus = collect_plus_lines p; let _ = classify true - (function _ -> Ast0.MINUS(ref([],Ast0.default_token_info))) + (function _ -> + Ast0.MINUS(ref(Ast.NOREPLACEMENT,Ast0.default_token_info))) minus_table m in let _ = classify false (function c -> Ast0.PLUS c) plus_table p in traverse minus_table plus_table; @@ -1041,7 +1124,9 @@ let context_neg minus plus = plus_lines := []; let _ = classify true - (function _ -> Ast0.MINUS(ref([],Ast0.default_token_info))) + (function _ -> + Ast0.MINUS(ref(Ast.NOREPLACEMENT, + Ast0.default_token_info))) minus_table m in loop(minus,pall) end