It is possible to iterate Coccinelle, giving the subsequent iterations a different set of virtual rules or virtual identifier bindings. Coccinelle currently supports iteration with both OCaml and Python scripting. An example with OCaml is fond in demos/iteration.cocci, a Python example is found in demos/python_iteration.cocci.
The OCaml scripting iteration example starts as follows.
virtual after_start @initialize:ocaml@ let tbl = Hashtbl.create(100) let add_if_not_present from f file = try let _ = Hashtbl.find tbl (f,file) in () with Not_found -> Hashtbl.add tbl (f,file) file; let it = new iteration() in (match file with Some fl -> it#set_files [fl] | None -> ()); it#add_virtual_rule After_start; it#add_virtual_identifier Err_ptr_function f; it#register()
The respective Python scripting iteration example starts as follows:
virtual after_start @initialize:python@ @@ seen = set() def add_if_not_present (source, f, file): if (f, file) not in seen: seen.add((f, file)) it = Iteration() if file != None: it.set_files([file]) it.add_virtual_rule(after_start) it.add_virtual_identifier(err_ptr_function, f) it.register()
The virtual rule after_start is used to distinguish between the first iteration (in which it is not considered to have matched) and all others. This is done by not mentioning after_start in the command line, but adding it on each iteration.
The main code for performing the iteration is found in the function add_if_not_present, between the lines calling new iteration and register. New iteration creates a structure representing the new iteration. set_files sets the list of files to be considered on the new iteration. If this function is not called, the new iteration treats the same files as the current iteration. add_virtual_rule a has the same effect as putting -D a on the command line. If using OCaml scripting instead of Python scripting the first letter of the rule name is capitalized, although this is not done elsewhere (technically, the rule name is an OCaml constructor). add_virtual_identifier x v has the same effect as putting -D x=v on the command line. Again, when using OCaml scripting there is a case change. extend_virtual_identifiers() (not shown) preserves all virtual identifiers of the current iteration that are not overridden by calls to add_virtual_identifier. Finally, the call to register queues the collected information to trigger a new iteration at some time in the future.
Modification is not allowed when using iteration. Thus, it is required to use the --no-show-diff, unless the semantic patch contains *s (a semantic match rather than a semantic patch).
When using Python scripting a tuple may be used to ensure that the same information is not enqueued more than once. When using OCaml scripting a hash table may be used for the same purpose. Coccinelle itself provides no support for obtaining information about what work has been queued and as such addressing this with scripting is necessary.