ASTMatchers: isVirtual and isOverride

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@google.com escribió:

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.

Yes, withInitializer takes an Matcher<Expr> (see
AST Matcher Reference)

But more importantly isImplicit() returns a Matcher<CXXConstructorDecl> -
and constructorDecl takes those.
So, if you insert
anyOf( constructorDecl(isImplicit()), ...)
that should do what you want...

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, that is, a matcher that matches certain Exprs (that meet a certain criteria). constructorDecl() yields a Matcher, 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