[cfe-dev] AST-dump

Manuel Klimek klimek at google.com
Mon Jun 10 02:49:11 PDT 2013


On Mon, Jun 10, 2013 at 10:13 AM, Pedro Delgado Perez
<pedro.delgado at uca.es>wrote:

>  Hi,
>
> Well, I'm going to rewind and try to give as much information of the
> problem as possible to clarify it to everyone.
>
> My intention is the next: I want to retrieve the default constructor of a
> class (not trivial if possible) and then to delete it so that the compiler
> provides one. For this purpose, I need to verify that the class that default
>
Why do you care whether the default constructor is trivial? Wouldn't you
also want to delete trivial constructors here?

> constructor belongs to, doesn't have any other constructors (with at least
> another constructor, the compiler doesn't provide the default constructor).
>
> So, I created the next matcher:
>
> DeclarationMatcher DefaultConstructorMatcher =
>  recordDecl(
>            unless(hasMethod(constructorDecl(
>                 allOf(hasAnyParameter(anything()),
> unless(isImplicit()))))),
>            hasMethod(constructorDecl(isDefinition(), parameterCountIs(0),
>                  anyOf(hasAnyConstructorInitializer(isWritten()),
> has(compoundStmt(has(stmt())))
>

What doesn't match here is hasMethod(constructorDecl(isDefinition())).
hasMethod will *not* loop over all declarations, but just the ones made in
the recordDecl.

To your specific problem (and tying into my above question): why not just
constructorDecl(parameterCountIs(0), unless(isImplicit()))?


> )).bind("default_constructor"))
>   ).bind("class_default_constructor");
>
> The first part helps me to discard classes with a constructor different
> from the default constructor and the second part gives me the default
> constructor I'm looking for.
>
> (Note: I put "unless(isImplicit())" to avoid other implicit constructors
> provides by the compiler)
>
> Then, I can do:
>
>  if
> (Result.Nodes.getNodeAs<clang::CXXRecordDecl>("class_default_constructor"))
>          const CXXConstructorDecl *FS =
> Result.Nodes.getNodeAs<clang::CXXConstructorDecl>("default_constructor");
>
> The problem now is:
>
> - Case 1:
>
> class E{
>     public:
>         E(){int a = 3;};
>         int e;
> };
>
> Constructor E() is retrieved.
>
> - Case 2:
> class E{
>     public:
>         E();
>         int e;
> };
>
> E::E(){
>    int a = 3;
> }
>
> Constructor E() is not retrieved. I think the problem is that there are
> two CXXConstructors in the AST, I suppose one for the declaration and the
> other for the definition:
>
> <CXXConstructor ptr="0xc7de070" name="E" prototype="true">
>    <FunctionProtoType ptr="0xc7de040" canonical="0xc7de040">
>     <BuiltinType ptr="0xc7ddc30" canonical="0xc7ddc30"/>
>     <parameters/>
>    </FunctionProtoType>
>   </CXXConstructor>
>
> ....
>
> <CXXConstructor used="1" ptr="0xc7de270" name="E" previous="0xc7de070"
> prototype="true">
>   <FunctionProtoType ptr="0xc7de040" canonical="0xc7de040">
>    <BuiltinType ptr="0xc7ddc30" canonical="0xc7ddc30"/>
>    <parameters/>
>   </FunctionProtoType>
>   <Stmt>
> CompoundStmt 0xc7de378 <./ABC.h:8:7, line:10:1>
> `-DeclStmt 0xc7de368 <line:9:2, col:11>
>   `-VarDecl 0xc7de320 <col:2, col:10> a 'int'
>     `-IntegerLiteral 0xc7de350 <col:10> 'int' 3
>
>   </Stmt>
>  </CXXConstructor>
>
> With all this information everyone could test that this is true. Now,
> responding your message:
>
> > *Did you mean "clang::Redeclarable< decl_type >" class?*
> *
> *
> Yes.*
> *
>
> I've been looking for a solution with this, but I definitively have no
> idea what can I do with it.
>
> > *I think your suggestion might be useful to me, so that the second
> declaration is not taken into account*
> *
> *
> Yes, that is the idea.*
> *
>
> Yes, but I need this only for the first part of the matcher, not for the
> second part as I need to determine whether the constructor is trivial or
> not.
>
> > *the matcher you are suggesting is previous to this or is included in
> the same matcher I'm trying to build?*
> *
> *
>
> I don't understand what you mean.
>
> What I was asking was whether I needed to change my matcher
> "DefaultConstructorMatcher" to do what you proposed or I had to create a
> new one to act before my matcher.
>
> Thanks for your concern,
>
> Pedro.
>
>
> *El dia 10 jun 2013 00:50, Gábor Kozár <kozargabor at gmail.com> escribió:*
>
> Hi,
> I reread your previous e-mail, and I do not know why your matcher is not
> working as intended in the example - I cannot find any problems with it.
> Did you try filtering out the methods that have been declared before, to
> see whether the E(); line or the E::E() line causes the matcher to fail?
> > *Did you mean "clang::Redeclarable< decl_type >" class?*
> *
> *
> Yes.*
> *
> > *I think your suggestion might be useful to me, so that the second
> declaration is not taken into account*
> *
> *
> Yes, that is the idea.*
> *
> > *but I can't still understand why the matcher is doing that if the
> second declaration doesn't fit that matcher's conditions.*
> *
> *
> Me neither, it appears that we're missing something.*
> *
> > *the matcher you are suggesting is previous to this or is included in
> the same matcher I'm trying to build?*
> *
> *
> I don't understand what you mean.*
> *
> Gabor
>
>
> 2013/5/31 Pedro Delgado Perez <pedro.delgado at uca.es>
>
>> Did you mean "clang::Redeclarable< decl_type >" class? I think your
>> suggestion might be useful to me, so that the second declaration is not
>> taken into account,  but I can't still understand why the matcher is doing
>> that if the second declaration doesn't fit that matcher's conditions.
>>
>> I will look into this, but the matcher you are suggesting is previous to
>> this or is included in the same matcher I'm trying to build?
>>
>> Thanks,
>>
>> Pedro.
>> *El dia 30 may 2013 21:36, Gábor Kozár <kozargabor at gmail.com> escribió:*
>>
>> Well, try filtering out declarations that are not first declarations - it
>> looks to me that would solve your issue.
>> I think you'll need to create a new matcher for this. In fact, this might
>> be useful to implement generally and contribute to Clang. I believe there
>> is a base class for redeclarable AST nodes, but can't remember the exact
>> name - you should use that for your matcher.
>>
>>
>> 2013/5/30 Pedro Delgado Perez <pedro.delgado at uca.es>
>>
>>> Hi,
>>>
>>> Default, copy, and move constructors are provided implicitly (under
>>> various conditions - obviously if you have members that aren't default,
>>> copy, or move constructible, you might not/cannot get all of those)
>>>
>>> Ok, but this keeps giving me trouble. I've used the isImplicit() matcher
>>> to avoid those implicit constructors, but it isn't working how I need yet.
>>>
>>> recordDecl(
>>>     unless(hasMethod(constructorDecl(
>>>                 allOf(hasAnyParameter(anything()), unless(isImplicit()))
>>>
>>> I know I shouldn't use the -ast-dump-xml option, but look at this. If I
>>> have a class like this:
>>>
>>> class E{
>>>     public:
>>>         E(){int a = 3;};
>>>         int e;
>>> };
>>>
>>> This is the dump of the constructor:
>>>
>>> <CXXConstructor used="1" ptr="0xd7d8070" name="E" prototype="true">
>>>    <FunctionProtoType ptr="0xd7d8040" canonical="0xd7d8040">
>>>     <BuiltinType ptr="0xd7d7c30" canonical="0xd7d7c30"/>
>>>     <parameters/>
>>>    </FunctionProtoType>
>>>    <Stmt>
>>> CompoundStmt 0xd7d81a8 <./ABC.h:4:6, col:17>
>>> `-DeclStmt 0xd7d8198 <col:7, col:16>
>>>   `-VarDecl 0xd7d8150 <col:7, col:15> a 'int'
>>>     `-IntegerLiteral 0xd7d8180 <col:15> 'int' 3
>>>
>>>    </Stmt>
>>>   </CXXConstructor>
>>>
>>> And this case is working fine. But when the class is this other way:
>>>
>>> class E{
>>>     public:
>>>         E();
>>>         int e;
>>> };
>>>
>>> E::E(){
>>>    int a = 3;
>>> }
>>>
>>> The dump creates two CXXConstructors, I suppose one for the declaration
>>> and the other for the definition:
>>>
>>> <CXXConstructor ptr="0xc7de070" name="E" prototype="true">
>>>    <FunctionProtoType ptr="0xc7de040" canonical="0xc7de040">
>>>     <BuiltinType ptr="0xc7ddc30" canonical="0xc7ddc30"/>
>>>     <parameters/>
>>>    </FunctionProtoType>
>>>   </CXXConstructor>
>>>
>>> ....
>>>
>>> <CXXConstructor used="1" ptr="0xc7de270" name="E" previous="0xc7de070"
>>> prototype="true">
>>>   <FunctionProtoType ptr="0xc7de040" canonical="0xc7de040">
>>>    <BuiltinType ptr="0xc7ddc30" canonical="0xc7ddc30"/>
>>>    <parameters/>
>>>   </FunctionProtoType>
>>>   <Stmt>
>>> CompoundStmt 0xc7de378 <./ABC.h:8:7, line:10:1>
>>> `-DeclStmt 0xc7de368 <line:9:2, col:11>
>>>   `-VarDecl 0xc7de320 <col:2, col:10> a 'int'
>>>     `-IntegerLiteral 0xc7de350 <col:10> 'int' 3
>>>
>>>   </Stmt>
>>>  </CXXConstructor>
>>>
>>> And this is the case my matcher is not retrieving the class E. I don't
>>> know if clang it's considering that first  CxxConstructor as implicit...
>>> The only difference I can see is the "used" attribute. I've tried creating
>>> a simple matcher to use the isUsed() method of Decl class:
>>>
>>> namespace clang{
>>>     namespace ast_matchers{
>>>         AST_MATCHER(Decl, isUsed)
>>>         {
>>>             return Node.isUsed();
>>>         }
>>>     }
>>> }
>>>
>>> but, this is having no influence.
>>>
>>> Maybe, I'm ignoring something.
>>>
>>> Thanks,
>>>
>>> Pedro.
>>>
>>>
>>>
>>> *El dia 28 may 2013 18:18, David Blaikie <dblaikie at gmail.com> escribió:*
>>>
>>>
>>>
>>>
>>> On Tue, May 28, 2013 at 2:07 AM, Pedro Delgado Perez <
>>> pedro.delgado at uca.es> wrote:
>>>
>>> That seems like an approach that works. I don't know that there's a
>>> different common property. Why's the default constructor different from the
>>> copy constructor here?
>>>
>>> First of all, sorry but I made a mistake in the example:
>>>
>>>
>>> class A{
>>> 1.    A(){...}
>>> 2.    A(int a){...}
>>>
>>> 3.    *A(const A& a){... ...}*
>>> };
>>>
>>> What I mean is that I need to find if there is at least one constructor
>>> that explicitly overloads the default constructor so that if I delete the
>>> default constructor the compiler won't provide the default constructor. So,
>>> my question was totally erroneous as the copy constructor does overload the
>>> default constructor if provided, but I don't want to take it into account
>>> if it wasn't explicitly provided.
>>>
>>> A better question is: which are the kind of constructors that the
>>> compiler provides if no constructors are explicitly supplied? Only the
>>> default and the copy constructor (in some situations)?
>>> Default, copy, and move constructors are provided implicitly (under
>>> various conditions - obviously if you have members that aren't default,
>>> copy, or move constructible, you might not/cannot get all of those)
>>>
>>> If "unless(allOf(... ...))" is the best solution, could someone
>>> enumerate the kind of constructors I must to indicate in that matcher?
>>>
>>> I'd suggest to not use ast-dump-xml any more. It's basically deprecated,
>>> and hopefully it'll be removed soon. -ast-dump gives you all the
>>> information (and more).
>>>
>>> Ok, I didn't know it.
>>>
>>> ... you can see that one is the default constructor and the other one is
>>> the copy constructor. If you just put "G g;" into the code instead of the
>>> second class, you'll also see that a simple use of G already triggers the
>>> copy constructor to appear. Others are probably better able to explain
>>> exactly when a copy constructor is created.
>>>
>>> Further information will be well received.
>>>
>>> Regards,
>>>
>>> Pedro.
>>> *El dia 27 may 2013 12:24, Manuel Klimek <klimek at google.com> escribió:*
>>> Hi Pedro,
>>> first, please always send those mails also to cfe-dev. There are people
>>> who are much more knowledgable about the AST on that list, and you'll often
>>> get better answers faster that way :)
>>> On Mon, May 27, 2013 at 10:00 AM, Pedro Delgado Perez <
>>> pedro.delgado at uca.es> wrote:
>>>
>>> Sorry Manuel, but I prefer to ask you all the things I don't know before
>>> you reply me:
>>>
>>> How do I know that a CXXConstructorDecl is a "simple" constructor of a
>>> class. I mean, I want to find all the constructors in a class, but not the
>>> copy, the move or things like this constructors. I'm not able to find this
>>> in the documentation. To clarify this, I'm going to put an example:
>>>
>>> class A{
>>> 1.    A(){...}
>>> 2.    A(int a){...}
>>> 3.    A(const &a){... ...}
>>> };
>>>
>>> I want to look only for 1 and 2 and not for 3 when I ask:
>>> recordDecl(hasMethod(constructDecl(...)));
>>>
>>> What can I do? Do I have to write "unless(allOf(isCopyConstructor(),
>>> isMoveConstructor()...))" for each type of existing constructors?
>>> That seems like an approach that works. I don't know that there's a
>>> different common property. Why's the default constructor different from the
>>> copy constructor here?
>>>
>>>
>>> Thanks,
>>>
>>> Pedro.
>>>
>>>
>>>
>>> Hi Manuel,
>>>
>>> I would like to ask you something about the AST built by Clang if you
>>> don't mind.  I've just have a look at your video  of introduction to Clang
>>> AST (By the way, nice tutorial!) and I think that you may have an answer
>>> for my trouble.
>>>
>>> Look, I was trying to look for classes that had only the default
>>> constructor through ASTMatchers. Well, I tested my matcher with the next
>>> classes:
>>>
>>> class G{
>>> public:
>>>         G():a(1){}
>>>         int a;
>>>         virtual int ma(int arg);
>>> };
>>>
>>> class L: *public G*{
>>>         public:
>>>                 L(){v = 1;}
>>>                 int b;
>>>                 int h;
>>>                 virtual int ma(int arg);
>>>         private:
>>>                 int v;
>>>                 int f();
>>> };
>>>
>>> My matcher only retrieved the class 'L' and not the 'G'. I was wondering
>>> what would be the problem when I had a look to the ast-dump-xml option:
>>> I'd suggest to not use ast-dump-xml any more. It's basically deprecated,
>>> and hopefully it'll be removed soon. -ast-dump gives you all the
>>> information (and more).
>>>
>>>  <CXXRecord ptr="0xd695f30" name="G" typeptr="0xd695f80">
>>>   <CXXRecord ptr="0xd695fd0" name="G" typeptr="0xd695f80"/>
>>>   <AccessSpec ptr="0xd696020" access="public"/>
>>>   *<CXXConstructor* used="1" ptr="0xd696080" name="G" prototype="true">
>>>    <FunctionProtoType ptr="0xd696050" canonical="0xd696050">
>>>     <BuiltinType ptr="0xd695c40" canonical="0xd695c40"/>
>>>     <parameters/>
>>>    </FunctionProtoType>
>>>    <Stmt>
>>> CompoundStmt 0xd696450 <tst.cpp:7:10, col:11>
>>>    </Stmt>
>>>   </CXXConstructor>
>>>
>>> ....
>>>
>>> *<CXXConstructor* ptr="0xd6aefc0" name="G" prototype="true"
>>> inline="true">
>>>    <FunctionProtoType ptr="0xd6af050" canonical="0xd6af030"
>>> exception_spec="unevaluated">
>>>     <BuiltinType ptr="0xd695c40" canonical="0xd695c40"/>
>>>     <parameters>
>>>      <LValueReferenceType ptr="0xd696240" canonical="0xd696240">
>>>       <QualType const="true">
>>>        <RecordType ptr="0xd695f80" canonical="0xd695f80">
>>>         <CXXRecord ref="0xd695f30"/>
>>>        </RecordType>
>>>       </QualType>
>>>      </LValueReferenceType>
>>>     </parameters>
>>>    </FunctionProtoType>
>>>    <ParmVar ptr="0xd6af070" name="" initstyle="c">
>>>     <LValueReferenceType ptr="0xd696240" canonical="0xd696240">
>>>      <QualType const="true">
>>>       <RecordType ptr="0xd695f80" canonical="0xd695f80">
>>>        <CXXRecord ref="0xd695f30"/>
>>>       </RecordType>
>>>      </QualType>
>>>     </LValueReferenceType>
>>>    </ParmVar>
>>>   </CXXConstructor>
>>>  </CXXRecord>
>>>
>>> Why class 'G' has two constructors? If I change the test program in
>>> order that class 'L' doesn't inherits from class 'G', this doesn't happen
>>> (class 'G' only has one constructor in the ast-dump-xml) Could you lend me
>>> a hand?
>>> If you look at -ast-dump:
>>> $ clang -cc1 -ast-dump t4.cc
>>> <snip>
>>> |-CXXRecordDecl 0x37faf80 <t4.cc:1:1, line:6:1> class G
>>> <snip>
>>> | |-CXXConstructorDecl 0x37fb1c0 <line:3:3, col:15> G 'void (void)'
>>> | | |-CXXCtorInitializer Field 0x37fb290 'a' 'int'
>>> | | | |-IntegerLiteral 0x382d018 <col:11> 'int' 1
>>> | | `-CompoundStmt 0x382d0a0 <col:14, col:15>
>>> <snip>
>>> | `-CXXConstructorDecl 0x382da70 <col:7> G 'void (const class G &)'
>>> inline
>>> |   `-ParmVarDecl 0x382f820 <col:7> 'const class G &'
>>> <snip>
>>> ... you can see that one is the default constructor and the other one is
>>> the copy constructor. If you just put "G g;" into the code instead of the
>>> second class, you'll also see that a simple use of G already triggers the
>>> copy constructor to appear. Others are probably better able to explain
>>> exactly when a copy constructor is created.
>>> cheers,
>>> /Manuel
>>>
>>> _______________________________________________
>>> 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
>>
>>
>
> _______________________________________________
> 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/20130610/297765af/attachment.html>


More information about the cfe-dev mailing list