I got the FunctionDecl for the definition of a function. There is no declaration for this function.
For example:
int foo(char c, double d)
{
...
}
How do I get the signature (qualifier, return type, function name, parametrs) as a valid signature I could use to make a declaration?
I found that the easiest way is to use the lexer to get the signature of the function. Since I wanted to make a declaration out of a definition, I wanted the declaration to look exactly like the definition.
Therefore I defined a SourceRange
from the start of the function to the beginning of the body of the function (minus the opening "{") and let the lexer give me this range as a string.
static std::string getDeclaration(const clang::FunctionDecl* D)
{
clang::ASTContext& ctx = D->getASTContext();
clang::SourceManager& mgr = ctx.getSourceManager();
clang::SourceRange range = clang::SourceRange(D->getSourceRange().getBegin(), D->getBody()->getSourceRange().getBegin());
StringRef s = clang::Lexer::getSourceText(clang::CharSourceRange::getTokenRange(range), mgr, ctx.getLangOpts());
return s.substr(0, s.size() - 2).str().append(";");
}
This solution assums that the FunctionDecl
is a definition (has a body).
Maybe this is what you were looking for...
bool VisitDecl(Decl* D) {
auto k = D->getDeclKindName();
auto r = D->getSourceRange();
auto b = r.getBegin();
auto e = r.getEnd();
auto& srcMgr = Context->getSourceManager();
if (srcMgr.isInMainFile(b)) {
auto d = depth - 2u;
auto fname = srcMgr.getFilename(b);
auto bOff = srcMgr.getFileOffset(b);
auto eOff = srcMgr.getFileOffset(e);
llvm::outs() << std::string(2*d,' ') << k << "Decl ";
llvm::outs() << "<" << fname << ", " << bOff << ", " << eOff << "> ";
if (D->getKind() == Decl::Kind::Function) {
auto fnDecl = reinterpret_cast<FunctionDecl*>(D);
llvm::outs() << fnDecl->getNameAsString() << " ";
llvm::outs() << "'" << fnDecl->getType().getAsString() << "' ";
} else if (D->getKind() == Decl::Kind::ParmVar) {
auto pvDecl = reinterpret_cast<ParmVarDecl*>(D);
llvm::outs() << pvDecl->getNameAsString() << " ";
llvm::outs() << "'" << pvDecl->getType().getAsString() << "' ";
}
llvm::outs() << "\n";
}
return true;
}
Sample output:
FunctionDecl <foo.c, 48, 94> foo 'int (unsigned int)'
ParmVarDecl <foo.c, 56, 69> x 'unsigned int'
CompoundStmt <foo.c, 72, 94>
ReturnStmt <foo.c, 76, 91>
ParenExpr <foo.c, 83, 91>
BinaryOperator <foo.c, 84, 17>
ImplicitCastExpr <foo.c, 84, 84>
DeclRefExpr <foo.c, 84, 84>
ParenExpr <foo.c, 28, 45>
BinaryOperator <foo.c, 29, 43>
ParenExpr <foo.c, 29, 39>
BinaryOperator <foo.c, 30, 12>
IntegerLiteral <foo.c, 30, 30>
IntegerLiteral <foo.c, 12, 12>
IntegerLiteral <foo.c, 43, 43>
You will notice the reinterpret_cast<OtherDecl*>(D)
function calls. Decl
is the base class for all AST OtherDecl
classes like FunctionDecl
or ParmVarDecl
. So reinterpreting the pointer is allowed and gets you access to that particular AST node's attributes. Since these more-specific AST Nodes inherit the NamedDecl
and ValueDecl
classes, obtaining the function name and the function type (signature) is simple. The same can be applied to the base class Stmt
and other inherited classes like the OtherExpr
classes.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With