On Sun, Jun 13, 2010 at 09:43:42PM +0200, Julia Lawall wrote:
> On Sun, 13 Jun 2010, Josh Triplett wrote:
> > I've just started trying to use Coccinelle to rewrite code written for
> > Xlib to use our replacement library XCB instead.
> > 
> > In trying some simple test patches and learning Coccinelle, I
> > encountered this error:
> > 
> > """
> > HANDLING: /tmp/bug.c
> > 
> > previous modification:
> > MINUS
> >   >>> xcb_disconnect(conn);
> > 
> > According to environment 0:
> > 
> > 
> > current modification:
> > MINUS
> > According to environment 0:
> > 
> > 
> > Fatal error: exception Failure("rule starting on line 1: already tagged 
> > token:
> > C code context
> > File "/tmp/bug.c", line 5, column 1,  charpos = 45
> >     around = 'XCloseDisplay', whole content =   XCloseDisplay (dpy);")
> > """
> 
> In general, what the error means is that it found two different things to 
> do for a token in the source program; once to remove it and add something 
> and another time just to remove it.
> 
> > I reduced the semantic patch and the source file to minimal test cases.
> > The semantic patch:
> > 
> > @@
> > identifier dpy;
> > @@
> > (
> > -if (dpy) { XCloseDisplay(dpy); }
> > +xcb_disconnect(conn);
> > |
> > -XCloseDisplay(dpy);
> > +xcb_disconnect(conn);
> > )
> 
> First point: if (dpy) { XCloseDisplay(dpy); } is also considered to match 
> if (dpy) XCloseDisplay(dpy); by an isomorphism.

Hmmm.  Does the reverse hold true as well?  If I write "if (dpy)
XCloseDisplay(dpy);" it doesn't seem to match "if (dpy) {
XCloseDisplay(dpy); }".

> Then, the basic idea of ( | ) is that it works from top to bottom; if the 
> first branch matches the second one should not be applied.  But the more 
> precise semantics is that this is what happens at the node level.  If you 
> look at the control-flow graph for your source program, which you can see 
> with the option -control_flow and just the name of the C file, you will 
> see that the header of an if statement and the branch are different nodes.
> 
> Since the root node matched by the if (dpy) XCloseDisplay(dpy); pattern is 
> different fro the root node matched by the XCloseDisplay(dpy); pattern, 
> they are just considered to be disjoint matches, and the top to bottom 
> semantics of ( | ) doesn't help.  Thus there are two possible and 
> conflicting matches.

Ah, I see!  That explains it.

> The solution is to separate the semantic patch into two rules, with the 
> first rule taking care of the if case and the second rule taking care of 
> any calls to XCloseDisplay(dpy); that are left over.

I'll remember that for the next time I encounter this situation.
As it turned out, I couldn't eliminate the if as I thought I could, so I
ended up with this rule, which worked:

@@
Display *dpy;
@@
(
-if (dpy) { XCloseDisplay(dpy); }
+if (conn) xcb_disconnect(conn);
|
 if (
-    !dpy
+    xcb_connection_has_error(conn)
    ) { ... }
)


As mentioned above, it seems that I have to write this rule with the
braces around XCloseDisplay, or it won't match when the if has braces.
The isomorphism does work in the other direction, though; this rule
matches cases *without* braces.


Thanks for the quick response!  I've had good luck with automated
translation of Xlib code to XCB code so far.  I'll write back if I run
into anything else I can't seem to express as a semantic patch, since I
strongly suspect it would indicate a limitation of my understanding
rather than of Coccinelle's functionality. :)

- Josh Triplett
_______________________________________________
Cocci mailing list
[email protected]
http://lists.diku.dk/mailman/listinfo/cocci
(Web access from inside DIKUs LAN only)

Reply via email to