[cfe-dev] How to write a matcher?

Richard legalize at xmission.com
Thu Mar 13 15:32:09 PDT 2014


My apologies to Stephen for not noticing that he was already doing
what I was suggesting (starting with remove-cstr-calls and modifying).

In article <lfmm58$e8i$1 at ger.gmane.org>,
    Stephen Kelly <steveire at gmail.com> writes:

> From the -ast-dump, it looks like I need to first match a 
> CXXOperatorCallExpr, so I write this matcher:
> 
>   Finder.addMatcher(
>       id("match", operatorCallExpr()),
>       &Callback);
> 
> which gives me lots of output, mostly from the iostream header. I need to 
> get narrower.

In my "remove-void-arg" example, I did an extra check to see if
something was declared extern "C", because we don't want to change

    extern "C" {
        int foo(void);
    }

into

    extern "C" {
        int foo();
    }

I'm pretty sure I'd run into the same problem as Stephen once my test
inputs were broadened from simple cases to real-world code.

I think this is a general problem -- namely that when you include header
files, either from the standard library or third party libraries, your
refactoring tool can match all kinds of code that is in their headers.

The Visual Assist X add-on for Visual Studio has a way of specifying a
directory hierarchy of "stable" includes that it ignores for various
operations, including refactoring operations.  By default, it puts all
the Visual Studio headers in this stable list.

I was thinking that a simple filter would be to look at the file
associated with the source location of the match and if that file
isn't one of the translation units mentioned in the compilation
database, then we would discount the match.  This works well for .cpp
files, but obviously misses header files.

It sounds like it would be useful to have an AST matcher that provided
this sort of filtering so you could just include it as an additional
predicate in your matcher and not have to repeat the work of filtering
out "uninteresting" source locations.

I looked on the matchers page and didn't seem to see any matchers that
filter based on the file origin of a node in the AST.

> In the -ast-dump output there is a CXXMemberCallExpr nested in the 
> CXXOperatorCallExpr. I make a logical jump at matching that:
> 
>   Finder.addMatcher(
>       id("match", operatorCallExpr(memberCallExpr())),
>       &Callback);
> 
> However, that produces no output, so my logical jump must be incorrect.

I think the reason you didn't get a match here is that the structure is:

CXXOperatorCallExpr
|-ImplicitCastExpr
|-DeclRefExpr
|-CXXOperatorCallExpr
| |-CXXMemberCallExpr

<http://clang.llvm.org/docs/LibASTMatchersReference.html> says that
operatorCallExpr expects a Matcher<CXXOperatorCallExpr> argument, but
you supplied memberCallExpr() which returns type Matcher<Stmt>.

operatorCallExpr() could take hasOverloadedOperatorName() in order to
narrow it to the specific operator.

I think then you need to narrow it further based on the arguments to
the operator.

I would have to verify this hypothesis by reproducing your experiment,
but perhaps another list reader with more experience can confirm my
hypothesis.

> How does one go about *actually* writing matcher code? 

I did something similar to what you did, but I think this process
still has some bumps in the road and could be made easier still.

The first bump I'm trying to help iron out is that the pre-built
packages don't have everything you need to build refactoring tools.

(aside: this made me laugh:
StringLiteral 0x275cc88 <col:17> 'const char [4]' lvalue "wtf")
-- 
"The Direct3D Graphics Pipeline" free book <http://tinyurl.com/d3d-pipeline>
     The Computer Graphics Museum <http://ComputerGraphicsMuseum.org>
         The Terminals Wiki <http://terminals.classiccmp.org>
  Legalize Adulthood! (my blog) <http://LegalizeAdulthood.wordpress.com>



More information about the cfe-dev mailing list