[cfe-dev] ASTMatchers: isVirtual and isOverride

Gábor Kozár kozargabor at gmail.com
Sat Apr 20 16:43:31 PDT 2013


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/20130421/39427f6c/attachment.html>


More information about the cfe-dev mailing list