[Lldb-commits] [lldb] Improve type and namespace lookup using parent chain (PR #108907)

via lldb-commits lldb-commits at lists.llvm.org
Mon Sep 16 20:03:26 PDT 2024


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-lldb

Author: None (jeffreytan81)

<details>
<summary>Changes</summary>

## Context
We have a customer reporting scenario that expanding "this" pointer for a non-trivial class method context takes more than **70~90 seconds**. This is a linux target with .debug_names index table enabled and using split dwarf dwo files to avoid debug info overflow.

Profiling shows the majority of the bottleneck is spent in `SymbolFileDWARF::FindTypes()` and `SymbolFileDWARF:: FindNamespace()` two functions searching types/namespaces in .debug_names index table with base name, then parsing/loading the underlying dwo files which can be very slow. 

## Summary
This PR improves `SymbolFileDWARF::FindTypes()` and `SymbolFileDWARF::FindNamespace()` by using the newly added parent chain `DW_IDX_parent` in .debug_names. The proposal is originally discussed in [this RFC](https://discourse.llvm.org/t/rfc-improve-dwarf-5-debug-names-type-lookup-parsing-speed/74151). 

This PR also implements a new algorithm in `DebugNamesDWARFIndex::SameAsEntryATName()` that can greatly avoid parsing the dwo files.

## Implementation
To leverage parent chain for `SymbolFileDWARF::FindTypes` and `SymbolFileDWARF:: FindNamespace`, the PR adds two new APIs `GetTypesWithParents` and `GetNamespacesWithParents` in `DWARFIndex` base class. These two APIs are performing the same semantics as `GetTypes/GetNamespaces` with extra filtering if `parent_names` parameter is not empty. Since only filtering is performed, the callback to all the callsites are not changed. A default implementation in DWARFIndex class is implemented to parse type context from each base name matched DIE. In `DebugNameDWARFIndex` override, it uses parent chain to perform much faster searching. 

Unlike `GetFullyQualifiedType` API which is the first one consuming `DW_IDX_parent` parent chain, these two new APIs do not perform exact matching, other than partial subset matching for the type/namespace queries. This is required to support anonymous/inline namespace queries from client. For example, users may ask for `NS1::NS2::NS3::Foo` while index table's parent chain may contain `NS1::inline_NS2::NS3::Foo` which would fail the exact matching. 

Another optimization performed is inside `DebugNamesDWARFIndex::SameAsEntryATName()`. The old implementation uses `GetNonSkeletonUnit()` which triggers parsing/loading of underlying dwo files which proves to be very expensive which we want to avoid. The new implementation tries to avoid touching dwo as much as possible. There are two ideas: 
1. Build `<pool_entry_range => NameEntry>` mapping table (built lazily as needed apparently), then we can query check the name of the parent entry.
2. Searching the name the entry tries to match from current `NameIndex`, then check if the parent entry can be found from the name entry. 

Per my testing/profiling, the 1) does not seem to improve wall-time because the cost to build the mapping table can be high. 2) has proved to be very fast. 

## Performance result
* [The other landed PR](https://github.com/llvm/llvm-project/pull/108414) reduces user's scenario wall-time from 70s => 50s 
* Using `GetTypesWithParents/GetNamespacesWithParents` reduces 50s => 13s
* Using the new algorithm to avoid touching dwo files in `DebugNamesDWARFIndex::SameAsEntryATName()` reduces 13s => 1.4s

Overall, these changes reduce from **70s => 1.4s**




---

Patch is 26.47 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/108907.diff


6 Files Affected:

- (modified) lldb/source/Plugins/SymbolFile/DWARF/DWARFIndex.cpp (+59) 
- (modified) lldb/source/Plugins/SymbolFile/DWARF/DWARFIndex.h (+22) 
- (modified) lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.cpp (+151-14) 
- (modified) lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.h (+30) 
- (modified) lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp (+107-73) 
- (modified) lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h (+2) 


``````````diff
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFIndex.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFIndex.cpp
index eafddbad03f57b..3101b1e137fbf3 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFIndex.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFIndex.cpp
@@ -126,3 +126,62 @@ bool DWARFIndex::GetFullyQualifiedTypeImpl(
     return callback(die);
   return true;
 }
+
+void DWARFIndex::GetNamespacesWithParents(
+    ConstString name, llvm::ArrayRef<llvm::StringRef> parent_names,
+    llvm::function_ref<bool(DWARFDIE die)> callback) {
+  GetNamespaces(name, [&](DWARFDIE die) {
+    return ProcessDieMatchParentNames(name, parent_names, die, callback);
+  });
+}
+
+void DWARFIndex::GetTypesWithParents(
+    ConstString name, llvm::ArrayRef<llvm::StringRef> parent_names,
+    llvm::function_ref<bool(DWARFDIE die)> callback) {
+  GetTypes(name, [&](DWARFDIE die) {
+    return ProcessDieMatchParentNames(name, parent_names, die, callback);
+  });
+}
+
+bool DWARFIndex::ProcessDieMatchParentNames(
+    ConstString name, llvm::ArrayRef<llvm::StringRef> query_parent_names,
+    DWARFDIE die, llvm::function_ref<bool(DWARFDIE die)> callback) {
+  std::vector<lldb_private::CompilerContext> type_context =
+      die.GetTypeLookupContext();
+  if (type_context.empty()) {
+    // If both type_context and query_parent_names and empty we have a match.
+    // Otherwise, this one does not match and we keep on searching.
+    if (query_parent_names.empty())
+      return callback(die);
+    return true;
+  }
+
+  // Type lookup context includes the current DIE as the last element.
+  // so revert it for easy matching.
+  std::reverse(type_context.begin(), type_context.end());
+
+  // type_context includes the name of the current DIE while query_parent_names
+  // doesn't. So start check from index 1 for dwarf_decl_ctx.
+  uint32_t i = 1, j = 0;
+  while (i < type_context.size() && j < query_parent_names.size()) {
+    // If type_context[i] has no name, skip it.
+    // e.g. this can happen for anonymous namespaces.
+    if (type_context[i].name.IsNull() || type_context[i].name.IsEmpty()) {
+      ++i;
+      continue;
+    }
+    // If the name doesn't match, skip it.
+    // e.g. this can happen for inline namespaces.
+    if (query_parent_names[j] != type_context[i].name) {
+      ++i;
+      continue;
+    }
+    ++i;
+    ++j;
+  }
+  // If not all query_parent_names were found in type_context.
+  // This die does not meet the criteria, try next one.
+  if (j != query_parent_names.size())
+    return true;
+  return callback(die);
+}
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFIndex.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFIndex.h
index cb3ae8a06d7885..1f457fda0282f5 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFIndex.h
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFIndex.h
@@ -64,6 +64,23 @@ class DWARFIndex {
   virtual void
   GetNamespaces(ConstString name,
                 llvm::function_ref<bool(DWARFDIE die)> callback) = 0;
+
+  /// Get type DIEs whose base name match \param name with \param parent_names
+  /// in its decl parent chain as subset.  A base implementation is provided,
+  /// Specializations should override this if they are able to provide a faster
+  /// implementation.
+  virtual void
+  GetTypesWithParents(ConstString name,
+                      llvm::ArrayRef<llvm::StringRef> parent_names,
+                      llvm::function_ref<bool(DWARFDIE die)> callback);
+  /// Get namespace DIEs whose base name match \param name with \param
+  /// parent_names in its decl parent chain as subset.  A base implementation is
+  /// provided. Specializations should override this if they are able to provide
+  /// a faster implementation.
+  virtual void
+  GetNamespacesWithParents(ConstString name,
+                           llvm::ArrayRef<llvm::StringRef> parent_names,
+                           llvm::function_ref<bool(DWARFDIE die)> callback);
   virtual void
   GetFunctions(const Module::LookupInfo &lookup_info, SymbolFileDWARF &dwarf,
                const CompilerDeclContext &parent_decl_ctx,
@@ -115,6 +132,11 @@ class DWARFIndex {
   bool
   GetFullyQualifiedTypeImpl(const DWARFDeclContext &context, DWARFDIE die,
                             llvm::function_ref<bool(DWARFDIE die)> callback);
+
+  /// Check if the \a die has \a parent_names in its decl parent chain.
+  bool ProcessDieMatchParentNames(
+      ConstString name, llvm::ArrayRef<llvm::StringRef> parent_names,
+      DWARFDIE die, llvm::function_ref<bool(DWARFDIE die)> callback);
 };
 } // namespace dwarf
 } // namespace lldb_private::plugin
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.cpp
index 32d8a92305aafa..76c80011791de6 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.cpp
@@ -12,6 +12,8 @@
 #include "Plugins/SymbolFile/DWARF/LogChannelDWARF.h"
 #include "Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.h"
 #include "lldb/Core/Module.h"
+#include "lldb/Core/Progress.h"
+#include "lldb/Utility/LLDBLog.h"
 #include "lldb/Utility/RegularExpression.h"
 #include "lldb/Utility/Stream.h"
 #include "llvm/ADT/Sequence.h"
@@ -301,7 +303,8 @@ using Entry = llvm::DWARFDebugNames::Entry;
 /// If any parent does not have an `IDX_parent`, or the Entry data is corrupted,
 /// nullopt is returned.
 std::optional<llvm::SmallVector<Entry, 4>>
-getParentChain(Entry entry, uint32_t max_parents) {
+getParentChain(Entry entry,
+               uint32_t max_parents = std::numeric_limits<uint32_t>::max()) {
   llvm::SmallVector<Entry, 4> parent_entries;
 
   do {
@@ -374,25 +377,40 @@ void DebugNamesDWARFIndex::GetFullyQualifiedType(
   m_fallback.GetFullyQualifiedType(context, callback);
 }
 
+bool DebugNamesDWARFIndex::SameAsEntryATName(
+    llvm::StringRef query_name, const DebugNames::Entry &entry) const {
+  auto maybe_dieoffset = entry.getDIEUnitOffset();
+  if (!maybe_dieoffset)
+    return false;
+
+  // [Optimization] instead of parsing the entry from dwo file, we simply
+  // check if the query_name can point to an entry of the same DIE offset.
+  // This greatly reduced number of dwo file parsed and thus improved the
+  // performance.
+  for (const DebugNames::Entry &query_entry :
+       entry.getNameIndex()->equal_range(query_name)) {
+    auto query_dieoffset = query_entry.getDIEUnitOffset();
+    if (!query_dieoffset)
+      continue;
+
+    if (*query_dieoffset == *maybe_dieoffset) {
+      return true;
+    } else if (*query_dieoffset > *maybe_dieoffset) {
+      // The pool entries of the same name are sequentially cluttered together
+      // so if the query name from `query_name` is after the target entry, this
+      // is definitely not the correct one, we can stop searching.
+      return false;
+    }
+  }
+  return false;
+}
+
 bool DebugNamesDWARFIndex::SameParentChain(
     llvm::ArrayRef<llvm::StringRef> parent_names,
     llvm::ArrayRef<DebugNames::Entry> parent_entries) const {
-
   if (parent_entries.size() != parent_names.size())
     return false;
 
-  auto SameAsEntryATName = [this](llvm::StringRef name,
-                                  const DebugNames::Entry &entry) {
-    // Peek at the AT_name of `entry` and test equality to `name`.
-    auto maybe_dieoffset = entry.getDIEUnitOffset();
-    if (!maybe_dieoffset)
-      return false;
-    DWARFUnit *unit = GetNonSkeletonUnit(entry);
-    if (!unit)
-      return false;
-    return name == unit->PeekDIEName(unit->GetOffset() + *maybe_dieoffset);
-  };
-
   // If the AT_name of any parent fails to match the expected name, we don't
   // have a match.
   for (auto [parent_name, parent_entry] :
@@ -402,6 +420,36 @@ bool DebugNamesDWARFIndex::SameParentChain(
   return true;
 }
 
+bool DebugNamesDWARFIndex::WithinParentChain(
+    llvm::ArrayRef<llvm::StringRef> query_parent_names,
+    llvm::ArrayRef<DebugNames::Entry> parent_chain) const {
+  if (parent_chain.size() < query_parent_names.size())
+    return false;
+
+  size_t query_idx = 0, chain_idx = 0;
+  while (query_idx < query_parent_names.size() &&
+         chain_idx < parent_chain.size()) {
+    if (SameAsEntryATName(query_parent_names[query_idx],
+                          parent_chain[chain_idx])) {
+      ++query_idx;
+      ++chain_idx;
+    } else {
+      // Name does not match, try next parent_chain entry if the current entry
+      // is namespace because the current one can be an inline namespace.
+      if (parent_chain[chain_idx].tag() != DW_TAG_namespace)
+        return false;
+
+      ++chain_idx;
+      if (query_parent_names.size() - query_idx >
+          parent_chain.size() - chain_idx) {
+        // Parent chain has not enough entries, we can't possibly have a match.
+        return false;
+      }
+    }
+  }
+  return query_idx == query_parent_names.size();
+}
+
 void DebugNamesDWARFIndex::GetTypes(
     ConstString name, llvm::function_ref<bool(DWARFDIE die)> callback) {
   for (const DebugNames::Entry &entry :
@@ -444,6 +492,95 @@ void DebugNamesDWARFIndex::GetNamespaces(
   m_fallback.GetNamespaces(name, callback);
 }
 
+void DebugNamesDWARFIndex::GetNamespacesWithParents(
+    ConstString name, llvm::ArrayRef<llvm::StringRef> parent_names,
+    llvm::function_ref<bool(DWARFDIE die)> callback) {
+  Progress progress("Get namespace from index for %s", name.GetCString());
+  for (const DebugNames::Entry &entry :
+       m_debug_names_up->equal_range(name.GetStringRef())) {
+    lldb_private::dwarf::Tag entry_tag = entry.tag();
+    if (entry_tag == DW_TAG_namespace ||
+        entry_tag == DW_TAG_imported_declaration) {
+      std::optional<llvm::SmallVector<Entry, 4>> parent_chain =
+          getParentChain(entry);
+      if (!parent_chain) {
+        // Fallback: use the base class implementation.
+        if (!ProcessEntry(entry, [&](DWARFDIE die) {
+              return ProcessDieMatchParentNames(name, parent_names, die,
+                                                callback);
+            }))
+          return;
+        continue;
+      }
+
+      // If parent_chain is shorter than parent_names, we can't possibly match.
+      if (parent_chain->size() < parent_names.size())
+        continue;
+      else if (parent_chain->size() == parent_names.size()) {
+        if (SameParentChain(parent_names, *parent_chain) &&
+            !ProcessEntry(entry, callback))
+          return;
+      } else {
+        // When parent_chain has more entries than parent_names we still
+        // possibly match if parent_chain contains inline namespaces.
+        if (WithinParentChain(parent_names, *parent_chain) &&
+            !ProcessEntry(entry, callback))
+          return;
+      }
+    }
+  }
+
+  m_fallback.GetNamespaces(name, callback);
+}
+
+void DebugNamesDWARFIndex::GetTypesWithParents(
+    ConstString name, llvm::ArrayRef<llvm::StringRef> parent_names,
+    llvm::function_ref<bool(DWARFDIE die)> callback) {
+  if (parent_names.empty())
+    return GetTypes(name, callback);
+
+  // For each entry, grab its parent chain and check if we have a match.
+  for (const DebugNames::Entry &entry : m_debug_names_up->equal_range(name)) {
+    if (!isType(entry.tag()))
+      continue;
+
+    // If we get a NULL foreign_tu back, the entry doesn't match the type unit
+    // in the .dwp file, or we were not able to load the .dwo file or the DWO ID
+    // didn't match.
+    std::optional<DWARFTypeUnit *> foreign_tu = GetForeignTypeUnit(entry);
+    if (foreign_tu && foreign_tu.value() == nullptr)
+      continue;
+
+    std::optional<llvm::SmallVector<Entry, 4>> parent_chain =
+        getParentChain(entry);
+    if (!parent_chain) {
+      // Fallback: use the base class implementation.
+      if (!ProcessEntry(entry, [&](DWARFDIE die) {
+            return ProcessDieMatchParentNames(name, parent_names, die,
+                                              callback);
+          }))
+        return;
+      continue;
+    }
+
+    // If parent_chain is shorter than parent_names, we can't possibly match.
+    if (parent_chain->size() < parent_names.size())
+      continue;
+    else if (parent_chain->size() == parent_names.size()) {
+      if (SameParentChain(parent_names, *parent_chain) &&
+          !ProcessEntry(entry, callback))
+        return;
+    } else {
+      // When parent_chain has more entries than parent_names we still possibly
+      // match if parent_chain contains inline namespaces.
+      if (WithinParentChain(parent_names, *parent_chain) &&
+          !ProcessEntry(entry, callback))
+        return;
+    }
+  }
+  m_fallback.GetTypesWithParents(name, parent_names, callback);
+}
+
 void DebugNamesDWARFIndex::GetFunctions(
     const Module::LookupInfo &lookup_info, SymbolFileDWARF &dwarf,
     const CompilerDeclContext &parent_decl_ctx,
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.h b/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.h
index cb15c1d4f994b3..1f9c87c76a99f8 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.h
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.h
@@ -52,6 +52,14 @@ class DebugNamesDWARFIndex : public DWARFIndex {
                 llvm::function_ref<bool(DWARFDIE die)> callback) override;
   void GetNamespaces(ConstString name,
                      llvm::function_ref<bool(DWARFDIE die)> callback) override;
+  void
+  GetTypesWithParents(ConstString name,
+                      llvm::ArrayRef<llvm::StringRef> parent_names,
+                      llvm::function_ref<bool(DWARFDIE die)> callback) override;
+  void GetNamespacesWithParents(
+      ConstString name, llvm::ArrayRef<llvm::StringRef> parent_names,
+      llvm::function_ref<bool(DWARFDIE die)> callback) override;
+
   void GetFunctions(const Module::LookupInfo &lookup_info,
                     SymbolFileDWARF &dwarf,
                     const CompilerDeclContext &parent_decl_ctx,
@@ -118,6 +126,28 @@ class DebugNamesDWARFIndex : public DWARFIndex {
   bool SameParentChain(llvm::ArrayRef<llvm::StringRef> parent_names,
                        llvm::ArrayRef<DebugNames::Entry> parent_entries) const;
 
+  /// Returns true if \a parent_names entries are within \a parent_chain.
+  /// This is diffferent from SameParentChain() which checks for exact match.
+  /// This function is required because \a parent_chain can contain inline
+  /// namespace entries which may not be specified in parent_names by client.
+  ///
+  /// \param[in] parent_names
+  ///   The list of parent names to check for.
+  ///
+  /// \param[in] parent_chain
+  ///   The fully qualified parent chain entries from .debug_names index table
+  ///   to check against.
+  ///
+  /// \returns
+  ///   True if all \a parent_names entries are can be sequentially found inside
+  ///   \a parent_chain, otherwise False.
+  bool WithinParentChain(llvm::ArrayRef<llvm::StringRef> parent_names,
+                         llvm::ArrayRef<DebugNames::Entry> parent_chain) const;
+
+  /// Returns true if .debug_names pool entry \p entry has name \p query_name.
+  bool SameAsEntryATName(llvm::StringRef query_name,
+                         const DebugNames::Entry &entry) const;
+
   static void MaybeLogLookupError(llvm::Error error,
                                   const DebugNames::NameIndex &ni,
                                   llvm::StringRef name);
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
index f721ca00fd3559..cc2497b7e484ba 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
@@ -2731,6 +2731,22 @@ uint64_t SymbolFileDWARF::GetDebugInfoSize(bool load_all_debug_info) {
   return debug_info_size;
 }
 
+llvm::SmallVector<llvm::StringRef>
+SymbolFileDWARF::GetTypeQueryParentNames(TypeQuery query) {
+  std::vector<lldb_private::CompilerContext> &query_decl_context =
+      query.GetContextRef();
+  llvm::SmallVector<llvm::StringRef> parent_names;
+  if (!query_decl_context.empty()) {
+    auto rbegin = query_decl_context.rbegin(), rend = query_decl_context.rend();
+    for (auto rit = rbegin + 1; rit != rend; ++rit)
+      if ((rit->kind & CompilerContextKind::AnyType) !=
+              CompilerContextKind::Invalid &&
+          !rit->name.IsEmpty())
+        parent_names.push_back(rit->name.GetStringRef());
+  }
+  return parent_names;
+}
+
 void SymbolFileDWARF::FindTypes(const TypeQuery &query, TypeResults &results) {
 
   // Make sure we haven't already searched this SymbolFile before.
@@ -2748,45 +2764,50 @@ void SymbolFileDWARF::FindTypes(const TypeQuery &query, TypeResults &results) {
 
   std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
 
+  TypeQuery query_full(query);
+  llvm::SmallVector<llvm::StringRef> parent_names =
+      GetTypeQueryParentNames(query_full);
   bool have_index_match = false;
-  m_index->GetTypes(type_basename, [&](DWARFDIE die) {
-    // Check the language, but only if we have a language filter.
-    if (query.HasLanguage()) {
-      if (!query.LanguageMatches(GetLanguageFamily(*die.GetCU())))
-        return true; // Keep iterating over index types, language mismatch.
-    }
+  m_index->GetTypesWithParents(
+      query.GetTypeBasename(), parent_names, [&](DWARFDIE die) {
+        // Check the language, but only if we have a language filter.
+        if (query.HasLanguage()) {
+          if (!query.LanguageMatches(GetLanguageFamily(*die.GetCU())))
+            return true; // Keep iterating over index types, language mismatch.
+        }
 
-    // Check the context matches
-    std::vector<lldb_private::CompilerContext> die_context;
-    if (query.GetModuleSearch())
-      die_context = die.GetDeclContext();
-    else
-      die_context = die.GetTypeLookupContext();
-    assert(!die_context.empty());
-    if (!query.ContextMatches(die_context))
-      return true; // Keep iterating over index types, context mismatch.
-
-    // Try to resolve the type.
-    if (Type *matching_type = ResolveType(die, true, true)) {
-      if (matching_type->IsTemplateType()) {
-        // We have to watch out for case where we lookup a type by basename and
-        // it matches a template with simple template names. Like looking up
-        // "Foo" and if we have simple template names then we will match
-        // "Foo<int>" and "Foo<double>" because all the DWARF has is "Foo" in
-        // the accelerator tables. The main case we see this in is when the
-        // expression parser is trying to parse "Foo<int>" and it will first do
-        // a lookup on just "Foo". We verify the type basename matches before
-        // inserting the type in the results.
-        auto CompilerTypeBasename =
-            matching_type->GetForwardCompilerType().GetTypeName(true);
-        if (CompilerTypeBasename != query.GetTypeBasename())
-          return true; // Keep iterating over index types, basename mismatch.
-      }
-      have_index_match = true;
-      results.InsertUnique(matching_type->shared_from_this());
-    }
-    return !results.Done(query); // Keep iterating if we aren't done.
-  });
+        // Check the context matches
+        std::vector<lldb_private::CompilerContext> die_context;
+        if (query.GetModuleSearch())
+          die_context = die.GetDeclContext();
+        else
+          die_context = die.GetTypeLookupContext();
+        assert(!die_context.empty());
+        if (!query.ContextMatches(die_context))
+          return true; // Keep iterating over index types, context mismatch.
+
+        // Try to resolve the type.
+        if (Type *matching_type = ResolveType(die, true, true)) {
+          if (matching_type->IsTemplateType()) {
+            // We have to watch out for case where we lookup a type by basename
+            // and it matches a template with simple template names. Like
+            // looking up "Foo" and if we have simple template names then we
+            // will match "Foo<int>" and "Foo<double>" because all the DWARF has
+            // is "Foo" in the accelerator tables. The main case we see this in
+            // is when the expression parser is trying to parse "Foo<int>" and
+            // it will first do a lookup on just "Foo". We verify the type
+            // basename matches before inserting the type in...
[truncated]

``````````

</details>


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


More information about the lldb-commits mailing list