2 * Copyright 2012, INRIA
3 * Julia Lawall, Gilles Muller
4 * Copyright 2010-2011, INRIA, University of Copenhagen
5 * Julia Lawall, Rene Rydhof Hansen, Gilles Muller, Nicolas Palix
6 * Copyright 2005-2009, Ecole des Mines de Nantes, University of Copenhagen
7 * Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller, Nicolas Palix
8 * This file is part of Coccinelle.
10 * Coccinelle is free software: you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation, according to version 2 of the License.
14 * Coccinelle is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with Coccinelle. If not, see <http://www.gnu.org/licenses/>.
22 * The authors reserve the right to distribute this or future versions of
23 * Coccinelle under other licenses.
29 * Copyright 2012, INRIA
30 * Julia Lawall, Gilles Muller
31 * Copyright 2010-2011, INRIA, University of Copenhagen
32 * Julia Lawall, Rene Rydhof Hansen, Gilles Muller, Nicolas Palix
33 * Copyright 2005-2009, Ecole des Mines de Nantes, University of Copenhagen
34 * Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller, Nicolas Palix
35 * This file is part of Coccinelle.
37 * Coccinelle is free software: you can redistribute it and/or modify
38 * it under the terms of the GNU General Public License as published by
39 * the Free Software Foundation, according to version 2 of the License.
41 * Coccinelle is distributed in the hope that it will be useful,
42 * but WITHOUT ANY WARRANTY; without even the implied warranty of
43 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
44 * GNU General Public License for more details.
46 * You should have received a copy of the GNU General Public License
47 * along with Coccinelle. If not, see <http://www.gnu.org/licenses/>.
49 * The authors reserve the right to distribute this or future versions of
50 * Coccinelle under other licenses.
55 (* For each rule return the list of variables that are used after it.
56 Also augment various parts of each rule with unitary, inherited, and freshness
59 (* metavar decls should be better integrated into computations of free
60 variables in plus code *)
62 module Ast
= Ast_cocci
63 module V
= Visitor_ast
64 module TC
= Type_cocci
66 let rec nub = function
68 | (x
::xs
) when (List.mem x xs
) -> nub xs
69 | (x
::xs
) -> x
::(nub xs
)
71 (* Collect all variable references in a minirule. For a disj, we collect
72 the maximum number (2 is enough) of references in any branch. *)
74 let collect_unitary_nonunitary free_usage
=
75 let free_usage = List.sort compare
free_usage in
76 let rec loop1 todrop
= function (* skips multiple occurrences *)
78 | (x
::xs
) as all
-> if x
= todrop
then loop1 todrop xs
else all
in
79 let rec loop2 = function
83 if x
= y
(* occurs more than once in free_usage *)
85 let (unitary
,non_unitary
) = loop2(loop1 x xs
) in
86 (unitary
,x
::non_unitary
)
87 else (* occurs only once in free_usage *)
88 let (unitary
,non_unitary
) = loop2 (y
::xs
) in
89 (x
::unitary
,non_unitary
) in
92 let collect_refs include_constraints
=
93 let bind x y
= x
@ y
in
94 let option_default = [] in
96 let donothing recursor k e
= k e
in (* just combine in the normal way *)
98 let donothing_a recursor k e
= (* anything is not wrapped *)
99 k e
in (* just combine in the normal way *)
101 (* the following considers that anything that occurs non-unitarily in one
102 branch occurs nonunitarily in all branches. This is not optimal, but
103 doing better seems to require a breadth-first traversal, which is
104 perhaps better to avoid. Also, unitarily is represented as occuring once,
105 while nonunitarily is represented as twice - more is irrelevant *)
106 (* cases for disjs and metavars *)
107 let bind_disj refs_branches
=
108 let (unitary
,nonunitary
) =
109 List.split
(List.map
collect_unitary_nonunitary refs_branches
) in
110 let unitary = nub (List.concat
unitary) in
111 let nonunitary = nub (List.concat
nonunitary) in
113 List.filter
(function x
-> not
(List.mem x
nonunitary)) unitary in
114 unitary@nonunitary@nonunitary in
116 let metaid (x
,_
,_
,_
) = x
in
118 let astfvident recursor k i
=
120 (match Ast.unwrap i
with
121 Ast.MetaId
(name
,idconstraint
,_
,_
) | Ast.MetaFunc
(name
,idconstraint
,_
,_
)
122 | Ast.MetaLocalFunc
(name
,idconstraint
,_
,_
) ->
124 if include_constraints
126 match idconstraint
with
127 Ast.IdNegIdSet
(_
,metas) -> metas
130 bind (List.rev
metas) [metaid name
]
131 | Ast.DisjId
(ids
) -> bind_disj (List.map k ids
)
132 | _
-> option_default) in
134 let rec type_collect res
= function
135 TC.ConstVol
(_
,ty
) | TC.Pointer
(ty
) | TC.FunctionPointer
(ty
)
136 | TC.Array
(ty
) -> type_collect res ty
137 | TC.EnumName
(TC.MV
(tyname
,_
,_
)) ->
139 | TC.StructUnionName
(_
,TC.MV
(tyname
,_
,_
)) ->
141 | TC.MetaType
(tyname
,_
,_
) ->
143 | TC.SignedT
(_
,Some ty
) -> type_collect res ty
146 let astfvexpr recursor k e
=
148 (match Ast.unwrap e
with
149 Ast.MetaExpr
(name
,constraints
,_
,Some type_list
,_
,_
) ->
150 let types = List.fold_left
type_collect option_default type_list
in
152 if include_constraints
154 match constraints
with
155 Ast.SubExpCstrt l
-> l
158 bind extra (bind [metaid name
] types)
159 | Ast.MetaErr
(name
,constraints
,_
,_
)
160 | Ast.MetaExpr
(name
,constraints
,_
,_
,_
,_
) ->
162 if include_constraints
164 match constraints
with
165 Ast.SubExpCstrt l
-> l
168 bind extra [metaid name
]
169 | Ast.MetaExprList
(name
,Ast.MetaListLen
(lenname
,_
,_
),_
,_
) ->
170 [metaid name
;metaid lenname
]
171 | Ast.MetaExprList
(name
,_
,_
,_
) -> [metaid name
]
172 | Ast.DisjExpr
(exps
) -> bind_disj (List.map k exps
)
173 | _
-> option_default) in
175 let astfvdecls recursor k d
=
177 (match Ast.unwrap d
with
178 Ast.MetaDecl
(name
,_
,_
) | Ast.MetaField
(name
,_
,_
) -> [metaid name
]
179 | Ast.MetaFieldList
(name
,Ast.MetaListLen
(lenname
,_
,_
),_
,_
) ->
180 [metaid name
;metaid lenname
]
181 | Ast.MetaFieldList
(name
,_
,_
,_
) ->
183 | Ast.DisjDecl
(decls
) -> bind_disj (List.map k decls
)
184 | _
-> option_default) in
186 let astfvfullType recursor k ty
=
188 (match Ast.unwrap ty
with
189 Ast.DisjType
(types) -> bind_disj (List.map k
types)
190 | _
-> option_default) in
192 let astfvtypeC recursor k ty
=
194 (match Ast.unwrap ty
with
195 Ast.MetaType
(name
,_
,_
) -> [metaid name
]
196 | _
-> option_default) in
198 let astfvinit recursor k ty
=
200 (match Ast.unwrap ty
with
201 Ast.MetaInit
(name
,_
,_
) -> [metaid name
]
202 | Ast.MetaInitList
(name
,Ast.MetaListLen
(lenname
,_
,_
),_
,_
) ->
203 [metaid name
;metaid lenname
]
204 | Ast.MetaInitList
(name
,_
,_
,_
) -> [metaid name
]
205 | _
-> option_default) in
207 let astfvparam recursor k p
=
209 (match Ast.unwrap p
with
210 Ast.MetaParam
(name
,_
,_
) -> [metaid name
]
211 | Ast.MetaParamList
(name
,Ast.MetaListLen
(lenname
,_
,_
),_
,_
) ->
212 [metaid name
;metaid lenname
]
213 | Ast.MetaParamList
(name
,_
,_
,_
) -> [metaid name
]
214 | _
-> option_default) in
216 let astfvrule_elem recursor k re
=
217 (*within a rule_elem, pattern3 manages the coherence of the bindings*)
220 (match Ast.unwrap re
with
221 Ast.MetaRuleElem
(name
,_
,_
) | Ast.MetaStmt
(name
,_
,_
,_
)
222 | Ast.MetaStmtList
(name
,_
,_
) -> [metaid name
]
223 | _
-> option_default)) in
225 let astfvstatement recursor k s
=
227 (match Ast.unwrap s
with
229 bind_disj (List.map recursor
.V.combiner_statement_dots stms
)
230 | _
-> option_default) in
233 if include_constraints
237 (function Ast.MetaPos
(name
,constraints
,_
,_
,_
) ->
238 (metaid name
)::constraints
)
239 (Ast.get_pos_var mc
))
240 else option_default in
242 V.combiner
bind option_default
243 mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode
244 donothing donothing donothing donothing donothing
245 astfvident astfvexpr astfvfullType astfvtypeC astfvinit astfvparam
246 astfvdecls astfvrule_elem astfvstatement donothing donothing donothing_a
248 let collect_all_refs = collect_refs true
249 let collect_non_constraint_refs = collect_refs false
251 let collect_all_rule_refs minirules
=
252 List.fold_left
(@) []
253 (List.map
collect_all_refs.V.combiner_top_level minirules
)
255 let collect_all_minirule_refs = collect_all_refs.V.combiner_top_level
257 (* ---------------------------------------------------------------- *)
260 let bind = Common.union_set
in
261 let option_default = [] in
263 let donothing recursor k e
= k e
in (* just combine in the normal way *)
265 let metaid (x
,_
,_
,_
) = x
in
267 (* cases for metavariables *)
268 let astfvident recursor k i
=
270 (match Ast.unwrap i
with
271 Ast.MetaId
(name
,_
,TC.Saved
,_
)
272 | Ast.MetaFunc
(name
,_
,TC.Saved
,_
)
273 | Ast.MetaLocalFunc
(name
,_
,TC.Saved
,_
) -> [metaid name
]
274 | _
-> option_default) in
276 let rec type_collect res
= function
277 TC.ConstVol
(_
,ty
) | TC.Pointer
(ty
) | TC.FunctionPointer
(ty
)
278 | TC.Array
(ty
) -> type_collect res ty
279 | TC.EnumName
(TC.MV
(tyname
,TC.Saved
,_
)) ->
281 | TC.StructUnionName
(_
,TC.MV
(tyname
,TC.Saved
,_
)) ->
283 | TC.MetaType
(tyname
,TC.Saved
,_
) ->
285 | TC.SignedT
(_
,Some ty
) -> type_collect res ty
288 let astfvexpr recursor k e
=
290 match Ast.unwrap e
with
291 Ast.MetaExpr
(name
,_
,_
,Some type_list
,_
,_
) ->
292 List.fold_left
type_collect option_default type_list
296 (match Ast.unwrap e
with
297 Ast.MetaErr
(name
,_
,TC.Saved
,_
) | Ast.MetaExpr
(name
,_
,TC.Saved
,_
,_
,_
)
299 | Ast.MetaExprList
(name
,Ast.MetaListLen
(lenname
,ls
,_
),ns
,_
) ->
301 match ns
with TC.Saved
-> [metaid name
] | _
-> [] in
303 match ls
with TC.Saved
-> [metaid lenname
] | _
-> [] in
305 | Ast.MetaExprList
(name
,_
,TC.Saved
,_
) -> [metaid name
]
306 | _
-> option_default) in
309 let astfvtypeC recursor k ty
=
311 (match Ast.unwrap ty
with
312 Ast.MetaType
(name
,TC.Saved
,_
) -> [metaid name
]
313 | _
-> option_default) in
315 let astfvinit recursor k ty
=
317 (match Ast.unwrap ty
with
318 Ast.MetaInit
(name
,TC.Saved
,_
) -> [metaid name
]
319 | Ast.MetaInitList
(name
,Ast.MetaListLen
(lenname
,ls
,_
),ns
,_
) ->
321 match ns
with TC.Saved
-> [metaid name
] | _
-> [] in
323 match ls
with TC.Saved
-> [metaid lenname
] | _
-> [] in
325 | _
-> option_default) in
327 let astfvparam recursor k p
=
329 (match Ast.unwrap p
with
330 Ast.MetaParam
(name
,TC.Saved
,_
) -> [metaid name
]
331 | Ast.MetaParamList
(name
,Ast.MetaListLen
(lenname
,ls
,_
),ns
,_
) ->
333 match ns
with TC.Saved
-> [metaid name
] | _
-> [] in
335 match ls
with TC.Saved
-> [metaid lenname
] | _
-> [] in
337 | Ast.MetaParamList
(name
,_
,TC.Saved
,_
) -> [metaid name
]
338 | _
-> option_default) in
340 let astfvdecls recursor k d
=
342 (match Ast.unwrap d
with
343 Ast.MetaDecl
(name
,TC.Saved
,_
) | Ast.MetaField
(name
,TC.Saved
,_
) ->
345 | Ast.MetaFieldList
(name
,Ast.MetaListLen
(lenname
,ls
,_
),ns
,_
) ->
347 match ns
with TC.Saved
-> [metaid name
] | _
-> [] in
349 match ls
with TC.Saved
-> [metaid lenname
] | _
-> [] in
351 | Ast.MetaFieldList
(name
,_
,TC.Saved
,_
) -> [metaid name
]
352 | _
-> option_default) in
354 let astfvrule_elem recursor k re
=
355 (*within a rule_elem, pattern3 manages the coherence of the bindings*)
358 (match Ast.unwrap re
with
359 Ast.MetaRuleElem
(name
,TC.Saved
,_
) | Ast.MetaStmt
(name
,TC.Saved
,_
,_
)
360 | Ast.MetaStmtList
(name
,TC.Saved
,_
) -> [metaid name
]
361 | _
-> option_default)) in
367 Ast.MetaPos
(name
,_
,_
,TC.Saved
,_
) -> (metaid name
) :: acc
369 option_default (Ast.get_pos_var e
) in
371 V.combiner
bind option_default
372 mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode
373 donothing donothing donothing donothing donothing
374 astfvident astfvexpr donothing astfvtypeC astfvinit astfvparam
375 astfvdecls astfvrule_elem donothing donothing donothing donothing
377 (* ---------------------------------------------------------------- *)
379 (* For the rules under a given metavariable declaration, collect all of the
380 variables that occur in the plus code *)
382 let cip_mcodekind r mck
=
383 let process_anything_list_list anythings
=
384 let astfvs = collect_all_refs.V.combiner_anything
in
385 List.fold_left
(@) []
386 (List.map
(function l
-> List.fold_left
(@) [] (List.map
astfvs l
))
389 Ast.MINUS
(_
,_
,_
,replacement
) ->
390 (match replacement
with
391 Ast.REPLACEMENT
(anythings
,_
) -> process_anything_list_list anythings
392 | Ast.NOREPLACEMENT
-> [])
393 | Ast.CONTEXT
(_
,befaft
) ->
395 Ast.BEFORE
(ll
,_
) -> process_anything_list_list ll
396 | Ast.AFTER
(ll
,_
) -> process_anything_list_list ll
397 | Ast.BEFOREAFTER
(llb
,lla
,_
) ->
398 (process_anything_list_list lla
) @
399 (process_anything_list_list llb
)
404 let collect_fresh_seed_env metavars l
=
409 Ast.MetaFreshIdDecl
(_
,seed
) as x
->
410 ((Ast.get_meta_name x
),seed
)::prev
413 let (seed_env
,seeds
) =
415 (function (seed_env
,seeds
) as prev
->
418 (let v = List.assoc x
fresh in
425 Ast.SeedId
(id
) -> id
::prev
428 ((x
,ids)::seed_env
,Common.union_set
ids seeds
)
429 | _
-> ((x
,[])::seed_env
,seeds
))
430 with Not_found
-> prev
)
432 (List.rev seed_env
,List.rev seeds
)
434 let collect_fresh_seed metavars l
=
435 let (_
,seeds
) = collect_fresh_seed_env metavars l
in seeds
437 let collect_in_plus_term =
439 let bind x y
= x
@ y
in
440 let option_default = [] in
441 let donothing r k e
= k e
in
443 (* no positions in the + code *)
444 let mcode r
(_
,_
,mck
,_
) = cip_mcodekind r mck
in
446 (* case for things with bef/aft mcode *)
448 let astfvrule_elem recursor k re
=
449 match Ast.unwrap re
with
450 Ast.FunHeader
(bef
,_
,fi
,nm
,_
,params
,_
) ->
455 Ast.FType
(ty
) -> collect_all_refs.V.combiner_fullType ty
458 let nm_metas = collect_all_refs.V.combiner_ident nm
in
460 match Ast.unwrap params
with
461 Ast.DOTS
(params
) | Ast.CIRCLES
(params
) ->
465 match Ast.unwrap p
with
466 Ast.VoidParam
(t
) | Ast.Param
(t
,_
) ->
467 collect_all_refs.V.combiner_fullType t
470 | _
-> failwith
"not allowed for params" in
474 (bind (cip_mcodekind recursor bef
) (k re
))))
475 | Ast.Decl
(bef
,_
,_
) ->
476 bind (cip_mcodekind recursor bef
) (k re
)
479 let astfvstatement recursor k s
=
480 match Ast.unwrap s
with
481 Ast.IfThen
(_
,_
,(_
,_
,_
,aft
)) | Ast.IfThenElse
(_
,_
,_
,_
,(_
,_
,_
,aft
))
482 | Ast.While
(_
,_
,(_
,_
,_
,aft
)) | Ast.For
(_
,_
,(_
,_
,_
,aft
))
483 | Ast.Iterator
(_
,_
,(_
,_
,_
,aft
)) ->
484 bind (k s
) (cip_mcodekind recursor aft
)
487 V.combiner
bind option_default
488 mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode
489 donothing donothing donothing donothing donothing
490 donothing donothing donothing donothing donothing donothing
491 donothing astfvrule_elem astfvstatement donothing donothing donothing
493 let collect_in_plus metavars minirules
=
495 (collect_fresh_seed metavars
497 (List.map
collect_in_plus_term.V.combiner_top_level minirules
)))
499 (* ---------------------------------------------------------------- *)
501 (* For the rules under a given metavariable declaration, collect all of the
502 variables that occur only once and more than once in the minus code *)
504 let collect_all_multirefs minirules
=
505 let refs = List.map
collect_all_refs.V.combiner_top_level minirules
in
506 collect_unitary_nonunitary (List.concat
refs)
508 (* ---------------------------------------------------------------- *)
510 (* classify as unitary (no binding) or nonunitary (env binding) or saved
513 let classify_variables metavar_decls minirules used_after
=
514 let metavars = List.map
Ast.get_meta_name metavar_decls
in
515 let (unitary,nonunitary) = collect_all_multirefs minirules
in
516 let inplus = collect_in_plus metavar_decls minirules
in
518 let donothing r k e
= k e
in
519 let check_unitary name inherited
=
520 if List.mem name
inplus or List.mem name used_after
522 else if not inherited
&& List.mem name
unitary
524 else TC.Nonunitary
in
526 let get_option f
= function Some x
-> Some
(f x
) | None
-> None
in
528 let classify (name
,_
,_
,_
) =
529 let inherited = not
(List.mem name
metavars) in
530 (check_unitary name
inherited,inherited) in
535 (function Ast.MetaPos
(name
,constraints
,per
,unitary,inherited) ->
536 let (unitary,inherited) = classify name
in
537 Ast.MetaPos
(name
,constraints
,per
,unitary,inherited))
538 (Ast.get_pos_var mc
) in
539 Ast.set_pos_var
p mc
in
543 match Ast.unwrap
e with
544 Ast.MetaId
(name
,constraints
,_
,_
) ->
545 let (unitary,inherited) = classify name
in
547 (Ast.MetaId
(name
,constraints
,unitary,inherited))
548 | Ast.MetaFunc
(name
,constraints
,_
,_
) ->
549 let (unitary,inherited) = classify name
in
550 Ast.rewrap
e (Ast.MetaFunc
(name
,constraints
,unitary,inherited))
551 | Ast.MetaLocalFunc
(name
,constraints
,_
,_
) ->
552 let (unitary,inherited) = classify name
in
553 Ast.rewrap
e (Ast.MetaLocalFunc
(name
,constraints
,unitary,inherited))
556 let rec type_infos = function
557 TC.ConstVol
(cv
,ty
) -> TC.ConstVol
(cv
,type_infos ty
)
558 | TC.Pointer
(ty
) -> TC.Pointer
(type_infos ty
)
559 | TC.FunctionPointer
(ty
) -> TC.FunctionPointer
(type_infos ty
)
560 | TC.Array
(ty
) -> TC.Array
(type_infos ty
)
561 | TC.EnumName
(TC.MV
(name
,_
,_
)) ->
562 let (unitary,inherited) = classify (name
,(),(),[]) in
563 TC.EnumName
(TC.MV
(name
,unitary,inherited))
564 | TC.StructUnionName
(su
,TC.MV
(name
,_
,_
)) ->
565 let (unitary,inherited) = classify (name
,(),(),[]) in
566 TC.StructUnionName
(su
,TC.MV
(name
,unitary,inherited))
567 | TC.MetaType
(name
,_
,_
) ->
568 let (unitary,inherited) = classify (name
,(),(),[]) in
569 Type_cocci.MetaType
(name
,unitary,inherited)
570 | TC.SignedT
(sgn
,Some ty
) -> TC.SignedT
(sgn
,Some
(type_infos ty
))
573 let expression r k
e =
575 match Ast.unwrap
e with
576 Ast.MetaErr
(name
,constraints
,_
,_
) ->
577 let (unitary,inherited) = classify name
in
578 Ast.rewrap
e (Ast.MetaErr
(name
,constraints
,unitary,inherited))
579 | Ast.MetaExpr
(name
,constraints
,_
,ty
,form
,_
) ->
580 let (unitary,inherited) = classify name
in
581 let ty = get_option (List.map
type_infos) ty in
582 Ast.rewrap
e (Ast.MetaExpr
(name
,constraints
,unitary,ty,form
,inherited))
583 | Ast.MetaExprList
(name
,Ast.MetaListLen
(lenname
,_
,_
),_
,_
) ->
584 (* lenname should have the same properties of being unitary or
586 let (unitary,inherited) = classify name
in
587 let (lenunitary
,leninherited
) = classify lenname
in
591 Ast.MetaListLen
(lenname
,lenunitary
,leninherited
),
593 | Ast.MetaExprList
(name
,lenname
,_
,_
) ->
594 (* lenname should have the same properties of being unitary or
596 let (unitary,inherited) = classify name
in
597 Ast.rewrap
e (Ast.MetaExprList
(name
,lenname
,unitary,inherited))
602 match Ast.unwrap
e with
603 Ast.MetaType
(name
,_
,_
) ->
604 let (unitary,inherited) = classify name
in
605 Ast.rewrap
e (Ast.MetaType
(name
,unitary,inherited))
610 match Ast.unwrap
e with
611 Ast.MetaInit
(name
,_
,_
) ->
612 let (unitary,inherited) = classify name
in
613 Ast.rewrap
e (Ast.MetaInit
(name
,unitary,inherited))
614 | Ast.MetaInitList
(name
,Ast.MetaListLen
(lenname
,_
,_
),_
,_
) ->
615 let (unitary,inherited) = classify name
in
616 let (lenunitary
,leninherited
) = classify lenname
in
619 (name
,Ast.MetaListLen
(lenname
,lenunitary
,leninherited
),
621 | Ast.MetaInitList
(name
,lenname
,_
,_
) ->
622 let (unitary,inherited) = classify name
in
623 Ast.rewrap
e (Ast.MetaInitList
(name
,lenname
,unitary,inherited))
628 match Ast.unwrap
e with
629 Ast.MetaParam
(name
,_
,_
) ->
630 let (unitary,inherited) = classify name
in
631 Ast.rewrap
e (Ast.MetaParam
(name
,unitary,inherited))
632 | Ast.MetaParamList
(name
,Ast.MetaListLen
(lenname
,_
,_
),_
,_
) ->
633 let (unitary,inherited) = classify name
in
634 let (lenunitary
,leninherited
) = classify lenname
in
637 (name
,Ast.MetaListLen
(lenname
,lenunitary
,leninherited
),
639 | Ast.MetaParamList
(name
,lenname
,_
,_
) ->
640 let (unitary,inherited) = classify name
in
641 Ast.rewrap
e (Ast.MetaParamList
(name
,lenname
,unitary,inherited))
646 match Ast.unwrap
e with
647 Ast.MetaDecl
(name
,_
,_
) ->
648 let (unitary,inherited) = classify name
in
649 Ast.rewrap
e (Ast.MetaDecl
(name
,unitary,inherited))
650 | Ast.MetaField
(name
,_
,_
) ->
651 let (unitary,inherited) = classify name
in
652 Ast.rewrap
e (Ast.MetaField
(name
,unitary,inherited))
653 | Ast.MetaFieldList
(name
,Ast.MetaListLen
(lenname
,_
,_
),_
,_
) ->
654 let (unitary,inherited) = classify name
in
655 let (lenunitary
,leninherited
) = classify lenname
in
658 (name
,Ast.MetaListLen
(lenname
,lenunitary
,leninherited
),
660 | Ast.MetaFieldList
(name
,lenname
,_
,_
) ->
661 let (unitary,inherited) = classify name
in
662 Ast.rewrap
e (Ast.MetaFieldList
(name
,lenname
,unitary,inherited))
665 let rule_elem r k
e =
667 match Ast.unwrap
e with
668 Ast.MetaStmt
(name
,_
,msi
,_
) ->
669 let (unitary,inherited) = classify name
in
670 Ast.rewrap
e (Ast.MetaStmt
(name
,unitary,msi
,inherited))
671 | Ast.MetaStmtList
(name
,_
,_
) ->
672 let (unitary,inherited) = classify name
in
673 Ast.rewrap
e (Ast.MetaStmtList
(name
,unitary,inherited))
677 mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode
678 donothing donothing donothing donothing donothing
679 ident expression donothing typeC init param decl rule_elem
680 donothing donothing donothing donothing in
682 List.map
fn.V.rebuilder_top_level minirules
684 (* ---------------------------------------------------------------- *)
686 (* For a minirule, collect the set of non-local (not in "bound") variables that
687 are referenced. Store them in a hash table. *)
689 (* bound means the metavariable was declared previously, not locally *)
691 (* Highly inefficient, because we call collect_all_refs on nested code
692 multiple times. But we get the advantage of not having too many variants
693 of the same functions. *)
695 (* Inherited doesn't include position constraints. If they are not bound
696 then there is no constraint. *)
698 let astfvs metavars bound
=
703 Ast.MetaFreshIdDecl
(_
,seed
) as x
->
704 ((Ast.get_meta_name x
),seed
)::prev
708 let collect_fresh l
=
709 let (matched
,freshvars
) =
711 (function (matched
,freshvars
) ->
713 try let v = List.assoc x
fresh in (matched
,(x
,v)::freshvars
)
714 with Not_found
-> (x
::matched
,freshvars
))
716 (List.rev matched
, List.rev freshvars
) in
718 (* cases for the elements of anything *)
719 let simple_setup getter k re
=
720 let minus_free = nub (getter
collect_all_refs re
) in
722 nub (getter
collect_non_constraint_refs re
) in
724 collect_fresh_seed metavars (getter
collect_in_plus_term re
) in
725 let free = Common.union_set
minus_free plus_free in
726 let nc_free = Common.union_set
minus_nc_free plus_free in
728 List.filter
(function x
-> not
(List.mem x bound
)) free in
730 List.filter
(function x
-> List.mem x bound
) nc_free in
732 List.filter
(function x
-> not
(List.mem x bound
)) minus_free in
733 let (matched
,fresh) = collect_fresh unbound in
735 Ast.free_vars
= matched
;
736 Ast.minus_free_vars
= munbound;
737 Ast.fresh_vars
= fresh;
738 Ast.inherited = inherited;
739 Ast.saved_witness
= []} in
741 let astfvrule_elem recursor k re
=
742 simple_setup (function x
-> x
.V.combiner_rule_elem
) k re
in
744 let astfvstatement recursor k s
=
745 let minus_free = nub (collect_all_refs.V.combiner_statement s
) in
747 nub (collect_non_constraint_refs.V.combiner_statement s
) in
749 collect_fresh_seed metavars
750 (collect_in_plus_term.V.combiner_statement s
) in
751 let free = Common.union_set
minus_free plus_free in
752 let nc_free = Common.union_set
minus_nc_free plus_free in
753 let classify free minus_free =
754 let (unbound,inherited) =
755 List.partition
(function x
-> not
(List.mem x bound
)) free in
757 List.filter
(function x
-> not
(List.mem x bound
)) minus_free in
758 let (matched
,fresh) = collect_fresh unbound in
759 (matched
,munbound,fresh,inherited) in
763 collect_fresh_seed metavars
764 (cip_mcodekind collect_in_plus_term aft
) in
765 match Ast.unwrap
res with
766 Ast.IfThen
(header
,branch
,(_
,_
,_
,aft
)) ->
767 let (unbound,_
,fresh,inherited) = classify (cip_plus aft
) [] in
768 Ast.IfThen
(header
,branch
,(unbound,fresh,inherited,aft
))
769 | Ast.IfThenElse
(header
,branch1
,els
,branch2
,(_
,_
,_
,aft
)) ->
770 let (unbound,_
,fresh,inherited) = classify (cip_plus aft
) [] in
771 Ast.IfThenElse
(header
,branch1
,els
,branch2
,
772 (unbound,fresh,inherited,aft
))
773 | Ast.While
(header
,body
,(_
,_
,_
,aft
)) ->
774 let (unbound,_
,fresh,inherited) = classify (cip_plus aft
) [] in
775 Ast.While
(header
,body
,(unbound,fresh,inherited,aft
))
776 | Ast.For
(header
,body
,(_
,_
,_
,aft
)) ->
777 let (unbound,_
,fresh,inherited) = classify (cip_plus aft
) [] in
778 Ast.For
(header
,body
,(unbound,fresh,inherited,aft
))
779 | Ast.Iterator
(header
,body
,(_
,_
,_
,aft
)) ->
780 let (unbound,_
,fresh,inherited) = classify (cip_plus aft
) [] in
781 Ast.Iterator
(header
,body
,(unbound,fresh,inherited,aft
))
784 let (matched
,munbound,fresh,_
) = classify free minus_free in
786 List.filter
(function x
-> List.mem x bound
) nc_free in
789 Ast.free_vars
= matched
;
790 Ast.minus_free_vars
= munbound;
791 Ast.fresh_vars
= fresh;
792 Ast.inherited = inherited;
793 Ast.saved_witness
= []} in
795 let astfvstatement_dots recursor k sd
=
796 simple_setup (function x
-> x
.V.combiner_statement_dots
) k sd
in
798 let astfvcase_line recursor k cl
=
799 simple_setup (function x
-> x
.V.combiner_case_line
) k cl
in
801 let astfvtoplevel recursor k tl
=
802 let saved = collect_saved.V.combiner_top_level tl
in
803 {(k tl
) with Ast.saved_witness
= saved} in
806 let donothing r k
e = k
e in
809 mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode
810 donothing donothing astfvstatement_dots donothing donothing
811 donothing donothing donothing donothing donothing donothing donothing
812 astfvrule_elem astfvstatement astfvcase_line astfvtoplevel donothing
815 let collect_astfvs rules =
816 let rec loop bound = function
818 | (metavars,(nm,rule_info,minirules))::rules ->
820 Common.minus_set bound (List.map Ast.get_meta_name metavars) in
822 (List.map (astfvs metavars bound).V.rebuilder_top_level minirules))::
823 (loop ((List.map Ast.get_meta_name metavars)@bound) rules) in
827 let collect_astfvs rules
=
828 let rec loop bound = function
830 | (metavars, rule
)::rules
->
832 Ast.ScriptRule
(_
,_
,_
,_
,script_vars
,_
) ->
833 (* why are metavars in rule, but outside for cocci rule??? *)
834 let bound = script_vars
@ bound in
835 rule
::(loop bound rules
)
836 | Ast.InitialScriptRule
(_
,_
,_
,_
) | Ast.FinalScriptRule
(_
,_
,_
,_
) ->
837 (* bound stays as is because script rules have no names, so no
838 inheritance is possible *)
839 rule
::(loop bound rules
)
840 | Ast.CocciRule
(nm
, rule_info
, minirules
, isexp
, ruletype
) ->
842 Common.minus_set
bound (List.map
Ast.get_meta_name
metavars) in
845 (List.map
(astfvs metavars bound).V.rebuilder_top_level
848 (loop ((List.map
Ast.get_meta_name
metavars)@bound) rules
) in
851 (* ---------------------------------------------------------------- *)
852 (* position variables that appear as a constraint on another position variable.
853 a position variable also cannot appear both positively and negatively in a
856 let get_neg_pos_list (_
,rule
) used_after_list
=
857 let donothing r k
e = k
e in
858 let bind (p1
,np1
) (p2
,np2
) =
859 (Common.union_set p1 p2
, Common.union_set np1 np2
) in
860 let option_default = ([],[]) in
861 let metaid (x
,_
,_
,_
) = x
in
866 Ast.MetaPos
(name
,constraints
,Ast.PER
,_
,_
) ->
867 ((metaid name
)::a
,constraints
@b
)
868 | Ast.MetaPos
(name
,constraints
,Ast.ALL
,_
,_
) ->
869 (a
,(metaid name
)::constraints
@b
)))
870 option_default (Ast.get_pos_var mc
) in
872 V.combiner
bind option_default
873 mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode
874 donothing donothing donothing donothing donothing
875 donothing donothing donothing donothing donothing donothing
876 donothing donothing donothing donothing donothing donothing in
878 Ast.CocciRule
(_
,_
,minirules
,_
,_
) ->
880 (function toplevel
->
881 let (positions
,neg_positions
) = v.V.combiner_top_level toplevel
in
882 (if List.exists
(function p -> List.mem
p neg_positions
) positions
885 "a variable cannot be used both as a position and a constraint");
888 | Ast.ScriptRule _
| Ast.InitialScriptRule _
| Ast.FinalScriptRule _
->
889 (*no negated positions*) []
891 (* ---------------------------------------------------------------- *)
893 (* collect used after lists, per minirule *)
895 (* defined is a list of variables that were declared in a previous metavar
898 (* Top-level used after: For each rule collect the set of variables that
899 are inherited, ie used but not defined. These are accumulated back to
900 their point of definition. *)
903 let collect_top_level_used_after metavar_rule_list
=
904 let drop_virt = List.filter
(function ("virtual",_
) -> false | _
-> true) in
905 let (used_after
,used_after_lists
) =
907 (function (metavar_list
,r
) ->
908 function (used_after
,used_after_lists
) ->
909 let locally_defined =
911 Ast.ScriptRule
(_
,_
,_
,_
,free_vars
,_
) -> free_vars
912 | _
-> List.map
Ast.get_meta_name metavar_list
in
913 let continue_propagation =
914 List.filter
(function x
-> not
(List.mem x
locally_defined))
918 Ast.ScriptRule
(_
,_
,_
,mv
,_
,_
) ->
919 drop_virt(List.map
(function (_
,(r
,v),_
) -> (r
,v)) mv
)
920 | Ast.InitialScriptRule
(_
,_
,_
,_
)
921 | Ast.FinalScriptRule
(_
,_
,_
,_
) -> []
922 | Ast.CocciRule
(_
,_
,rule
,_
,_
) ->
924 (Common.union_set
(nub (collect_all_rule_refs rule
))
925 (collect_in_plus metavar_list rule
)) in
927 List.filter
(function x
-> not
(List.mem x
locally_defined))
929 (Common.union_set
inherited continue_propagation,
930 used_after
::used_after_lists
))
931 metavar_rule_list
([],[]) in
932 match used_after
with
933 [] -> used_after_lists
936 (Printf.sprintf
"collect_top_level_used_after: unbound variables %s"
937 (String.concat
" " (List.map
(function (_
,x
) -> x
) used_after
)))
939 let collect_local_used_after metavars minirules used_after
=
940 let locally_defined = List.map
Ast.get_meta_name
metavars in
941 let rec loop = function
942 [] -> (used_after
,[],[],[],[])
944 (* In a rule there are three kinds of local variables:
945 1. Variables referenced in the minus or context code.
946 These get a value by matching. This value can be used in
948 2. Fresh variables referenced in the plus code.
949 3. Variables referenced in the seeds of the fresh variables.
950 There are also non-local variables. These may either be variables
951 referenced in the minus, context, or plus code, or they may be
952 variables referenced in the seeds of the fresh variables. *)
953 (* Step 1: collect all references in minus/context, plus, seed
955 let variables_referenced_in_minus_context_code =
956 nub (collect_all_minirule_refs minirule
) in
957 let variables_referenced_in_plus_code =
958 collect_in_plus_term.V.combiner_top_level minirule
in
959 let (env_of_fresh_seeds
,seeds_and_plus
) =
960 collect_fresh_seed_env
961 metavars variables_referenced_in_plus_code in
963 Common.union_set
variables_referenced_in_minus_context_code
965 (* Step 2: identify locally defined ones *)
966 let local_fresh = List.map fst env_of_fresh_seeds
in
968 List.partition
(function x
-> List.mem x
locally_defined) in
969 let local_env_of_fresh_seeds =
970 (* these have to be restricted to only one value if the associated
971 fresh variable is used after *)
972 List.map
(function (f
,ss
) -> (f
,is_local ss
)) env_of_fresh_seeds
in
973 let (local_all_free_vars
,nonlocal_all_free_vars
) =
974 is_local all_free_vars in
975 (* Step 3, recurse on the rest of the rules, making available whatever
976 has been defined in this one *)
977 let (mini_used_after
,fvs_lists
,mini_used_after_lists
,
978 mini_fresh_used_after_lists
,mini_fresh_used_after_seeds
) =
980 (* Step 4: collect the results. These are:
981 1. All of the variables used non-locally in the rules starting
983 2. All of the free variables to the end of the semantic patch
984 3. The variables that are used afterwards and defined here by
985 matching (minus or context code)
986 4. The variables that are used afterwards and are defined here as
988 5. The variables that are used as seeds in computing the bindings
989 of the variables collected in part 4. *)
990 let (local_used_after
, nonlocal_used_after
) =
991 is_local mini_used_after
in
992 let (fresh_local_used_after
(*4*),matched_local_used_after
) =
993 List.partition
(function x
-> List.mem x
local_fresh)
995 let matched_local_used_after(*3*) =
996 Common.union_set
matched_local_used_after nonlocal_used_after
in
997 let new_used_after = (*1*)
998 Common.union_set nonlocal_all_free_vars nonlocal_used_after
in
999 let fresh_local_used_after_seeds =
1001 (* no point to keep variables that already are gtd to have only
1003 (function x
-> not
(List.mem x
matched_local_used_after))
1004 (List.fold_left
(function p -> function c
-> Common.union_set c
p)
1008 fst
(List.assoc fua
local_env_of_fresh_seeds))
1009 fresh_local_used_after
)) in
1010 (new_used_after,all_free_vars::fvs_lists
(*2*),
1011 matched_local_used_after::mini_used_after_lists
,
1012 fresh_local_used_after
::mini_fresh_used_after_lists
,
1013 fresh_local_used_after_seeds::mini_fresh_used_after_seeds
) in
1014 let (_
,fvs_lists
,used_after_lists
(*ua*),
1015 fresh_used_after_lists
(*fua*),fresh_used_after_lists_seeds
(*fuas*)) =
1017 (fvs_lists
,used_after_lists
,
1018 fresh_used_after_lists
,fresh_used_after_lists_seeds
)
1022 let collect_used_after metavar_rule_list
=
1023 let used_after_lists = collect_top_level_used_after metavar_rule_list
in
1025 (function (metavars,r
) ->
1026 function used_after
->
1028 Ast.ScriptRule
(_
,_
,_
,_
,_
,_
) (* no minirules, so nothing to do? *)
1029 | Ast.InitialScriptRule
(_
,_
,_
,_
) | Ast.FinalScriptRule
(_
,_
,_
,_
) ->
1030 ([], [used_after
], [[]], [])
1031 | Ast.CocciRule
(name
, rule_info
, minirules
, _
,_
) ->
1032 collect_local_used_after metavars minirules used_after
1034 metavar_rule_list
used_after_lists
1036 let rec split4 = function
1038 | (a
,b
,c
,d
)::l
-> let (a1
,b1
,c1
,d1
) = split4 l
in (a
::a1
,b
::b1
,c
::c1
,d
::d1
)
1040 (* ---------------------------------------------------------------- *)
1043 let free_vars rules
=
1044 let metavars = List.map
(function (mv
,rule
) -> mv
) rules
in
1045 let (fvs_lists
,used_after_matched_lists
,
1046 fresh_used_after_lists
,fresh_used_after_lists_seeds
) =
1047 split4 (collect_used_after rules
) in
1049 List.map2
get_neg_pos_list rules used_after_matched_lists
in
1050 let positions_list = (* for all rules, assume all positions are used after *)
1052 (function (mv
, r
) ->
1054 Ast.ScriptRule _
(* doesn't declare position variables *)
1055 | Ast.InitialScriptRule _
| Ast.FinalScriptRule _
-> []
1056 | Ast.CocciRule
(_
,_
,rule
,_
,_
) ->
1060 function Ast.MetaPosDecl
(_
,nm
) -> nm
::prev
| _
-> prev
)
1062 List.map
(function _
-> positions) rule
)
1067 function (ua
,fua
) ->
1070 | Ast.InitialScriptRule _
| Ast.FinalScriptRule _
-> r
1071 | Ast.CocciRule
(nm
, rule_info
, r
, is_exp
,ruletype
) ->
1074 classify_variables mv r
1075 ((List.concat ua
) @ (List.concat fua
)),
1077 rules
(List.combine used_after_matched_lists fresh_used_after_lists
) in
1078 let new_rules = collect_astfvs (List.combine
metavars new_rules) in
1079 (metavars,new_rules,
1080 fvs_lists
,neg_pos_lists,
1081 (used_after_matched_lists
,
1082 fresh_used_after_lists
,fresh_used_after_lists_seeds
),