How to get Function Definition from CallExpr

Hello,

I have a piece of C code like so:

Hello,

I have a piece of C code like so:

==========================================
void foo(); // just a declaration (sometimes in a header file instead)

void bar() {
    // definition here
}

int main() {
    bar(); // this one is fine
    foo(); // this one doesn't work
}

void foo() {
    // definition here
}

I'm using VisitStmt and looking at the CallExprs in main(). For the "bar()"
function above, I can get the FunctionDecl* using
CallExpr::getDirectCallee(). However, that doesn't work for the "foo()"
function -- calling getDirectCallee() gives me the function prototype, not
the definition of "foo()"...

So I tried using the Redeclarable class's "redecl_iterator" to dump each
redeclaration starting from getDirectCallee()->redecls_begin. However, it
only iterates once for the function prototype and doesn't include the actual
definition of "foo()."

Note that you probably just want to use FunctionDecl::hasBody instead
of iterating over the redeclaration chain.

How can I get the real definition of foo() at the bottom of the code above?
I know it's probably something easy, but I just can't seem to get there.

Are your sure clang has actually parsed the definition at the point
where you are dumping it?

-Eli

Thanks so much for your quick reply.

I have been using hasBody(), isThisDeclarationADefinition(), etc… to determine if the Decl* i’m looking at is actually a definition – those are useful. I was merely testing things with the redecl chain just to see if I could get the definition that way even if getDirectCallee() returned the function prototype.

How would I determine if clang has parsed the definition? Sorry, I’m a bit of a beginner here. I thought that Clang first parsed the source file, built an AST, and then allowed you to Visit each type of AST node. All I know is, at that point, Clang would not yet have visited the definition of foo(), but I assume it would have parsed it…?

Is it wrong to try to access or jump to a later function definition before visiting it first?

~Kevin

Thanks so much for your quick reply.

I have been using hasBody(), isThisDeclarationADefinition(), etc... to
determine if the Decl* i'm looking at is actually a definition -- those are
useful. I was merely testing things with the redecl chain just to see if I
could get the definition that way even if getDirectCallee() returned the
function prototype.

There's also a form of FunctionDecl::hasBody() which lets you retrieve
the definition.

How would I determine if clang has parsed the definition? Sorry, I'm a bit
of a beginner here. I thought that Clang first parsed the source file, built
an AST, and then allowed you to Visit each type of AST node. All I know is,
at that point, Clang would not yet have visited the definition of foo(), but
I assume it would have parsed it...?

It depends on how exactly you're getting at the AST. The ASTConsumer
API in particular returns one declaration at a time.

-Eli

Ah, I see now that there are multiple hasBody() functions. I just tried using that hasBody(FunctionDecl *&), and it returns false. Makes sense because it’s essentially the same as me manually iterating over each redecl.

I am indeed using ASTConsumer alongside a RecursiveASTVisitor in the libtooling environment. So you’re saying that my code (some analysis inside VisitFunctionDecl or VisitStmt, per se) will be unaware of the existence of a future foo() definition until VisitFunctionDecl is called on that foo() definition?

If so, then there is no way to inspect the body/definition of foo() until VisitFunctionDecl visits it, right? Specifically, while visiting the main() FunctionDecl*, I cannot access the Stmts inside the foo() definition? That’s really what I need.

Thanks again,
Kevin

You can... you just have to call your visitor from the
HandleTranslationUnit callback.

-Eli

Oh, that was my problem, thank you so much!

Apparently, when following a tutorial, I glossed over the important distinction between what gets parsed when using HandleTopLevelDecl vs. HandleTranslationUnit.

Much thanks,
Kevin