Release coccinelle-0.2.5-rc2
[bpt/coccinelle.git] / parsing_cocci / check_meta.ml
CommitLineData
c491d8ee
C
1(*
2 * Copyright 2010, INRIA, University of Copenhagen
3 * Julia Lawall, Rene Rydhof Hansen, Gilles Muller, Nicolas Palix
4 * Copyright 2005-2009, Ecole des Mines de Nantes, University of Copenhagen
5 * Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller, Nicolas Palix
6 * This file is part of Coccinelle.
7 *
8 * Coccinelle is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation, according to version 2 of the License.
11 *
12 * Coccinelle is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with Coccinelle. If not, see <http://www.gnu.org/licenses/>.
19 *
20 * The authors reserve the right to distribute this or future versions of
21 * Coccinelle under other licenses.
22 *)
23
24
34e49164
C
25(* For minus fragment, checks that all of the identifier metavariables that
26are used are not declared as fresh, and check that all declared variables
27are used. For plus fragment, just check that the variables declared as
28fresh are used. What is the issue about error variables? (don't remember) *)
29
30module Ast0 = Ast0_cocci
31module Ast = Ast_cocci
32module V0 = Visitor_ast0
b1b2de81 33module VT0 = Visitor_ast0_types
34e49164
C
34
35(* all fresh identifiers *)
ae4735db 36let fresh_table = (Hashtbl.create(50) : (Ast.meta_name, unit) Hashtbl.t)
34e49164
C
37
38let warning s = Printf.fprintf stderr "warning: %s\n" s
39
708f4980 40let promote name = (name,(),Ast0.default_info(),(),None,-1)
34e49164
C
41
42(* --------------------------------------------------------------------- *)
43
44let find_loop table name =
45 let rec loop = function
46 [] -> raise Not_found
47 | x::xs -> (try Hashtbl.find x name with Not_found -> loop xs) in
48 loop table
49
708f4980 50let check_table table minus (name,_,info,_,_,_) =
0708f913 51 let rl = info.Ast0.pos_info.Ast0.line_start in
34e49164
C
52 if minus
53 then
54 (try (find_loop table name) := true
55 with
56 Not_found ->
57 (try
58 Hashtbl.find fresh_table name;
59 let (_,name) = name in
60 failwith
61 (Printf.sprintf
62 "%d: unexpected use of a fresh identifier %s" rl name)
63 with Not_found -> ()))
64 else (try (find_loop table name) := true with Not_found -> ())
65
66let get_opt fn = Common.do_option fn
67
68(* --------------------------------------------------------------------- *)
69(* Dots *)
70
71let dots fn d =
72 match Ast0.unwrap d with
73 Ast0.DOTS(x) -> List.iter fn x
74 | Ast0.CIRCLES(x) -> List.iter fn x
75 | Ast0.STARS(x) -> List.iter fn x
76
77(* --------------------------------------------------------------------- *)
78(* Identifier *)
79
80type context = ID | FIELD | FN | GLOBAL
81
82(* heuristic for distinguishing ifdef variables from undeclared metavariables*)
83let is_ifdef name =
84 String.length name > 2 && String.uppercase name = name
85
86let ident context old_metas table minus i =
87 match Ast0.unwrap i with
3a314143
C
88 Ast0.Id((name,_,info,_,_,_) : string Ast0.mcode) ->
89 let rl = info.Ast0.pos_info.Ast0.line_start in
90 let is_plus i =
91 match Ast0.get_mcodekind i with Ast0.PLUS _ -> true | _ -> false in
92 let err =
93 if List.exists (function x -> x = name) old_metas
951c7801 94 && (minus || is_plus i)
3a314143
C
95 then
96 begin
97 warning
98 (Printf.sprintf
99 "line %d: %s, previously declared as a metavariable, is used as an identifier" rl name);
100 true
101 end
102 else false in
103 (match context with
104 ID ->
105 if not (is_ifdef name) && minus && not err(* warn only once per id *)
34e49164 106 then
3a314143
C
107 warning
108 (Printf.sprintf "line %d: should %s be a metavariable?" rl name)
109 | _ -> ())
110 | Ast0.MetaId(name,_,_) -> check_table table minus name
111 | Ast0.MetaFunc(name,_,_) -> check_table table minus name
112 | Ast0.MetaLocalFunc(name,_,_) -> check_table table minus name
113 | Ast0.OptIdent(_) | Ast0.UniqueIdent(_) ->
114 failwith "unexpected code"
115
34e49164
C
116(* --------------------------------------------------------------------- *)
117(* Expression *)
118
119let rec expression context old_metas table minus e =
120 match Ast0.unwrap e with
121 Ast0.Ident(id) ->
122 ident context old_metas table minus id
123 | Ast0.FunCall(fn,lp,args,rp) ->
124 expression FN old_metas table minus fn;
125 dots (expression ID old_metas table minus) args
126 | Ast0.Assignment(left,op,right,_) ->
127 expression context old_metas table minus left;
128 expression ID old_metas table minus right
129 | Ast0.CondExpr(exp1,why,exp2,colon,exp3) ->
130 expression ID old_metas table minus exp1;
131 get_opt (expression ID old_metas table minus) exp2;
132 expression ID old_metas table minus exp3
133 | Ast0.Postfix(exp,op) ->
134 expression ID old_metas table minus exp
135 | Ast0.Infix(exp,op) ->
136 expression ID old_metas table minus exp
137 | Ast0.Unary(exp,op) ->
138 expression ID old_metas table minus exp
139 | Ast0.Binary(left,op,right) ->
140 expression ID old_metas table minus left;
141 expression ID old_metas table minus right
142 | Ast0.Paren(lp,exp,rp) ->
143 expression ID old_metas table minus exp
144 | Ast0.ArrayAccess(exp1,lb,exp2,rb) ->
145 expression ID old_metas table minus exp1;
146 expression ID old_metas table minus exp2
147 | Ast0.RecordAccess(exp,pt,field) ->
148 expression ID old_metas table minus exp;
149 ident FIELD old_metas table minus field
150 | Ast0.RecordPtAccess(exp,ar,field) ->
151 expression ID old_metas table minus exp;
152 ident FIELD old_metas table minus field
153 | Ast0.Cast(lp,ty,rp,exp) ->
154 typeC old_metas table minus ty; expression ID old_metas table minus exp
155 | Ast0.SizeOfExpr(szf,exp) -> expression ID old_metas table minus exp
156 | Ast0.SizeOfType(szf,lp,ty,rp) -> typeC old_metas table minus ty
157 | Ast0.TypeExp(ty) -> typeC old_metas table minus ty
158 | Ast0.MetaExpr(name,_,Some tys,_,_) ->
159 List.iter
160 (function x ->
161 match get_type_name x with
162 Some(ty) -> check_table table minus (promote ty)
163 | None -> ())
164 tys;
165 check_table table minus name
166 | Ast0.MetaExpr(name,_,_,_,_) | Ast0.MetaErr(name,_,_) ->
167 check_table table minus name
88e71198 168 | Ast0.MetaExprList(name,Ast0.MetaListLen lenname,_) ->
34e49164
C
169 check_table table minus name;
170 check_table table minus lenname
88e71198
C
171 | Ast0.MetaExprList(name,_,_) ->
172 check_table table minus name
34e49164 173 | Ast0.DisjExpr(_,exps,_,_) ->
0708f913 174 List.iter (expression context old_metas table minus) exps
34e49164
C
175 | Ast0.NestExpr(_,exp_dots,_,w,_) ->
176 dots (expression ID old_metas table minus) exp_dots;
177 get_opt (expression ID old_metas table minus) w
178 | Ast0.Edots(_,Some x) | Ast0.Ecircles(_,Some x) | Ast0.Estars(_,Some x) ->
179 expression ID old_metas table minus x
180 | _ -> () (* no metavariable subterms *)
181
182and get_type_name = function
faf9a90c
C
183 Type_cocci.ConstVol(_,ty) | Type_cocci.SignedT(_,Some ty)
184 | Type_cocci.Pointer(ty)
34e49164 185 | Type_cocci.FunctionPointer(ty) | Type_cocci.Array(ty) -> get_type_name ty
e6509c05
C
186 | Type_cocci.EnumName(Type_cocci.MV(nm,_,_)) -> Some nm
187 | Type_cocci.StructUnionName(_,Type_cocci.MV(nm,_,_)) -> Some nm
34e49164
C
188 | Type_cocci.MetaType(nm,_,_) -> Some nm
189 | _ -> None
190
191(* --------------------------------------------------------------------- *)
192(* Types *)
193
194and typeC old_metas table minus t =
195 match Ast0.unwrap t with
196 Ast0.ConstVol(cv,ty) -> typeC old_metas table minus ty
faf9a90c
C
197 | Ast0.Signed(sgn,ty) ->
198 get_opt (typeC old_metas table minus) ty
34e49164
C
199 | Ast0.Pointer(ty,star) -> typeC old_metas table minus ty
200 | Ast0.FunctionPointer(ty,lp1,star,rp1,lp2,params,rp2) ->
201 typeC old_metas table minus ty;
202 parameter_list old_metas table minus params
203 | Ast0.FunctionType(ty,lp1,params,rp1) ->
204 get_opt (typeC old_metas table minus) ty;
205 parameter_list old_metas table minus params
206 | Ast0.Array(ty,lb,size,rb) ->
207 typeC old_metas table minus ty;
208 get_opt (expression ID old_metas table minus) size
209 | Ast0.MetaType(name,_) ->
210 check_table table minus name
211 | Ast0.DisjType(_,types,_,_) ->
212 List.iter (typeC old_metas table minus) types
c491d8ee
C
213 | Ast0.EnumName(en,Some id) -> ident GLOBAL old_metas table minus id
214 | Ast0.EnumDef(ty,lb,ids,rb) ->
215 typeC old_metas table minus ty;
216 dots (expression GLOBAL old_metas table minus) ids
34e49164
C
217 | Ast0.StructUnionName(su,Some id) -> ident GLOBAL old_metas table minus id
218 | Ast0.StructUnionDef(ty,lb,decls,rb) ->
219 typeC old_metas table minus ty;
220 dots (declaration GLOBAL old_metas table minus) decls
221 | Ast0.OptType(ty) | Ast0.UniqueType(ty) ->
222 failwith "unexpected code"
223 | _ -> () (* no metavariable subterms *)
224
225(* --------------------------------------------------------------------- *)
226(* Variable declaration *)
227(* Even if the Cocci program specifies a list of declarations, they are
228 split out into multiple declarations of a single variable each. *)
229
230and declaration context old_metas table minus d =
231 match Ast0.unwrap d with
413ffc02
C
232 Ast0.MetaDecl(name,_) | Ast0.MetaField(name,_) ->
233 check_table table minus name
234 | Ast0.Init(stg,ty,id,eq,ini,sem) ->
34e49164
C
235 (match Ast0.unwrap ini with
236 Ast0.InitExpr exp ->
237 typeC old_metas table minus ty;
238 ident context old_metas table minus id;
239 expression ID old_metas table minus exp
240 | _ ->
241 (*
242 if minus
243 then
244 failwith "complex initializer specification not allowed in - code"
245 else*)
246 (typeC old_metas table minus ty;
247 ident context old_metas table minus id;
248 initialiser old_metas table minus ini))
249 | Ast0.UnInit(stg,ty,id,sem) ->
250 typeC old_metas table minus ty; ident context old_metas table minus id
251 | Ast0.MacroDecl(name,lp,args,rp,sem) ->
faf9a90c 252 ident GLOBAL old_metas table minus name;
34e49164
C
253 dots (expression ID old_metas table minus) args
254 | Ast0.TyDecl(ty,sem) -> typeC old_metas table minus ty
255 | Ast0.Typedef(stg,ty,id,sem) ->
256 typeC old_metas table minus ty;
257 typeC old_metas table minus id
258 | Ast0.DisjDecl(_,decls,_,_) ->
259 List.iter (declaration ID old_metas table minus) decls
260 | Ast0.Ddots(_,Some x) -> declaration ID old_metas table minus x
261 | Ast0.Ddots(_,None) -> ()
262 | Ast0.OptDecl(_) | Ast0.UniqueDecl(_) ->
263 failwith "unexpected code"
264
265(* --------------------------------------------------------------------- *)
266(* Initialiser *)
267
268and initialiser old_metas table minus ini =
269 match Ast0.unwrap ini with
113803cf
C
270 Ast0.MetaInit(name,_) ->
271 check_table table minus name
272 | Ast0.InitExpr(exp) -> expression ID old_metas table minus exp
c491d8ee 273 | Ast0.InitList(lb,initlist,rb,ordered) ->
34e49164 274 dots (initialiser old_metas table minus) initlist
113803cf
C
275 | Ast0.InitGccExt(designators,eq,ini) ->
276 List.iter (designator old_metas table minus) designators;
34e49164
C
277 initialiser old_metas table minus ini
278 | Ast0.InitGccName(name,eq,ini) ->
279 ident FIELD old_metas table minus name;
280 initialiser old_metas table minus ini
34e49164
C
281 | Ast0.Idots(_,Some x) -> initialiser old_metas table minus x
282 | Ast0.OptIni(_) | Ast0.UniqueIni(_) ->
283 failwith "unexpected code"
284 | _ -> () (* no metavariable subterms *)
285
113803cf
C
286and designator old_metas table minus = function
287 Ast0.DesignatorField(dot,id) ->
288 ident FIELD old_metas table minus id
289 | Ast0.DesignatorIndex(lb,exp,rb) ->
290 expression ID old_metas table minus exp
291 | Ast0.DesignatorRange(lb,min,dots,max,rb) ->
292 expression ID old_metas table minus min;
293 expression ID old_metas table minus max
294
34e49164
C
295and initialiser_list old_metas table minus =
296 dots (initialiser old_metas table minus)
297
298(* --------------------------------------------------------------------- *)
299(* Parameter *)
300
301and parameterTypeDef old_metas table minus param =
302 match Ast0.unwrap param with
303 Ast0.Param(ty,id) ->
304 get_opt (ident ID old_metas table minus) id;
305 typeC old_metas table minus ty
306 | Ast0.MetaParam(name,_) ->
307 check_table table minus name
88e71198 308 | Ast0.MetaParamList(name,Ast0.MetaListLen lenname,_) ->
34e49164
C
309 check_table table minus name;
310 check_table table minus lenname
88e71198
C
311 | Ast0.MetaParamList(name,_,_) ->
312 check_table table minus name
34e49164
C
313 | _ -> () (* no metavariable subterms *)
314
315and parameter_list old_metas table minus =
316 dots (parameterTypeDef old_metas table minus)
317
318(* --------------------------------------------------------------------- *)
319(* Top-level code *)
320
321and statement old_metas table minus s =
322 match Ast0.unwrap s with
323 Ast0.Decl(_,decl) -> declaration ID old_metas table minus decl
324 | Ast0.Seq(lbrace,body,rbrace) -> dots (statement old_metas table minus) body
325 | Ast0.ExprStatement(exp,sem) -> expression ID old_metas table minus exp
326 | Ast0.IfThen(iff,lp,exp,rp,branch,_) ->
327 expression ID old_metas table minus exp;
328 statement old_metas table minus branch
329 | Ast0.IfThenElse(iff,lp,exp,rp,branch1,els,branch2,_) ->
330 expression ID old_metas table minus exp;
331 statement old_metas table minus branch1;
332 statement old_metas table minus branch2
333 | Ast0.While(wh,lp,exp,rp,body,_) ->
334 expression ID old_metas table minus exp;
335 statement old_metas table minus body
336 | Ast0.Do(d,body,wh,lp,exp,rp,sem) ->
337 statement old_metas table minus body;
338 expression ID old_metas table minus exp
339 | Ast0.For(fr,lp,exp1,sem1,exp2,sem2,exp3,rp,body,_) ->
340 get_opt (expression ID old_metas table minus) exp1;
341 get_opt (expression ID old_metas table minus) exp2;
342 get_opt (expression ID old_metas table minus) exp3;
343 statement old_metas table minus body
344 | Ast0.Iterator(nm,lp,args,rp,body,_) ->
faf9a90c 345 ident GLOBAL old_metas table minus nm;
34e49164
C
346 dots (expression ID old_metas table minus) args;
347 statement old_metas table minus body
fc1ad971 348 | Ast0.Switch(switch,lp,exp,rp,lb,decls,cases,rb) ->
34e49164 349 expression ID old_metas table minus exp;
fc1ad971 350 dots (statement old_metas table minus) decls;
34e49164
C
351 dots (case_line old_metas table minus) cases
352 | Ast0.ReturnExpr(ret,exp,sem) -> expression ID old_metas table minus exp
353 | Ast0.MetaStmt(name,_) -> check_table table minus name
354 | Ast0.MetaStmtList(name,_) -> check_table table minus name
355 | Ast0.Exp(exp) -> expression ID old_metas table minus exp
356 | Ast0.TopExp(exp) -> expression ID old_metas table minus exp
357 | Ast0.Ty(ty) -> typeC old_metas table minus ty
1be43e12 358 | Ast0.TopInit(init) -> initialiser old_metas table minus init
34e49164
C
359 | Ast0.Disj(_,rule_elem_dots_list,_,_) ->
360 List.iter (dots (statement old_metas table minus)) rule_elem_dots_list
361 | Ast0.Nest(_,rule_elem_dots,_,w,_) ->
362 dots (statement old_metas table minus) rule_elem_dots;
363 List.iter (whencode (dots (statement old_metas table minus))
1be43e12
C
364 (statement old_metas table minus)
365 (expression ID old_metas table minus))
34e49164
C
366 w
367 | Ast0.Dots(_,x) | Ast0.Circles(_,x) | Ast0.Stars(_,x) ->
368 List.iter
369 (whencode (dots (statement old_metas table minus))
1be43e12
C
370 (statement old_metas table minus)
371 (expression ID old_metas table minus)) x
34e49164
C
372 | Ast0.FunDecl(_,fi,name,lp,params,rp,lbrace,body,rbrace) ->
373 ident FN old_metas table minus name;
374 List.iter (fninfo old_metas table minus) fi;
375 parameter_list old_metas table minus params;
376 dots (statement old_metas table minus) body
377 | Ast0.Include(inc,s) -> () (* no metavariables possible *)
3a314143
C
378 | Ast0.Undef(def,id) ->
379 ident GLOBAL old_metas table minus id
7f004419 380 | Ast0.Define(def,id,params,body) ->
34e49164 381 ident GLOBAL old_metas table minus id;
7f004419 382 define_parameters old_metas table minus params;
34e49164 383 dots (statement old_metas table minus) body
978fd7e5 384 | Ast0.Label(i,_) -> ident ID old_metas table minus i
34e49164
C
385 | Ast0.Goto(_,i,_) -> ident ID old_metas table minus i
386 | _ -> () (* no metavariable subterms *)
387
7f004419
C
388and define_param old_metas table minus p =
389 match Ast0.unwrap p with
390 Ast0.DParam(id) -> ident GLOBAL old_metas table minus id
391 | Ast0.DPComma(_) | Ast0.DPdots(_) | Ast0.DPcircles(_) ->
392 () (* no metavariable subterms *)
393 | Ast0.OptDParam(dp) -> define_param old_metas table minus dp
394 | Ast0.UniqueDParam(dp) -> define_param old_metas table minus dp
395
396and define_parameters old_metas table minus x =
397 match Ast0.unwrap x with
398 Ast0.NoParams -> ()
399 | Ast0.DParams(lp,dp,rp) -> dots (define_param old_metas table minus) dp
400
34e49164
C
401and fninfo old_metas table minus = function
402 Ast0.FStorage(stg) -> ()
403 | Ast0.FType(ty) -> typeC old_metas table minus ty
404 | Ast0.FInline(inline) -> ()
405 | Ast0.FAttr(attr) -> ()
406
1be43e12 407and whencode notfn alwaysfn expression = function
34e49164
C
408 Ast0.WhenNot a -> notfn a
409 | Ast0.WhenAlways a -> alwaysfn a
410 | Ast0.WhenModifier(_) -> ()
1be43e12
C
411 | Ast0.WhenNotTrue a -> expression a
412 | Ast0.WhenNotFalse a -> expression a
34e49164
C
413
414and case_line old_metas table minus c =
415 match Ast0.unwrap c with
416 Ast0.Default(def,colon,code) ->
417 dots (statement old_metas table minus) code
418 | Ast0.Case(case,exp,colon,code) ->
c491d8ee 419 expression GLOBAL old_metas table minus exp;
34e49164 420 dots (statement old_metas table minus) code
fc1ad971
C
421 | Ast0.DisjCase(_,case_lines,_,_) ->
422 List.iter (case_line old_metas table minus) case_lines
34e49164
C
423 | Ast0.OptCase(case) -> failwith "unexpected code"
424
425(* --------------------------------------------------------------------- *)
426(* Rules *)
427
428let top_level old_metas table minus t =
429 match Ast0.unwrap t with
430 Ast0.DECL(stmt) -> statement old_metas table minus stmt
431 | Ast0.CODE(stmt_dots) -> dots (statement old_metas table minus) stmt_dots
432 | Ast0.ERRORWORDS(exps) ->
433 List.iter (expression FN old_metas table minus) exps
434 | _ -> () (* no metavariables possible *)
435
436let rule old_metas table minus rules =
437 List.iter (top_level old_metas table minus) rules
438
439(* --------------------------------------------------------------------- *)
440
441let positions table rules =
442 let mcode x =
443 match Ast0.get_pos x with
444 Ast0.MetaPos(name,constraints,_) ->
445 let pos = Ast0.unwrap_mcode name in
446 (find_loop table pos) := true
447 | _ -> () in
448 let option_default = () in
449 let bind x y = () in
450 let donothing r k e = k e in
451 let fn =
b1b2de81 452 V0.flat_combiner bind option_default
34e49164 453 mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode
34e49164
C
454 donothing donothing donothing donothing donothing donothing
455 donothing donothing donothing donothing donothing donothing donothing
456 donothing donothing in
457
b1b2de81 458 List.iter fn.VT0.combiner_rec_top_level rules
34e49164
C
459
460let dup_positions rules =
461 let mcode x =
462 match Ast0.get_pos x with
463 Ast0.MetaPos(name,constraints,_) ->
464 let pos = Ast0.unwrap_mcode name in [pos]
465 | _ -> [] in
466 let option_default = [] in
467 let bind x y = x@y in
468
469 (* Case for everything that has a disj.
470 Note, no positions on ( | ) of a disjunction, so no need to recurse on
471 these. *)
472
473 let expression r k e =
474 match Ast0.unwrap e with
475 Ast0.DisjExpr(_,explist,_,_) ->
476 List.fold_left Common.union_set option_default
b1b2de81 477 (List.map r.VT0.combiner_rec_expression explist)
34e49164
C
478 | _ -> k e in
479
480 let typeC r k e = (* not sure relevent because "only after iso" *)
481 match Ast0.unwrap e with
482 Ast0.DisjType(_,types,_,_) ->
483 List.fold_left Common.union_set option_default
b1b2de81 484 (List.map r.VT0.combiner_rec_typeC types)
34e49164
C
485 | _ -> k e in
486
487 let declaration r k e =
488 match Ast0.unwrap e with
489 Ast0.DisjDecl(_,decls,_,_) ->
490 List.fold_left Common.union_set option_default
b1b2de81 491 (List.map r.VT0.combiner_rec_declaration decls)
34e49164
C
492 | _ -> k e in
493
494 let statement r k e =
495 match Ast0.unwrap e with
496 Ast0.Disj(_,stmts,_,_) ->
497 List.fold_left Common.union_set option_default
b1b2de81 498 (List.map r.VT0.combiner_rec_statement_dots stmts)
34e49164
C
499 | _ -> k e in
500
501 let donothing r k e = k e in
502 let fn =
b1b2de81 503 V0.flat_combiner bind option_default
34e49164 504 mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode
34e49164
C
505 donothing donothing donothing donothing donothing donothing
506 donothing expression typeC donothing donothing declaration statement
507 donothing donothing in
508
509 let res =
510 List.sort compare
511 (List.fold_left Common.union_set option_default
b1b2de81 512 (List.map fn.VT0.combiner_rec_top_level rules)) in
34e49164
C
513 let rec loop = function
514 [] | [_] -> ()
515 | ((rule,name) as x)::y::_ when x = y ->
ae4735db
C
516 failwith
517 (Printf.sprintf "duplicate use of %s.%s" rule name)
34e49164
C
518 | _::xs -> loop xs in
519 loop res
520
521(* --------------------------------------------------------------------- *)
522
523let make_table l =
524 let table =
525 (Hashtbl.create(List.length l) :
ae4735db 526 (Ast.meta_name, bool ref) Hashtbl.t) in
34e49164
C
527 List.iter
528 (function x -> Hashtbl.add table (Ast.get_meta_name x) (ref false)) l;
529 table
530
531let add_to_fresh_table l =
532 List.iter
533 (function x ->
534 let name = Ast.get_meta_name x in Hashtbl.replace fresh_table name ())
535 l
536
537let check_all_marked rname err table after_err =
538 Hashtbl.iter
539 (function name ->
540 function (cell) ->
541 if not (!cell)
542 then
543 let (_,name) = name in
544 warning
545 (Printf.sprintf "%s: %s %s not used %s" rname err name after_err))
546 table
547
548let check_meta rname old_metas inherited_metavars metavars minus plus =
549 let old_metas =
550 List.map (function (_,x) -> x) (List.map Ast.get_meta_name old_metas) in
551 let (fresh,other) =
552 List.partition (function Ast.MetaFreshIdDecl(_,_) -> true | _ -> false)
553 metavars in
554 let (err,other) =
555 List.partition (function Ast.MetaErrDecl(_,_) -> true | _ -> false)
556 other in
557 let (ierr,iother) =
558 List.partition (function Ast.MetaErrDecl(_,_) -> true | _ -> false)
559 inherited_metavars in
560 let fresh_table = make_table fresh in
561 let err_table = make_table (err@ierr) in
562 let other_table = make_table other in
563 let iother_table = make_table iother in
564 add_to_fresh_table fresh;
565 rule old_metas [iother_table;other_table;err_table] true minus;
566 positions [iother_table;other_table] minus;
567 dup_positions minus;
568 check_all_marked rname "metavariable" other_table "in the - or context code";
569 rule old_metas [iother_table;fresh_table;err_table] false plus;
faf9a90c 570 check_all_marked rname "inherited metavariable" iother_table
34e49164
C
571 "in the -, +, or context code";
572 check_all_marked rname "metavariable" fresh_table "in the + code";
573 check_all_marked rname "error metavariable" err_table ""