[cfe-dev] AST-dump

Manuel Klimek klimek at google.com
Mon Jun 10 05:07:31 PDT 2013


On Mon, Jun 10, 2013 at 1:51 PM, Pedro Delgado Perez
<pedro.delgado at uca.es>wrote:

>  I think I have found the solution. This is the matcher:
>
> DeclarationMatcher DefaultMatcher =
>     constructorDecl(
>             isDefinition(), parameterCountIs(0),
>              anyOf(
>                 hasAnyConstructorInitializer(isWritten()),
> has(compoundStmt(has(stmt())))
>             ),
>             ofClass(
>                 recordDecl(
>                     unless(
>                         hasMethod(
>                             constructorDecl(
>                                 allOf(
>                                     hasAnyParameter(anything()),
> unless(isImplicit())
>                                 )
>                             )
>                         )
>                     )
>                 )
>             )
>     ).bind("default_matcher");
>
> I look for the constructor definition and then ask if the class it belongs
> to a class with the constraints I need. It is simply a swap in the
> approach. How do you see it? I've been testing it and it works, but I would
> like you to verify it as I might be forgetting something with all this mess
> :)
>

Yes, that should work, too.


> Well, you first have to get to the actual definition. Since it's not in
> the class, you could take the declaration you found and look for
> redeclarations that are definitions - one could build a matcher for that
> that would work like hasRedeclaration(...).
>
> Of course, this would be great as well.
>
> Thanks,
>
> Pedro.
> *El dia 10 jun 2013 13:38, Manuel Klimek <klimek at google.com> escribió:*
>
> On Mon, Jun 10, 2013 at 12:11 PM, Pedro Delgado Perez <
> pedro.delgado at uca.es> wrote:
>
>> Why do you care whether the default constructor is trivial? Wouldn't you
>> also want to delete trivial constructors here?
>>
>> 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())
>>
>> Well, my purpose is to delete it so that the compiler provides one. It is
>> pointless to delete it if the compiler is going to provide the same
>> constructor again. There is no change, but if there isn't another option...
>>
> I don't think it's pointless to delete code that's unnecessary :)
>
>> Maybe, I can look for the matcher you suggest
>> "constructorDecl(parameterCountIs(0), unless(isImplicit())" and then only
>> go on with the process determining if the constructor matched is a
>> definition and it is not trivial as I was trying to do inside the matcher.
>> Is that ok?
>>
> Well, you first have to get to the actual definition. Since it's not in
> the class, you could take the declaration you found and look for
> redeclarations that are definitions - one could build a matcher for that
> that would work like hasRedeclaration(...).
> Cheers,
> /Manuel
>
>
>> Thanks,
>>
>> Pedro.
>>
>>
>>
>>
>> *El dia 10 jun 2013 11:49, Manuel Klimek <klimek at google.com> escribió:*
>>
>> 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/d5521620/attachment.html>


More information about the cfe-dev mailing list