Release coccinelle-0.2.4
[bpt/coccinelle.git] / engine / c_vs_c.ml
CommitLineData
9bc82bae
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
c491d8ee
C
25(*
26 * Copyright 2010, INRIA, University of Copenhagen
27 * Julia Lawall, Rene Rydhof Hansen, Gilles Muller, Nicolas Palix
28 * Copyright 2005-2009, Ecole des Mines de Nantes, University of Copenhagen
29 * Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller, Nicolas Palix
30 * This file is part of Coccinelle.
31 *
32 * Coccinelle is free software: you can redistribute it and/or modify
33 * it under the terms of the GNU General Public License as published by
34 * the Free Software Foundation, according to version 2 of the License.
35 *
36 * Coccinelle is distributed in the hope that it will be useful,
37 * but WITHOUT ANY WARRANTY; without even the implied warranty of
38 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
39 * GNU General Public License for more details.
40 *
41 * You should have received a copy of the GNU General Public License
42 * along with Coccinelle. If not, see <http://www.gnu.org/licenses/>.
43 *
44 * The authors reserve the right to distribute this or future versions of
45 * Coccinelle under other licenses.
46 *)
47
48
34e49164
C
49open Common
50
51open Ast_c
52
53(* For the moment I do only eq_type and not eq_expr, etc. The reason
54 * for eq_type is related to the typedef and struct isomorphism. Sometimes
55 * one use the typedef and sometimes the structname.
ae4735db 56 *
34e49164
C
57 * TODO: should use the isomorphisms engine of julia.
58 * Maybe I can transform my ast_c in ast_cocci, and use julia's code ?
59 * Maybe I can add some Disj in my ast_c ?
60 *)
61
62
ae4735db
C
63module type PARAM =
64 sig
34e49164
C
65 type tin
66 type 'x tout
67
68 type 'a matcher = 'a -> 'a -> tin -> 'a tout
69
ae4735db
C
70 val (>>=):
71 (tin -> 'a tout) ->
72 ('a -> (tin -> 'b tout)) ->
34e49164
C
73 (tin -> 'b tout)
74
75 val (>&&>) : bool -> (tin -> 'x tout) -> (tin -> 'x tout)
76
77 val return : 'a -> tin -> 'a tout
78 val fail : tin -> 'a tout
79end
80
81
82module C_VS_C =
ae4735db 83 functor (X : PARAM) ->
34e49164
C
84struct
85
86type 'a matcher = 'a -> 'a -> X.tin -> 'a X.tout
87
88let (>>=) = X.(>>=)
89let (>&&>) = X.(>&&>)
90let return = X.return
91let fail = X.fail
92
93let (option: 'a matcher -> ('a option matcher)) = fun f t1 t2 ->
94 match (t1,t2) with
ae4735db
C
95 | (Some t1, Some t2) ->
96 f t1 t2 >>= (fun t ->
34e49164
C
97 return (Some t)
98 )
99 | (None, None) -> return None
100 | _ -> fail
101
102
ae4735db 103let same_s saopt sbopt =
b1b2de81
C
104 match saopt, sbopt with
105 | None, None -> true
ae4735db 106 | Some namea, Some nameb ->
b1b2de81
C
107 let sa = Ast_c.str_of_name namea in
108 let sb = Ast_c.str_of_name nameb in
109 sa =$= sb
ae4735db 110 | _ -> false
b1b2de81
C
111
112
ae4735db 113let rec fullType a b =
34e49164
C
114 let ((qua,iiqa), tya) = a in
115 let ((qub,iiqb), tyb) = b in
116 (qua.const =:= qub.const && qua.volatile =:= qub.volatile) >&&>
117
ae4735db
C
118 let (qu,iiq) = (qua, iiqa) in
119 typeC tya tyb >>= (fun ty ->
34e49164
C
120 return ((qu,iiq), ty)
121 )
122
ae4735db 123and typeC tya tyb =
34e49164
C
124 let (a, iia) = tya in
125 let (b, iib) = tyb in
126
127 let iix = iia in
128
129 match a, b with
ae4735db 130 | BaseType a, BaseType b ->
34e49164 131 a =*= b >&&> return (BaseType a, iix)
ae4735db 132 | Pointer a, Pointer b ->
34e49164
C
133 fullType a b >>= (fun x -> return (Pointer x, iix))
134
ae4735db
C
135 | StructUnionName (sua, sa), StructUnionName (sub, sb) ->
136 (sua =*= sub && sa =$= sb) >&&>
34e49164
C
137 return (StructUnionName (sua, sa), iix)
138
ae4735db 139 | TypeName (namea, opta), TypeName (nameb, optb) ->
b1b2de81
C
140 let sa = Ast_c.str_of_name namea in
141 let sb = Ast_c.str_of_name nameb in
ae4735db 142
34e49164
C
143 (* assert compatible opta optb ? *)
144 (*option fullType opta optb*)
ae4735db
C
145 sa =$= sb >&&>
146 let opt =
34e49164
C
147 (match opta, optb with
148 | None, None -> None
b1b2de81 149
ae4735db
C
150 | Some x, _
151 | _, Some x
b1b2de81 152
34e49164 153 -> Some x
ae4735db 154 )
34e49164 155 in
b1b2de81 156 return (TypeName (namea, opt), iix)
34e49164 157
ae4735db
C
158
159 | Array (ea, a), Array (eb,b) ->
34e49164
C
160 let get_option f = function Some x -> Some (f x) | None -> None in
161 let ea = get_option Lib_parsing_c.al_expr ea in
162 let eb = get_option Lib_parsing_c.al_expr eb in
163 ea =*= eb >&&> fullType a b >>= (fun x -> return (Array (ea, x), iix))
164
ae4735db 165 | FunctionType (returna, paramsa), FunctionType (returnb, paramsb) ->
34e49164
C
166 let (tsa, (ba,iihas3dotsa)) = paramsa in
167 let (tsb, (bb,iihas3dotsb)) = paramsb in
168
169 let bx = ba in
170 let iihas3dotsx = iihas3dotsa in
171
b1b2de81 172 (ba =:= bb && List.length tsa =|= List.length tsb) >&&>
ae4735db 173 fullType returna returnb >>= (fun returnx ->
34e49164 174
ae4735db 175 Common.zip tsa tsb +> List.fold_left
34e49164
C
176 (fun acc ((parama,iia),(paramb,iib))->
177 let iix = iia in
ae4735db 178 acc >>= (fun xs ->
34e49164 179
ae4735db 180 let {p_register = (ba,iiba); p_namei = saopt; p_type = ta} =
b1b2de81 181 parama in
ae4735db 182 let {p_register = (bb,iibb); p_namei = sbopt; p_type = tb} =
b1b2de81 183 paramb in
34e49164
C
184
185 let bx = ba in
b1b2de81
C
186 let iibx = iiba in
187
34e49164 188 let sxopt = saopt in
b1b2de81 189
34e49164 190
485bce71 191 (* todo? iso on name or argument ? *)
b1b2de81 192 (ba =:= bb && same_s saopt sbopt) >&&>
ae4735db 193 fullType ta tb >>= (fun tx ->
b1b2de81
C
194 let paramx = { p_register = (bx, iibx);
195 p_namei = sxopt;
196 p_type = tx; } in
34e49164
C
197 return ((paramx,iix)::xs)
198 )
199 )
200 ) (return [])
ae4735db 201 >>= (fun tsx ->
34e49164
C
202 let paramsx = (List.rev tsx, (bx, iihas3dotsx)) in
203 return (FunctionType (returnx, paramsx), iix)
204 ))
205
ae4735db 206 | Enum (saopt, enuma), Enum (sbopt, enumb) ->
34e49164 207 (saopt =*= sbopt &&
ae4735db
C
208 List.length enuma =|= List.length enumb &&
209 Common.zip enuma enumb +> List.for_all (fun
b1b2de81 210 (((namesa,eopta), iicommaa), ((namesb,eoptb),iicommab))
ae4735db 211 ->
b1b2de81
C
212 let sa = str_of_name namesa in
213 let sb = str_of_name namesb in
ae4735db 214 sa =$= sb &&
b1b2de81 215 (* todo ? eopta and b can have some info so ok to use =*= ? *)
ae4735db 216 eopta =*= eoptb
34e49164
C
217 )
218 ) >&&>
219 return (Enum (saopt, enuma), iix)
220
221 | EnumName sa, EnumName sb -> sa =$= sb >&&> return (EnumName sa, iix)
222
ae4735db 223 | ParenType a, ParenType b ->
34e49164 224 (* iso here ? *)
ae4735db 225 fullType a b >>= (fun x ->
34e49164
C
226 return (ParenType x, iix)
227 )
228
ae4735db 229 | TypeOfExpr ea, TypeOfExpr eb ->
34e49164
C
230 let ea = Lib_parsing_c.al_expr ea in
231 let eb = Lib_parsing_c.al_expr eb in
232 ea =*= eb >&&> return (TypeOfExpr ea, iix)
233
ae4735db 234 | TypeOfType a, TypeOfType b ->
34e49164
C
235 fullType a b >>= (fun x -> return (TypeOfType x, iix))
236
ae4735db
C
237(* | TypeOfType a, b ->
238 | a, TypeOfType b ->
34e49164
C
239*)
240
241
ae4735db
C
242 | StructUnion (sua, saopt, sta), StructUnion (sub, sbopt, stb) ->
243 (sua =*= sub && saopt =*= sbopt && List.length sta =|= List.length stb)
244 >&&>
245 Common.zip sta stb +> List.fold_left
246 (fun acc ((fielda), (fieldb)) ->
247 acc >>= (fun xs ->
248 match fielda, fieldb with
249 | EmptyField iia, EmptyField iib ->
708f4980
C
250 let iix = iia in
251 return ((EmptyField iix)::xs)
34e49164 252
ae4735db
C
253 | DeclarationField (FieldDeclList (fa, iipta)),
254 DeclarationField (FieldDeclList (fb, iiptb)) ->
485bce71 255 let iipt = iipta in (* TODO ?*)
ae4735db 256 (List.length fa =|= List.length fb) >&&>
34e49164 257
ae4735db
C
258 Common.zip fa fb +> List.fold_left
259 (fun acc2 ((fielda,iia),(fieldb,iib))->
34e49164 260 let iix = iia in
ae4735db 261 acc2 >>= (fun xs ->
b1b2de81 262 match fielda, fieldb with
ae4735db 263 | Simple (nameaopt, ta), Simple (namebopt, tb) ->
b1b2de81 264
ae4735db
C
265
266 same_s nameaopt namebopt >&&>
267 fullType ta tb >>= (fun tx ->
b1b2de81 268 return (((Simple (nameaopt, tx)), iix)::xs)
34e49164 269 )
ae4735db
C
270
271 | BitField (nameopta, ta, infoa, ea),
272 BitField (nameoptb, tb, infob, eb) ->
b1b2de81 273 let infox = infoa in
ae4735db
C
274 (same_s nameopta nameoptb && ea =*= eb) >&&>
275 fullType ta tb >>= (fun tx ->
b1b2de81 276 return (((BitField (nameopta,tx,infox,ea)), iix)::xs)
34e49164
C
277 )
278 | _,_ -> fail
279 )
280 ) (return [])
ae4735db
C
281 >>= (fun fx ->
282 return (((DeclarationField
708f4980 283 (FieldDeclList (List.rev fx,iipt))))::xs)
34e49164
C
284 )
285 | _ -> fail
286 )
287
288
289 ) (return [])
ae4735db 290 >>= (fun stx ->
34e49164
C
291 return (StructUnion (sua, saopt, List.rev stx), iix)
292 )
293
294
295
296 (* choose the lub.
297 * subtil: in the return must put iia, not iix, and in following case
298 * must put iib and not iix, because we want the token corresponding
299 * to the typedef.
300 *)
ae4735db
C
301 | TypeName (name, Some a), _ ->
302 fullType a (Ast_c.nQ, tyb) >>= (fun x ->
303 return (TypeName (name, Some x), iia)
34e49164
C
304 )
305
ae4735db
C
306 | _, TypeName (name, Some b) ->
307 fullType b (Ast_c.nQ, tya) >>= (fun x ->
b1b2de81 308 return (TypeName (name, Some x), iib) (* subtil: *)
34e49164
C
309 )
310
311 | _, _ -> fail
312
313
314
315end
316
317module XEQ = struct
318 type tin = unit
319 type 'a tout = 'a option
320
321 type 'a matcher = 'a -> 'a -> tin -> 'a tout
322
323 let return x = fun tin -> Some x
324 let fail = fun tin -> None
325
ae4735db 326 let (>>=) m f = fun tin ->
34e49164
C
327 match m tin with
328 | None -> None
329 | Some x -> f x tin
330
ae4735db 331 let (>&&>) b m = fun tin ->
34e49164
C
332 if b then m tin
333 else fail tin
334
335end
336
337module EQ = C_VS_C (XEQ)
338
339
340let eq_type2 a b = EQ.fullType a b () <> None
341let merge_type2 a b = Common.some (EQ.fullType a b ())
342
ae4735db 343let eq_type a b =
34e49164
C
344 Common.profile_code "C_vs_c" (fun () -> eq_type2 a b)
345
ae4735db 346let merge_type a b =
34e49164 347 Common.profile_code "C_vs_c" (fun () -> merge_type2 a b)
5636bb2c
C
348
349
350(* ------------------------------------------------------------------------- *)
351
352(* This seemed like a reasonable place to put this, given the file name,
353but not sure that it is the case... This has to be compatible with the
354function equal_inh_metavarval. It is indeed not so clear why that is
355defined in cocci_vs_c.ml, and not here, since it is comparing C code to C
356code. *)
357
358let subexpression_of_expression small_exp big_exp =
359 let res = ref false in (* because no appropriate functional visitor... *)
360 let expr (k,bigf) big_exp =
361 (* comparison used in Cocci_vs_c.equal_inh_metavarval *)
362 (* have to strip each subexp, because stripping puts some offsets in the
363 term rather than setting everything to 0. No idea why... *)
364 if small_exp =*= Lib_parsing_c.al_inh_expr big_exp
365 then res := true
366 else k big_exp in
367 let bigf = { Visitor_c.default_visitor_c with Visitor_c.kexpr = expr } in
368 Visitor_c.vk_expr bigf big_exp;
369 (*Printf.printf "comparison gives %b\n" !res;
370 Pretty_print_c.pp_expression_simple small_exp;
371 Format.print_newline();
372 Pretty_print_c.pp_expression_simple big_exp;
373 Format.print_newline();
374 Printf.printf "--------------------------------\n";*)
375 !res