1 (* For each rule return the list of variables that are used after it.
2 Also augment various parts of each rule with unitary, inherited, and freshness
5 (* metavar decls should be better integrated into computations of free
6 variables in plus code *)
10 module TC
= Type_cocci
12 let rec nub = function
14 | (x
::xs
) when (List.mem x xs
) -> nub xs
15 | (x
::xs
) -> x
::(nub xs
)
17 (* Collect all variable references in a minirule. For a disj, we collect
18 the maximum number (2 is enough) of references in any branch. *)
20 let collect_unitary_nonunitary free_usage
=
21 let free_usage = List.sort compare
free_usage in
22 let rec loop1 todrop
= function (* skips multiple occurrences *)
24 | (x
::xs
) as all
-> if x
= todrop
then loop1 todrop xs
else all
in
25 let rec loop2 = function
29 if x
= y
(* occurs more than once in free_usage *)
31 let (unitary
,non_unitary
) = loop2(loop1 x xs
) in
32 (unitary
,x
::non_unitary
)
33 else (* occurs only once in free_usage *)
34 let (unitary
,non_unitary
) = loop2 (y
::xs
) in
35 (x
::unitary
,non_unitary
) in
38 let collect_refs include_constraints
=
39 let bind x y
= x
@ y
in
40 let option_default = [] in
42 let donothing recursor k e
= k e
in (* just combine in the normal way *)
44 let donothing_a recursor k e
= (* anything is not wrapped *)
45 k e
in (* just combine in the normal way *)
47 (* the following considers that anything that occurs non-unitarily in one
48 branch occurs nonunitarily in all branches. This is not optimal, but
49 doing better seems to require a breadth-first traversal, which is
50 perhaps better to avoid. Also, unitarily is represented as occuring once,
51 while nonunitarily is represented as twice - more is irrelevant *)
52 (* cases for disjs and metavars *)
53 let bind_disj refs_branches
=
54 let (unitary
,nonunitary
) =
55 List.split
(List.map
collect_unitary_nonunitary refs_branches
) in
56 let unitary = nub (List.concat
unitary) in
57 let nonunitary = nub (List.concat
nonunitary) in
59 List.filter
(function x
-> not
(List.mem x
nonunitary)) unitary in
60 unitary@nonunitary@nonunitary in
62 let metaid (x
,_
,_
,_
) = x
in
64 let astfvident recursor k i
=
66 (match Ast.unwrap i
with
67 Ast.MetaId
(name
,_
,_
,_
) | Ast.MetaFunc
(name
,_
,_
,_
)
68 | Ast.MetaLocalFunc
(name
,_
,_
,_
) -> [metaid name
]
69 | _
-> option_default) in
71 let rec type_collect res
= function
72 TC.ConstVol
(_
,ty
) | TC.Pointer
(ty
) | TC.FunctionPointer
(ty
)
73 | TC.Array
(ty
) -> type_collect res ty
74 | TC.MetaType
(tyname
,_
,_
) -> bind [tyname
] res
75 | TC.SignedT
(_
,Some ty
) -> type_collect res ty
78 let astfvexpr recursor k e
=
80 (match Ast.unwrap e
with
81 Ast.MetaExpr
(name
,_
,_
,Some type_list
,_
,_
) ->
82 let types = List.fold_left
type_collect option_default type_list
in
83 bind [metaid name
] types
84 | Ast.MetaErr
(name
,_
,_
,_
) | Ast.MetaExpr
(name
,_
,_
,_
,_
,_
) -> [metaid name
]
85 | Ast.MetaExprList
(name
,None
,_
,_
) -> [metaid name
]
86 | Ast.MetaExprList
(name
,Some
(lenname
,_
,_
),_
,_
) ->
87 [metaid name
;metaid lenname
]
88 | Ast.DisjExpr
(exps
) -> bind_disj (List.map k exps
)
89 | _
-> option_default) in
91 let astfvdecls recursor k d
=
93 (match Ast.unwrap d
with
94 Ast.DisjDecl
(decls
) -> bind_disj (List.map k decls
)
95 | _
-> option_default) in
97 let astfvfullType recursor k ty
=
99 (match Ast.unwrap ty
with
100 Ast.DisjType
(types) -> bind_disj (List.map k
types)
101 | _
-> option_default) in
103 let astfvtypeC recursor k ty
=
105 (match Ast.unwrap ty
with
106 Ast.MetaType
(name
,_
,_
) -> [metaid name
]
107 | _
-> option_default) in
109 let astfvinit recursor k ty
=
111 (match Ast.unwrap ty
with
112 Ast.MetaInit
(name
,_
,_
) -> [metaid name
]
113 | _
-> option_default) in
115 let astfvparam recursor k p
=
117 (match Ast.unwrap p
with
118 Ast.MetaParam
(name
,_
,_
) -> [metaid name
]
119 | Ast.MetaParamList
(name
,None
,_
,_
) -> [metaid name
]
120 | Ast.MetaParamList
(name
,Some
(lenname
,_
,_
),_
,_
) ->
121 [metaid name
;metaid lenname
]
122 | _
-> option_default) in
124 let astfvrule_elem recursor k re
=
125 (*within a rule_elem, pattern3 manages the coherence of the bindings*)
128 (match Ast.unwrap re
with
129 Ast.MetaRuleElem
(name
,_
,_
) | Ast.MetaStmt
(name
,_
,_
,_
)
130 | Ast.MetaStmtList
(name
,_
,_
) -> [metaid name
]
131 | _
-> option_default)) in
133 let astfvstatement recursor k s
=
135 (match Ast.unwrap s
with
137 bind_disj (List.map recursor
.V.combiner_statement_dots stms
)
138 | _
-> option_default) in
141 if include_constraints
143 match Ast.get_pos_var mc
with
144 Ast.MetaPos
(name
,constraints
,_
,_
,_
) -> (metaid name
)::constraints
145 | _
-> option_default
146 else option_default in
148 V.combiner
bind option_default
149 mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode
150 donothing donothing donothing donothing
151 astfvident astfvexpr astfvfullType astfvtypeC astfvinit astfvparam
152 astfvdecls astfvrule_elem astfvstatement donothing donothing donothing_a
154 let collect_all_refs = collect_refs true
155 let collect_non_constraint_refs = collect_refs false
157 let collect_all_rule_refs minirules
=
158 List.fold_left
(@) []
159 (List.map
collect_all_refs.V.combiner_top_level minirules
)
161 let collect_all_minirule_refs = collect_all_refs.V.combiner_top_level
163 (* ---------------------------------------------------------------- *)
166 let bind = Common.union_set
in
167 let option_default = [] in
169 let donothing recursor k e
= k e
in (* just combine in the normal way *)
171 let metaid (x
,_
,_
,_
) = x
in
173 (* cases for metavariables *)
174 let astfvident recursor k i
=
176 (match Ast.unwrap i
with
177 Ast.MetaId
(name
,_
,TC.Saved
,_
) | Ast.MetaFunc
(name
,_
,TC.Saved
,_
)
178 | Ast.MetaLocalFunc
(name
,_
,TC.Saved
,_
) -> [metaid name
]
179 | _
-> option_default) in
181 let rec type_collect res
= function
182 TC.ConstVol
(_
,ty
) | TC.Pointer
(ty
) | TC.FunctionPointer
(ty
)
183 | TC.Array
(ty
) -> type_collect res ty
184 | TC.MetaType
(tyname
,TC.Saved
,_
) -> bind [tyname
] res
185 | TC.SignedT
(_
,Some ty
) -> type_collect res ty
188 let astfvexpr recursor k e
=
190 match Ast.unwrap e
with
191 Ast.MetaExpr
(name
,_
,_
,Some type_list
,_
,_
) ->
192 List.fold_left
type_collect option_default type_list
196 (match Ast.unwrap e
with
197 Ast.MetaErr
(name
,_
,TC.Saved
,_
) | Ast.MetaExpr
(name
,_
,TC.Saved
,_
,_
,_
)
198 | Ast.MetaExprList
(name
,None
,TC.Saved
,_
) -> [metaid name
]
199 | Ast.MetaExprList
(name
,Some
(lenname
,ls
,_
),ns
,_
) ->
201 match ns
with TC.Saved
-> [metaid name
] | _
-> [] in
203 match ls
with TC.Saved
-> [metaid lenname
] | _
-> [] in
205 | _
-> option_default) in
208 let astfvtypeC recursor k ty
=
210 (match Ast.unwrap ty
with
211 Ast.MetaType
(name
,TC.Saved
,_
) -> [metaid name
]
212 | _
-> option_default) in
214 let astfvinit recursor k ty
=
216 (match Ast.unwrap ty
with
217 Ast.MetaInit
(name
,TC.Saved
,_
) -> [metaid name
]
218 | _
-> option_default) in
220 let astfvparam recursor k p
=
222 (match Ast.unwrap p
with
223 Ast.MetaParam
(name
,TC.Saved
,_
)
224 | Ast.MetaParamList
(name
,None
,_
,_
) -> [metaid name
]
225 | Ast.MetaParamList
(name
,Some
(lenname
,ls
,_
),ns
,_
) ->
227 match ns
with TC.Saved
-> [metaid name
] | _
-> [] in
229 match ls
with TC.Saved
-> [metaid lenname
] | _
-> [] in
231 | _
-> option_default) in
233 let astfvrule_elem recursor k re
=
234 (*within a rule_elem, pattern3 manages the coherence of the bindings*)
237 (match Ast.unwrap re
with
238 Ast.MetaRuleElem
(name
,TC.Saved
,_
) | Ast.MetaStmt
(name
,TC.Saved
,_
,_
)
239 | Ast.MetaStmtList
(name
,TC.Saved
,_
) -> [metaid name
]
240 | _
-> option_default)) in
243 match Ast.get_pos_var e
with
244 Ast.MetaPos
(name
,_
,_
,TC.Saved
,_
) -> [metaid name
]
245 | _
-> option_default in
247 V.combiner
bind option_default
248 mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode
249 donothing donothing donothing donothing
250 astfvident astfvexpr donothing astfvtypeC astfvinit astfvparam
251 donothing astfvrule_elem donothing donothing donothing donothing
253 (* ---------------------------------------------------------------- *)
255 (* For the rules under a given metavariable declaration, collect all of the
256 variables that occur in the plus code *)
258 let cip_mcodekind r mck
=
259 let process_anything_list_list anythings
=
260 let astfvs = collect_all_refs.V.combiner_anything
in
261 List.fold_left
(@) []
262 (List.map
(function l
-> List.fold_left
(@) [] (List.map
astfvs l
))
265 Ast.MINUS
(_
,_
,_
,anythings
) -> process_anything_list_list anythings
266 | Ast.CONTEXT
(_
,befaft
) ->
268 Ast.BEFORE
(ll
,_
) -> process_anything_list_list ll
269 | Ast.AFTER
(ll
,_
) -> process_anything_list_list ll
270 | Ast.BEFOREAFTER
(llb
,lla
,_
) ->
271 (process_anything_list_list lla
) @
272 (process_anything_list_list llb
)
277 let collect_fresh_seed_env metavars l
=
282 Ast.MetaFreshIdDecl
(_
,seed
) as x
->
283 ((Ast.get_meta_name x
),seed
)::prev
286 let (seed_env
,seeds
) =
288 (function (seed_env
,seeds
) as prev
->
291 (let v = List.assoc x
fresh in
298 Ast.SeedId
(id
) -> id
::prev
301 ((x
,ids)::seed_env
,Common.union_set
ids seeds
)
302 | _
-> ((x
,[])::seed_env
,seeds
))
303 with Not_found
-> prev
)
305 (List.rev seed_env
,List.rev seeds
)
307 let collect_fresh_seed metavars l
=
308 let (_
,seeds
) = collect_fresh_seed_env metavars l
in seeds
310 let collect_in_plus_term =
312 let bind x y
= x
@ y
in
313 let option_default = [] in
314 let donothing r k e
= k e
in
316 (* no positions in the + code *)
317 let mcode r
(_
,_
,mck
,_
) = cip_mcodekind r mck
in
319 (* case for things with bef/aft mcode *)
321 let astfvrule_elem recursor k re
=
322 match Ast.unwrap re
with
323 Ast.FunHeader
(bef
,_
,fi
,nm
,_
,params
,_
) ->
328 Ast.FType
(ty
) -> collect_all_refs.V.combiner_fullType ty
331 let nm_metas = collect_all_refs.V.combiner_ident nm
in
333 match Ast.unwrap params
with
334 Ast.DOTS
(params
) | Ast.CIRCLES
(params
) ->
338 match Ast.unwrap p
with
339 Ast.VoidParam
(t
) | Ast.Param
(t
,_
) ->
340 collect_all_refs.V.combiner_fullType t
343 | _
-> failwith
"not allowed for params" in
347 (bind (cip_mcodekind recursor bef
) (k re
))))
348 | Ast.Decl
(bef
,_
,_
) ->
349 bind (cip_mcodekind recursor bef
) (k re
)
352 let astfvstatement recursor k s
=
353 match Ast.unwrap s
with
354 Ast.IfThen
(_
,_
,(_
,_
,_
,aft
)) | Ast.IfThenElse
(_
,_
,_
,_
,(_
,_
,_
,aft
))
355 | Ast.While
(_
,_
,(_
,_
,_
,aft
)) | Ast.For
(_
,_
,(_
,_
,_
,aft
))
356 | Ast.Iterator
(_
,_
,(_
,_
,_
,aft
)) ->
357 bind (k s
) (cip_mcodekind recursor aft
)
360 V.combiner
bind option_default
361 mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode
362 donothing donothing donothing donothing
363 donothing donothing donothing donothing donothing donothing
364 donothing astfvrule_elem astfvstatement donothing donothing donothing
366 let collect_in_plus metavars minirules
=
368 (collect_fresh_seed metavars
370 (List.map
collect_in_plus_term.V.combiner_top_level minirules
)))
372 (* ---------------------------------------------------------------- *)
374 (* For the rules under a given metavariable declaration, collect all of the
375 variables that occur only once and more than once in the minus code *)
377 let collect_all_multirefs minirules
=
378 let refs = List.map
collect_all_refs.V.combiner_top_level minirules
in
379 collect_unitary_nonunitary (List.concat
refs)
381 (* ---------------------------------------------------------------- *)
383 (* classify as unitary (no binding) or nonunitary (env binding) or saved
386 let classify_variables metavar_decls minirules used_after
=
387 let metavars = List.map
Ast.get_meta_name metavar_decls
in
388 let (unitary,nonunitary) = collect_all_multirefs minirules
in
389 let inplus = collect_in_plus metavar_decls minirules
in
391 let donothing r k e
= k e
in
392 let check_unitary name inherited
=
393 if List.mem name
inplus or List.mem name used_after
395 else if not inherited
&& List.mem name
unitary
397 else TC.Nonunitary
in
399 let get_option f
= function Some x
-> Some
(f x
) | None
-> None
in
401 let classify (name
,_
,_
,_
) =
402 let inherited = not
(List.mem name
metavars) in
403 (check_unitary name
inherited,inherited) in
406 match Ast.get_pos_var mc
with
407 Ast.MetaPos
(name
,constraints
,per
,unitary,inherited) ->
408 let (unitary,inherited) = classify name
in
409 Ast.set_pos_var
(Ast.MetaPos
(name
,constraints
,per
,unitary,inherited))
415 match Ast.unwrap
e with
416 Ast.MetaId
(name
,constraints
,_
,_
) ->
417 let (unitary,inherited) = classify name
in
418 Ast.rewrap
e (Ast.MetaId
(name
,constraints
,unitary,inherited))
419 | Ast.MetaFunc
(name
,constraints
,_
,_
) ->
420 let (unitary,inherited) = classify name
in
421 Ast.rewrap
e (Ast.MetaFunc
(name
,constraints
,unitary,inherited))
422 | Ast.MetaLocalFunc
(name
,constraints
,_
,_
) ->
423 let (unitary,inherited) = classify name
in
424 Ast.rewrap
e (Ast.MetaLocalFunc
(name
,constraints
,unitary,inherited))
427 let rec type_infos = function
428 TC.ConstVol
(cv
,ty
) -> TC.ConstVol
(cv
,type_infos ty
)
429 | TC.Pointer
(ty
) -> TC.Pointer
(type_infos ty
)
430 | TC.FunctionPointer
(ty
) -> TC.FunctionPointer
(type_infos ty
)
431 | TC.Array
(ty
) -> TC.Array
(type_infos ty
)
432 | TC.MetaType
(name
,_
,_
) ->
433 let (unitary,inherited) = classify (name
,(),(),Ast.NoMetaPos
) in
434 Type_cocci.MetaType
(name
,unitary,inherited)
435 | TC.SignedT
(sgn
,Some ty
) -> TC.SignedT
(sgn
,Some
(type_infos ty
))
438 let expression r k
e =
440 match Ast.unwrap
e with
441 Ast.MetaErr
(name
,constraints
,_
,_
) ->
442 let (unitary,inherited) = classify name
in
443 Ast.rewrap
e (Ast.MetaErr
(name
,constraints
,unitary,inherited))
444 | Ast.MetaExpr
(name
,constraints
,_
,ty
,form
,_
) ->
445 let (unitary,inherited) = classify name
in
446 let ty = get_option (List.map
type_infos) ty in
447 Ast.rewrap
e (Ast.MetaExpr
(name
,constraints
,unitary,ty,form
,inherited))
448 | Ast.MetaExprList
(name
,None
,_
,_
) ->
449 (* lenname should have the same properties of being unitary or
451 let (unitary,inherited) = classify name
in
452 Ast.rewrap
e (Ast.MetaExprList
(name
,None
,unitary,inherited))
453 | Ast.MetaExprList
(name
,Some
(lenname
,_
,_
),_
,_
) ->
454 (* lenname should have the same properties of being unitary or
456 let (unitary,inherited) = classify name
in
457 let (lenunitary
,leninherited
) = classify lenname
in
460 (name
,Some
(lenname
,lenunitary
,leninherited
),unitary,inherited))
465 match Ast.unwrap
e with
466 Ast.MetaType
(name
,_
,_
) ->
467 let (unitary,inherited) = classify name
in
468 Ast.rewrap
e (Ast.MetaType
(name
,unitary,inherited))
473 match Ast.unwrap
e with
474 Ast.MetaInit
(name
,_
,_
) ->
475 let (unitary,inherited) = classify name
in
476 Ast.rewrap
e (Ast.MetaInit
(name
,unitary,inherited))
481 match Ast.unwrap
e with
482 Ast.MetaParam
(name
,_
,_
) ->
483 let (unitary,inherited) = classify name
in
484 Ast.rewrap
e (Ast.MetaParam
(name
,unitary,inherited))
485 | Ast.MetaParamList
(name
,None
,_
,_
) ->
486 let (unitary,inherited) = classify name
in
487 Ast.rewrap
e (Ast.MetaParamList
(name
,None
,unitary,inherited))
488 | Ast.MetaParamList
(name
,Some
(lenname
,_
,_
),_
,_
) ->
489 let (unitary,inherited) = classify name
in
490 let (lenunitary
,leninherited
) = classify lenname
in
493 (name
,Some
(lenname
,lenunitary
,leninherited
),unitary,inherited))
496 let rule_elem r k
e =
498 match Ast.unwrap
e with
499 Ast.MetaStmt
(name
,_
,msi
,_
) ->
500 let (unitary,inherited) = classify name
in
501 Ast.rewrap
e (Ast.MetaStmt
(name
,unitary,msi
,inherited))
502 | Ast.MetaStmtList
(name
,_
,_
) ->
503 let (unitary,inherited) = classify name
in
504 Ast.rewrap
e (Ast.MetaStmtList
(name
,unitary,inherited))
508 mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode
509 donothing donothing donothing donothing
510 ident expression donothing typeC init param donothing rule_elem
511 donothing donothing donothing donothing in
513 List.map
fn.V.rebuilder_top_level minirules
515 (* ---------------------------------------------------------------- *)
517 (* For a minirule, collect the set of non-local (not in "bound") variables that
518 are referenced. Store them in a hash table. *)
520 (* bound means the metavariable was declared previously, not locally *)
522 (* Highly inefficient, because we call collect_all_refs on nested code
523 multiple times. But we get the advantage of not having too many variants
524 of the same functions. *)
526 (* Inherited doesn't include position constraints. If they are not bound
527 then there is no constraint. *)
529 let astfvs metavars bound
=
534 Ast.MetaFreshIdDecl
(_
,seed
) as x
->
535 ((Ast.get_meta_name x
),seed
)::prev
539 let collect_fresh l
=
540 let (matched
,freshvars
) =
542 (function (matched
,freshvars
) ->
544 try let v = List.assoc x
fresh in (matched
,(x
,v)::freshvars
)
545 with Not_found
-> (x
::matched
,freshvars
))
547 (List.rev matched
, List.rev freshvars
) in
549 (* cases for the elements of anything *)
550 let simple_setup getter k re
=
551 let minus_free = nub (getter
collect_all_refs re
) in
553 nub (getter
collect_non_constraint_refs re
) in
555 collect_fresh_seed metavars (getter
collect_in_plus_term re
) in
556 let free = Common.union_set
minus_free plus_free in
557 let nc_free = Common.union_set
minus_nc_free plus_free in
559 List.filter
(function x
-> not
(List.mem x bound
)) free in
561 List.filter
(function x
-> List.mem x bound
) nc_free in
563 List.filter
(function x
-> not
(List.mem x bound
)) minus_free in
564 let (matched
,fresh) = collect_fresh unbound in
566 Ast.free_vars
= matched
;
567 Ast.minus_free_vars
= munbound;
568 Ast.fresh_vars
= fresh;
569 Ast.inherited = inherited;
570 Ast.saved_witness
= []} in
572 let astfvrule_elem recursor k re
=
573 simple_setup (function x
-> x
.V.combiner_rule_elem
) k re
in
575 let astfvstatement recursor k s
=
576 let minus_free = nub (collect_all_refs.V.combiner_statement s
) in
578 nub (collect_non_constraint_refs.V.combiner_statement s
) in
580 collect_fresh_seed metavars
581 (collect_in_plus_term.V.combiner_statement s
) in
582 let free = Common.union_set
minus_free plus_free in
583 let nc_free = Common.union_set
minus_nc_free plus_free in
584 let classify free minus_free =
585 let (unbound,inherited) =
586 List.partition
(function x
-> not
(List.mem x bound
)) free in
588 List.filter
(function x
-> not
(List.mem x bound
)) minus_free in
589 let (matched
,fresh) = collect_fresh unbound in
590 (matched
,munbound,fresh,inherited) in
594 collect_fresh_seed metavars
595 (cip_mcodekind collect_in_plus_term aft
) in
596 match Ast.unwrap
res with
597 Ast.IfThen
(header
,branch
,(_
,_
,_
,aft
)) ->
598 let (unbound,_
,fresh,inherited) = classify (cip_plus aft
) [] in
599 Ast.IfThen
(header
,branch
,(unbound,fresh,inherited,aft
))
600 | Ast.IfThenElse
(header
,branch1
,els
,branch2
,(_
,_
,_
,aft
)) ->
601 let (unbound,_
,fresh,inherited) = classify (cip_plus aft
) [] in
602 Ast.IfThenElse
(header
,branch1
,els
,branch2
,
603 (unbound,fresh,inherited,aft
))
604 | Ast.While
(header
,body
,(_
,_
,_
,aft
)) ->
605 let (unbound,_
,fresh,inherited) = classify (cip_plus aft
) [] in
606 Ast.While
(header
,body
,(unbound,fresh,inherited,aft
))
607 | Ast.For
(header
,body
,(_
,_
,_
,aft
)) ->
608 let (unbound,_
,fresh,inherited) = classify (cip_plus aft
) [] in
609 Ast.For
(header
,body
,(unbound,fresh,inherited,aft
))
610 | Ast.Iterator
(header
,body
,(_
,_
,_
,aft
)) ->
611 let (unbound,_
,fresh,inherited) = classify (cip_plus aft
) [] in
612 Ast.Iterator
(header
,body
,(unbound,fresh,inherited,aft
))
615 let (matched
,munbound,fresh,_
) = classify free minus_free in
617 List.filter
(function x
-> List.mem x bound
) nc_free in
620 Ast.free_vars
= matched
;
621 Ast.minus_free_vars
= munbound;
622 Ast.fresh_vars
= fresh;
623 Ast.inherited = inherited;
624 Ast.saved_witness
= []} in
626 let astfvstatement_dots recursor k sd
=
627 simple_setup (function x
-> x
.V.combiner_statement_dots
) k sd
in
629 let astfvcase_line recursor k cl
=
630 simple_setup (function x
-> x
.V.combiner_case_line
) k cl
in
632 let astfvtoplevel recursor k tl
=
633 let saved = collect_saved.V.combiner_top_level tl
in
634 {(k tl
) with Ast.saved_witness
= saved} in
637 let donothing r k
e = k
e in
640 mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode
641 donothing donothing astfvstatement_dots donothing
642 donothing donothing donothing donothing donothing donothing donothing
643 astfvrule_elem astfvstatement astfvcase_line astfvtoplevel donothing
646 let collect_astfvs rules =
647 let rec loop bound = function
649 | (metavars,(nm,rule_info,minirules))::rules ->
651 Common.minus_set bound (List.map Ast.get_meta_name metavars) in
653 (List.map (astfvs metavars bound).V.rebuilder_top_level minirules))::
654 (loop ((List.map Ast.get_meta_name metavars)@bound) rules) in
658 let collect_astfvs rules
=
659 let rec loop bound = function
661 | (metavars, rule
)::rules
->
663 Ast.ScriptRule
(_
,_
,_
,_
)
664 | Ast.InitialScriptRule
(_
,_
) | Ast.FinalScriptRule
(_
,_
) ->
665 (* bound stays as is because script rules have no names, so no
666 inheritance is possible *)
667 rule
::(loop bound rules
)
668 | Ast.CocciRule
(nm
, rule_info
, minirules
, isexp
, ruletype
) ->
670 Common.minus_set
bound (List.map
Ast.get_meta_name
metavars) in
673 (List.map
(astfvs metavars bound).V.rebuilder_top_level
676 (loop ((List.map
Ast.get_meta_name
metavars)@bound) rules
) in
679 (* ---------------------------------------------------------------- *)
680 (* position variables that appear as a constraint on another position variable.
681 a position variable also cannot appear both positively and negatively in a
684 let get_neg_pos_list (_
,rule
) used_after_list
=
685 let donothing r k
e = k
e in
686 let bind (p1
,np1
) (p2
,np2
) =
687 (Common.union_set p1 p2
, Common.union_set np1 np2
) in
688 let option_default = ([],[]) in
689 let metaid (x
,_
,_
,_
) = x
in
691 match Ast.get_pos_var mc
with
692 Ast.MetaPos
(name
,constraints
,Ast.PER
,_
,_
) ->
693 ([metaid name
],constraints
)
694 | Ast.MetaPos
(name
,constraints
,Ast.ALL
,_
,_
) ->
695 ([],(metaid name
)::constraints
)
696 | _
-> option_default in
698 V.combiner
bind option_default
699 mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode
700 donothing donothing donothing donothing
701 donothing donothing donothing donothing donothing donothing
702 donothing donothing donothing donothing donothing donothing in
704 Ast.CocciRule
(_
,_
,minirules
,_
,_
) ->
706 (function toplevel
->
707 let (positions
,neg_positions
) = v.V.combiner_top_level toplevel
in
708 (if List.exists
(function p
-> List.mem p neg_positions
) positions
711 "a variable cannot be used both as a position and a constraint");
714 | Ast.ScriptRule _
| Ast.InitialScriptRule _
| Ast.FinalScriptRule _
->
715 (*no negated positions*) []
717 (* ---------------------------------------------------------------- *)
719 (* collect used after lists, per minirule *)
721 (* defined is a list of variables that were declared in a previous metavar
724 (* Top-level used after: For each rule collect the set of variables that
725 are inherited, ie used but not defined. These are accumulated back to
726 their point of definition. *)
729 let collect_top_level_used_after metavar_rule_list
=
730 let (used_after
,used_after_lists
) =
732 (function (metavar_list
,r
) ->
733 function (used_after
,used_after_lists
) ->
734 let locally_defined = List.map
Ast.get_meta_name metavar_list
in
735 let continue_propagation =
736 List.filter
(function x
-> not
(List.mem x
locally_defined))
740 Ast.ScriptRule
(_
,_
,mv
,_
) ->
741 List.map
(function (_
,(r
,v)) -> (r
,v)) mv
742 | Ast.InitialScriptRule
(_
,_
) | Ast.FinalScriptRule
(_
,_
) -> []
743 | Ast.CocciRule
(_
,_
,rule
,_
,_
) ->
744 Common.union_set
(nub (collect_all_rule_refs rule
))
745 (collect_in_plus metavar_list rule
) in
747 List.filter
(function x
-> not
(List.mem x
locally_defined))
749 (Common.union_set
inherited continue_propagation,
750 used_after
::used_after_lists
))
751 metavar_rule_list
([],[]) in
752 match used_after
with
753 [] -> used_after_lists
756 (Printf.sprintf
"collect_top_level_used_after: unbound variables %s"
757 (String.concat
" " (List.map
(function (_
,x
) -> x
) used_after
)))
759 let collect_local_used_after metavars minirules used_after
=
760 let locally_defined = List.map
Ast.get_meta_name
metavars in
761 let rec loop = function
762 [] -> (used_after
,[],[],[],[])
764 (* In a rule there are three kinds of local variables:
765 1. Variables referenced in the minus or context code.
766 These get a value by matching. This value can be used in
768 2. Fresh variables referenced in the plus code.
769 3. Variables referenced in the seeds of the fresh variables.
770 There are also non-local variables. These may either be variables
771 referenced in the minus, context, or plus code, or they may be
772 variables referenced in the seeds of the fresh variables. *)
773 (* Step 1: collect all references in minus/context, plus, seed
775 let variables_referenced_in_minus_context_code =
776 nub (collect_all_minirule_refs minirule
) in
777 let variables_referenced_in_plus_code =
778 collect_in_plus_term.V.combiner_top_level minirule
in
779 let (env_of_fresh_seeds
,seeds_and_plus
) =
780 collect_fresh_seed_env
781 metavars variables_referenced_in_plus_code in
783 Common.union_set
variables_referenced_in_minus_context_code
785 (* Step 2: identify locally defined ones *)
786 let local_fresh = List.map fst env_of_fresh_seeds
in
788 List.partition
(function x
-> List.mem x
locally_defined) in
789 let local_env_of_fresh_seeds =
790 (* these have to be restricted to only one value if the associated
791 fresh variable is used after *)
792 List.map
(function (f
,ss
) -> (f
,is_local ss
)) env_of_fresh_seeds
in
793 let (local_all_free_vars
,nonlocal_all_free_vars
) =
794 is_local all_free_vars in
795 (* Step 3, recurse on the rest of the rules, making available whatever
796 has been defined in this one *)
797 let (mini_used_after
,fvs_lists
,mini_used_after_lists
,
798 mini_fresh_used_after_lists
,mini_fresh_used_after_seeds
) =
800 (* Step 4: collect the results. These are:
801 1. All of the variables used non-locally in the rules starting
803 2. All of the free variables to the end of the semantic patch
804 3. The variables that are used afterwards and defined here by
805 matching (minus or context code)
806 4. The variables that are used afterwards and are defined here as
808 5. The variables that are used as seeds in computing the bindings
809 of the variables collected in part 4. *)
810 let (local_used_after
, nonlocal_used_after
) =
811 is_local mini_used_after
in
812 let (fresh_local_used_after
(*4*),matched_local_used_after
) =
813 List.partition
(function x
-> List.mem x
local_fresh)
815 let matched_local_used_after(*3*) =
816 Common.union_set
matched_local_used_after nonlocal_used_after
in
817 let new_used_after = (*1*)
818 Common.union_set nonlocal_all_free_vars nonlocal_used_after
in
819 let fresh_local_used_after_seeds =
821 (* no point to keep variables that already are gtd to have only
823 (function x
-> not
(List.mem x
matched_local_used_after))
824 (List.fold_left
(function p
-> function c
-> Common.union_set c p
)
828 fst
(List.assoc fua
local_env_of_fresh_seeds))
829 fresh_local_used_after
)) in
830 (new_used_after,all_free_vars::fvs_lists
(*2*),
831 matched_local_used_after::mini_used_after_lists
,
832 fresh_local_used_after
::mini_fresh_used_after_lists
,
833 fresh_local_used_after_seeds::mini_fresh_used_after_seeds
) in
834 let (_
,fvs_lists
,used_after_lists
(*ua*),
835 fresh_used_after_lists
(*fua*),fresh_used_after_lists_seeds
(*fuas*)) =
837 (fvs_lists
,used_after_lists
,
838 fresh_used_after_lists
,fresh_used_after_lists_seeds
)
842 let collect_used_after metavar_rule_list
=
843 let used_after_lists = collect_top_level_used_after metavar_rule_list
in
845 (function (metavars,r
) ->
846 function used_after
->
848 Ast.ScriptRule
(_
,_
,_
,_
)
849 | Ast.InitialScriptRule
(_
,_
) | Ast.FinalScriptRule
(_
,_
) ->
850 ([], [used_after
], [], [])
851 | Ast.CocciRule
(name
, rule_info
, minirules
, _
,_
) ->
852 collect_local_used_after metavars minirules used_after
854 metavar_rule_list
used_after_lists
856 let rec split4 = function
858 | (a
,b
,c
,d
)::l
-> let (a1
,b1
,c1
,d1
) = split4 l
in (a
::a1
,b
::b1
,c
::c1
,d
::d1
)
860 (* ---------------------------------------------------------------- *)
863 let free_vars rules
=
864 let metavars = List.map
(function (mv
,rule
) -> mv
) rules
in
865 let (fvs_lists
,used_after_matched_lists
,
866 fresh_used_after_lists
,fresh_used_after_lists_seeds
) =
867 split4 (collect_used_after rules
) in
869 List.map2
get_neg_pos_list rules used_after_matched_lists
in
870 let positions_list = (* for all rules, assume all positions are used after *)
875 | Ast.InitialScriptRule _
| Ast.FinalScriptRule _
-> []
876 | Ast.CocciRule
(_
,_
,rule
,_
,_
) ->
880 function Ast.MetaPosDecl
(_
,nm
) -> nm
::prev
| _
-> prev
)
882 List.map
(function _
-> positions) rule
)
890 | Ast.InitialScriptRule _
| Ast.FinalScriptRule _
-> r
891 | Ast.CocciRule
(nm
, rule_info
, r
, is_exp
,ruletype
) ->
894 classify_variables mv r
895 ((List.concat ua
) @ (List.concat fua
)),
897 rules
(List.combine used_after_matched_lists fresh_used_after_lists
) in
898 let new_rules = collect_astfvs (List.combine
metavars new_rules) in
900 fvs_lists
,neg_pos_lists,
901 (used_after_matched_lists
,
902 fresh_used_after_lists
,fresh_used_after_lists_seeds
),