CXCursor_CXXBaseSpecifier for template instantiated base class

Hi,

When I use clang_visitChildren() to visit a class, I can't get a
CXCursor_CXXBaseSpecifier for its base class if the base class is a
template. For example:

template <typename BaseType>
class RecursiveBase : public BaseType
{
public:
   virtual void SomeFunc()
   {
      // prevent optimizer to remove the function
      global_var++;
   }
};

class Derived : public RecursiveBase<Base>, public Base2, public Base3
{
public:
   Derived() = default;

   void Func() override {}
};

I can get a CXCursor_CXXBaseSpecifier cursor as children of the
"Derived" cursor, but not RecursiveBase. How can I find out references
to all base classes including templates?

Thanks.

Nestal

You should be getting three times the CXCursor_CXXBaseSpecifier, one for each class you’re inheriting from. I ran the analysis on my machine (clang 3.8) and that is exactly what I am getting: RecursiveBase<class Base>, Base2, Base3. Maybe you could use clang -Xclang -ast-dump -fsyntax-only <this_demo> to see the output of Clang’s built-in AST dumper. It should contain these entries. Otherwise, clang version you’re running might be an older one.

Thanks for the reply.

-CXXRecordDecl 0x55e6db0f5ad8 <line:53:1, line:59:1> line:53:7 invalid class
Derived definition

>-public 'class Base2'
>-public 'class Base3'
>-CXXRecordDecl 0x55e6db0f5df8 <col:1, col:7> col:7 implicit referenced

class Derived

>-AccessSpecDecl 0x55e6db0f5e88 <line:55:1, col:7> col:1 public
>-CXXConstructorDecl 0x55e6db0f5ef0 <line:56:2, col:20> col:2 Derived 'void

(void)' noexcept-unevaluated 0x55e6db0f5ef0

`-CXXMethodDecl 0x55e6db0f5fd0 <line:58:2, col:24> col:7 Func 'void (void)'
`-CompoundStmt 0x55e6db0f6118 <col:23, col:24>

Sometimes I got "invalid class Derived definition", but if I extract the
classes in another source file, the result is different:

-CXXRecordDecl 0x55ccfcb583b0 <line:33:1, line:39:1> line:33:7 class Derived

definition

>-public 'RecursiveBase<class Base>':'class RecursiveBase<class Base>'
>-public 'class Base2'
>-public 'class Base3'
>-CXXRecordDecl 0x55ccfcb58c70 <col:1, col:7> col:7 implicit referenced

class Derived

What does it mean the class definition is invalid? There is no compile error.

Nestal

It is hard to tell without more context why you’re getting this error, but my guess is that you’re missing some command line args (i.e. include paths, preprocessor flags, etc.) which is specific to the code you’re analyzing and which is required in order to get the parsing stage done right. Very often this is the case and which is why you should, whenever you have doubts, always try to come up with a small reproducible example (without dependencies) and have it validated separately.

Additionally, you can try to extract diagnostics for the given translation unit and see if you get any hints there. Normally, you should get hints if clang parser was not able to fully parse the source code because it was missing some information such as failing to find particular headers.

Cheers,
Adi

Thanks Adi,

Like you said, I solve the problem by fixing the errors that were
indicated by the diagnostic messages.

Now I have another question, if you don't mind I keep using this thread.

I wish know the class hierarchy of "Derived". That means getting the
base class the the instantiated RecursiveBase<Base> template. That
should be "Base".

When I visit "Dervied", I got a cursor to a CXCursor_CXXBaseSpecifier.
I tried to get the type by:

CXType recursive_base =
clang_getCursorType(clang_getCursorDefinition(cxx_base_specifier));

"recursive_base" refers to the RecursiveBase<Base> instantiation. How
can I get the base type of this class? I know I can get the cursor to
the template that instantiate it (i.e. template <typename BaseType>
RecursiveBase), and I can see it inherits "BaseType" by visiting it
and look for CXCursor_CXXBaseSpecifier. But how can I know "BaseType"
will become "Base" when we instantiate it? Will the CXType provides me
this linkage or I need to use LibTooling instead?

Thanks again.

Nestal

This is an interesting question I was also wondering about the other day... (sorry, if you were hoping for an answer;)

The best thing I figured out was: get the type of template parameter RecursiveBase<Base> (via clang_Type_getTemplateArgumentAsType), then go to the referenced template RecursiveBase and do the parameter mapping myself. Of course this will get more complicated if that again derives from a template using that parameter...

Running the example through "clang++ -Xclang -ast-dump -fsyntax-only .." I see the needed ClassTemplateSpecializationDecls, also for further base templates, carrying the proper specialized parameter types...

I would have expected clang_getSpecializedCursorTemplate giving me these specialized versions of the templates, but either I understand it wrong what is supposed to do or it's implementation is incomplete here? Some insight on this question would be appreciated.

Thanks

Michael

Hi Nestal,

I am not sure if I understood you correctly but you want to find out the structure/hierarchy of your “Derived” class, that is all of the base classes that your derived class is inheriting from? If this is what you are asking for, then you can accomplish this by enumerating all of the CXCursor_TypeRef's of corresponding CXCursor_CXXBaseSpecifier cursors which are descendants (children) of class declaration (CXCursor_ClassDecl) which you’re interested in (i.e. “Derived”).

When parser is run on your example, CXCursor_CXXBaseSpecifier cursors are RecursiveBase<class Base>, class Base2 and class Base3. Corresponding CXCursor_TypeRef cursors are class Base, class Base2 and class Base3. This is what I believe you’re looking for.

For a generic and full-proof solution, you will want to do the same thing recursively for each CXCursor_CXXBaseSpecifier found.

Cheers,
Adi

Thanks, Adi! Do you mean that CXCursor_TypeRef is a child under the
CXCursor_CXXBaseSpecifier?

Yes. I think clang_getSpecializedCursorTemplate() will definitely be
useful for me. Thanks for the info.

Looking at the ast-dump, I think I want to get a cursor to this node:

ClassTemplateSpecializationDecl 0x557ff8ef4e10 <line:16:1, line:25:1>
line:17:7 class RecursiveBase definition

The dump indicates it to be under:

ClassTemplateDecl 0x557ff8eed798 <line:16:1, line:25:1> line:17:7 RecursiveBase

But I can't see this ClassTemplateSpecializationDecl to be a child of
the CXCursor_ClassTemplate. Am I missing something here?

Does the CXCursor_ClassTemplate cursor corresponds to the
ClassTemplateSpecializationDecl in the AST dump?

Many thanks!

Well, at least for me it didn't really help, it did not do what I would have expected it to do... i.e. return the specialized versions of the template, "RecursiveBase<Base>" and more importantly it's base "Base" in your example.

Do you mean this?

`-ClassTemplateSpecializationDecl 0x557ff8ef4e10 <line:16:1,

line:25:1> line:17:7 class RecursiveBase definition

  >-public 'class Base':'class Base'
  >-TemplateArgument type 'class Base'
  >-CXXRecordDecl 0x557ff8ef5098 prev 0x557ff8ef4e10 <col:1, col:7>

col:7 implicit class RecursiveBase

  >-AccessSpecDecl 0x557ff8ef5130 <line:19:1, col:7> col:1 public

I can see it from the AST dump, but not know how to get a cursor to it.

Yes, that's right. `CXCursor_TypeRef` is going to be a child of
`CXCursor_CXXBaseSpecifier` cursor.

But I would advise you to make yourself a big favor and write a simple AST
traversal function which dumps _all_ the information you can extract from
cursors. Clang built-in AST dump is a good one but does not contain every
bit of information which might be quite important while you're debugging or
developing a new specific use-case which, for example, is not covered by
libclang API. Given you have such debugging tool you would immediately see
that `CXCursor_TypeRef`s are descendants of `CXCursor_CXXBaseSpecifier`
cursors as well as many other similar details for other use-cases.

I've developed such debugging tool for myself and you can have a look at it
to get some inspiration:

Well, yes, and no. In this particular case you can do the mapping. One could also use clang_Type_getTemplateArgumentAsType. But you loose this relation if you go a bit further, like:

template
class BaseTemplate : public BaseType
{
void bar(BaseType arg1);
}

template
class RecursiveBase : public BaseTemplate
{
void foo(BaseType arg2);
}

You also want to know that the specialised parameter of “BaseTemplate" is “Base”
And you also want to know that arg1 and arg2 of the specialised “RecursiveBase” are of type “Base”
The methods are only accessible through the referenced raw template (ClassTemplate?), where you only have the raw template parameters.
It’s still possible to figure out the types in this case, yes, but it gets more and more cumbersome in the more general cases.

With a cursor directly at the specialised version of the template everything would already be resolved, readily usable. As you can see when dumping the tree with commandline clang. It seems just that libclang does not expose that information.

I was able to get this information with clang_getSpecializedCursorTemplate for partially specialised templates. But not for any other kind of specialisation. In those cases the function returns just a null cursor.

I might be missing something, though…

Michael

Hmm, I don’t have my code atm. to compare, but yes, I think this is what I mean.

template <typename BaseType>
class BaseTemplate : public BaseType
{
void bar(BaseType arg1);
}

template <typename BaseType>
class RecursiveBase : public BaseTemplate<BaseType>
{
void foo(BaseType arg2);
}

I am not sure if I understood you correctly but:

You also want to know that the specialised parameter of “BaseTemplate" is
“Base”

Sure, you can get this information once you _instantiate_ a class from your
class template. I.e.
    class Base {};
    class Derived : public RecursiveBase<Base> {};

Traversing the AST and getting to the 'CXCursor_TypeRef's of 'Derived' will
get you this information.

And you also want to know that arg1 and arg2 of the specialised
“RecursiveBase” are of type “Base”

If you have the information that 'Derived' is built with 'Base', which you
do have, then you should be able to match this information against
'foo()'/'bar()' and corresponding arguments. I.e. if we have the following:

    void fun() {
        Derived d;
        d.foo(Base());
    }

Then AST dump for 'd.foo(Base())' line would look something like this:

-`CXCursor_UnexposedExpr`: ''
   >-`CXCursor_CallExpr`: 'foo'
       >-`CXCursor_MemberRefExpr`: 'foo'
           >-`CXCursor_UnexposedExpr`: 'd'
               >-`CXCursor_DeclRefExpr`: 'd'
       >-`CXCursor_CallExpr`: ''
           >-`CXCursor_UnexposedExpr`: ''
               >-`CXCursor_CallExpr`: 'Base'

If we wanted to find out more information about 'foo' we would do the
follow-up on 'CXCursor_MemberRefExpr' : 'foo' node by using a
'clang_getCursorReferenced()' and dumping the information we get from
resulting node. You will find out that type spelling of referenced
(resulting) node will be set to 'void (Base)', and not to 'void (BaseType)'
as it was for a 'RecursiveBase' template class. I am not sure but there
might be a libclang API from this point on wards to get the number of
arguments and their types.

The methods are only accessible through the referenced raw template

(ClassTemplate?), where you only have the raw template parameters.
It’s still possible to figure out the types in this case, yes, but it gets
more and more cumbersome in the more general cases.

With a cursor directly at the specialised version of the template
everything would already be resolved, readily usable. As you can see when
dumping the tree with commandline clang. It seems just that libclang does
not expose that information.

Not every use-case is covered and exposed via libclang API. There are
situations where you will have to handle your specific use-cases manually
with your code (as shown above). If shown that these use-cases might be
relevant for general purpose then you might go ahead and issue a patch to
libclang API.

Cheers,
Adi

I am not sure if I understood you correctly but:

    You also want to know that the specialised parameter of
    “BaseTemplate" is “Base”

Sure, you can get this information once you _instantiate_ a class from
your class template. I.e.
    class Base {};
    class Derived : public RecursiveBase<Base> {};

Traversing the AST and getting to the 'CXCursor_TypeRef's of 'Derived'
will get you this information.

    And you also want to know that arg1 and arg2 of the specialised
    “RecursiveBase” are of type “Base”

If you have the information that 'Derived' is built with 'Base', which
you do have, then you should be able to match this information against
'foo()'/'bar()' and corresponding arguments.

Plus you have to take the detour via the ClassTemplates to find out which and where template parameters are used and passed on to possible base templates... So yes, this is basically what I said. It's possible to match things manually. But it gets cumbersome in the general case, if you have deeper hierarchies, more parameters.
(While the needed information is actually already available in clang as ClassTemplateSpecializationDecl, just not exposed by libclang.)

Not every use-case is covered and exposed via libclang API. There are
situations where you will have to handle your specific use-cases
manually with your code (as shown above). If shown that these use-cases
might be relevant for general purpose then you might go ahead and issue
a patch to libclang API.

Right, I might actually do that. I just wanted to figure out first whether I'm maybe just missing something.

Thanks

Michael