ASTMatchers: isVirtual and isOverride

Hi,

This is indeed something I haven’t considered, but should be easy to fix. Looking at the documentation for CXXCtorInitializer, you’ll see that there’s a member called isBaseInitializer(). The other thing you’ll need to check (probably, if that is what you need) for is whether the base ctor call is implicit, which is probably done best by constraining the CXXConstructExpr with argumentCountIs(0). Putting together a custom matcher using these should be simple.

I found isWritten() member for CXXCtorInitializer:
“Returns true if this initializer is explicitly written in the source code.”
And finally, I accomplished what I wanted. Now, only B constructor is matched in:

class A{
public: A(){}
};

class B: public A{
public: int b, h;
B():A(){b=0; h=0;}
};

class C: public A{
public C(){}
};

But thanks for the members you have indicated: i’m sure I’ll have to use them in the future.

Also keep in mind that if you put together a generic and useful enough matcher, you should totally contribute it as a patch, so that others in need of a similar thing have it available in the future.

Ok. But I don’t know where I should put or send these matchers to share them. Could you indicate me?

Yes, you need to use these in the matcher callback. It is indeed inefficient, but we’ve been unable to come up with any better solution. The problem is in the underlying compiler technology, i.e. the nature of header files.

Is it possible to search for nodes only in some files indicated by the user?

Sure, take a look at the clang::ast_matchers::match functions - they allow you to run a matcher on the specified node, not the whole AST. Unfortunately I do not think this will help you in this case, as you cannot distinguish the parts of the TU coming from system header files and the parts coming from user files at the AST level.

Ok, that’s a setback i should have in mind. When you say “they allow you to run a matcher on the specified node, not the whole AST.” you mean something like this?:

Result.Nodes.getNodeAs<clang::ForStmt>("forLoop"))

This is the way I retrieve the nodes I need to match at this moment.

The problem for me is that I’ll have to make some source-to-source translations: sometimes I’ll have to modify the .cpp file and sometimes the .h (or even both of them) For instance, if i want to know if a certain method is declared as “virtual”, I would need to examinate the .h file. Thus, I cannot exclude all .h files. So, how can I manage this?

> I have seen that every file has “id” and, for instance, instead of using “isInSystemHeader” and “isInExternCSystemHeader” could i do the next?:

I’m not sure I understand what you’re trying to do here… As the error you’re getting, it’s because getSourceManager is missing the paranthesis, i.e. the () that would indicate it’s a method call.

What I was trying to do is to examinate the nodes only from the file provided by the user in the execution (for instance, if I run bin/default-constructor test.cpp, I only want the nodes from test.cpp) I tought that with member getMainFileID() I would achieve what I wanted, but this isn’t working as expected (sorry for the error of getSourceManager(), but I tested it really quick and late only to write the message). I have also tried with:
if (!Context->getSourceManager().isInSystemHeader(FullLocation) && ! Context->getSourceManager().isInExternCSystemHeader(FullLocation)){

}

but it is still matching nodes in other files, such as ostream, bits/basic_ios.h or bits/streambuf_interator.h because I included the iostream header. I need to avoid all these nodes, but I don’t know how to do it.

Yes, that’s quite possible, as I’m using clang 3.2. Nonetheless, you should be able to figure out what the issue is, as I’ve given you a draft (a pattern, if you will).

Ok. I’m going to check this like you taugth me :wink:

And a last question if you don’t mind. I based my examples for the moment in the matcher shown in:
http://clang.llvm.org/docs/LibASTMatchersTutorial.html
But you told me that it’s possible to merge the usage of Matchers and RecursiveASTVisitor as in:
http://clang.llvm.org/docs/RAVFrontendAction.html
I see that I can retrieve some nodes using matchers and then use a RecursiveASTVisitor on that nodes, but I can’t clearly see the contrary: if I’m visiting only a kind of node, I know that I can directly use the methods of that class, but how could I use a matcher in the same way as in the example below?:

virtual void run(const MatchFinder::MatchResult &Result) {    if (const ForStmt *FS = Result.Nodes.getNodeAs<clang::ForStmt>("forLoop"))      FS->dump();  }

I hope you can understand what I mean.

Thank you for all your help,

Pedro

El dia 21 abr 2013 01:43, Gábor Kozár kozargabor@gmail.com escribió:

Hi,

I found isWritten() member for CXXCtorInitializer:

Nice find, I actually did not know about this.

Ok. But I don’t know where I should put or send these matchers to share them. Could you indicate me?

In the source code, the place for these is ASTMatchers.h. When you have something that you would like to propose to be integrated into the clang repository, I think what you need to do is send an e-mail to this mailing list, with the diff attached (that shows what changes you made), and ask for it to reviewed. But you probably should look at the website and see if there’s any guideline for this - or just ask it on the mailing list.

When you say “they allow you to run a matcher on the specified node, not the whole AST.” you mean something like this?:

The code snippet you sent shows how to retrieve a node that has been accepted and bound by a matcher.

What I mean is that if you have a CXXRecordDecl* object for example (from whatever source), and you want to find some nodes in it that match a specific condition - for example, you want to check if another type is used anywhere within this specific C++ class - you can use clang::ast_matchers::match, because you only need the nodes that satisfy this condition inside the record declaration that you have, and not anywhere in the AST.
To be honest I’m not sure what causes the confusion here, I think this is fairly self-explanatory.

The problem for me is that I’ll have to make some source-to-source translations: sometimes I’ll have to modify the .cpp file and sometimes the .h (or even both of them) For instance, if i want to know if a certain method is declared as “virtual”, I would need to examinate the .h file. Thus, I cannot exclude all .h files. So, how can I manage this?

Well, you exclude just the system header files in the match callback, as I’ve showed before, using SourceManager :: isInSystemHeader and isInExternCSystemHeader.

but it is still matching nodes in other files, such as ostream, bits/basic_ios.h or bits/streambuf_interator.h because I included the iostream header. I need to avoid all these nodes, but I don’t know how to do it.

You’ll need to show me some more code than that. How does your match callback function look like? What is FullLocation?

I see that I can retrieve some nodes using matchers and then use a RecursiveASTVisitor on that nodes, but I can’t clearly see the contrary: if I’m visiting only a kind of node, I know that I can directly use the methods of that class, but how could I use a matcher in the same way as in the example below?:

Both RecursiveASTVisitor and the matchers serve the exact same purpose, and they work in exactly the same way (in fact, the matchers use RecursiveASTVisitor internally) - the only different is that matchers are higher-level concepts, allowing for a more intuitive definition of match conditions. It’s like a regular expression for ASTs.

When you work with matchers, you need two things: a matcher expression, constructed from the matcher functions like functionDecl(), isDefinition(), has(), allOf(), etc. and a match callback, i.e. a function that will be called for every AST node the matcher accepts while it is traversing the AST (i.e. running). You can use the .bind() method of the matchers to bind nodes accepted by the specified matcher to a name, and later retrieve it in the callback using result.Nodes.getNodeAs. For example: functionDecl(has(compoundStmt().bind(“c”))).bind(“f”). When this matcher expression accepts an AST node, and runs the callback, you can access the matched FunctionDecl and CompoundStmt nodes by result.Nodes.getNodeAs(“f”) and result.Nodes.getNodeAs(“c”), respectively. What you with these afterwards is up to you - if you want, you can even run another matcher on them using clang::ast_matchers::match, as I’ve already explained above.

In your example code, the matcher callback retrieves a bound node (a ForStmt) with the name of “forLoop”, and then writes its AST to the console. For example you can use with this matcher expression: forStmt(unless(has(compoundStmt()))), which will cause the AST of all for loops whose body is just a single statement with the {} brackets to appear on the screen.

Gabor

Hi,

> *I found isWritten() member for CXXCtorInitializer:*

Nice find, I actually did not know about this.*
*

> *Ok. But I don't know where I should put or send these matchers to
share them. Could you indicate me?*
*
*
In the source code, the place for these is ASTMatchers.h. When you have
something that you would like to propose to be integrated into the clang
repository, I think what you need to do is send an e-mail to this mailing
list, with the diff attached (that shows what changes you made), and ask
for it to reviewed. But you probably should look at the website and see if
there's any guideline for this - or just ask it on the mailing list.

Just FYI: yes, this is generally the process - I'd also highly appreciate
using phabricator for those patches (Code Reviews with Phabricator — LLVM 18.0.0git documentation)
:slight_smile:

Cheers,
/Manuel