[cfe-dev] ASTMatchers: isVirtual and isOverride

Manuel Klimek klimek at google.com
Wed Apr 24 21:38:48 PDT 2013


On Thu, Apr 25, 2013 at 1:51 AM, Gábor Kozár <kozargabor at gmail.com> wrote:

> Hi,
>
>
> > *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?*
>
> Unfortunately, class declarations and class definitions (including method
> definitions) can be anywhere, regardless of whether that file is a header
> file or not (e.g. when templates are considered, or when a class is
> considered an implementation detail, etc.). Also unless you're working in a
> very anti-oop environment, I think it is a safe bet that all files will
> usually contain classes - or if not, then they are very small, and don't
> have a considerable impact on performance. So I think you can't do much
> better than filtering out only the system header files.
>
> > *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?*
>
> Sorry, what I meant was FunctionDecl :: isDefined (
> http://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html#a4a68908ca34bfedaaf8b0a80d865f54f
> ).
>
>
> > *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.
>
> *
> I think what Manuel means - and which is a very good point by the way - is
> that it's possible that a class or method was declared multiple times,
> because C++ allows this. (Of course, it still needs to have at most one
> definition.) You can handle this by going through the declaration chain
> using FunctionDecl :: getPreviousDecl (
> http://clang.llvm.org/doxygen/classclang_1_1Redeclarable.html#ae865b5549d99099ecb62d8b3a104f033
> ).
>
> Otherwise, in less well-behaving cases (which is usually what you want to
> be prepared for) you might need to perform the work in two steps: first,
> gather all constructor declarations (ideally some kind map, where the key
> is a constructor definition, and the value is a list of declarations
> belonging to that definition) that are potentially of interest to you, and
> in the second step iterate through the gathered declarations, and you
> should be able to make the final decision based on that collected data
> (since you'll have all definitions and declarations gathered).
>

That's pretty much what I meant (but was unable to explain well enough :),
apart from that I'd also build up a map where the key is the constructor
definition and the value is "is this interesting".


> (Sorry for going over your head, Manuel!)
>

Never worry about that! :) My head is very small ...

And btw thanks a lot for all the great user support you're giving here!

Cheers,
/Manuel


>
> Gabor
>
>
> 2013/4/24 Pedro Delgado Perez <pedro.delgadoperez at mail.uca.es>
>
>>  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.
>>
>> 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/20130425/bb9518aa/attachment.html>


More information about the cfe-dev mailing list