Author: Augusto Noronha
Date: 2025-12-03T16:15:36-08:00
New Revision: d7fb086668dff682fd2693a3df87a90b2b15a3c6

URL: 
https://github.com/llvm/llvm-project/commit/d7fb086668dff682fd2693a3df87a90b2b15a3c6
DIFF: 
https://github.com/llvm/llvm-project/commit/d7fb086668dff682fd2693a3df87a90b2b15a3c6.diff

LOG: [lldb] Refactor LookupInfo object to be per-language (#168797)

Some months ago, the LookupInfo constructor logic was refactored to not
depend on language specific logic, and use languages plugins instead. In
this refactor, when the language type is unknown, a single LookupInfo
object will handle multiple languages. This doesn't work well, as
multiple languages might want to configure the LookupInfo object in
different ways. For example, different languages might want to set the
m_lookup_name differently from each other, but the previous
implementation would pick the first name a language provided, and
effectively ignored every other language. Other fields of the LookupInfo
object are also configured in incompatible ways.

This approach doesn't seem to be a problem upstream, since only the
C++/Objective-C language plugins are available, but it broke downstream
on the Swift fork, as adding Swift to the list of default languages when
the language type is unknown breaks C++ tests.

This patch makes it so instead of building a single LookupInfo object
for multiple languages, one LookupInfo object is built per language
instead.

rdar://159531216

Added: 
    lldb/unittests/Core/ModuleTest.cpp

Modified: 
    lldb/include/lldb/Core/Module.h
    lldb/include/lldb/Symbol/SymbolContext.h
    lldb/include/lldb/Symbol/SymbolFile.h
    lldb/source/Breakpoint/BreakpointResolverName.cpp
    lldb/source/Core/Module.cpp
    lldb/source/Core/ModuleList.cpp
    lldb/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.cpp
    lldb/source/Plugins/SymbolFile/DWARF/DWARFIndex.cpp
    lldb/source/Plugins/SymbolFile/DWARF/DWARFIndex.h
    lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
    lldb/source/Symbol/SymbolContext.cpp
    lldb/source/Symbol/SymbolFile.cpp
    
lldb/test/API/functionalities/breakpoint/serialize/TestBreakpointSerialization.py
    lldb/tools/lldb-test/lldb-test.cpp
    lldb/unittests/Core/CMakeLists.txt

Removed: 
    


################################################################################
diff  --git a/lldb/include/lldb/Core/Module.h b/lldb/include/lldb/Core/Module.h
index 8513e147ee523..96ae8364c94e5 100644
--- a/lldb/include/lldb/Core/Module.h
+++ b/lldb/include/lldb/Core/Module.h
@@ -315,6 +315,15 @@ class Module : public std::enable_shared_from_this<Module>,
                      const ModuleFunctionSearchOptions &options,
                      SymbolContextList &sc_list);
 
+  /// Find functions by a vector of lookup infos.
+  ///
+  /// If the function is an inlined function, it will have a block,
+  /// representing the inlined function, and the function will be the
+  /// containing function.  If it is not inlined, then the block will be NULL.
+  void FindFunctions(const std::vector<LookupInfo> &lookup_infos,
+                     const CompilerDeclContext &parent_decl_ctx,
+                     const ModuleFunctionSearchOptions &options,
+                     SymbolContextList &sc_list);
   /// Find functions by name.
   ///
   /// If the function is an inlined function, it will have a block,
@@ -917,8 +926,29 @@ class Module : public std::enable_shared_from_this<Module>,
   public:
     LookupInfo() = default;
 
-    LookupInfo(ConstString name, lldb::FunctionNameType name_type_mask,
-               lldb::LanguageType language);
+    /// Creates a vector of lookup infos for function name resolution.
+    ///
+    /// \param[in] name
+    ///     The function name to search for. This can be a simple name like
+    ///     "foo" or a qualified name like "Class::method".
+    ///
+    /// \param[in] name_type_mask
+    ///     A bitmask specifying what types of names to search for
+    ///     (e.g., eFunctionNameTypeFull, eFunctionNameTypeBase,
+    ///     eFunctionNameTypeMethod, eFunctionNameTypeAuto). Multiple types
+    ///     can be combined with bitwise OR.
+    ///
+    /// \param[in] lang_type
+    ///     The language to create lookups for. If eLanguageTypeUnknown is
+    ///     passed, creates one LookupInfo for each language plugin currently
+    ///     available in LLDB. If a specific language is provided, creates only
+    //      a single LookupInfo for that language.
+    ///
+    /// \return
+    ///     A vector of LookupInfo objects, one per relevant language.
+    static std::vector<LookupInfo>
+    MakeLookupInfos(ConstString name, lldb::FunctionNameType name_type_mask,
+                    lldb::LanguageType lang_type);
 
     ConstString GetName() const { return m_name; }
 
@@ -959,6 +989,10 @@ class Module : public std::enable_shared_from_this<Module>,
     /// If \b true, then demangled names that match will need to contain
     /// "m_name" in order to be considered a match
     bool m_match_name_after_lookup = false;
+
+  private:
+    LookupInfo(ConstString name, lldb::FunctionNameType name_type_mask,
+               lldb::LanguageType lang_type);
   };
 
   /// Get a unique hash for this module.

diff  --git a/lldb/include/lldb/Symbol/SymbolContext.h 
b/lldb/include/lldb/Symbol/SymbolContext.h
index af2f694e554de..0834825cdbd25 100644
--- a/lldb/include/lldb/Symbol/SymbolContext.h
+++ b/lldb/include/lldb/Symbol/SymbolContext.h
@@ -231,6 +231,20 @@ class SymbolContext {
 
   lldb::LanguageType GetLanguage() const;
 
+  /// Compares the two symbol contexts, considering that the symbol may or may
+  /// not be present. If both symbols are present, compare them, if one of the
+  /// symbols is not present, consider the symbol contexts as equal as long as
+  /// the other fields are equal.
+  ///
+  /// This function exists because SymbolContexts are often created without the
+  /// symbol, which is filled in later on, after its creation.
+  static bool CompareConsideringPossiblyNullSymbol(const SymbolContext &lhs,
+                                                   const SymbolContext &rhs);
+
+  /// Compares the two symbol contexts, except for the symbol field.
+  static bool CompareWithoutSymbol(const SymbolContext &lhs,
+                                   const SymbolContext &rhs);
+
   /// Find a block that defines the function represented by this symbol
   /// context.
   ///

diff  --git a/lldb/include/lldb/Symbol/SymbolFile.h 
b/lldb/include/lldb/Symbol/SymbolFile.h
index 3b4d7bc01d132..305eb0f201b37 100644
--- a/lldb/include/lldb/Symbol/SymbolFile.h
+++ b/lldb/include/lldb/Symbol/SymbolFile.h
@@ -309,6 +309,10 @@ class SymbolFile : public PluginInterface {
   virtual void FindFunctions(const Module::LookupInfo &lookup_info,
                              const CompilerDeclContext &parent_decl_ctx,
                              bool include_inlines, SymbolContextList &sc_list);
+  virtual void
+  FindFunctions(const std::vector<Module::LookupInfo> &lookup_infos,
+                const CompilerDeclContext &parent_decl_ctx,
+                bool include_inlines, SymbolContextList &sc_list);
   virtual void FindFunctions(const RegularExpression &regex,
                              bool include_inlines, SymbolContextList &sc_list);
 

diff  --git a/lldb/source/Breakpoint/BreakpointResolverName.cpp 
b/lldb/source/Breakpoint/BreakpointResolverName.cpp
index 4f252f91cccdc..2025f59eacb92 100644
--- a/lldb/source/Breakpoint/BreakpointResolverName.cpp
+++ b/lldb/source/Breakpoint/BreakpointResolverName.cpp
@@ -218,19 +218,22 @@ StructuredData::ObjectSP 
BreakpointResolverName::SerializeToStructuredData() {
 
 void BreakpointResolverName::AddNameLookup(ConstString name,
                                            FunctionNameType name_type_mask) {
-
-  Module::LookupInfo lookup(name, name_type_mask, m_language);
-  m_lookups.emplace_back(lookup);
+  std::vector<Module::LookupInfo> infos =
+      Module::LookupInfo::MakeLookupInfos(name, name_type_mask, m_language);
+  llvm::append_range(m_lookups, infos);
 
   auto add_variant_funcs = [&](Language *lang) {
     for (Language::MethodNameVariant variant :
          lang->GetMethodNameVariants(name)) {
       // FIXME: Should we be adding variants that aren't of type Full?
       if (variant.GetType() & lldb::eFunctionNameTypeFull) {
-        Module::LookupInfo variant_lookup(name, variant.GetType(),
-                                          lang->GetLanguageType());
-        variant_lookup.SetLookupName(variant.GetName());
-        m_lookups.emplace_back(variant_lookup);
+        std::vector<Module::LookupInfo> variant_lookups =
+            Module::LookupInfo::MakeLookupInfos(name, variant.GetType(),
+                                                lang->GetLanguageType());
+        llvm::for_each(variant_lookups, [&](auto &variant_lookup) {
+          variant_lookup.SetLookupName(variant.GetName());
+        });
+        llvm::append_range(m_lookups, variant_lookups);
       }
     }
     return IterationAction::Continue;
@@ -401,14 +404,22 @@ void BreakpointResolverName::GetDescription(Stream *s) {
   if (m_match_type == Breakpoint::Regexp)
     s->Printf("regex = '%s'", m_regex.GetText().str().c_str());
   else {
-    size_t num_names = m_lookups.size();
-    if (num_names == 1)
-      s->Printf("name = '%s'", m_lookups[0].GetName().GetCString());
+    // Since there may be many lookups objects for the same name breakpoint 
(one
+    // per language available), unique them by name, and operate on those 
unique
+    // names.
+    std::vector<ConstString> unique_lookups;
+    for (auto &lookup : m_lookups) {
+      if (!llvm::is_contained(unique_lookups, lookup.GetName()))
+        unique_lookups.push_back(lookup.GetName());
+    }
+    if (unique_lookups.size() == 1)
+      s->Printf("name = '%s'", unique_lookups[0].GetCString());
     else {
+      size_t num_names = unique_lookups.size();
       s->Printf("names = {");
       for (size_t i = 0; i < num_names; i++) {
         s->Printf("%s'%s'", (i == 0 ? "" : ", "),
-                  m_lookups[i].GetName().GetCString());
+                  unique_lookups[i].GetCString());
       }
       s->Printf("}");
     }

diff  --git a/lldb/source/Core/Module.cpp b/lldb/source/Core/Module.cpp
index 815cc9dada2c1..eb2f95b105a5d 100644
--- a/lldb/source/Core/Module.cpp
+++ b/lldb/source/Core/Module.cpp
@@ -643,26 +643,13 @@ void Module::FindCompileUnits(const FileSpec &path,
 
 Module::LookupInfo::LookupInfo(ConstString name,
                                FunctionNameType name_type_mask,
-                               LanguageType language)
-    : m_name(name), m_lookup_name(name), m_language(language) {
+                               LanguageType lang_type)
+    : m_name(name), m_lookup_name(name), m_language(lang_type) {
   std::optional<ConstString> basename;
-
-  std::vector<Language *> languages;
-  {
-    std::vector<LanguageType> lang_types;
-    if (language != eLanguageTypeUnknown)
-      lang_types.push_back(language);
-    else
-      lang_types = {eLanguageTypeObjC, eLanguageTypeC_plus_plus};
-
-    for (LanguageType lang_type : lang_types) {
-      if (Language *lang = Language::FindPlugin(lang_type))
-        languages.push_back(lang);
-    }
-  }
+  Language *lang = Language::FindPlugin(lang_type);
 
   if (name_type_mask & eFunctionNameTypeAuto) {
-    for (Language *lang : languages) {
+    if (lang) {
       auto info = lang->GetFunctionNameInfo(name);
       if (info.first != eFunctionNameTypeNone) {
         m_name_type_mask |= info.first;
@@ -679,7 +666,7 @@ Module::LookupInfo::LookupInfo(ConstString name,
 
   } else {
     m_name_type_mask = name_type_mask;
-    for (Language *lang : languages) {
+    if (lang) {
       auto info = lang->GetFunctionNameInfo(name);
       if (info.first & m_name_type_mask) {
         // If the user asked for FunctionNameTypes that aren't possible,
@@ -688,14 +675,12 @@ Module::LookupInfo::LookupInfo(ConstString name,
         // ObjC)
         m_name_type_mask &= info.first;
         basename = info.second;
-        break;
-      }
-      // Still try and get a basename in case someone specifies a name type 
mask
-      // of eFunctionNameTypeFull and a name like "A::func"
-      if (name_type_mask & eFunctionNameTypeFull &&
-          info.first != eFunctionNameTypeNone && !basename && info.second) {
+      } else if (name_type_mask & eFunctionNameTypeFull &&
+                 info.first != eFunctionNameTypeNone && !basename &&
+                 info.second) {
+        // Still try and get a basename in case someone specifies a name type
+        // mask of eFunctionNameTypeFull and a name like "A::func"
         basename = info.second;
-        break;
       }
     }
   }
@@ -711,6 +696,36 @@ Module::LookupInfo::LookupInfo(ConstString name,
   }
 }
 
+std::vector<Module::LookupInfo>
+Module::LookupInfo::MakeLookupInfos(ConstString name,
+                                    lldb::FunctionNameType name_type_mask,
+                                    lldb::LanguageType lang_type) {
+  std::vector<LanguageType> lang_types;
+  if (lang_type != eLanguageTypeUnknown) {
+    lang_types.push_back(lang_type);
+  } else {
+    // If the language type was not specified, look up in every language
+    // available.
+    Language::ForEach([&](Language *lang) {
+      auto lang_type = lang->GetLanguageType();
+      if (!llvm::is_contained(lang_types, lang_type))
+        lang_types.push_back(lang_type);
+      return IterationAction::Continue;
+    });
+
+    if (lang_types.empty())
+      lang_types = {eLanguageTypeObjC, eLanguageTypeC_plus_plus};
+  }
+
+  std::vector<Module::LookupInfo> infos;
+  infos.reserve(lang_types.size());
+  for (LanguageType lang_type : lang_types) {
+    Module::LookupInfo info(name, name_type_mask, lang_type);
+    infos.push_back(info);
+  }
+  return infos;
+}
+
 bool Module::LookupInfo::NameMatchesLookupInfo(
     ConstString function_name, LanguageType language_type) const {
   // We always keep unnamed symbols
@@ -824,18 +839,29 @@ void Module::FindFunctions(const Module::LookupInfo 
&lookup_info,
   }
 }
 
+void Module::FindFunctions(const std::vector<Module::LookupInfo> &lookup_infos,
+                           const CompilerDeclContext &parent_decl_ctx,
+                           const ModuleFunctionSearchOptions &options,
+                           SymbolContextList &sc_list) {
+  for (auto &lookup_info : lookup_infos)
+    FindFunctions(lookup_info, parent_decl_ctx, options, sc_list);
+}
+
 void Module::FindFunctions(ConstString name,
                            const CompilerDeclContext &parent_decl_ctx,
                            FunctionNameType name_type_mask,
                            const ModuleFunctionSearchOptions &options,
                            SymbolContextList &sc_list) {
-  const size_t old_size = sc_list.GetSize();
-  LookupInfo lookup_info(name, name_type_mask, eLanguageTypeUnknown);
-  FindFunctions(lookup_info, parent_decl_ctx, options, sc_list);
-  if (name_type_mask & eFunctionNameTypeAuto) {
-    const size_t new_size = sc_list.GetSize();
-    if (old_size < new_size)
-      lookup_info.Prune(sc_list, old_size);
+  std::vector<LookupInfo> lookup_infos =
+      LookupInfo::MakeLookupInfos(name, name_type_mask, eLanguageTypeUnknown);
+  for (auto &lookup_info : lookup_infos) {
+    const size_t old_size = sc_list.GetSize();
+    FindFunctions(lookup_info, parent_decl_ctx, options, sc_list);
+    if (name_type_mask & eFunctionNameTypeAuto) {
+      const size_t new_size = sc_list.GetSize();
+      if (old_size < new_size)
+        lookup_info.Prune(sc_list, old_size);
+    }
   }
 }
 

diff  --git a/lldb/source/Core/ModuleList.cpp b/lldb/source/Core/ModuleList.cpp
index 5444c04e74522..be6ff723e0ffa 100644
--- a/lldb/source/Core/ModuleList.cpp
+++ b/lldb/source/Core/ModuleList.cpp
@@ -453,21 +453,22 @@ void ModuleList::FindFunctions(ConstString name,
                                FunctionNameType name_type_mask,
                                const ModuleFunctionSearchOptions &options,
                                SymbolContextList &sc_list) const {
-  const size_t old_size = sc_list.GetSize();
-
   if (name_type_mask & eFunctionNameTypeAuto) {
-    Module::LookupInfo lookup_info(name, name_type_mask, eLanguageTypeUnknown);
-
+    std::vector<Module::LookupInfo> lookup_infos =
+        Module::LookupInfo::MakeLookupInfos(name, name_type_mask,
+                                            eLanguageTypeUnknown);
     std::lock_guard<std::recursive_mutex> guard(m_modules_mutex);
-    for (const ModuleSP &module_sp : m_modules) {
-      module_sp->FindFunctions(lookup_info, CompilerDeclContext(), options,
-                               sc_list);
-    }
-
-    const size_t new_size = sc_list.GetSize();
+    for (const auto &lookup_info : lookup_infos) {
+      const size_t old_size = sc_list.GetSize();
+      for (const ModuleSP &module_sp : m_modules) {
+        module_sp->FindFunctions(lookup_info, CompilerDeclContext(), options,
+                                 sc_list);
+      }
 
-    if (old_size < new_size)
-      lookup_info.Prune(sc_list, old_size);
+      const size_t new_size = sc_list.GetSize();
+      if (old_size < new_size)
+        lookup_info.Prune(sc_list, old_size);
+    }
   } else {
     std::lock_guard<std::recursive_mutex> guard(m_modules_mutex);
     for (const ModuleSP &module_sp : m_modules) {
@@ -480,21 +481,24 @@ void ModuleList::FindFunctions(ConstString name,
 void ModuleList::FindFunctionSymbols(ConstString name,
                                      lldb::FunctionNameType name_type_mask,
                                      SymbolContextList &sc_list) {
-  const size_t old_size = sc_list.GetSize();
-
   if (name_type_mask & eFunctionNameTypeAuto) {
-    Module::LookupInfo lookup_info(name, name_type_mask, eLanguageTypeUnknown);
+    std::vector<Module::LookupInfo> lookup_infos =
+        Module::LookupInfo::MakeLookupInfos(name, name_type_mask,
+                                            eLanguageTypeUnknown);
 
     std::lock_guard<std::recursive_mutex> guard(m_modules_mutex);
-    for (const ModuleSP &module_sp : m_modules) {
-      module_sp->FindFunctionSymbols(lookup_info.GetLookupName(),
-                                     lookup_info.GetNameTypeMask(), sc_list);
-    }
+    for (const auto &lookup_info : lookup_infos) {
+      const size_t old_size = sc_list.GetSize();
+      for (const ModuleSP &module_sp : m_modules) {
+        module_sp->FindFunctionSymbols(lookup_info.GetLookupName(),
+                                       lookup_info.GetNameTypeMask(), sc_list);
+      }
 
-    const size_t new_size = sc_list.GetSize();
+      const size_t new_size = sc_list.GetSize();
 
-    if (old_size < new_size)
-      lookup_info.Prune(sc_list, old_size);
+      if (old_size < new_size)
+        lookup_info.Prune(sc_list, old_size);
+    }
   } else {
     std::lock_guard<std::recursive_mutex> guard(m_modules_mutex);
     for (const ModuleSP &module_sp : m_modules) {

diff  --git a/lldb/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.cpp 
b/lldb/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.cpp
index ce2ba69be2e96..14932e957d081 100644
--- a/lldb/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.cpp
+++ b/lldb/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.cpp
@@ -437,7 +437,7 @@ void SymbolFileBreakpad::FindFunctions(
       sc.comp_unit = cu_sp.get();
       sc.function = func_sp.get();
       sc.module_sp = func_sp->CalculateSymbolContextModule();
-      sc_list.Append(sc);
+      sc_list.AppendIfUnique(sc, /*merge_symbol_into_function=*/true);
     }
   }
 }

diff  --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFIndex.cpp 
b/lldb/source/Plugins/SymbolFile/DWARF/DWARFIndex.cpp
index 64a8005308454..c4efc06ab7873 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFIndex.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFIndex.cpp
@@ -173,6 +173,14 @@ void DWARFIndex::GetNamespacesWithParents(
   });
 }
 
+void DWARFIndex::GetFunctions(
+    const std::vector<Module::LookupInfo> &lookup_infos, SymbolFileDWARF 
&dwarf,
+    const CompilerDeclContext &parent_decl_ctx,
+    llvm::function_ref<IterationAction(DWARFDIE die)> callback) {
+  for (auto &lookup_info : lookup_infos)
+    GetFunctions(lookup_info, dwarf, parent_decl_ctx, callback);
+}
+
 IterationAction DWARFIndex::ProcessNamespaceDieMatchParents(
     const CompilerDeclContext &parent_decl_ctx, DWARFDIE die,
     llvm::function_ref<IterationAction(DWARFDIE die)> callback) {

diff  --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFIndex.h 
b/lldb/source/Plugins/SymbolFile/DWARF/DWARFIndex.h
index be73255aaf141..eaf1da123602e 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFIndex.h
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFIndex.h
@@ -86,6 +86,11 @@ class DWARFIndex {
                const CompilerDeclContext &parent_decl_ctx,
                llvm::function_ref<IterationAction(DWARFDIE die)> callback) = 0;
   virtual void
+  GetFunctions(const std::vector<Module::LookupInfo> &lookup_infos,
+               SymbolFileDWARF &dwarf,
+               const CompilerDeclContext &parent_decl_ctx,
+               llvm::function_ref<IterationAction(DWARFDIE die)> callback);
+  virtual void
   GetFunctions(const RegularExpression &regex,
                llvm::function_ref<IterationAction(DWARFDIE die)> callback) = 0;
 

diff  --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp 
b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
index 7ba765371c54f..b755f3a6faaa0 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
@@ -2481,7 +2481,7 @@ bool SymbolFileDWARF::ResolveFunction(const DWARFDIE 
&orig_die,
         sc.block = function_block.FindBlockByID(inlined_die.GetOffset());
     }
 
-    sc_list.Append(sc);
+    sc_list.AppendIfUnique(sc, /*merge_symbol_into_function=*/true);
     return true;
   }
 
@@ -2549,11 +2549,11 @@ SymbolFileDWARF::FindFunctionDefinition(const 
FunctionCallLabel &label,
                                         const DWARFDIE &declaration) {
   auto do_lookup = [this](llvm::StringRef lookup_name) -> DWARFDIE {
     DWARFDIE found;
-    Module::LookupInfo info(ConstString(lookup_name),
-                            lldb::eFunctionNameTypeFull,
-                            lldb::eLanguageTypeUnknown);
+    auto lookup_infos = Module::LookupInfo::MakeLookupInfos(
+        ConstString(lookup_name), lldb::eFunctionNameTypeFull,
+        lldb::eLanguageTypeUnknown);
 
-    m_index->GetFunctions(info, *this, {}, [&](DWARFDIE entry) {
+    m_index->GetFunctions(lookup_infos, *this, {}, [&](DWARFDIE entry) {
       if (entry.GetAttributeValueAsUnsigned(llvm::dwarf::DW_AT_declaration, 0))
         return IterationAction::Continue;
 

diff  --git a/lldb/source/Symbol/SymbolContext.cpp 
b/lldb/source/Symbol/SymbolContext.cpp
index 3bbd1eff824e6..ead924afa9fc2 100644
--- a/lldb/source/Symbol/SymbolContext.cpp
+++ b/lldb/source/Symbol/SymbolContext.cpp
@@ -324,12 +324,32 @@ uint32_t SymbolContext::GetResolvedMask() const {
 
 bool lldb_private::operator==(const SymbolContext &lhs,
                               const SymbolContext &rhs) {
-  return lhs.function == rhs.function && lhs.symbol == rhs.symbol &&
+  return SymbolContext::CompareWithoutSymbol(lhs, rhs) &&
+         lhs.symbol == rhs.symbol;
+}
+
+bool SymbolContext::CompareConsideringPossiblyNullSymbol(
+    const SymbolContext &lhs, const SymbolContext &rhs) {
+  if (!CompareWithoutSymbol(lhs, rhs))
+    return false;
+
+  // If one (or both) of the symbol context's symbol is empty, consider them
+  // equal.
+  if (!lhs.symbol || !rhs.symbol)
+    return true;
+
+  // If both symbols are present, make sure they're the same.
+  return lhs.symbol == rhs.symbol;
+}
+
+bool SymbolContext::CompareWithoutSymbol(const SymbolContext &lhs,
+                                         const SymbolContext &rhs) {
+  return lhs.function == rhs.function &&
          lhs.module_sp.get() == rhs.module_sp.get() &&
          lhs.comp_unit == rhs.comp_unit &&
          lhs.target_sp.get() == rhs.target_sp.get() &&
          LineEntry::Compare(lhs.line_entry, rhs.line_entry) == 0 &&
-         lhs.variable == rhs.variable;
+         lhs.variable == rhs.variable && lhs.block == rhs.block;
 }
 
 bool lldb_private::operator!=(const SymbolContext &lhs,
@@ -1200,7 +1220,10 @@ bool SymbolContextList::AppendIfUnique(const 
SymbolContext &sc,
                                        bool merge_symbol_into_function) {
   collection::iterator pos, end = m_symbol_contexts.end();
   for (pos = m_symbol_contexts.begin(); pos != end; ++pos) {
-    if (*pos == sc)
+    // Because symbol contexts might first be built without the symbol,
+    // which is then appended later on, compare the symbol contexts taking into
+    // accout that one (or either) of them might not have a symbol yet.
+    if (SymbolContext::CompareConsideringPossiblyNullSymbol(*pos, sc))
       return false;
   }
   if (merge_symbol_into_function && sc.symbol != nullptr &&

diff  --git a/lldb/source/Symbol/SymbolFile.cpp 
b/lldb/source/Symbol/SymbolFile.cpp
index 870d778dca740..2aea802b6c826 100644
--- a/lldb/source/Symbol/SymbolFile.cpp
+++ b/lldb/source/Symbol/SymbolFile.cpp
@@ -126,6 +126,14 @@ void SymbolFile::FindFunctions(const Module::LookupInfo 
&lookup_info,
                                bool include_inlines,
                                SymbolContextList &sc_list) {}
 
+void SymbolFile::FindFunctions(
+    const std::vector<Module::LookupInfo> &lookup_infos,
+    const CompilerDeclContext &parent_decl_ctx, bool include_inlines,
+    SymbolContextList &sc_list) {
+  for (const auto &lookup_info : lookup_infos)
+    FindFunctions(lookup_info, parent_decl_ctx, include_inlines, sc_list);
+}
+
 void SymbolFile::FindFunctions(const RegularExpression &regex,
                                bool include_inlines,
                                SymbolContextList &sc_list) {}

diff  --git 
a/lldb/test/API/functionalities/breakpoint/serialize/TestBreakpointSerialization.py
 
b/lldb/test/API/functionalities/breakpoint/serialize/TestBreakpointSerialization.py
index 411ce9c67da02..55cc12e894d42 100644
--- 
a/lldb/test/API/functionalities/breakpoint/serialize/TestBreakpointSerialization.py
+++ 
b/lldb/test/API/functionalities/breakpoint/serialize/TestBreakpointSerialization.py
@@ -210,6 +210,11 @@ def check_equivalence(self, source_bps, do_write=True):
                 "Source and dest breakpoints are not identical: \nsource: 
%s\ndest: %s"
                 % (source_text, copy_text),
             )
+            self.assertEqual(
+                source_bp.GetNumLocations(),
+                copy_bp.GetNumLocations(),
+                "Source and dest num locations are not the same",
+            )
 
     def do_check_resolvers(self):
         """Use Python APIs to check serialization of breakpoint resolvers"""
@@ -386,7 +391,7 @@ def do_check_appending(self):
         source_bps.Clear()
 
         bkpt = self.orig_target.BreakpointCreateByName(
-            "blubby", lldb.eFunctionNameTypeAuto, empty_module_list, 
empty_cu_list
+            "main", lldb.eFunctionNameTypeAuto, empty_module_list, 
empty_cu_list
         )
         bkpt.SetIgnoreCount(10)
         bkpt.SetThreadName("grubby")
@@ -394,7 +399,7 @@ def do_check_appending(self):
         all_bps.Append(bkpt)
 
         bkpt = self.orig_target.BreakpointCreateByName(
-            "blubby", lldb.eFunctionNameTypeFull, empty_module_list, 
empty_cu_list
+            "main", lldb.eFunctionNameTypeFull, empty_module_list, 
empty_cu_list
         )
         bkpt.SetCondition("something != something_else")
         bkpt.SetQueueName("grubby")

diff  --git a/lldb/tools/lldb-test/lldb-test.cpp 
b/lldb/tools/lldb-test/lldb-test.cpp
index 3f198d963a93b..84e83da230029 100644
--- a/lldb/tools/lldb-test/lldb-test.cpp
+++ b/lldb/tools/lldb-test/lldb-test.cpp
@@ -523,9 +523,10 @@ Error opts::symbols::findFunctions(lldb_private::Module 
&Module) {
         ContextOr->IsValid() ? *ContextOr : CompilerDeclContext();
 
     List.Clear();
-    lldb_private::Module::LookupInfo lookup_info(
-        ConstString(Name), getFunctionNameFlags(), eLanguageTypeUnknown);
-    Symfile.FindFunctions(lookup_info, ContextPtr, true, List);
+    std::vector<lldb_private::Module::LookupInfo> lookup_infos =
+        lldb_private::Module::LookupInfo::MakeLookupInfos(
+            ConstString(Name), getFunctionNameFlags(), eLanguageTypeUnknown);
+    Symfile.FindFunctions(lookup_infos, ContextPtr, true, List);
   }
   outs() << formatv("Found {0} functions:\n", List.GetSize());
   StreamString Stream;

diff  --git a/lldb/unittests/Core/CMakeLists.txt 
b/lldb/unittests/Core/CMakeLists.txt
index f0c9a9a9d5056..d69432d332f44 100644
--- a/lldb/unittests/Core/CMakeLists.txt
+++ b/lldb/unittests/Core/CMakeLists.txt
@@ -9,6 +9,7 @@ add_lldb_unittest(LLDBCoreTests
   MangledTest.cpp
   ModuleListTest.cpp
   ModuleSpecTest.cpp
+  ModuleTest.cpp
   PluginManagerTest.cpp
   ProgressReportTest.cpp
   RichManglingContextTest.cpp

diff  --git a/lldb/unittests/Core/ModuleTest.cpp 
b/lldb/unittests/Core/ModuleTest.cpp
new file mode 100644
index 0000000000000..011554d1b0939
--- /dev/null
+++ b/lldb/unittests/Core/ModuleTest.cpp
@@ -0,0 +1,125 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Core/Module.h"
+#include "Plugins/Language/CPlusPlus/CPlusPlusLanguage.h"
+#include "Plugins/ObjectFile/ELF/ObjectFileELF.h"
+#include "Plugins/SymbolFile/Symtab/SymbolFileSymtab.h"
+#include "TestingSupport/SubsystemRAII.h"
+#include "TestingSupport/TestUtilities.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Host/FileSystem.h"
+#include "lldb/Host/HostInfo.h"
+#include "lldb/Target/Language.h"
+#include "gtest/gtest.h"
+#include <optional>
+
+using namespace lldb;
+using namespace lldb_private;
+
+// Test that Module::FindFunctions correctly finds C++ mangled symbols
+// even when multiple language plugins are registered.
+TEST(ModuleTest, FindFunctionsCppMangledName) {
+  // Create a mock language. The point of this language is to return something
+  // in GetFunctionNameInfo that would interfere with the C++ language plugin,
+  // were they sharing the same LookupInfo.
+  class MockLanguageWithBogusLookupInfo : public Language {
+  public:
+    MockLanguageWithBogusLookupInfo() = default;
+    ~MockLanguageWithBogusLookupInfo() override = default;
+
+    lldb::LanguageType GetLanguageType() const override {
+      // The language here doesn't really matter, it just has to be something
+      // that is not C/C++/ObjC.
+      return lldb::eLanguageTypeSwift;
+    }
+
+    llvm::StringRef GetPluginName() override { return "mock-bogus-language"; }
+
+    bool IsSourceFile(llvm::StringRef file_path) const override {
+      return file_path.ends_with(".swift");
+    }
+
+    std::pair<lldb::FunctionNameType, std::optional<ConstString>>
+    GetFunctionNameInfo(ConstString name) const override {
+      // Say that every function is a selector.
+      return {lldb::eFunctionNameTypeSelector, ConstString("BOGUS_BASENAME")};
+    }
+
+    static void Initialize() {
+      PluginManager::RegisterPlugin(GetPluginNameStatic(), "Mock Language",
+                                    CreateInstance);
+    }
+
+    static void Terminate() { PluginManager::UnregisterPlugin(CreateInstance); 
}
+
+    static lldb_private::Language *CreateInstance(lldb::LanguageType language) 
{
+      if (language == lldb::eLanguageTypeSwift)
+        return new MockLanguageWithBogusLookupInfo();
+      return nullptr;
+    }
+
+    static llvm::StringRef GetPluginNameStatic() {
+      return "mock-bogus-language";
+    }
+  };
+  SubsystemRAII<FileSystem, HostInfo, ObjectFileELF, SymbolFileSymtab,
+                CPlusPlusLanguage, MockLanguageWithBogusLookupInfo>
+      subsystems;
+
+  // Create a simple ELF module with std::vector::size() as the only symbol.
+  auto ExpectedFile = TestFile::fromYaml(R"(
+--- !ELF
+FileHeader:
+  Class:           ELFCLASS64
+  Data:            ELFDATA2LSB
+  Type:            ET_DYN
+  Machine:         EM_X86_64
+Sections:
+  - Name:            .text
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC, SHF_EXECINSTR ]
+    Address:         0x1000
+    AddressAlign:    0x10
+    Size:            0x100
+Symbols:
+  - Name:            _ZNSt6vectorIiE4sizeEv
+    Type:            STT_FUNC
+    Section:         .text
+    Value:           0x1030
+    Size:            0x20
+...
+)");
+  ASSERT_THAT_EXPECTED(ExpectedFile, llvm::Succeeded());
+
+  auto module_sp = std::make_shared<Module>(ExpectedFile->moduleSpec());
+
+  // Verify both C++ and our mock language are registered.
+  Language *cpp_lang = Language::FindPlugin(lldb::eLanguageTypeC_plus_plus);
+  Language *mock_lang = Language::FindPlugin(lldb::eLanguageTypeSwift);
+  ASSERT_NE(cpp_lang, nullptr) << "C++ language plugin should be registered";
+  ASSERT_NE(mock_lang, nullptr)
+      << "Mock Swift language plugin should be registered";
+
+  ModuleFunctionSearchOptions function_options;
+  function_options.include_symbols = true;
+
+  ConstString symbol_name("_ZNSt6vectorIiE4sizeEv");
+  SymbolContextList results;
+  module_sp->FindFunctions(symbol_name, CompilerDeclContext(),
+                           eFunctionNameTypeAuto, function_options, results);
+
+  // Assert that we found one symbol.
+  ASSERT_EQ(results.GetSize(), 1u);
+
+  auto result = results[0];
+  auto name = result.GetFunctionName();
+  // Assert that the symbol we found is what we expected.
+  ASSERT_EQ(name, "std::vector<int>::size()");
+  ASSERT_EQ(result.GetLanguage(), eLanguageTypeC_plus_plus);
+}


        
_______________________________________________
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to