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.
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.
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.
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/>.
20 * The authors reserve the right to distribute this or future versions of
21 * Coccinelle under other licenses.
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.
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.
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.
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/>.
44 * The authors reserve the right to distribute this or future versions of
45 * Coccinelle under other licenses.
49 (* get a list of all of the constants in the - slice of a SmPL file, to be
50 used to select which files to process *)
52 (* This could be made more efficient, by finding only the important things.
53 eg, if we have a function and its arguments, we could just pick the function.
54 And we could try to pick only the things annotated with -, and only pick
55 something else if there is no -. In general, we only want the most important
56 constant, not all the constants. *)
58 module Ast
= Ast_cocci
59 module V
= Visitor_ast
60 module TC
= Type_cocci
62 let keep_some_bind x y
= match x
with [] -> y
| _
-> x
63 let or_bind x y
= match x
with [] -> [] | _
-> x
64 let keep_all_bind = Common.union_set
66 let get_minus_constants bind orbind
=
67 let donothing r k e
= k e
in
68 let option_default = [] in
69 let mcode _ _
= option_default in
71 (* if one branch gives no information, then we have to take anything *)
72 let disj_union_all l
=
73 if List.exists
(function [] -> true | _
-> false) l
74 then orbind
[] (Common.union_all l
)
75 else Common.union_all l
in
77 (* need special cases for everything with a disj, because the bind above
78 would throw away all but the first disj *)
81 match Ast.unwrap e
with
83 (match Ast.unwrap_mcode name
with
84 "NULL" -> [] (* special case, because this is too generic *)
88 let expression r k e
=
89 match Ast.unwrap e
with
90 Ast.RecordAccess
(exp
,_
,fld
) | Ast.RecordPtAccess
(exp
,_
,fld
) ->
93 (List.map
(function id
-> ["."^id
;"->"^id
])
94 (r
.V.combiner_ident fld
)))
95 (r
.V.combiner_expression exp
)
96 | Ast.SizeOfExpr
(sizeof
,_
) | Ast.SizeOfType
(sizeof
,_
,_
,_
) ->
97 bind
(k e
) [Ast.unwrap_mcode sizeof
]
98 | Ast.DisjExpr
(exps
) ->
99 disj_union_all (List.map r
.V.combiner_expression exps
)
100 | Ast.Edots
(_
,_
) | Ast.Ecircles
(_
,_
) | Ast.Estars
(_
,_
) -> []
101 | Ast.NestExpr
(starter
,expr_dots
,ender
,whencode
,false) -> []
102 | Ast.NestExpr
(starter
,expr_dots
,ender
,whencode
,true) ->
103 r
.V.combiner_expression_dots expr_dots
107 match Ast.unwrap e
with
112 (_
,_
,Ast.MINUS
(_
,_
,_
,_
),_
) -> [Ast.unwrap_mcode ty
]
114 else [Ast.unwrap_mcode ty
]
118 match Ast.unwrap e
with
119 Ast.DisjType
(types
) ->
120 disj_union_all (List.map r
.V.combiner_fullType types
)
123 let declaration r k e
=
124 match Ast.unwrap e
with
125 Ast.DisjDecl
(decls
) ->
126 disj_union_all (List.map r
.V.combiner_declaration decls
)
127 | Ast.Ddots
(dots
,whencode
) -> []
130 let rule_elem r k e
=
131 match Ast.unwrap e
with
132 Ast.DisjRuleElem
(res
) ->
133 disj_union_all (List.map r
.V.combiner_rule_elem res
)
136 let statement r k e
=
137 match Ast.unwrap e
with
138 Ast.Disj
(stmt_dots
) ->
139 disj_union_all (List.map r
.V.combiner_statement_dots stmt_dots
)
140 | Ast.Dots
(d
,whn
,_
,_
) | Ast.Circles
(d
,whn
,_
,_
) | Ast.Stars
(d
,whn
,_
,_
) -> []
141 | Ast.Nest
(starter
,stmt_dots
,ender
,whn
,false,_
,_
) -> []
142 | Ast.Nest
(starter
,stmt_dots
,ender
,whn
,true,_
,_
) ->
143 r
.V.combiner_statement_dots stmt_dots
146 V.combiner bind
option_default
147 mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode
148 donothing donothing donothing donothing
149 ident expression fullType typeC donothing donothing declaration
150 rule_elem statement donothing donothing donothing
152 (* ------------------------------------------------------------------------ *)
154 let get_all_minus_constants =
155 let donothing r k e
= k e
in
156 let bind = Common.union_set
in
157 let option_default = [] in
158 let mcode r
(x
,_
,mcodekind
,_
) =
160 Ast.MINUS
(_
,_
,_
,_
) -> [x
]
162 let other r
(x
,_
,mcodekind
,_
) = [] in
164 V.combiner
bind option_default
165 other mcode other other other other other other other other other other
167 donothing donothing donothing donothing
168 donothing donothing donothing donothing donothing donothing donothing
169 donothing donothing donothing donothing donothing
170 (* ------------------------------------------------------------------------ *)
172 let get_plus_constants =
173 let donothing r k e
= k e
in
174 let bind = Common.union_set
in
175 let option_default = [] in
176 let mcode r
(_
,_
,mcodekind
,_
) =
182 let fn = get_minus_constants keep_all_bind keep_all_bind in
183 bind (fn.V.combiner_anything cur
) prev
))
186 Ast.MINUS
(_
,_
,_
,anythings
) -> recurse anythings
187 | Ast.CONTEXT
(_
,Ast.BEFORE
(a
,_
)) -> recurse a
188 | Ast.CONTEXT
(_
,Ast.AFTER
(a
,_
)) -> recurse a
189 | Ast.CONTEXT
(_
,Ast.BEFOREAFTER
(a1
,a2
,_
)) ->
190 Common.union_set
(recurse a1
) (recurse a2
)
193 V.combiner
bind option_default
194 mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode
195 donothing donothing donothing donothing
196 donothing donothing donothing donothing donothing donothing donothing
197 donothing donothing donothing donothing donothing
199 (* ------------------------------------------------------------------------ *)
200 (* see if there are any inherited variables that must be bound for this rule
203 let check_inherited nm
=
204 let donothing r k e
= k e
in
205 let option_default = false in
206 let bind x y
= x
or y
in
207 let inherited (nm1
,_
) = not
(nm
= nm1
) in
208 let minherited mc
= inherited (Ast.unwrap_mcode mc
) in
210 match Ast.get_pos_var x
with
211 Ast.MetaPos
(name
,constraints
,_
,keep
,inh
) -> minherited name
212 | _
-> option_default in
214 (* a case for everything for there is a metavariable, also disjunctions
215 or optional things *)
217 let strictident recursor k i
=
218 match Ast.unwrap i
with
219 Ast.MetaId
(name
,_
,_
,_
) | Ast.MetaFunc
(name
,_
,_
,_
)
220 | Ast.MetaLocalFunc
(name
,_
,_
,_
) -> bind (k i
) (minherited name
)
223 let rec type_collect res
= function
224 TC.ConstVol
(_
,ty
) | TC.Pointer
(ty
) | TC.FunctionPointer
(ty
)
225 | TC.Array
(ty
) -> type_collect res ty
226 | TC.MetaType
(tyname
,_
,_
) ->
230 let strictexpr recursor k e
=
231 match Ast.unwrap e
with
232 Ast.MetaExpr
(name
,_
,_
,Some type_list
,_
,_
) ->
233 let types = List.fold_left
type_collect option_default type_list
in
234 bind (minherited name
) types
235 | Ast.MetaErr
(name
,_
,_
,_
) | Ast.MetaExpr
(name
,_
,_
,_
,_
,_
) ->
236 bind (k e
) (minherited name
)
237 | Ast.MetaExprList
(name
,None
,_
,_
) -> bind (k e
) (minherited name
)
238 | Ast.MetaExprList
(name
,Some
(lenname
,_
,_
),_
,_
) ->
239 bind (k e
) (bind (minherited name
) (minherited lenname
))
240 | Ast.DisjExpr
(exps
) ->
241 (* could see if there are any variables that appear in all branches,
242 but perhaps not worth it *)
246 let strictdecls recursor k d
=
247 match Ast.unwrap d
with
248 Ast.MetaDecl
(name
,_
,_
) | Ast.MetaField
(name
,_
,_
) ->
249 bind (k p
) (minherited name
)
250 | Ast.DisjDecl
(decls
) -> option_default
253 let strictfullType recursor k ty
=
254 match Ast.unwrap ty
with
255 Ast.DisjType
(types) -> option_default
258 let stricttypeC recursor k ty
=
259 match Ast.unwrap ty
with
260 Ast.MetaType
(name
,_
,_
) -> bind (k ty
) (minherited name
)
263 let strictparam recursor k p
=
264 match Ast.unwrap p
with
265 Ast.MetaParam
(name
,_
,_
) -> bind (k p
) (minherited name
)
266 | Ast.MetaParamList
(name
,None
,_
,_
) -> bind (k p
) (minherited name
)
267 | Ast.MetaParamList
(name
,Some
(lenname
,_
,_
),_
,_
) ->
268 bind (k p
) (bind (minherited name
) (minherited lenname
))
271 let strictrule_elem recursor k re
=
272 (*within a rule_elem, pattern3 manages the coherence of the bindings*)
273 match Ast.unwrap re
with
274 Ast.MetaRuleElem
(name
,_
,_
) | Ast.MetaStmt
(name
,_
,_
,_
)
275 | Ast.MetaStmtList
(name
,_
,_
) -> bind (k re
) (minherited name
)
278 let strictstatement recursor k s
=
279 match Ast.unwrap s
with
280 Ast.Disj
(stms
) -> option_default
283 V.combiner
bind option_default
284 mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode
285 donothing donothing donothing donothing
286 strictident strictexpr strictfullType stricttypeC donothing strictparam
287 strictdecls strictrule_elem strictstatement donothing donothing donothing
289 (* ------------------------------------------------------------------------ *)
291 let rec dependent = function
293 | Ast.AntiDep s
-> false
294 | Ast.EverDep s
-> true
295 | Ast.NeverDep s
-> false
296 | Ast.AndDep
(d1
,d2
) -> dependent d1
or dependent d2
297 | Ast.OrDep
(d1
,d2
) -> dependent d1
&& dependent d2
299 | Ast.FailDep
-> true
301 (* ------------------------------------------------------------------------ *)
303 let rule_fn tls in_plus
=
305 (function (rest_info
,in_plus
) ->
307 let mfn = get_minus_constants keep_some_bind or_bind in
308 let minuses = mfn.V.combiner_top_level cur
in
311 then [] (* nothing removed for sgrep *)
312 else get_all_minus_constants.V.combiner_top_level cur
in
313 let plusses = get_plus_constants.V.combiner_top_level cur
in
314 (* the following is for eg -foo(2) +foo(x) then in another rule
315 -foo(10); don't want to consider that foo is guaranteed to be
316 created by the rule. not sure this works completely: what if foo is
317 in both - and +, but in an or, so the cases aren't related?
318 not sure this whole thing is a good idea. how do we know that
319 something that is only in plus is really freshly created? *)
320 let plusses = Common.minus_set
plusses all_minuses in
321 let new_minuses = Common.minus_set
minuses in_plus
in
322 let new_plusses = Common.union_set
plusses in_plus
in
323 (Common.union_set
new_minuses rest_info
, new_plusses))
328 let get_constants rules
=
332 (function (rest_info
,in_plus
) ->
335 Ast.ScriptRule
(_
,_
,_
,_
)
336 | Ast.InitialScriptRule
(_
,_
,_
) | Ast.FinalScriptRule
(_
,_
,_
) ->
338 | Ast.CocciRule
(nm
, (dep
,_
,_
), cur
, _
, _
) ->
339 let (cur_info
,cur_plus
) = rule_fn cur in_plus
in
341 (* no dependencies if dependent on another rule; then we
342 need to find the constants of that rule *)
344 List.for_all
(check_inherited nm
).V.combiner_top_level cur
347 if cur_info = [] then raise No_info
else cur_info in
348 (Common.union_set
[cur_info] rest_info
,cur_plus
))
351 with No_info
-> List.map
(function _
-> []) rules