1 (* For minus fragment, checks that all of the identifier metavariables that
2 are used are not declared as fresh, and check that all declared variables
3 are used. For plus fragment, just check that the variables declared as
4 fresh are used. What is the issue about error variables? (don't remember) *)
6 module Ast0
= Ast0_cocci
8 module V0
= Visitor_ast0
9 module VT0
= Visitor_ast0_types
11 (* all fresh identifiers *)
12 let fresh_table = (Hashtbl.create
(50) : ((string * string), unit) Hashtbl.t
)
14 let warning s
= Printf.fprintf stderr
"warning: %s\n" s
16 let promote name
= (name
,(),Ast0.default_info
(),(),None
,-1)
18 (* --------------------------------------------------------------------- *)
20 let find_loop table name
=
21 let rec loop = function
23 | x
::xs
-> (try Hashtbl.find x name
with Not_found
-> loop xs
) in
26 let check_table table minus
(name
,_
,info
,_
,_
,_
) =
27 let rl = info
.Ast0.pos_info
.Ast0.line_start
in
30 (try (find_loop table name
) := true
34 Hashtbl.find
fresh_table name
;
35 let (_
,name
) = name
in
38 "%d: unexpected use of a fresh identifier %s" rl name
)
39 with Not_found
-> ()))
40 else (try (find_loop table name
) := true with Not_found
-> ())
42 let get_opt fn
= Common.do_option fn
44 (* --------------------------------------------------------------------- *)
48 match Ast0.unwrap d
with
49 Ast0.DOTS
(x
) -> List.iter fn x
50 | Ast0.CIRCLES
(x
) -> List.iter fn x
51 | Ast0.STARS
(x
) -> List.iter fn x
53 (* --------------------------------------------------------------------- *)
56 type context
= ID
| FIELD
| FN
| GLOBAL
58 (* heuristic for distinguishing ifdef variables from undeclared metavariables*)
60 String.length name
> 2 && String.uppercase name
= name
62 let ident context old_metas table minus i
=
63 match Ast0.unwrap i
with
64 Ast0.Id
((name
,_
,info
,_
,_
,_
) : string Ast0.mcode
) ->
65 let rl = info
.Ast0.pos_info
.Ast0.line_start
in
67 match Ast0.get_mcodekind i
with Ast0.PLUS _
-> true | _
-> false in
69 if List.exists
(function x
-> x
= name
) old_metas
70 && (minus
|| is_plus i
)
75 "line %d: %s, previously declared as a metavariable, is used as an identifier" rl name
);
81 if not
(is_ifdef name
) && minus
&& not
err(* warn only once per id *)
84 (Printf.sprintf
"line %d: should %s be a metavariable?" rl name
)
86 | Ast0.MetaId
(name
,_
,_
) -> check_table table minus name
87 | Ast0.MetaFunc
(name
,_
,_
) -> check_table table minus name
88 | Ast0.MetaLocalFunc
(name
,_
,_
) -> check_table table minus name
89 | Ast0.OptIdent
(_
) | Ast0.UniqueIdent
(_
) ->
90 failwith
"unexpected code"
92 (* --------------------------------------------------------------------- *)
95 let rec expression context old_metas table minus e
=
96 match Ast0.unwrap e
with
98 ident context old_metas table minus id
99 | Ast0.FunCall
(fn
,lp
,args
,rp
) ->
100 expression FN old_metas table minus fn
;
101 dots (expression ID old_metas table minus
) args
102 | Ast0.Assignment
(left
,op
,right
,_
) ->
103 expression context old_metas table minus left
;
104 expression ID old_metas table minus right
105 | Ast0.CondExpr
(exp1
,why
,exp2
,colon
,exp3
) ->
106 expression ID old_metas table minus exp1
;
107 get_opt (expression ID old_metas table minus
) exp2
;
108 expression ID old_metas table minus exp3
109 | Ast0.Postfix
(exp
,op
) ->
110 expression ID old_metas table minus exp
111 | Ast0.Infix
(exp
,op
) ->
112 expression ID old_metas table minus exp
113 | Ast0.Unary
(exp
,op
) ->
114 expression ID old_metas table minus exp
115 | Ast0.Binary
(left
,op
,right
) ->
116 expression ID old_metas table minus left
;
117 expression ID old_metas table minus right
118 | Ast0.Paren
(lp
,exp
,rp
) ->
119 expression ID old_metas table minus exp
120 | Ast0.ArrayAccess
(exp1
,lb
,exp2
,rb
) ->
121 expression ID old_metas table minus exp1
;
122 expression ID old_metas table minus exp2
123 | Ast0.RecordAccess
(exp
,pt
,field
) ->
124 expression ID old_metas table minus exp
;
125 ident FIELD old_metas table minus field
126 | Ast0.RecordPtAccess
(exp
,ar
,field
) ->
127 expression ID old_metas table minus exp
;
128 ident FIELD old_metas table minus field
129 | Ast0.Cast
(lp
,ty
,rp
,exp
) ->
130 typeC old_metas table minus ty
; expression ID old_metas table minus exp
131 | Ast0.SizeOfExpr
(szf
,exp
) -> expression ID old_metas table minus exp
132 | Ast0.SizeOfType
(szf
,lp
,ty
,rp
) -> typeC old_metas table minus ty
133 | Ast0.TypeExp
(ty
) -> typeC old_metas table minus ty
134 | Ast0.MetaExpr
(name
,_
,Some tys
,_
,_
) ->
137 match get_type_name x
with
138 Some
(ty
) -> check_table table minus
(promote ty
)
141 check_table table minus name
142 | Ast0.MetaExpr
(name
,_
,_
,_
,_
) | Ast0.MetaErr
(name
,_
,_
) ->
143 check_table table minus name
144 | Ast0.MetaExprList
(name
,None
,_
) ->
145 check_table table minus name
146 | Ast0.MetaExprList
(name
,Some lenname
,_
) ->
147 check_table table minus name
;
148 check_table table minus lenname
149 | Ast0.DisjExpr
(_
,exps
,_
,_
) ->
150 List.iter
(expression context old_metas table minus
) exps
151 | Ast0.NestExpr
(_
,exp_dots
,_
,w
,_
) ->
152 dots (expression ID old_metas table minus
) exp_dots
;
153 get_opt (expression ID old_metas table minus
) w
154 | Ast0.Edots
(_
,Some x
) | Ast0.Ecircles
(_
,Some x
) | Ast0.Estars
(_
,Some x
) ->
155 expression ID old_metas table minus x
156 | _
-> () (* no metavariable subterms *)
158 and get_type_name
= function
159 Type_cocci.ConstVol
(_
,ty
) | Type_cocci.SignedT
(_
,Some ty
)
160 | Type_cocci.Pointer
(ty
)
161 | Type_cocci.FunctionPointer
(ty
) | Type_cocci.Array
(ty
) -> get_type_name ty
162 | Type_cocci.MetaType
(nm
,_
,_
) -> Some nm
165 (* --------------------------------------------------------------------- *)
168 and typeC old_metas table minus t
=
169 match Ast0.unwrap t
with
170 Ast0.ConstVol
(cv
,ty
) -> typeC old_metas table minus ty
171 | Ast0.Signed
(sgn
,ty
) ->
172 get_opt (typeC old_metas table minus
) ty
173 | Ast0.Pointer
(ty
,star
) -> typeC old_metas table minus ty
174 | Ast0.FunctionPointer
(ty
,lp1
,star
,rp1
,lp2
,params
,rp2
) ->
175 typeC old_metas table minus ty
;
176 parameter_list old_metas table minus params
177 | Ast0.FunctionType
(ty
,lp1
,params
,rp1
) ->
178 get_opt (typeC old_metas table minus
) ty
;
179 parameter_list old_metas table minus params
180 | Ast0.Array
(ty
,lb
,size
,rb
) ->
181 typeC old_metas table minus ty
;
182 get_opt (expression ID old_metas table minus
) size
183 | Ast0.MetaType
(name
,_
) ->
184 check_table table minus name
185 | Ast0.DisjType
(_
,types
,_
,_
) ->
186 List.iter
(typeC old_metas table minus
) types
187 | Ast0.EnumName
(en
,id
) -> ident GLOBAL old_metas table minus id
188 | Ast0.StructUnionName
(su
,Some id
) -> ident GLOBAL old_metas table minus id
189 | Ast0.StructUnionDef
(ty
,lb
,decls
,rb
) ->
190 typeC old_metas table minus ty
;
191 dots (declaration GLOBAL old_metas table minus
) decls
192 | Ast0.OptType
(ty
) | Ast0.UniqueType
(ty
) ->
193 failwith
"unexpected code"
194 | _
-> () (* no metavariable subterms *)
196 (* --------------------------------------------------------------------- *)
197 (* Variable declaration *)
198 (* Even if the Cocci program specifies a list of declarations, they are
199 split out into multiple declarations of a single variable each. *)
201 and declaration context old_metas table minus d
=
202 match Ast0.unwrap d
with
203 Ast0.Init
(stg
,ty
,id
,eq
,ini
,sem
) ->
204 (match Ast0.unwrap ini
with
206 typeC old_metas table minus ty
;
207 ident context old_metas table minus id
;
208 expression ID old_metas table minus exp
213 failwith "complex initializer specification not allowed in - code"
215 (typeC old_metas table minus ty
;
216 ident context old_metas table minus id
;
217 initialiser old_metas table minus ini
))
218 | Ast0.UnInit
(stg
,ty
,id
,sem
) ->
219 typeC old_metas table minus ty
; ident context old_metas table minus id
220 | Ast0.MacroDecl
(name
,lp
,args
,rp
,sem
) ->
221 ident GLOBAL old_metas table minus name
;
222 dots (expression ID old_metas table minus
) args
223 | Ast0.TyDecl
(ty
,sem
) -> typeC old_metas table minus ty
224 | Ast0.Typedef
(stg
,ty
,id
,sem
) ->
225 typeC old_metas table minus ty
;
226 typeC old_metas table minus id
227 | Ast0.DisjDecl
(_
,decls
,_
,_
) ->
228 List.iter
(declaration ID old_metas table minus
) decls
229 | Ast0.Ddots
(_
,Some x
) -> declaration ID old_metas table minus x
230 | Ast0.Ddots
(_
,None
) -> ()
231 | Ast0.OptDecl
(_
) | Ast0.UniqueDecl
(_
) ->
232 failwith
"unexpected code"
234 (* --------------------------------------------------------------------- *)
237 and initialiser old_metas table minus ini
=
238 match Ast0.unwrap ini
with
239 Ast0.MetaInit
(name
,_
) ->
240 check_table table minus name
241 | Ast0.InitExpr
(exp
) -> expression ID old_metas table minus exp
242 | Ast0.InitList
(lb
,initlist
,rb
) ->
243 dots (initialiser old_metas table minus
) initlist
244 | Ast0.InitGccExt
(designators
,eq
,ini
) ->
245 List.iter
(designator old_metas table minus
) designators
;
246 initialiser old_metas table minus ini
247 | Ast0.InitGccName
(name
,eq
,ini
) ->
248 ident FIELD old_metas table minus name
;
249 initialiser old_metas table minus ini
250 | Ast0.Idots
(_
,Some x
) -> initialiser old_metas table minus x
251 | Ast0.OptIni
(_
) | Ast0.UniqueIni
(_
) ->
252 failwith
"unexpected code"
253 | _
-> () (* no metavariable subterms *)
255 and designator old_metas table minus
= function
256 Ast0.DesignatorField
(dot
,id
) ->
257 ident FIELD old_metas table minus id
258 | Ast0.DesignatorIndex
(lb
,exp
,rb
) ->
259 expression ID old_metas table minus exp
260 | Ast0.DesignatorRange
(lb
,min
,dots,max
,rb
) ->
261 expression ID old_metas table minus min
;
262 expression ID old_metas table minus max
264 and initialiser_list old_metas table minus
=
265 dots (initialiser old_metas table minus
)
267 (* --------------------------------------------------------------------- *)
270 and parameterTypeDef old_metas table minus param
=
271 match Ast0.unwrap param
with
273 get_opt (ident ID old_metas table minus
) id
;
274 typeC old_metas table minus ty
275 | Ast0.MetaParam
(name
,_
) ->
276 check_table table minus name
277 | Ast0.MetaParamList
(name
,None
,_
) ->
278 check_table table minus name
279 | Ast0.MetaParamList
(name
,Some lenname
,_
) ->
280 check_table table minus name
;
281 check_table table minus lenname
282 | _
-> () (* no metavariable subterms *)
284 and parameter_list old_metas table minus
=
285 dots (parameterTypeDef old_metas table minus
)
287 (* --------------------------------------------------------------------- *)
290 and statement old_metas table minus s
=
291 match Ast0.unwrap s
with
292 Ast0.Decl
(_
,decl
) -> declaration ID old_metas table minus decl
293 | Ast0.Seq
(lbrace
,body
,rbrace
) -> dots (statement old_metas table minus
) body
294 | Ast0.ExprStatement
(exp
,sem
) -> expression ID old_metas table minus exp
295 | Ast0.IfThen
(iff
,lp
,exp
,rp
,branch
,_
) ->
296 expression ID old_metas table minus exp
;
297 statement old_metas table minus branch
298 | Ast0.IfThenElse
(iff
,lp
,exp
,rp
,branch1
,els
,branch2
,_
) ->
299 expression ID old_metas table minus exp
;
300 statement old_metas table minus branch1
;
301 statement old_metas table minus branch2
302 | Ast0.While
(wh
,lp
,exp
,rp
,body
,_
) ->
303 expression ID old_metas table minus exp
;
304 statement old_metas table minus body
305 | Ast0.Do
(d
,body
,wh
,lp
,exp
,rp
,sem
) ->
306 statement old_metas table minus body
;
307 expression ID old_metas table minus exp
308 | Ast0.For
(fr
,lp
,exp1
,sem1
,exp2
,sem2
,exp3
,rp
,body
,_
) ->
309 get_opt (expression ID old_metas table minus
) exp1
;
310 get_opt (expression ID old_metas table minus
) exp2
;
311 get_opt (expression ID old_metas table minus
) exp3
;
312 statement old_metas table minus body
313 | Ast0.Iterator
(nm
,lp
,args
,rp
,body
,_
) ->
314 ident GLOBAL old_metas table minus nm
;
315 dots (expression ID old_metas table minus
) args
;
316 statement old_metas table minus body
317 | Ast0.Switch
(switch
,lp
,exp
,rp
,lb
,decls
,cases
,rb
) ->
318 expression ID old_metas table minus exp
;
319 dots (statement old_metas table minus
) decls
;
320 dots (case_line old_metas table minus
) cases
321 | Ast0.ReturnExpr
(ret
,exp
,sem
) -> expression ID old_metas table minus exp
322 | Ast0.MetaStmt
(name
,_
) -> check_table table minus name
323 | Ast0.MetaStmtList
(name
,_
) -> check_table table minus name
324 | Ast0.Exp
(exp
) -> expression ID old_metas table minus exp
325 | Ast0.TopExp
(exp
) -> expression ID old_metas table minus exp
326 | Ast0.Ty
(ty
) -> typeC old_metas table minus ty
327 | Ast0.TopInit
(init
) -> initialiser old_metas table minus init
328 | Ast0.Disj
(_
,rule_elem_dots_list
,_
,_
) ->
329 List.iter
(dots (statement old_metas table minus
)) rule_elem_dots_list
330 | Ast0.Nest
(_
,rule_elem_dots
,_
,w
,_
) ->
331 dots (statement old_metas table minus
) rule_elem_dots
;
332 List.iter
(whencode
(dots (statement old_metas table minus
))
333 (statement old_metas table minus
)
334 (expression ID old_metas table minus
))
336 | Ast0.Dots
(_
,x
) | Ast0.Circles
(_
,x
) | Ast0.Stars
(_
,x
) ->
338 (whencode
(dots (statement old_metas table minus
))
339 (statement old_metas table minus
)
340 (expression ID old_metas table minus
)) x
341 | Ast0.FunDecl
(_
,fi
,name
,lp
,params
,rp
,lbrace
,body
,rbrace
) ->
342 ident FN old_metas table minus name
;
343 List.iter
(fninfo old_metas table minus
) fi
;
344 parameter_list old_metas table minus params
;
345 dots (statement old_metas table minus
) body
346 | Ast0.Include
(inc
,s
) -> () (* no metavariables possible *)
347 | Ast0.Define
(def
,id
,params
,body
) ->
348 ident GLOBAL old_metas table minus id
;
349 define_parameters old_metas table minus params
;
350 dots (statement old_metas table minus
) body
351 | Ast0.Label
(i
,_
) -> ident ID old_metas table minus i
352 | Ast0.Goto
(_
,i
,_
) -> ident ID old_metas table minus i
353 | _
-> () (* no metavariable subterms *)
355 and define_param old_metas table minus p
=
356 match Ast0.unwrap p
with
357 Ast0.DParam
(id
) -> ident GLOBAL old_metas table minus id
358 | Ast0.DPComma
(_
) | Ast0.DPdots
(_
) | Ast0.DPcircles
(_
) ->
359 () (* no metavariable subterms *)
360 | Ast0.OptDParam
(dp
) -> define_param old_metas table minus dp
361 | Ast0.UniqueDParam
(dp
) -> define_param old_metas table minus dp
363 and define_parameters old_metas table minus x
=
364 match Ast0.unwrap x
with
366 | Ast0.DParams
(lp
,dp
,rp
) -> dots (define_param old_metas table minus
) dp
368 and fninfo old_metas table minus
= function
369 Ast0.FStorage
(stg
) -> ()
370 | Ast0.FType
(ty
) -> typeC old_metas table minus ty
371 | Ast0.FInline
(inline
) -> ()
372 | Ast0.FAttr
(attr
) -> ()
374 and whencode notfn alwaysfn
expression = function
375 Ast0.WhenNot a
-> notfn a
376 | Ast0.WhenAlways a
-> alwaysfn a
377 | Ast0.WhenModifier
(_
) -> ()
378 | Ast0.WhenNotTrue a
-> expression a
379 | Ast0.WhenNotFalse a
-> expression a
381 and case_line old_metas table minus c
=
382 match Ast0.unwrap c
with
383 Ast0.Default
(def
,colon
,code
) ->
384 dots (statement old_metas table minus
) code
385 | Ast0.Case
(case
,exp
,colon
,code
) ->
386 dots (statement old_metas table minus
) code
387 | Ast0.DisjCase
(_
,case_lines
,_
,_
) ->
388 List.iter
(case_line old_metas table minus
) case_lines
389 | Ast0.OptCase
(case
) -> failwith
"unexpected code"
391 (* --------------------------------------------------------------------- *)
394 let top_level old_metas table minus t
=
395 match Ast0.unwrap t
with
396 Ast0.DECL
(stmt
) -> statement old_metas table minus stmt
397 | Ast0.CODE
(stmt_dots
) -> dots (statement old_metas table minus
) stmt_dots
398 | Ast0.ERRORWORDS
(exps
) ->
399 List.iter
(expression FN old_metas table minus
) exps
400 | _
-> () (* no metavariables possible *)
402 let rule old_metas table minus rules
=
403 List.iter
(top_level old_metas table minus
) rules
405 (* --------------------------------------------------------------------- *)
407 let positions table rules
=
409 match Ast0.get_pos x
with
410 Ast0.MetaPos
(name
,constraints
,_
) ->
411 let pos = Ast0.unwrap_mcode name
in
412 (find_loop table
pos) := true
414 let option_default = () in
416 let donothing r k e
= k e
in
418 V0.flat_combiner
bind option_default
419 mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode
420 donothing donothing donothing donothing donothing donothing
421 donothing donothing donothing donothing donothing donothing donothing
422 donothing donothing in
424 List.iter
fn.VT0.combiner_rec_top_level rules
426 let dup_positions rules
=
428 match Ast0.get_pos x
with
429 Ast0.MetaPos
(name
,constraints
,_
) ->
430 let pos = Ast0.unwrap_mcode name
in [pos]
432 let option_default = [] in
433 let bind x y
= x
@y
in
435 (* Case for everything that has a disj.
436 Note, no positions on ( | ) of a disjunction, so no need to recurse on
439 let expression r k e
=
440 match Ast0.unwrap e
with
441 Ast0.DisjExpr
(_
,explist
,_
,_
) ->
442 List.fold_left
Common.union_set
option_default
443 (List.map r
.VT0.combiner_rec_expression explist
)
446 let typeC r k e
= (* not sure relevent because "only after iso" *)
447 match Ast0.unwrap e
with
448 Ast0.DisjType
(_
,types
,_
,_
) ->
449 List.fold_left
Common.union_set
option_default
450 (List.map r
.VT0.combiner_rec_typeC types
)
453 let declaration r k e
=
454 match Ast0.unwrap e
with
455 Ast0.DisjDecl
(_
,decls
,_
,_
) ->
456 List.fold_left
Common.union_set
option_default
457 (List.map r
.VT0.combiner_rec_declaration decls
)
460 let statement r k e
=
461 match Ast0.unwrap e
with
462 Ast0.Disj
(_
,stmts
,_
,_
) ->
463 List.fold_left
Common.union_set
option_default
464 (List.map r
.VT0.combiner_rec_statement_dots stmts
)
467 let donothing r k e
= k e
in
469 V0.flat_combiner
bind option_default
470 mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode
471 donothing donothing donothing donothing donothing donothing
472 donothing expression typeC donothing donothing declaration statement
473 donothing donothing in
477 (List.fold_left
Common.union_set
option_default
478 (List.map
fn.VT0.combiner_rec_top_level rules
)) in
479 let rec loop = function
481 | ((rule,name
) as x
)::y
::_
when x
= y
->
482 failwith
(Printf.sprintf
"duplicate use of %s.%s" rule name
)
483 | _
::xs
-> loop xs
in
486 (* --------------------------------------------------------------------- *)
490 (Hashtbl.create
(List.length l
) :
491 ((string * string), bool ref) Hashtbl.t
) in
493 (function x
-> Hashtbl.add
table (Ast.get_meta_name x
) (ref false)) l
;
496 let add_to_fresh_table l
=
499 let name = Ast.get_meta_name x
in Hashtbl.replace
fresh_table name ())
502 let check_all_marked rname
err table after_err
=
508 let (_
,name) = name in
510 (Printf.sprintf
"%s: %s %s not used %s" rname
err name after_err
))
513 let check_meta rname old_metas inherited_metavars metavars minus plus
=
515 List.map
(function (_
,x
) -> x
) (List.map
Ast.get_meta_name
old_metas) in
517 List.partition
(function Ast.MetaFreshIdDecl
(_
,_
) -> true | _
-> false)
520 List.partition
(function Ast.MetaErrDecl
(_
,_
) -> true | _
-> false)
523 List.partition
(function Ast.MetaErrDecl
(_
,_
) -> true | _
-> false)
524 inherited_metavars
in
525 let fresh_table = make_table fresh
in
526 let err_table = make_table (err@ierr
) in
527 let other_table = make_table other
in
528 let iother_table = make_table iother
in
529 add_to_fresh_table fresh
;
530 rule old_metas [iother_table;other_table;err_table] true minus
;
531 positions [iother_table;other_table] minus
;
533 check_all_marked rname
"metavariable" other_table "in the - or context code";
534 rule old_metas [iother_table;fresh_table;err_table] false plus
;
535 check_all_marked rname
"inherited metavariable" iother_table
536 "in the -, +, or context code";
537 check_all_marked rname
"metavariable" fresh_table "in the + code";
538 check_all_marked rname
"error metavariable" err_table ""