Missing FieldDecl from macro calls and template arguments

Hi,

I've implemented an ASTConsumer deriving from RecursiveASTVisitor to
rename field names. The consumer implements VisitFieldDecl and
VisitMemberExpr,
but it seems that (at least) two kinds of expressions are not visited.

1- First, function arguments that are instance of templates, e.g.:

    template<typename T>
    struct Foo
    {
        int bar;

        void copy(const Foo<T>& other) {
            bar = other.bar; /// bar is visited but not other.bar
        }
    };

If I write the same code but with a non-template Foo struct, all bar
member expressions are visited.

2- Code inside macros, e.g.:

    Foo foo;
    foo.bar = 2; // bar is visited
    assert(foo.bar == 2); // bar is not visited

Do I have to get the body of the macro from the Preprocessor and make
something with it?

In both cases I really don't have a clue why these expressions are not visited.

Thanks for the hints,
Adrien

Hi,

I've implemented an ASTConsumer deriving from RecursiveASTVisitor to
rename field names. The consumer implements VisitFieldDecl and
VisitMemberExpr,
but it seems that (at least) two kinds of expressions are not visited.

1- First, function arguments that are instance of templates, e.g.:

template<typename T>
struct Foo
{
int bar;

   void copy\(const Foo&lt;T&gt;&amp; other\) \{
       bar = other\.bar;  /// bar is visited but not other\.bar
   \}

};

other.bar in this situation is a CXXDependentScopeMemberExpr, I think...

If I write the same code but with a non-template Foo struct, all bar
member expressions are visited.

2- Code inside macros, e.g.:

Foo foo;
foo.bar = 2; // bar is visited
assert(foo.bar == 2); // bar is not visited

Do I have to get the body of the macro from the Preprocessor and make
something with it?

Are you sure you're compiling the given file with asserts enabled?
The expression won't show up in the AST if it gets #define'ed out.

-Eli

Hi,

I've implemented an ASTConsumer deriving from RecursiveASTVisitor to
rename field names. The consumer implements VisitFieldDecl and
VisitMemberExpr,
but it seems that (at least) two kinds of expressions are not visited.

1- First, function arguments that are instance of templates, e.g.:

template<typename T>
struct Foo
{
int bar;

   void copy\(const Foo&lt;T&gt;&amp; other\) \{
       bar = other\.bar;  /// bar is visited but not other\.bar
   \}

};

other.bar in this situation is a CXXDependentScopeMemberExpr, I think...

Thanks I will definitely try that!

If I write the same code but with a non-template Foo struct, all bar
member expressions are visited.

2- Code inside macros, e.g.:

Foo foo;
foo.bar = 2; // bar is visited
assert(foo.bar == 2); // bar is not visited

Do I have to get the body of the macro from the Preprocessor and make
something with it?

Are you sure you're compiling the given file with asserts enabled?
The expression won't show up in the AST if it gets #define'ed out.

I didn't disable asserts with -DNDEBUG, so are they not enabled by default?

-Eli

Thanks again,
Adrien

If you didn't define NDEBUG, they should be enabled... not sure what's
going on here. If the node is getting compiled, it should show up in
the AST, though. Maybe take a look at the output of -ast-dump?

-Eli

Hi,

I've implemented an ASTConsumer deriving from RecursiveASTVisitor to
rename field names. The consumer implements VisitFieldDecl and
VisitMemberExpr,
but it seems that (at least) two kinds of expressions are not visited.

1- First, function arguments that are instance of templates, e.g.:

template<typename T>
struct Foo
{
int bar;

   void copy\(const Foo&lt;T&gt;&amp; other\) \{
       bar = other\.bar;  /// bar is visited but not other\.bar
   \}

};

other.bar in this situation is a CXXDependentScopeMemberExpr, I think...

Thanks I will definitely try that!

If I write the same code but with a non-template Foo struct, all bar
member expressions are visited.

2- Code inside macros, e.g.:

Foo foo;
foo.bar = 2; // bar is visited
assert(foo.bar == 2); // bar is not visited

Do I have to get the body of the macro from the Preprocessor and make
something with it?

Are you sure you're compiling the given file with asserts enabled?
The expression won't show up in the AST if it gets #define'ed out.

I didn't disable asserts with -DNDEBUG, so are they not enabled by default?

If you didn't define NDEBUG, they should be enabled... not sure what's
going on here. If the node is getting compiled, it should show up in
the AST, though. Maybe take a look at the output of -ast-dump?

Thanks for the tip! I'm not really familiar with the output of
ast-dump but it looks really nice and assert is definitely there. I'm
going to investigate this. Maybe it's because I filtered out the
expressions based on their locations. If the expression inside an
assert is located in assert.h, that should answer my question. I
thought it would be located in the source file where assert is called.

Thanks,
Adrien

How exactly are you getting the source location? There are multiple
locations associated with an expression inside a macro instantiation.

-Eli

Xcode does not define DEBUG (ie, -DDEBUG) for debug builds; and does
not define NDEBUG (ie, -DNDEBUG) for release builds. You'll have to do
it yourself under the project's settings.

Per POSIX/IEEE, assert() calls abort(). If you want to change the
[useless] behavior, use the ASSERT below (and don't use little
assert). I'm an avid asserter - all my projects use it (from Xcode to
Visual Studio [modified] to Linux). Its my intentions to have the code
debug itself whenever possible.

Jeff

#if defined(DEBUG) || defined(_DEBUG)
# define ASSERT(exp) { if(!(exp)) { fprintf(stderr, "Assertion
failed: %s (%d): %s\n", (strrchr(__FILE__, '/')+1), __LINE__,
__func__); raise(SIGTRAP); } }
#else
# define ASSERT(exp)
#endif

My bad - I confused lists (thought it was cocoa-dev).

Jeff

I use:

     bool VisitMemberExpr(MemberExpr *Node)
     {
         SourceLocation loc = Node->getExprLoc();
        ...
     }

By the way, I didn't get the difference between loc and:

   instanciated_loc = my_src_manager.getInstatiationLoc(loc);

Thanks,
Adrien

As noted at

  http://clang.llvm.org/docs/InternalsManual.html#SourceLocation

a source location for a macro instantiation encodes both the spelling location (where the characters came from) and the instantiation location (where the macro was expanded).

  - Doug

Thanks! It works now. It was indeed a problem of
getInstanciationLocation/getSpellingLocation.

If I summarize what I understood...

Given a SourceLocation "loc" taken from an expression inside a macro call:

- SourceManager::getInstanciationLoc(loc) gives where the macro was
expanded in the code after the preprocessing step
- SourceManager::getSpellingLocation(loc) gives where the characters
came from in the original source code before expansion (before
preprocessing)

but "loc" itself contains a third location which is different from
instanciation and spelling locations. From my tests, I believe this is
where the macro is defined. Is it?

Thanks,
Adrien

IIRC, it's the location inside the token-pasted buffer for the macro instantiation.

  - Doug

Hi,

I've implemented an ASTConsumer deriving from RecursiveASTVisitor to
rename field names. The consumer implements VisitFieldDecl and
VisitMemberExpr,
but it seems that (at least) two kinds of expressions are not visited.

1- First, function arguments that are instance of templates, e.g.:

template<typename T>
struct Foo
{
int bar;

   void copy\(const Foo&lt;T&gt;&amp; other\) \{
       bar = other\.bar;  /// bar is visited but not other\.bar
   \}

};

other.bar in this situation is a CXXDependentScopeMemberExpr, I think...

Thanks I will definitely try that!

I tried this and it works well because for now I only need the name of
the member and the location.
But I tried as well to see if I could get the member declaration out
of the DeclarationName and I'm having a hard time... do I need to use
the IdentiferInfo, find a connection to an IdentifierResolver?

If I write the same code but with a non-template Foo struct, all bar
member expressions are visited.

2- Code inside macros, e.g.:

Foo foo;
foo.bar = 2; // bar is visited
assert(foo.bar == 2); // bar is not visited

Do I have to get the body of the macro from the Preprocessor and make
something with it?

Are you sure you're compiling the given file with asserts enabled?
The expression won't show up in the AST if it gets #define'ed out.

I didn't disable asserts with -DNDEBUG, so are they not enabled by default?

If you didn't define NDEBUG, they should be enabled... not sure what's
going on here. If the node is getting compiled, it should show up in
the AST, though. Maybe take a look at the output of -ast-dump?

Thanks for the tip! I'm not really familiar with the output of
ast-dump but it looks really nice and assert is definitely there. I'm
going to investigate this. Maybe it's because I filtered out the
expressions based on their locations. If the expression inside an
assert is located in assert.h, that should answer my question. I
thought it would be located in the source file where assert is called.

How exactly are you getting the source location? There are multiple
locations associated with an expression inside a macro instantiation.

-Eli

I use:

bool VisitMemberExpr\(MemberExpr \*Node\)
\{
    SourceLocation loc = Node\-&gt;getExprLoc\(\);
   \.\.\.
\}

By the way, I didn't get the difference between loc and:

instanciated_loc = my_src_manager.getInstatiationLoc(loc);

As noted at

http://clang.llvm.org/docs/InternalsManual.html#SourceLocation

a source location for a macro instantiation encodes both the spelling location (where the characters came from) and the instantiation location (where the macro was expanded).

- Doug

Thanks! It works now. It was indeed a problem of
getInstanciationLocation/getSpellingLocation.

If I summarize what I understood...

Given a SourceLocation "loc" taken from an expression inside a macro call:

- SourceManager::getInstanciationLoc(loc) gives where the macro was
expanded in the code after the preprocessing step
- SourceManager::getSpellingLocation(loc) gives where the characters
came from in the original source code before expansion (before
preprocessing)

but "loc" itself contains a third location which is different from
instanciation and spelling locations. From my tests, I believe this is
where the macro is defined. Is it?

IIRC, it's the location inside the token-pasted buffer for the macro instantiation.

I'm not sure to understand... at least this location is in the file
whre the macro is defined, not in the file where the macro is called?

Adrien