Getting the pointer to an out-of-class VarDecl

Hi guys. I’m trying to get a pointer to the last VarDecl from the first VarDecl, so I can access the initialization Expr. As you can see below, There are two VarDecls, and I’d like to get a pointer to the out-of-class one. Also, I can’t figure out how the second VarDecl gets its parent pointer.

I just hope I don’t have to recurse the AST again each time.

class Foo {
	static int poop;
};

int Foo::poop = 3;

Well, it seems that I can get a list of redeclarations for each VarDecl, since they inherit Redeclarable, but it also looks like only the second VarDecl contains the first VarDecl as a redeclaration, whereas the first VarDecl does not contain the second VarDecl as a redeclaration (only itself). It looks like Redeclarations are added on as they are redeclared, and are not added to previous Decls, although intuitively that would make more sense.

So it still looks like I’ll have to recurse the AST twice, in order to get a pointer to the second VarDecl for the first VarDecl, but maybe someone can still help with an idea on how to avoid that?

Cheers!

There is a helper like getDefiningDecl which will get the second vardecl if you’ve already parsed it.

A redeclaration chain contains all redeclarations, that’s the idea, it is a circular singly-linked list.
You should be able to traverse the chain with getFirstDecl(), getMostRecentDecl() and friends from Redeclarable.h.

Yaron

There is a helper like getDefiningDecl which will get the second vardecl if you’ve already parsed it.

Can you be more specific please? I can’t find this helper method in any class.

A redeclaration chain contains all redeclarations, that’s the idea, it is a circular singly-linked list.
You should be able to traverse the chain with getFirstDecl(), getMostRecentDecl() and friends from Redeclarable.h.

I am able to traverse the chain, but if I traverse it inside VisitVarDecl() or TraverseVarDecl(), upon the first VarDecl, the list only contains itself, and uopn the second VarDecl, the list contains both.

The code I used to test is this:

void printSourceRange(SourceRange r) {
llvm::outs()
<< r.getBegin().printToString(ci.getSourceManager())
<< “—”
<< r.getEnd().printToString(ci.getSourceManager());
}

bool TraverseVarDecl(VarDecl *d) {
llvm::outs() << “VarDecl " << d->getName() << " @”;
printSourceRange(d->getSourceRange());
llvm::outs() << “\n”;
llvm::outs() << “first decl @”;
printSourceRange(d->getFirstDecl()->getSourceRange());
llvm::outs() << “\n”;
llvm::outs() << “most recent decl @”;
printSourceRange(d->getMostRecentDecl()->getSourceRange());
llvm::outs() << “\n”;
for(auto r: d->redecls()) {
llvm::outs() << “redecl " << d->getName() << " @”;
printSourceRange(r->getSourceRange());
llvm::outs() << “\n”;
}
return true;
}

Output looks like this:

VarDecl poop @foo.cpp:2:2—foo.cpp:2:13
first decl @foo.cpp:2:2—foo.cpp:2:13
most recent decl @foo.cpp:2:2—foo.cpp:2:13
redecl poop @foo.cpp:2:2—foo.cpp:2:13

VarDecl poop @foo.cpp:5:1—foo.cpp:5:17
first decl @foo.cpp:2:2—foo.cpp:2:13
most recent decl @foo.cpp:5:1—foo.cpp:5:17
redecl poop @foo.cpp:5:1—foo.cpp:5:17
redecl poop @foo.cpp:2:2—foo.cpp:2:13

As you can see, the only reference to the VarDecl at foo.cpp:5:1 i get is upon the second call of TraverseVarDecl, and I want to get it at the first call.

Am I misunderstanding something, or doing something wrong? It looks like the two VarDecls have two different lists of redeclarations, which do not correspond.

Thanks.

Ah, I’ve figured out why this happens, it’s because I call TraverseDecl from ASTConsumer::HandleTopLevelDecl(), so the full AST isn’t traversed at this point. So now I need to figure out how to traverse the AST only after fully parsing it…

class MyASTConsumer : public ASTConsumer {
public:
virtual bool HandleTopLevelDecl(DeclGroupRef d) {
typedef DeclGroupRef::iterator iter;
MyRecursiveASTVisitor rv;
for (iter b = d.begin(), e = d.end(); b != e; ++b) {
rv.TraverseDecl(*b);
}
return true;
}
};

Ah, I’ve figured out why this happens, it’s because I call TraverseDecl from ASTConsumer::HandleTopLevelDecl(), so the full AST isn’t traversed at this point. So now I need to figure out how to traverse the AST only after fully parsing it…

class MyASTConsumer : public ASTConsumer {
public:
virtual bool HandleTopLevelDecl(DeclGroupRef d) {
typedef DeclGroupRef::iterator iter;
MyRecursiveASTVisitor rv;
for (iter b = d.begin(), e = d.end(); b != e; ++b) {
rv.TraverseDecl(*b);
}
return true;
}
};

http://clang.llvm.org/docs/RAVFrontendAction.html
→ use HandleTranslationUnit

Cheers,
/Manuel

Yes, wait until translation unit is parsed without any errors. Then,
you can check whether the decl you are visiting is the definition (see
VarDecl::isThisDeclarationADefinition()).