获取 FunctionDecl 的签名
Getting the signature of a FunctionDecl
我得到了函数定义的 FunctionDecl。此函数没有声明。
例如:
int foo(char c, double d)
{
...
}
如何将签名(限定符、return 类型、函数名称、参数)作为我可以用来进行声明的有效签名?
我发现最简单的方法是使用词法分析器来获取函数的签名。因为我想从定义中做出声明,所以我希望声明看起来与定义完全一样。
因此我定义了一个 SourceRange
从函数的开始到函数体的开始(减去开头的“{”)并让词法分析器将这个范围作为字符串给我。
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(";");
}
此解决方案假定 FunctionDecl
是一个定义(有主体)。
也许这就是您要找的...
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;
}
示例输出:
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>
您会注意到 reinterpret_cast<OtherDecl*>(D)
函数调用。 Decl
是所有 AST OtherDecl
class 的基础 class,例如 FunctionDecl
或 ParmVarDecl
。因此,允许重新解释指针并让您访问该特定 AST 节点的属性。由于这些更具体的 AST 节点继承了 NamedDecl
和 ValueDecl
classes,因此获取函数名称和函数类型(签名)很简单。同样可以应用于基础 class Stmt
和其他继承的 classes,如 OtherExpr
classes.
我得到了函数定义的 FunctionDecl。此函数没有声明。
例如:
int foo(char c, double d)
{
...
}
如何将签名(限定符、return 类型、函数名称、参数)作为我可以用来进行声明的有效签名?
我发现最简单的方法是使用词法分析器来获取函数的签名。因为我想从定义中做出声明,所以我希望声明看起来与定义完全一样。
因此我定义了一个 SourceRange
从函数的开始到函数体的开始(减去开头的“{”)并让词法分析器将这个范围作为字符串给我。
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(";");
}
此解决方案假定 FunctionDecl
是一个定义(有主体)。
也许这就是您要找的...
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;
}
示例输出:
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>
您会注意到 reinterpret_cast<OtherDecl*>(D)
函数调用。 Decl
是所有 AST OtherDecl
class 的基础 class,例如 FunctionDecl
或 ParmVarDecl
。因此,允许重新解释指针并让您访问该特定 AST 节点的属性。由于这些更具体的 AST 节点继承了 NamedDecl
和 ValueDecl
classes,因此获取函数名称和函数类型(签名)很简单。同样可以应用于基础 class Stmt
和其他继承的 classes,如 OtherExpr
classes.