我正在使用 Clang 解析一些 C++ 代码。我想打印我遇到的每个
FunctionDecl
的名称和损坏的名称。
通过将其添加到我的
RecursiveASTVisitor
中,我可以相当轻松地打印函数名称:
bool VisitFunctionDecl(FunctionDecl* f) {
auto declName = f->getNameInfo().getName();
auto functionName = declName.getAsString();
std::cout << functionName << std::endl;
return true;
}
如何打印损坏的名字?
我按照塞巴斯蒂安的指示生成的工作代码:
const auto getMangledName = [&](FunctionDecl* decl) {
auto mangleContext = context.createMangleContext();
if (!mangleContext->shouldMangleDeclName(decl)) {
return decl->getNameInfo().getName().getAsString();
}
std::string mangledName;
llvm::raw_string_ostream ostream(mangledName);
mangleContext->mangleName(decl, ostream);
ostream.flush();
delete mangleContext;
return mangledName;
};
损坏的名称不是 AST 的一部分,因为它取决于 ABI。要获得损坏的名称,您需要创建适当的
clang::MangleContext
子类(来自 clang/AST/Mangle.h
)。目前有 MicrosoftMangleContext
用于与 Visual Studio 兼容的修改,以及 ItaniumMangleContext
用于常见的 C++ ABI 修改。
在最简单的版本中,您只需调用
mangleName
,传入要修改其名称的 NamedDecl
,以及写入修改后的名称的 raw_ostream
。
对于像 lambda 之类的更复杂的东西,您可能还需要在适当的时候调用
startNewFunction
,因为它们的损坏取决于它们所在的函数。
我找到了更安全的解决方案。
让我们看看
JSONNodeDumper
是如何工作的:
llvm-project-llvmorg-16.0.4/clang/lib/AST/JSONNodeDumper.cpp
void JSONNodeDumper::VisitNamedDecl(const NamedDecl *ND) {
if (ND && ND->getDeclName()) {
JOS.attribute("name", ND->getNameAsString());
// FIXME: There are likely other contexts in which it makes no sense to ask
// for a mangled name.
if (isa<RequiresExprBodyDecl>(ND->getDeclContext()))
return;
// Mangled names are not meaningful for locals, and may not be well-defined
// in the case of VLAs.
auto *VD = dyn_cast<VarDecl>(ND);
if (VD && VD->hasLocalStorage())
return;
std::string MangledName = ASTNameGen.getName(ND);
if (!MangledName.empty())
JOS.attribute("mangledName", MangledName);
}
}
JSONNodeDumper
利用 ASTNameGenerator::getName
来破坏 NamedDecl
。
如果你阅读了
ASTNameGenerator::getName
的源代码,你会发现它最终通过MangleContext::mangleName
破坏了名字。在调用 MangleContext::mangleName
之前,ASTNameGenerator::getName
会执行许多检查以防止异常。
创建
ASTNameGenerator
对象非常简单,只需将 ASTContext
传递给其构造函数即可:
explicit ASTNameGenerator(ASTContext &Ctx);
不确定如何获得
?首先查看这些官方教程:ASTContext
https://clang.llvm.org/docs/Tooling.html
https://clang.llvm.org/docs/RAVFrontendAction.html
最终代码如下:
#include "clang/AST/Mangle.h"
std::string getMangledName(const NamedDecl* decl) {
if (decl && decl->getDeclName()) {
if (isa<RequiresExprBodyDecl>(decl->getDeclContext()))
return "";
auto *varDecl = dyn_cast<VarDecl>(decl);
if (varDecl && varDecl->hasLocalStorage())
return "";
// astNameGenerator is your ASTNameGenerator object
return astNameGenerator.getName(decl);
}
return "";
}