How do I get the mangled name of a NamedDecl in Clang?
Asked Answered
S

2

10

I am using Clang to parse some C++ code. I would like to print the name and mangled name for every FunctionDecl that I encounter.

I can print the function name fairly easily by adding this to my RecursiveASTVisitor:

bool VisitFunctionDecl(FunctionDecl* f) {

  auto declName = f->getNameInfo().getName();
  auto functionName = declName.getAsString();

  std::cout << functionName << std::endl;

  return true;
}

How can I also print the mangled name?


Working code I produced after following Sebastian's pointers:

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;
};
Sharika answered 22/11, 2016 at 11:24 Comment(1)
I know it's been ages, but your working code leaks the mangle context if the early return is taken. You should capture it in a smart pointer.Hernardo
H
10

The mangled name is not part of the AST, since it depends on the ABI. To get a mangled name, you need to create an appropriate clang::MangleContext subclass (from clang/AST/Mangle.h). Currently there's MicrosoftMangleContext for the Visual Studio-compatible mangling, and ItaniumMangleContext for the common C++ ABI mangling.

In the most simple version, you then just call mangleName, passing in a NamedDecl whose name you want to mangle, and a raw_ostream that the mangled name is written to.

For more complex things like lambdas, you may also have to call startNewFunction at appropriate points, since their mangling depends on what function they are in.

Hernardo answered 22/11, 2016 at 11:34 Comment(1)
Also, there are a lot of small details here and there: several variants for constructors and destructors, thunks for virtual methods. clang::index::CodegenNameGenerator might be used as a reference here.Fading
C
0

I have found a safer solution.

Let's take a look at how JSONNodeDumper works:

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 leverages ASTNameGenerator::getName to mangle a NamedDecl.

If you read the source code of ASTNameGenerator::getName, you will find that it ultimately mangles the name through MangleContext::mangleName. Before calling MangleContext::mangleName, ASTNameGenerator::getName will perform many checks to prevent exceptions.

Creating an ASTNameGenerator object is very simple, you just need to pass your ASTContext to its constructor:

explicit ASTNameGenerator(ASTContext &Ctx);

Not sure how to obtain ASTContext? Start by reviewing these official tutorials:
https://clang.llvm.org/docs/Tooling.html
https://clang.llvm.org/docs/RAVFrontendAction.html

The final code is as follows:

#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 "";
}
Carhop answered 9/10, 2023 at 9:8 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.