Release coccinelle-0.2.5-rc2
[bpt/coccinelle.git] / parsing_c / parsing_stat.ml
1 (* Yoann Padioleau
2 *
3 * Copyright (C) 2010, University of Copenhagen DIKU and INRIA.
4 * Copyright (C) 2008, 2009 University of Urbana Champaign
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License (GPL)
8 * version 2 as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * file license.txt for more details.
14 *)
15
16 open Common
17
18 (* if do .mli:
19 val print_parsing_stat_list: parsing_stat list -> unit
20 *)
21
22 (*****************************************************************************)
23 (* Stat *)
24 (*****************************************************************************)
25 type parsing_stat = {
26 filename: filename;
27 mutable have_timeout: bool;
28
29 mutable correct: int;
30 mutable bad: int;
31
32 mutable commentized: int; (* by our cpp commentizer *)
33
34 (* if want to know exactly what was passed through, uncomment:
35 *
36 * mutable passing_through_lines: int;
37 *
38 * it differs from bad by starting from the error to
39 * the synchro point instead of starting from start of
40 * function to end of function.
41 *)
42
43 mutable problematic_lines:
44 (string list (* ident in error line *) * int (* line_error *)) list;
45
46 }
47
48 let default_stat file = {
49 filename = file;
50 have_timeout = false;
51 correct = 0; bad = 0;
52 commentized = 0;
53 problematic_lines = [];
54 }
55
56 (* todo: stat per dir ? give in terms of func_or_decl numbers:
57 * nbfunc_or_decl pbs / nbfunc_or_decl total ?/
58 *
59 * note: cela dit si y'a des fichiers avec des #ifdef dont on connait pas les
60 * valeurs alors on parsera correctement tout le fichier et pourtant y'aura
61 * aucune def et donc aucune couverture en fait.
62 * ==> TODO evaluer les parties non parsé ?
63 *)
64
65 let print_parsing_stat_list ?(verbose=false) = fun statxs ->
66 let total = List.length statxs in
67 let perfect =
68 statxs
69 +> List.filter (function
70 {have_timeout = false; bad = 0} -> true | _ -> false)
71 +> List.length
72 in
73
74 if verbose then begin
75 pr "\n\n\n---------------------------------------------------------------";
76 pr "pbs with files:";
77 statxs
78 +> List.filter (function
79 | {have_timeout = true} -> true
80 | {bad = n} when n > 0 -> true
81 | _ -> false)
82 +> List.iter (function
83 {filename = file; have_timeout = timeout; bad = n} ->
84 pr (file ^ " " ^ (if timeout then "TIMEOUT" else i_to_s n));
85 );
86
87 pr "\n\n\n";
88 pr "files with lots of tokens passed/commentized:";
89 let threshold_passed = 100 in
90 statxs
91 +> List.filter (function
92 | {commentized = n} when n > threshold_passed -> true
93 | _ -> false)
94 +> List.iter (function
95 {filename = file; commentized = n} ->
96 pr (file ^ " " ^ (i_to_s n));
97 );
98
99 pr "\n\n\n---------------------------------------------------------------";
100 end;
101
102 pr (
103 (sprintf "NB total files = %d; " total) ^
104 (sprintf "perfect = %d; " perfect) ^
105 (sprintf "pbs = %d; " (statxs +> List.filter (function
106 {have_timeout = b; bad = n} when n > 0 -> true | _ -> false)
107 +> List.length)) ^
108 (sprintf "timeout = %d; " (statxs +> List.filter (function
109 {have_timeout = true; bad = n} -> true | _ -> false)
110 +> List.length)) ^
111 (sprintf "=========> %d" ((100 * perfect) / total)) ^ "%"
112
113 );
114 let good = statxs +> List.fold_left (fun acc {correct = x} -> acc+x) 0 in
115 let bad = statxs +> List.fold_left (fun acc {bad = x} -> acc+x) 0 in
116 let passed = statxs +> List.fold_left (fun acc {commentized = x} -> acc+x) 0
117 in
118 let gf, badf = float_of_int good, float_of_int bad in
119 let passedf = float_of_int passed in
120 pr (
121 (sprintf "nb good = %d, nb passed = %d " good passed) ^
122 (sprintf "=========> %f" (100.0 *. (passedf /. gf)) ^ "% passed")
123 );
124 pr (
125 (sprintf "nb good = %d, nb bad = %d " good bad) ^
126 (sprintf "=========> %f" (100.0 *. (gf /. (gf +. badf))) ^ "% good"
127 )
128 )
129
130 (*****************************************************************************)
131 (* Recurring error diagnostic *)
132 (*****************************************************************************)
133 (* asked/inspired by reviewer of CC'09 *)
134
135 let lines_around_error_line ~context (file, line) =
136 let arr = Common.cat_array file in
137
138 let startl = max 0 (line - context) in
139 let endl = min (Array.length arr) (line + context) in
140 let res = ref [] in
141
142 for i = startl to endl -1 do
143 Common.push2 arr.(i) res
144 done;
145 List.rev !res
146
147
148
149 let print_recurring_problematic_tokens xs =
150 let h = Hashtbl.create 101 in
151 xs +> List.iter (fun x ->
152 let file = x.filename in
153 x.problematic_lines +> List.iter (fun (xs, line_error) ->
154 xs +> List.iter (fun s ->
155 Common.hupdate_default s
156 (fun (old, example) -> old + 1, example)
157 (fun() -> 0, (file, line_error)) h;
158 )));
159 pr2_xxxxxxxxxxxxxxxxx();
160 pr2 ("maybe 10 most problematic tokens");
161 pr2_xxxxxxxxxxxxxxxxx();
162 Common.hash_to_list h
163 +> List.sort (fun (k1,(v1,_)) (k2,(v2,_)) -> compare v2 v1)
164 +> Common.take_safe 10
165 +> List.iter (fun (k,(i, (file_ex, line_ex))) ->
166 pr2 (spf "%s: present in %d parsing errors" k i);
167 pr2 ("example: ");
168 let lines = lines_around_error_line ~context:2 (file_ex, line_ex) in
169 lines +> List.iter (fun s -> pr2 (" " ^ s));
170
171 );
172 pr2_xxxxxxxxxxxxxxxxx();
173 ()
174
175
176
177
178 (*****************************************************************************)
179 (* Stat *)
180 (*****************************************************************************)
181
182 (* Those variables were written for CC09, to evaluate the need for
183 * some of our heuristics and extensions.
184 *
185 * coupling: if you add a new var, modify also assoc_stat_number below
186 *)
187
188 let nTypedefInfer = ref 0
189
190 let nIncludeGrammar = ref 0
191 let nIncludeHack = ref 0
192
193 let nIteratorGrammar = ref 0
194 let nIteratorHeuristic = ref 0
195
196 let nMacroTopDecl = ref 0
197 let nMacroStructDecl = ref 0
198 let nMacroDecl = ref 0
199 let nMacroStmt = ref 0
200 let nMacroString = ref 0
201 let nMacroHigherOrder = ref 0 (* actions *)
202 let nMacrohigherTypeGrammar = ref 0
203 let nMacroAttribute = ref 0
204
205 let nIfdefTop = ref 0
206 let nIfdefStmt = ref 0
207 let nIfdefStruct = ref 0
208 let nIfdefInitializer = ref 0
209 (* nIfdefExpr, nIfdefType *)
210
211 let nIfdefFunheader = ref 0
212
213 let nIfdefExprPassing = ref 0
214 let nIfdefPassing = ref 0
215
216 let nIncludePassing = ref 0
217 let nUndefPassing = ref 0
218 let nDefinePassing = ref 0
219
220 let nIfdefZero = ref 0
221 let nIfdefVersion = ref 0
222
223
224
225 let nGccTypeof = ref 0
226 let nGccLongLong = ref 0
227 let nGccAsm = ref 0
228 let nGccInline = ref 0
229 let nGccAttribute = ref 0
230 let nGccCaseRange = ref 0
231 let nGccMixDecl = ref 0
232 let nGccDesignator = ref 0
233 let nGccStmtExpr = ref 0
234 let nGccConstructor = ref 0
235 let nGccEmptyStruct = ref 0
236 let nGccNestedFunc = ref 0
237
238 let nGccMisc = ref 0
239
240
241
242 let nDefineHack = ref 0
243
244 let nDefineConstant = ref 0
245 let nDefineStmt = ref 0
246 let nDefineExpr = ref 0
247 (* both below require some heuristic support *)
248 let nDefineWhile0 = ref 0
249 let nDefineInit = ref 0
250
251 let nDefineOther = ref 0
252
253 let nUndef = ref 0
254 let nPragmaAndCo = ref 0
255
256 (* let nDirectiveTop = ref 0 *)
257 let nDirectiveStmt = ref 0
258 let nDirectiveStruct = ref 0
259 let nDirectiveInitializer = ref 0
260
261
262 (* from standard.h *)
263 let nMacroHint = ref 0
264 let nMacroExpand = ref 0
265
266 let nNotParsedCorrectly = ref 0
267
268 let assoc_stat_number =
269 [
270 "nTypedefInfer", nTypedefInfer;
271
272 "nIteratorHeuristic", nIteratorHeuristic;
273
274 "nMacroTopDecl", nMacroTopDecl;
275 "nMacroStructDecl", nMacroStructDecl;
276 "nMacroDecl", nMacroDecl;
277 "nMacroStmt", nMacroStmt;
278 "nMacroString", nMacroString;
279 "nMacroHigherOrder", nMacroHigherOrder;
280 "nMacroAttribute", nMacroAttribute;
281
282 "nMacrohigherTypeGrammar", nMacrohigherTypeGrammar;
283
284 "nIfdefTop", nIfdefTop;
285 "nIfdefStmt", nIfdefStmt;
286 "nIfdefStruct", nIfdefStruct;
287 "nIfdefInitializer", nIfdefInitializer;
288
289 "nIfdefFunheader", nIfdefFunheader;
290 "nIfdefZero", nIfdefZero;
291 "nIfdefVersion", nIfdefVersion;
292 "nIfdefExprPassing", nIfdefExprPassing;
293 "nIfdefPassing", nIfdefPassing;
294
295 "nIncludePassing", nIncludePassing;
296 "nDefinePassing", nDefinePassing;
297 "nUndefPassing", nUndefPassing;
298
299 "nMacroExpand", nMacroExpand;
300 "nMacroHint", nMacroHint;
301
302
303 "nGccTypeof", nGccTypeof;
304 "nGccLongLong", nGccLongLong;
305 "nGccAsm", nGccAsm;
306 "nGccInline", nGccInline;
307 "nGccAttribute", nGccAttribute;
308 "nGccCaseRange", nGccCaseRange;
309 "nGccMixDecl", nGccMixDecl;
310 "nGccDesignator", nGccDesignator;
311 "nGccStmtExpr", nGccStmtExpr;
312 "nGccConstructor", nGccConstructor;
313 "nGccEmptyStruct", nGccEmptyStruct;
314 "nGccNestedFunc", nGccNestedFunc;
315
316 "nGccMisc", nGccMisc;
317
318
319 "nDefineHack", nDefineHack;
320
321 "nDefineConstant", nDefineConstant;
322 "nDefineStmt", nDefineStmt;
323 "nDefineExpr", nDefineExpr;
324 "nDefineInit", nDefineInit;
325 "nDefineOther", nDefineOther;
326
327 "nUndef", nUndef;
328 "nPragmaAndCo", nPragmaAndCo;
329
330 "nDirectiveStmt", nDirectiveStmt;
331 "nDirectiveStruct", nDirectiveStruct;
332 "nDirectiveInitializer", nDirectiveInitializer;
333
334 "nNotParsedCorrectly", nNotParsedCorrectly;
335
336
337 (* less *)
338 "nIncludeGrammar", nIncludeGrammar;
339 "nIncludeHack", nIncludeHack;
340
341 "nIteratorGrammar", nIteratorGrammar;
342 ]
343
344 let print_stat_numbers () =
345 assoc_stat_number +> List.iter (fun (k, vref) ->
346 pr2 (spf "%-30s -> %d" k !vref);
347 )