[cfe-dev] ASTMatchers: isVirtual and isOverride

Manuel Klimek klimek at google.com
Wed Apr 24 08:18:46 PDT 2013


On Wed, Apr 24, 2013 at 12:49 PM, Pedro Delgado Perez <
pedro.delgadoperez at mail.uca.es> wrote:

>  What I usually do is: in the callback, take the source location of the
> node, look at the file name, and do a regexp on the file to determine
> whether you want to examine the node or not.
>
> Well, but imagine that you have a .cpp with the definition of the methods
> of 3 classes, for example, and you only want to match nodes of that 3
> classes (definitions and declarations). Then, you know each class has its
> declaration in one/some of the header files included, but you don't know a
> priori where they are (normally, each class has a .h file with the same
> name as the class, but this is not always this way, so regular expressions
> don't fit this case). However, you may have some other header files with
> other classes that you don't want to match. How can I manage this? I know
> this is maybe a "extreme" case, but I think it's important to me. This is
> why I insist.
>
>
> What you can do, as Manuel suggested, is to perform the check in the
> callback. The SourceManager classs has various methods that are available
> for you to figure out where exactly a given SourceLocation is, and we've
> already mentioned several of them. I suggest you read through the
> documentation to find out what's the best way to do what you're trying to
> do.
>
> Um, maybe I could firstly look for the classes' names in the main file and
> then look for the location of their declarations so I was able to know
> which of the header files interest to me. Or do you think this is a though
> job?
>
> The functionDecl() matcher in itself will match any FunctionDecl nodes,
> regardless of whether it is a definition or only a declaration. In
> addition, there is a method called FunctionDecl :: isDefinition, which also
> gives you the FunctionDecl object that represents the definition belonging
> to the current declaration.
> Now I think the simplest solution would be to create a matcher for this,
> that would allow you to express constraints on the actual definition of the
> function, and then you'd be able to modify your existing matcher expression
> to accommodate for this.
>
> I can't find FunctionDecl :: isDefinition, but isDefined or TagTypeLoc::
> isDefinition (I suppose you refer to this latter) , but these methods don't
> give you the object that represents the definition belonging to the current
> declaration, just tell you if they are defitions as well, am I right?
>
> If you are sure that all declarations of the constructor will be visible
> where it is implemented, you can match for the non-trivial default
> constructor, and then go backwards to all the decls you see from that TU.
> If this is not true in your case (which in this example shouldn't happen,
> I think), you can always output:
> a) for all destructors, all declarations / definitions
> b) for all non-trivial destructors, the fact that they're non-trivial
> Then you merge this information in a post-processing step. Things like
> this are quite common, which is why we've put together a MapReduce pipeline
> to support that kind of operation at a large scale, but for smaller code
> bases you can do something with a simple text format
>
> Sorry, but I can't follow you here. I'm not able to understand your
> explanation.
>
This is not really an explanation, but a follow-up to your real case: if
you want to delete only non-trivial methods, aren't all methods
automatically non-trivial once they're user-defined?

Cheers,
/Manuel


> Regards,
>
> Pedro.
> *El dia 24 abr 2013 11:14, Gábor Kozár <kozargabor at gmail.com> escribió:*
>
> Hi,
> > *And I only want to retrieve nodes inside class A (in A.h and A.cpp),
> but not inside B.h because I'm not interested in this class. How can I
> avoid this?*
> *
> *
> This is something you can't express with matchers, as you can only run
> them on AST nodes, and there is no AST node to represent header files
> (there is only TranslationUnitDecl, but that represents a whole translation
> unit, i.e. a cpp file with all included files).*
> *
> What you can do, as Manuel suggested, is to perform the check in the
> callback. The SourceManager classs has various methods that are available
> for you to figure out where exactly a given SourceLocation is, and we've
> already mentioned several of them. I suggest you read through the
> documentation to find out what's the best way to do what you're trying to
> do.
> > *We have considered 1 and 2, but not 3 nor 4. Imagine that we have the
> case 3 and I want to delete the constructor both in A.h(declaration) and
> A.cpp(definition). Do I have to prepare two different matchers to look for
> them? Or is there a way that, for example, I find the definition and then I
> can refer its declaration? Of course, I need to make sure that both,
> definition and declaration are deleted.*
> *
> *
> The functionDecl() matcher in itself will match any FunctionDecl nodes,
> regardless of whether it is a definition or only a declaration. In
> addition, there is a method called FunctionDecl :: isDefinition, which also
> gives you the FunctionDecl object that represents the definition belonging
> to the current declaration.
> Now I think the simplest solution would be to create a matcher for this,
> that would allow you to express constraints on the actual definition of the
> function, and then you'd be able to modify your existing matcher expression
> to accommodate for this.
> Gabor
>
>
> 2013/4/24 Pedro Delgado Perez <pedro.delgadoperez at mail.uca.es>
>
>> Hi,
>>
>> Thank you for all your explanations, now everything is much clearer. But,
>> please, let me ask you another last question regarding:
>>
>>
>> *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.
>>
>> Ok, I see that i can exclude all the system headers, but imagine the next
>> cpp:
>>
>> #include "A.h"
>> #include "B.h"
>>
>> A::A() {
>> ... ...
>> }
>>
>> int A::m() {
>> B b;  //B.h header has been included because it's needed in a member
>> function of A
>> ... ...
>> }
>>
>> ... ...
>>
>> And I only want to retrieve nodes inside class A (in A.h and A.cpp), but
>> not inside B.h because I'm not interested in this class. How can I avoid
>> this?
>>
>> In addition, in the matcher we've working on, we looked for default
>> constructors declarations defined inline. But several options more were
>> possible:
>>
>> 1. I have both declaration and definition inline in A.h
>> 2. I have both declaration and definition inline in A.cpp
>> 3. I have declaration in A.h and definition in A.cpp (the example above)
>> 4. I have declaration and definition (but not inline) in A.cpp
>>
>> We have considered 1 and 2, but not 3 nor 4. Imagine that we have the
>> case 3 and I want to delete the constructor both in A.h(declaration) and
>> A.cpp(definition). Do I have to prepare two different matchers to look for
>> them? Or is there a way that, for example, I find the definition and then I
>> can refer its declaration? Of course, I need to make sure that both,
>> definition and declaration are deleted.
>>
>> I hope you know what I mean.
>>
>> Thanks for everything Gábor,
>>
>> Pedro.
>>
>>
>>
>>
>> *El dia 22 abr 2013 21:52, Gábor Kozár <kozargabor at 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<T>. 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<FunctionDecl>("f")* and *
>> result.Nodes.getNodeAs<CompoundStmt>("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
>>
>>
>> 2013/4/21 Pedro Delgado Perez <pedro.delgadoperez at mail.uca.es>
>>
>>> 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 ;)
>>>
>>> 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 at gmail.com> escribió:*
>>>
>>> Hi,
>>> > *The default constructor of C is also matched as there is an implicit
>>> call to the default constructor of class A (and effectively, this is an
>>> expression and not a declaration as I said in the last message). So, I've
>>> been thinking about it and, though I don't have the solution, I'm quite
>>> sure we have to change "anything()" inside "hasAnyConstructorInitializer()"
>>> to avoid this exception. Any suggestion?*
>>> *
>>> *
>>> 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.*
>>> *
>>> 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.
>>> > *On the other hand, I've been trying to use the methods you told me,
>>> but I have to use those methods after the matcher execution, haven't I?
>>> This is a bit inefficiently as the mathcer is looking up in some files that
>>> are not needed.*
>>> *
>>> *
>>> 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.
>>> *
>>> *
>>> *> 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.
>>> > *Umm... What a strange thing... I will get over this one more time
>>> and see if I did something wrong.
>>> Maybe something is missing or is different in AStMatchersInternal or
>>> ASTMatchersMacros.*
>>> 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).*
>>> *
>>> Good luck!
>>> Gabor
>>>
>>>
>>> 2013/4/21 Pedro Delgado Perez <pedro.delgadoperez at mail.uca.es>
>>>
>>>> Hi and thanks again,
>>>>
>>>> I clearly expressed incorretly the problem. I'll try to explain it more
>>>> in detail:
>>>>
>>>> If we have the classes below:
>>>>
>>>> class A{
>>>>     public: A(){}
>>>> };
>>>>
>>>> class B: public A{
>>>>     public: int b, h;
>>>>         B():A(){b=0; h=0;}
>>>> };
>>>>
>>>> class C: public A{
>>>>     public C(){}
>>>> };
>>>>
>>>> I want my matcher retrieves ONLY the default constructor declaration of
>>>> B. However this is what happened with the matcher you proposed me:
>>>>
>>>> CXXConstructorDecl 0xa1f6080
>>>> </home/pedro/clang-llvm/build/testClases.cpp:14:3, col:25> B 'void (void)'
>>>> |-CXXCtorInitializer 'class A'
>>>> | |-CXXConstructExpr 0xa1f6608 <col:8, col:10> 'class A' 'void (void)'
>>>> `-CompoundStmt 0xa1f6710 <col:11, col:25>
>>>>   |-BinaryOperator 0xa1f6698 <col:12, col:16> 'int' lvalue '='
>>>>   | |-MemberExpr 0xa1f6660 <col:12> 'int' lvalue ->b 0xa1f6100
>>>>   | | `-CXXThisExpr 0xa1f6650 <col:12> 'class B *' this
>>>>   | `-IntegerLiteral 0xa1f6680 <col:16> 'int' 0
>>>>   `-BinaryOperator 0xa1f66f8 <col:19, col:23> 'int' lvalue '='
>>>>     |-MemberExpr 0xa1f66c0 <col:19> 'int' lvalue ->h 0xa1f6140
>>>>     | `-CXXThisExpr 0xa1f66b0 <col:19> 'class B *' this
>>>>     `-IntegerLiteral 0xa1f66e0 <col:23> 'int' 0
>>>> Found declaration at 14:3
>>>> CXXConstructorDecl 0xa1f68b0
>>>> </home/pedro/clang-llvm/build/testClases.cpp:25:3, col:7> C 'void (void)'
>>>> |-CXXCtorInitializer 'class A'
>>>> | |-CXXConstructExpr 0xa1f6c08 <col:3> 'class A' 'void (void)'
>>>> `-CompoundStmt 0xa1f6c58 <col:6, col:7>
>>>> Found declaration at 25:3
>>>>
>>>> The default constructor of C is also matched as there is an implicit
>>>> call to the default constructor of class A (and effectively, this is an
>>>> expression and not a declaration as I said in the last message). So, I've
>>>> been thinking about it and, though I don't have the solution, I'm quite
>>>> sure we have to change "anything()" inside "hasAnyConstructorInitializer()"
>>>> to avoid this exception. Any suggestion?
>>>>
>>>>
>>>> On the other hand, I've been trying to use the methods you told me, but
>>>> I have to use those methods after the matcher execution, haven't I? This is
>>>> a bit inefficiently as the mathcer is looking up in some files that are not
>>>> needed. Is it possible to search for nodes only in some files indicated by
>>>> the user? Normally, a class is declared in a .h file and defined in the
>>>> .cpp file and i would like to search in both of them.
>>>> I have seen that every file has "id" and, for instance, instead of
>>>> using "isInSystemHeader" and "isInExternCSystemHeader" could i do the next?:
>>>>
>>>> class DefaultConstructor : public MatchFinder::MatchCallback {
>>>> public :
>>>>   virtual void run(const MatchFinder::MatchResult &Result) {
>>>>   ASTContext *Context = Result.Context;
>>>>   FileID mainFileID = Context->getSourceManager.getMainFileID();
>>>>   if (const CXXConstructorDecl *FS =
>>>> Result.Nodes.getNodeAs<clang::CXXConstructorDecl>("methods")){
>>>>       FullSourceLoc FullLocation =
>>>> Context->getFullLoc(FS->getLocStart());
>>>>       if (FullLocation.isValid() && FullLocation.getFileID() ==
>>>> mainFileID)
>>>>         ... ...
>>>>     }
>>>>   }
>>>> };
>>>>
>>>> ( I got an error with this: reference to non-static member function
>>>> must be called
>>>>   FileID mainFileID = (Context->getSourceManager).getMainFileID();
>>>>                       ^~~~~~~~~~~~~~~~~~~~~~~~~~~ )
>>>>
>>>> > *Thank you for your time Gábor. I have put this, but I don't know
>>>> why it doesn't fetch any nodes at all... Could you test this?
>>>>
>>>> *
>>>> I did test it, and worked fine for me. Not sure what could be the issue.
>>>>
>>>> Umm... What a strange thing... I will get over this one more time and
>>>> see if I did something wrong.
>>>> Maybe something is missing or is different in AStMatchersInternal or
>>>> ASTMatchersMacros.
>>>>
>>>> Thanks,
>>>>
>>>> Pedro.
>>>>
>>>> *El dia 19 abr 2013 16:28, Gábor Kozár <kozargabor at gmail.com> escribió:
>>>> *
>>>>
>>>> Hi,
>>>>
>>>> > *Thank you for your time Gábor. I have put this, but I don't know
>>>> why it doesn't fetch any nodes at all... Could you test this?
>>>>
>>>> *
>>>>
>>>> I did test it, and worked fine for me. Not sure what could be the issue.
>>>>
>>>> > *An implicit node is detected: the default constructor of class A in
>>>> the list of constructors in default constructor of class B. So, I tried to
>>>> fix this doing  this:*
>>>>
>>>> I believe this is what you need then, as Manuel suggested:
>>>>
>>>> constructorDecl(isDefinition(), parameterCountIs(0),
>>>> unless(isImplicit()),
>>>>         anyOf(hasAnyConstructorInitializer(anything()),
>>>> has(compoundStmt(has(stmt())))));
>>>> How you compose your matchers dictate how they will behave. Lets take a
>>>> simple example: functionDecl(isDefinition()). Here the fact that
>>>> isDefinition() was given as a parameter to functionDecl() indicates that it
>>>> refines that matcher, i.e. imposes further conditions that have to be met
>>>> in order for a node to be matched.
>>>> Now with this logic, lets look at what you tried:
>>>> withInitializer(constructorDecl(isImplicit()))
>>>>
>>>> This means something like "an initializer that is an implicit
>>>> constructor declaration" - which obviously makes no sense, and thanks to
>>>> template voodoo magic, it doesn't compile either. The reason is that
>>>> withInitializer expects a Matcher<Expr>, that is, a matcher that matches
>>>> certain Exprs (that meet a certain criteria). constructorDecl() yields a
>>>> Matcher<CXXConstructorDecl>, because it is a matcher that accepts
>>>> CXXConstructorDecl objects.
>>>>
>>>> > *In addition, I would like to work only with the code that is
>>>> explicit and for example when I try to match "methodDecl(isOverride())" a
>>>> lot of implicit methods  (and even methods from other files apart of
>>>> mine) are detected with this matcher. How can I avoid this?*
>>>>
>>>> I'm not sure what you mean by "implicit" methods here. Obviously you'll
>>>> get matches in header files as well, most notably, system header files.
>>>> SourceManager::isInSystemHeader and isInExternCSystemHeader is what you're
>>>> looking for if you want to avoid that - you'll place such a check in your
>>>> matcher callback function.
>>>>
>>>> Gabor
>>>>
>>>>
>>>> 2013/4/19 Pedro Delgado Perez <pedro.delgadoperez at mail.uca.es>
>>>>
>>>>> Thank you ver much both of you, it really helps:
>>>>>
>>>>> All of the ways you cite make sense. What you want really depends on
>>>>> what kind of control you want. Note that you can always easily start with
>>>>> AST matchers to find higher level things you're interested in, and then
>>>>> drill down through the AST nodes by calling the methods or even by using a
>>>>> RecursiveASTVisitor on a node...
>>>>>
>>>>>  Ok, Manuel. I need to study this a bit more to catch on the best way
>>>>> for me, but it's good to know I can merge both strategies.
>>>>>
>>>>> I have put together quickly the matcher that I believe suits your
>>>>> needs, just so that you can see how it works:
>>>>>
>>>>> namespace clang {
>>>>> namespace ast_matchers {
>>>>>
>>>>> using namespace clang::ast_matchers::internal;
>>>>>
>>>>> AST_MATCHER(CXXConstructorDecl, defaultNonTrivialCtor)
>>>>> {
>>>>>     return Node.isThisDeclarationADefinition()
>>>>>         && Node.isDefaultConstructor()
>>>>>         && (Node.getNumCtorInitializers() != 0 ||
>>>>> !Node.hasTrivialBody());
>>>>> }
>>>>>
>>>>> } // ast_matchers
>>>>> } // clang
>>>>>
>>>>> (Don't forget to include ASTMatchers.h, ASTMatchersInternal.h and
>>>>> ASTMatchersMacros.h)
>>>>>
>>>>> Thank you for your time Gábor. I have put this, but I don't know why
>>>>> it doesn't fetch any nodes at all... Could you test this?
>>>>>
>>>>> constructorDecl(isDefinition(), parameterCountIs(0),
>>>>>         anyOf(hasAnyConstructorInitializer(anything()),
>>>>> has(compoundStmt(has(stmt())))));
>>>>> (I did a quick test, and seems to work as intended, but you should
>>>>> make sure to test it thoroughly yourself.)
>>>>>
>>>>> I have put this as well and this time does it works, but indeed it
>>>>> needs something more, because if we have:
>>>>>
>>>>> class A{
>>>>> public:
>>>>> A(){}
>>>>> ...
>>>>> };
>>>>>
>>>>> class B: public A{
>>>>> public:
>>>>> B(){}
>>>>> ...
>>>>> };
>>>>>
>>>>> An implicit node is detected: the default constructor of class A in
>>>>> the list of constructors in default constructor of class B. So, I tried to
>>>>> fix this doing  this:
>>>>>
>>>>> constructorDecl(isDefinition(), parameterCountIs(0),
>>>>>         anyOf(hasAnyConstructorInitializer(*
>>>>> unless(withInitializer(constructorDecl(isImplicit())))*)),
>>>>> has(compoundStmt(has(stmt())))));
>>>>>
>>>>> But, I newbie in this and it doesn't work as constructorDecl returns a
>>>>> Decl and withInitializer a Expr (i think). How could I do this? Sorry for
>>>>> this, but I would like to have at least an example complete.
>>>>>
>>>>> In addition, I would like to work only with the code that is explicit
>>>>> and for example when I try to match "methodDecl(isOverride())" a lot of
>>>>> implicit methods  (and even methods from other files apart of mine)
>>>>> are detected with this matcher. How can I avoid this?
>>>>>
>>>>> Thanks,
>>>>>
>>>>> Pedro.
>>>>> *El dia 19 abr 2013 13:50, Manuel Klimek <klimek at google.com> escribió:
>>>>> *
>>>>>
>>>>> On Fri, Apr 19, 2013 at 12:18 PM, Pedro Delgado Perez <
>>>>> pedro.delgadoperez at mail.uca.es> wrote:
>>>>>
>>>>>> Hi again,
>>>>>>
>>>>>> Well, I've just understood that not all the methods in a class have a
>>>>>> matcher related. For instance, I'm trying to match the default constructor
>>>>>> declaration of a class:
>>>>>>
>>>>>> class Foo {
>>>>>> public:
>>>>>> *Foo(){}*
>>>>>> Foo(int a){... ...}
>>>>>> }
>>>>>>
>>>>>> And in CXXConstructorDecl we have isDefaultConstructor(), but I can't
>>>>>> find an AST_MATCHER to do this. So, I suppose I would have to implement a
>>>>>> new AST_MATCHER like this:
>>>>>>
>>>>>> *AST_MATCHER(CXXConstructorDecl, isDefaultConstructor){*
>>>>>> *return Node.isDefaultConstructor();*
>>>>>> *}*
>>>>>>
>>>>>> Wouldn't it? But, this happens often, so... would you recommend me
>>>>>> use AST_MATCHERS? Or it would be better to do something like it is
>>>>>> explained in http://clang.llvm.org/docs/RAVFrontendAction.html ?
>>>>>> This way, I can directly use the methods in the classes. For instance:
>>>>>>
>>>>>>  bool VisitCXXConstructorDecl(CXXConstructorDecl *Declaration) {    if (Declaration->isDefaultConstructor()) {
>>>>>>
>>>>>> I have to visit a lot of kind of nodes with different features, not
>>>>>> only this.
>>>>>>
>>>>> All of the ways you cite make sense. What you want really depends on
>>>>> what kind of control you want. Note that you can always easily start with
>>>>> AST matchers to find higher level things you're interested in, and then
>>>>> drill down through the AST nodes by calling the methods or even by using a
>>>>> RecursiveASTVisitor on a node...
>>>>> Cheers,
>>>>> /Manuel
>>>>>
>>>>>
>>>>>> Please, I need a path to get down to work.
>>>>>>
>>>>>> Thanks in advance,
>>>>>>
>>>>>> Pedro.
>>>>>>
>>>>>> *El dia 19 abr 2013 01:58, Gábor Kozár <kozargabor at gmail.com>
>>>>>> escribió:*
>>>>>>
>>>>>> Hi,
>>>>>>
>>>>>> What version are you using? The matchers isOverride() and isVirtual()
>>>>>> I know for certain were not in version 3.2, and can only be found on SVN
>>>>>> (in this file:
>>>>>> http://llvm.org/svn/llvm-project/cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h
>>>>>> ).
>>>>>>
>>>>>> Nonetheless, you can implement them all very easily manually, or just
>>>>>> indeed copy their implementation from the link above. Also, instead of
>>>>>> isDefaultConstructor(), you could use argumentCountIs(0).
>>>>>>
>>>>>> Gabor
>>>>>>
>>>>>>
>>>>>> 2013/4/18 Pedro Delgado Perez <pedro.delgadoperez at mail.uca.es>
>>>>>>
>>>>>>> Hi,
>>>>>>>
>>>>>>> I'm newbie using ASTMatchers and I'm trying to learn little by
>>>>>>> little how to use them.
>>>>>>>
>>>>>>> I was basing on the matcher recordDecl(hasName("Foo"), isDerivedFrom("Bar"))
>>>>>>> shown in http://clang.llvm.org/docs/LibASTMatchers.html trying to
>>>>>>> include new features. For instance, I tried to look for classes which have
>>>>>>> at least one virtual method:
>>>>>>>
>>>>>>> recordDecl(hasName("Foo"), isDerivedFrom("Bar"),
>>>>>>> hasMethod(isVirtual()))
>>>>>>>
>>>>>>> Or I tried to match protected overriden methods:
>>>>>>>
>>>>>>> methodDecl(allOf(isProtected(), isOverride());
>>>>>>>
>>>>>>> But neither of them worked as it couldn't find "isOverride" and
>>>>>>> "isVirtual" identifiers. I was trying a lot of combinations, but I can't
>>>>>>> understand this well.
>>>>>>>
>>>>>>> Finally, I tried to look for the the default constructor of a
>>>>>>> certain class:
>>>>>>>
>>>>>>> constructorDecl(hasName("Foo"), isDefaultConstructor())
>>>>>>>
>>>>>>> but this is wrong. What I'm doing bad? Please, any information you
>>>>>>> give me will be fine to me to understand how to use matchers.
>>>>>>>
>>>>>>> Thanks in advance,
>>>>>>>
>>>>>>> Pedro.
>>>>>>>
>>>>>>>
>>>>>>> _______________________________________________
>>>>>>> cfe-dev mailing list
>>>>>>> cfe-dev at cs.uiuc.edu
>>>>>>>
>>>>>> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev
>>>>>>
>>>>>>
>>>>>> _______________________________________________
>>>>>> cfe-dev mailing list
>>>>>> cfe-dev at cs.uiuc.edu
>>>>>>
>>>>> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev
>>>>>
>>>>>
>>>>
>>>
>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-dev/attachments/20130424/2290c7da/attachment.html>


More information about the cfe-dev mailing list