2 * Copyright 2012, INRIA
3 * Julia Lawall, Gilles Muller
4 * Copyright 2010-2011, INRIA, University of Copenhagen
5 * Julia Lawall, Rene Rydhof Hansen, Gilles Muller, Nicolas Palix
6 * Copyright 2005-2009, Ecole des Mines de Nantes, University of Copenhagen
7 * Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller, Nicolas Palix
8 * This file is part of Coccinelle.
10 * Coccinelle is free software: you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation, according to version 2 of the License.
14 * Coccinelle is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with Coccinelle. If not, see <http://www.gnu.org/licenses/>.
22 * The authors reserve the right to distribute this or future versions of
23 * Coccinelle under other licenses.
27 (* get a list of all of the constants in the - slice of a SmPL file, to be
28 used to select which files to process *)
30 (* This could be made more efficient, by finding only the important things.
31 eg, if we have a function and its arguments, we could just pick the function.
32 And we could try to pick only the things annotated with -, and only pick
33 something else if there is no -. In general, we only want the most important
34 constant, not all the constants. *)
36 module Ast
= Ast_cocci
37 module V
= Visitor_ast
38 module TC
= Type_cocci
40 let keep_some_bind x y
= match x
with [] -> y
| _
-> x
41 let or_bind x y
= match x
with [] -> [] | _
-> x
42 let keep_all_bind = Common.union_set
44 let get_minus_constants bind orbind
=
45 let donothing r k e
= k e
in
46 let option_default = [] in
47 let mcode _ _
= option_default in
49 (* if one branch gives no information, then we have to take anything *)
50 let disj_union_all l
=
51 if List.exists
(function [] -> true | _
-> false) l
52 then orbind
[] (Common.union_all l
)
53 else Common.union_all l
in
55 (* need special cases for everything with a disj, because the bind above
56 would throw away all but the first disj *)
59 match Ast.unwrap e
with
61 (match Ast.unwrap_mcode name
with
62 "NULL" -> [] (* special case, because this is too generic *)
66 let expression r k e
=
67 match Ast.unwrap e
with
68 Ast.RecordAccess
(exp
,_
,fld
) | Ast.RecordPtAccess
(exp
,_
,fld
) ->
71 (List.map
(function id
-> ["."^id
;"->"^id
])
72 (r
.V.combiner_ident fld
)))
73 (r
.V.combiner_expression exp
)
74 | Ast.SizeOfExpr
(sizeof
,_
) | Ast.SizeOfType
(sizeof
,_
,_
,_
) ->
75 bind
(k e
) [Ast.unwrap_mcode sizeof
]
76 | Ast.DisjExpr
(exps
) ->
77 disj_union_all (List.map r
.V.combiner_expression exps
)
78 | Ast.Edots
(_
,_
) | Ast.Ecircles
(_
,_
) | Ast.Estars
(_
,_
) -> []
79 | Ast.NestExpr
(starter
,expr_dots
,ender
,whencode
,false) -> []
80 | Ast.NestExpr
(starter
,expr_dots
,ender
,whencode
,true) ->
81 r
.V.combiner_expression_dots expr_dots
85 match Ast.unwrap e
with
90 (_
,_
,Ast.MINUS
(_
,_
,_
,_
),_
) -> [Ast.unwrap_mcode ty
]
92 else [Ast.unwrap_mcode ty
]
96 match Ast.unwrap e
with
97 Ast.DisjType
(types
) ->
98 disj_union_all (List.map r
.V.combiner_fullType types
)
101 let declaration r k e
=
102 match Ast.unwrap e
with
103 Ast.DisjDecl
(decls
) ->
104 disj_union_all (List.map r
.V.combiner_declaration decls
)
105 | Ast.Ddots
(dots
,whencode
) -> []
108 let rule_elem r k e
=
109 match Ast.unwrap e
with
110 Ast.DisjRuleElem
(res
) ->
111 disj_union_all (List.map r
.V.combiner_rule_elem res
)
114 let statement r k e
=
115 match Ast.unwrap e
with
116 Ast.Disj
(stmt_dots
) ->
117 disj_union_all (List.map r
.V.combiner_statement_dots stmt_dots
)
118 | Ast.Dots
(d
,whn
,_
,_
) | Ast.Circles
(d
,whn
,_
,_
) | Ast.Stars
(d
,whn
,_
,_
) -> []
119 | Ast.Nest
(starter
,stmt_dots
,ender
,whn
,false,_
,_
) -> []
120 | Ast.Nest
(starter
,stmt_dots
,ender
,whn
,true,_
,_
) ->
121 r
.V.combiner_statement_dots stmt_dots
124 V.combiner bind
option_default
125 mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode
126 donothing donothing donothing donothing
127 ident expression fullType typeC donothing donothing declaration
128 rule_elem statement donothing donothing donothing
130 (* ------------------------------------------------------------------------ *)
132 let get_all_minus_constants =
133 let donothing r k e
= k e
in
134 let bind = Common.union_set
in
135 let option_default = [] in
136 let mcode r
(x
,_
,mcodekind
,_
) =
138 Ast.MINUS
(_
,_
,_
,_
) -> [x
]
140 let other r
(x
,_
,mcodekind
,_
) = [] in
142 V.combiner
bind option_default
143 other mcode other other other other other other other other other other
145 donothing donothing donothing donothing
146 donothing donothing donothing donothing donothing donothing donothing
147 donothing donothing donothing donothing donothing
148 (* ------------------------------------------------------------------------ *)
150 let get_plus_constants =
151 let donothing r k e
= k e
in
152 let bind = Common.union_set
in
153 let option_default = [] in
154 let mcode r
(_
,_
,mcodekind
,_
) =
160 let fn = get_minus_constants keep_all_bind keep_all_bind in
161 bind (fn.V.combiner_anything cur
) prev
))
164 Ast.MINUS
(_
,_
,_
,anythings
) -> recurse anythings
165 | Ast.CONTEXT
(_
,Ast.BEFORE
(a
,_
)) -> recurse a
166 | Ast.CONTEXT
(_
,Ast.AFTER
(a
,_
)) -> recurse a
167 | Ast.CONTEXT
(_
,Ast.BEFOREAFTER
(a1
,a2
,_
)) ->
168 Common.union_set
(recurse a1
) (recurse a2
)
171 V.combiner
bind option_default
172 mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode
173 donothing donothing donothing donothing
174 donothing donothing donothing donothing donothing donothing donothing
175 donothing donothing donothing donothing donothing
177 (* ------------------------------------------------------------------------ *)
178 (* see if there are any inherited variables that must be bound for this rule
181 let check_inherited nm
=
182 let donothing r k e
= k e
in
183 let option_default = false in
184 let bind x y
= x
or y
in
185 let inherited (nm1
,_
) = not
(nm
= nm1
) in
186 let minherited mc
= inherited (Ast.unwrap_mcode mc
) in
188 match Ast.get_pos_var x
with
189 Ast.MetaPos
(name
,constraints
,_
,keep
,inh
) -> minherited name
190 | _
-> option_default in
192 (* a case for everything for there is a metavariable, also disjunctions
193 or optional things *)
195 let strictident recursor k i
=
196 match Ast.unwrap i
with
197 Ast.MetaId
(name
,_
,_
,_
) | Ast.MetaFunc
(name
,_
,_
,_
)
198 | Ast.MetaLocalFunc
(name
,_
,_
,_
) -> bind (k i
) (minherited name
)
201 let rec type_collect res
= function
202 TC.ConstVol
(_
,ty
) | TC.Pointer
(ty
) | TC.FunctionPointer
(ty
)
203 | TC.Array
(ty
) -> type_collect res ty
204 | TC.MetaType
(tyname
,_
,_
) ->
208 let strictexpr recursor k e
=
209 match Ast.unwrap e
with
210 Ast.MetaExpr
(name
,_
,_
,Some type_list
,_
,_
) ->
211 let types = List.fold_left
type_collect option_default type_list
in
212 bind (minherited name
) types
213 | Ast.MetaErr
(name
,_
,_
,_
) | Ast.MetaExpr
(name
,_
,_
,_
,_
,_
) ->
214 bind (k e
) (minherited name
)
215 | Ast.MetaExprList
(name
,None
,_
,_
) -> bind (k e
) (minherited name
)
216 | Ast.MetaExprList
(name
,Some
(lenname
,_
,_
),_
,_
) ->
217 bind (k e
) (bind (minherited name
) (minherited lenname
))
218 | Ast.DisjExpr
(exps
) ->
219 (* could see if there are any variables that appear in all branches,
220 but perhaps not worth it *)
224 let strictdecls recursor k d
=
225 match Ast.unwrap d
with
226 Ast.MetaDecl
(name
,_
,_
) | Ast.MetaField
(name
,_
,_
) ->
227 bind (k p
) (minherited name
)
228 | Ast.DisjDecl
(decls
) -> option_default
231 let strictfullType recursor k ty
=
232 match Ast.unwrap ty
with
233 Ast.DisjType
(types) -> option_default
236 let stricttypeC recursor k ty
=
237 match Ast.unwrap ty
with
238 Ast.MetaType
(name
,_
,_
) -> bind (k ty
) (minherited name
)
241 let strictparam recursor k p
=
242 match Ast.unwrap p
with
243 Ast.MetaParam
(name
,_
,_
) -> bind (k p
) (minherited name
)
244 | Ast.MetaParamList
(name
,None
,_
,_
) -> bind (k p
) (minherited name
)
245 | Ast.MetaParamList
(name
,Some
(lenname
,_
,_
),_
,_
) ->
246 bind (k p
) (bind (minherited name
) (minherited lenname
))
249 let strictrule_elem recursor k re
=
250 (*within a rule_elem, pattern3 manages the coherence of the bindings*)
251 match Ast.unwrap re
with
252 Ast.MetaRuleElem
(name
,_
,_
) | Ast.MetaStmt
(name
,_
,_
,_
)
253 | Ast.MetaStmtList
(name
,_
,_
) -> bind (k re
) (minherited name
)
256 let strictstatement recursor k s
=
257 match Ast.unwrap s
with
258 Ast.Disj
(stms
) -> option_default
261 V.combiner
bind option_default
262 mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode
263 donothing donothing donothing donothing
264 strictident strictexpr strictfullType stricttypeC donothing strictparam
265 strictdecls strictrule_elem strictstatement donothing donothing donothing
267 (* ------------------------------------------------------------------------ *)
269 let rec dependent = function
271 | Ast.AntiDep s
-> false
272 | Ast.EverDep s
-> true
273 | Ast.NeverDep s
-> false
274 | Ast.AndDep
(d1
,d2
) -> dependent d1
or dependent d2
275 | Ast.OrDep
(d1
,d2
) -> dependent d1
&& dependent d2
277 | Ast.FailDep
-> true
279 (* ------------------------------------------------------------------------ *)
281 let rule_fn tls in_plus
=
283 (function (rest_info
,in_plus
) ->
285 let mfn = get_minus_constants keep_some_bind or_bind in
286 let minuses = mfn.V.combiner_top_level cur
in
289 then [] (* nothing removed for sgrep *)
290 else get_all_minus_constants.V.combiner_top_level cur
in
291 let plusses = get_plus_constants.V.combiner_top_level cur
in
292 (* the following is for eg -foo(2) +foo(x) then in another rule
293 -foo(10); don't want to consider that foo is guaranteed to be
294 created by the rule. not sure this works completely: what if foo is
295 in both - and +, but in an or, so the cases aren't related?
296 not sure this whole thing is a good idea. how do we know that
297 something that is only in plus is really freshly created? *)
298 let plusses = Common.minus_set
plusses all_minuses in
299 let new_minuses = Common.minus_set
minuses in_plus
in
300 let new_plusses = Common.union_set
plusses in_plus
in
301 (Common.union_set
new_minuses rest_info
, new_plusses))
306 let get_constants rules
=
310 (function (rest_info
,in_plus
) ->
313 Ast.ScriptRule
(_
,_
,_
,_
)
314 | Ast.InitialScriptRule
(_
,_
,_
) | Ast.FinalScriptRule
(_
,_
,_
) ->
316 | Ast.CocciRule
(nm
, (dep
,_
,_
), cur
, _
, _
) ->
317 let (cur_info
,cur_plus
) = rule_fn cur in_plus
in
319 (* no dependencies if dependent on another rule; then we
320 need to find the constants of that rule *)
322 List.for_all
(check_inherited nm
).V.combiner_top_level cur
325 if cur_info = [] then raise No_info
else cur_info in
326 (Common.union_set
[cur_info] rest_info
,cur_plus
))
329 with No_info
-> List.map
(function _
-> []) rules