[Lldb-commits] [lldb] [lldb][NativePDB] Use decl context from a method's class (PR #199221)

via lldb-commits lldb-commits at lists.llvm.org
Thu May 28 02:12:31 PDT 2026


================
@@ -360,6 +360,79 @@ PdbAstBuilderClang::CreateDeclInfoForUndecoratedName(llvm::StringRef name) {
   return {context, std::string(uname)};
 }
 
+std::pair<clang::DeclContext *, std::string>
+PdbAstBuilderClang::CreateDeclInfoForCompilandSymbol(PdbCompilandSymId uid) {
+  SymbolFileNativePDB *pdb = static_cast<SymbolFileNativePDB *>(
+      m_clang.GetSymbolFile()->GetBackingSymbolFile());
+  PdbIndex &index = pdb->GetIndex();
+  CVSymbol sym = index.ReadSymbolRecord(uid);
+
+  llvm::StringRef symbol_name = getSymbolName(sym);
+
+  std::optional<PdbTypeSymId> func_id = GetFunctionType(sym);
+  if (!func_id || !symbol_name.contains("::"))
+    return CreateDeclInfoForUndecoratedName(symbol_name);
+
+  // Try to get the context from class type of an LF_MFUNCTION.
+  // For some types, we might not find a class type.
+  auto get_member_fn_context = [&]() -> clang::DeclContext * {
+    TypeIndex id = func_id->index;
+
+    if (func_id->is_ipi) {
+      // Type from IPI, for example from S_INLINESITE
+      std::optional<CVType> func_id_type =
+          index.ipi().tryGetType(func_id->index);
+      if (!func_id_type || func_id_type->kind() != LF_MFUNC_ID)
+        return nullptr;
+
+      MemberFuncIdRecord record;
+      llvm::Error err = TypeDeserializer::deserializeAs<MemberFuncIdRecord>(
+          *func_id_type, record);
+      if (err) {
+        llvm::consumeError(std::move(err));
+        return nullptr;
+      }
+
+      id = record.FunctionType;
+    }
+
+    std::optional<CVType> func_type = index.tpi().tryGetType(id);
+    if (!func_type || func_type->kind() != LF_MFUNCTION)
+      return nullptr;
+
+    MemberFunctionRecord mfr(TypeRecordKind::MemberFunction);
+
+    llvm::Error err =
+        TypeDeserializer::deserializeAs<MemberFunctionRecord>(*func_type, mfr);
+    if (err || mfr.ClassType.isNoneType()) {
+      llvm::consumeError(std::move(err));
+      return nullptr;
+    }
+
+    clang::QualType qt = GetOrCreateClangType(mfr.ClassType);
+    if (qt.isNull())
+      return nullptr;
+    clang::TagDecl *tag = qt->getAsTagDecl();
+    if (!tag)
+      return nullptr;
+
+    return clang::TagDecl::castToDeclContext(tag);
+  };
+
+  clang::DeclContext *context = get_member_fn_context();
+  if (!context)
+    return CreateDeclInfoForUndecoratedName(symbol_name);
+
+  MSVCUndecoratedNameParser parser(symbol_name);
+  llvm::ArrayRef<MSVCUndecoratedNameSpecifier> specifiers =
+      parser.GetSpecifiers();
+  if (specifiers.size() < 2) {
+    assert(false && "Member function name with less than two scopes");
+    return CreateDeclInfoForUndecoratedName(symbol_name);
+  }
+  return {context, std::string(specifiers.back().GetFullName())};
----------------
Nerixyz wrote:

> I think `std::string(specifiers.back().GetFullName())` is the reason why we get the full name of the method of a lambda. Can we use the base_name instead to just get the base name of the method?

We didn't use this return value at here. Only `.first` was used. I removed that second value ([`22a6e5c` (this PR)](https://github.com/llvm/llvm-project/pull/199221/commits/22a6e5c2121932247fa60cba1688c69d4f2289a3)). 

[`PdbAstBuilderClang::GetOrCreateFunctionDecl`](https://github.com/llvm/llvm-project/blob/0513c9cba2a02fb853b0af385c0b47503e6678ff/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilderClang.cpp#L1057-L1065) is the reason we get the full name. It gets the context name from the decl context it retrieves. But there, we can be a bit smarter. If the function name doesn't start with the context, we can instead use the basename. I did that in [`26b0b74` (this PR)](https://github.com/llvm/llvm-project/pull/199221/commits/26b0b7406a15fcff210631e40d9871f0ddfe583b).

https://github.com/llvm/llvm-project/pull/199221


More information about the lldb-commits mailing list