Getting the FieldDecl from a CXXDependentScopeMemberExpr

Hi,

I'm using the following code in an ASTConsumer/RecursiveASTVisitor:

   bool VisitCXXDependentScopeMemberExpr(CXXDependentScopeMemberExpr* expr)
   {
        // skip accesses that are not written in the sources
        if (expr->isImplicitAccess())
                return true;

        DeclRefExpr* decl_ref_expr = dyn_cast<DeclRefExpr>(expr->getBase());
        assert(decl_ref_expr);

        ValueDecl* v = decl_ref_expr->getDecl();
        VarDecl* var_decl = dyn_cast<VarDecl>(v);
        assert(var_decl);

        const Type* t = var_decl->getType().getTypePtr();
        assert(t);
        assert(t->isDependentType()); // Ok
        //assert(t->isRecordType()); // Error

        return true;
   }

This AST visitor function is used on this code:

    template<typename T>
    struct Foo
    {
        T bar;
        Foo(const Foo<T>& rhs) { bar = bar.x; }
    };

I'm trying to get the FieldDecl but I have no clue where to go from
this code...
The assert(t->isRecordType()) fails and I don't know why (because it's
a dependent type?).

So I have a VarDecl* or a Type* that is a dependent type, but I don't
know how to extract much more information from these two.

Thanks for your help,
Adrien

I'm using the following code in an ASTConsumer/RecursiveASTVisitor:

  bool VisitCXXDependentScopeMemberExpr(CXXDependentScopeMemberExpr* expr)
  {
       // skip accesses that are not written in the sources
       if (expr->isImplicitAccess())
               return true;

       DeclRefExpr* decl_ref_expr = dyn_cast<DeclRefExpr>(expr->getBase());
       assert(decl_ref_expr);

Instead of dyn_cast / assert, you should use cast<DeclRefExpr>.

       ValueDecl* v = decl_ref_expr->getDecl();
       VarDecl* var_decl = dyn_cast<VarDecl>(v);
       assert(var_decl);

       const Type* t = var_decl->getType().getTypePtr();
       assert(t);
       assert(t->isDependentType()); // Ok
       //assert(t->isRecordType()); // Error

       return true;
  }

I'm trying to get the FieldDecl but I have no clue where to go from
this code...
The assert(t->isRecordType()) fails and I don't know why (because it's
a dependent type?).

Yes, because it's a dependent type.

We make CXXDependentScopeMemberExprs in precisely the situations
where we can't resolve the member down to something. There is no way
to figure out the field here; it could be totally different fields depending on
how the code is instantiated. Your code just has to deal with the fact
that you often can't resolve things within a template pattern.

John.

Thanks a lot!

If I understand well, the AST is of little help for dependent names
inside template classes.
Is there any tool to deal with it? Without instanciation, can we do
anything with class templates?

Adrien

Thanks a lot!

If I understand well, the AST is of little help for dependent names
inside template classes.

Correct. The language is of little help here, either, since it's a fundamental part of the C++ template model.

Is there any tool to deal with it? Without instanciation, can we do
anything with class templates?

Not really. You could guess by looking into the primary templates, but the answers you get will be wrong if any specializations come along, and you may not even be able to get enough type information to determine which primary template to look in.

  - Doug

Thanks!

By any chance, would it be possible to try and instantiate a primary
template with a list of dumb template parameter types (say ints), skip
it if it fails, and if there is no specialization and the instatiation
succeeds, draw some conclusions on the primary template?

Adrien

There's no infrastructure for doing this, but it should be possible. However, I don't think you'd want to instantiate with ints… rather, you'd want to instantiate with some dummy type that doesn't imply any specific behavior.

However, it depends on your goals. It might just be easier to inspect the contents of the primary template directly, since there's a full AST there anyway.

  - Doug

My goals are very simple for now: I would like to have a tool to
rename all fields contained in the source code of a given project
(then of course classes, functions, etc...) according to the naming
conventions chosen for the project.

For instance, I would like to rename:

    template<typename T>
    struct Foo
    {
        std::pair<T,T> bar;

        void set(T x, T y)
        {
            bar.first = x;
            bar.second = y;
        }
    };

into:

    template<typename T>
    struct Foo
    {
        std::pair<T,T> m_bar; // bar -> m_bar

        void set(T x, T y)
        {
            m_bar.first = x; // bar -> m_bar but not first -> m_first
            m_bar.second = y;
        }
    };

I use VisitCXXDependentScopeMemberExpr but from that I get only the
name of the member and its location.
As std::pair<T,T> is a dependent name, I can't get access to its
primary class template, whose location is not inside the project root
directory so, of course, I don't want to rename its fields "first" and
"second", but I do want to rename "bar".

Is there a way to get this kind of information using the AST of the
primary template Foo without instantiating it?

Another piece of information I would need is to know if a given
CXXDependentScopeMemberExpr refers to a field or a method. This
information lies in the AST since if the parent expression is a
CallExpr it's a method, otherwise it's a field. But I'm not sure there
is a simple way to get the parent of a given expr (I only saw
iterators on children expr), otherwise I suppose you have to hack the
traversal of the AST and store some information on the traversed
nodes.

Thanks,
Adrien

Thanks a lot!

If I understand well, the AST is of little help for dependent names
inside template classes.

Correct. The language is of little help here, either, since it's a fundamental part of the C++ template model.

Is there any tool to deal with it? Without instanciation, can we do
anything with class templates?

Not really. You could guess by looking into the primary templates, but the answers you get will be wrong if any specializations come along, and you may not even be able to get enough type information to determine which primary template to look in.

       - Doug

Thanks!

By any chance, would it be possible to try and instantiate a primary
template with a list of dumb template parameter types (say ints), skip
it if it fails, and if there is no specialization and the instatiation
succeeds, draw some conclusions on the primary template?

There's no infrastructure for doing this, but it should be possible. However, I don't think you'd want to instantiate with ints… rather, you'd want to instantiate with some dummy type that doesn't imply any specific behavior.

However, it depends on your goals. It might just be easier to inspect the contents of the primary template directly, since there's a full AST there anyway.

       - Doug

My goals are very simple for now: I would like to have a tool to
rename all fields contained in the source code of a given project
(then of course classes, functions, etc...) according to the naming
conventions chosen for the project.

I wish C++ allowed this to be simple :slight_smile:

For instance, I would like to rename:

   template<typename T>
   struct Foo
   {
       std::pair<T,T> bar;

       void set(T x, T y)
       {
           bar.first = x;
           bar.second = y;
       }
   };

into:

   template<typename T>
   struct Foo
   {
       std::pair<T,T> m_bar; // bar -> m_bar

       void set(T x, T y)
       {
           m_bar.first = x; // bar -> m_bar but not first -> m_first
           m_bar.second = y;
       }
   };

I use VisitCXXDependentScopeMemberExpr but from that I get only the
name of the member and its location.

Right.

As std::pair<T,T> is a dependent name, I can't get access to its
primary class template, whose location is not inside the project root
directory so, of course, I don't want to rename its fields "first" and
"second", but I do want to rename "bar".

Is there a way to get this kind of information using the AST of the
primary template Foo without instantiating it?

In this case, it's likely that m_bar will have the type pair<T, T>, which will be a ClassTemplateSpecializationType. You could look at the ClassTemplateDecl (pair) and its primary template definition (a CXXRecordDecl) to lookup the name.

Alternatively, you could look at the actual instantiations of this set() function and see what fields that actually refer to.

Another piece of information I would need is to know if a given
CXXDependentScopeMemberExpr refers to a field or a method. This
information lies in the AST since if the parent expression is a
CallExpr it's a method, otherwise it's a field.

Unfortunately, that's not always true. You could have a call to a field whose type has an overloaded operator() or is a function pointer.

But I'm not sure there
is a simple way to get the parent of a given expr (I only saw
iterators on children expr), otherwise I suppose you have to hack the
traversal of the AST and store some information on the traversed
nodes.

We don't encode that information directly in the AST, although you can get that information using the ParentMap structure in clang/AST/ParentMap.h.

  - Doug

Thanks a lot!

If I understand well, the AST is of little help for dependent names
inside template classes.

Correct. The language is of little help here, either, since it's a fundamental part of the C++ template model.

Is there any tool to deal with it? Without instanciation, can we do
anything with class templates?

Not really. You could guess by looking into the primary templates, but the answers you get will be wrong if any specializations come along, and you may not even be able to get enough type information to determine which primary template to look in.

   \- Doug

Thanks!

By any chance, would it be possible to try and instantiate a primary
template with a list of dumb template parameter types (say ints), skip
it if it fails, and if there is no specialization and the instatiation
succeeds, draw some conclusions on the primary template?

There's no infrastructure for doing this, but it should be possible. However, I don't think you'd want to instantiate with ints… rather, you'd want to instantiate with some dummy type that doesn't imply any specific behavior.

However, it depends on your goals. It might just be easier to inspect the contents of the primary template directly, since there's a full AST there anyway.

   \- Doug

My goals are very simple for now: I would like to have a tool to
rename all fields contained in the source code of a given project
(then of course classes, functions, etc...) according to the naming
conventions chosen for the project.

I wish C++ allowed this to be simple :slight_smile:

Yes at least the goals are simple to describe :wink: but indeed not to implement.

For instance, I would like to rename:

template<typename T>
struct Foo
{
std::pair<T,T> bar;

   void set\(T x, T y\)
   \{
       bar\.first = x;
       bar\.second = y;
   \}

};

into:

template<typename T>
struct Foo
{
std::pair<T,T> m_bar; // bar -> m_bar

   void set\(T x, T y\)
   \{
       m\_bar\.first = x;   // bar \-&gt; m\_bar but not first \-&gt; m\_first
       m\_bar\.second = y;
   \}

};

I use VisitCXXDependentScopeMemberExpr but from that I get only the
name of the member and its location.

Right.

As std::pair<T,T> is a dependent name, I can't get access to its
primary class template, whose location is not inside the project root
directory so, of course, I don't want to rename its fields "first" and
"second", but I do want to rename "bar".

Is there a way to get this kind of information using the AST of the
primary template Foo without instantiating it?

In this case, it's likely that m_bar will have the type pair<T, T>, which will be a ClassTemplateSpecializationType. You could look at the ClassTemplateDecl (pair) and its primary template definition (a CXXRecordDecl) to lookup the name.

Yes indeed in this case we get a MemberExpr so we're saved.

The problem arises in this case:

   template<typename T>
   struct Foo
   {
       std::pair<T,T> bar;

       void setFromOther(const Foo<T>& other)
       {
           bar.first = other.bar.first;
       }
   };

Here I have a lot of info on "this->bar" but nearly nothing on "other".

Alternatively, you could look at the actual instantiations of this set() function and see what fields that actually refer to.

Yes (if the function is actually used in the project, but sure if it's
not it's another problem). I think I understand how to get from an
instanciation to the primary template, but what about finding all the
instantiations of a given primary template? Are there some kind of
links in the AST?

Another problem comes if, even if all the functions of the primary
template are used in the project, they are not all used in the same
translation unit.

Another piece of information I would need is to know if a given
CXXDependentScopeMemberExpr refers to a field or a method. This
information lies in the AST since if the parent expression is a
CallExpr it's a method, otherwise it's a field.

Unfortunately, that's not always true. You could have a call to a field whose type has an overloaded operator() or is a function pointer.

Yes indeed.

But I'm not sure there
is a simple way to get the parent of a given expr (I only saw
iterators on children expr), otherwise I suppose you have to hack the
traversal of the AST and store some information on the traversed
nodes.

We don't encode that information directly in the AST, although you can get that information using the ParentMap structure in clang/AST/ParentMap.h.

I'm going to look at that, thanks.

   \- Doug

Thanks,
Adrien

You can ask a template for all of its specializations (which includes its instantiations).

  - Doug