diff --git a/lldb/include/lldb/Core/Module.h b/lldb/include/lldb/Core/Module.h --- a/lldb/include/lldb/Core/Module.h +++ b/lldb/include/lldb/Core/Module.h @@ -415,70 +415,19 @@ void FindGlobalVariables(const RegularExpression ®ex, size_t max_matches, VariableList &variable_list); - /// Find types by name. - /// - /// Type lookups in modules go through the SymbolFile. The SymbolFile needs to - /// be able to lookup types by basename and not the fully qualified typename. - /// This allows the type accelerator tables to stay small, even with heavily - /// templatized C++. The type search will then narrow down the search - /// results. If "exact_match" is true, then the type search will only match - /// exact type name matches. If "exact_match" is false, the type will match - /// as long as the base typename matches and as long as any immediate - /// containing namespaces/class scopes that are specified match. So to - /// search for a type "d" in "b::c", the name "b::c::d" can be specified and - /// it will match any class/namespace "b" which contains a class/namespace - /// "c" which contains type "d". We do this to allow users to not always - /// have to specify complete scoping on all expressions, but it also allows - /// for exact matching when required. - /// - /// \param[in] type_name - /// The name of the type we are looking for that is a fully - /// or partially qualified type name. - /// - /// \param[in] exact_match - /// If \b true, \a type_name is fully qualified and must match - /// exactly. If \b false, \a type_name is a partially qualified - /// name where the leading namespaces or classes can be - /// omitted to make finding types that a user may type - /// easier. - /// - /// \param[out] types - /// A type list gets populated with any matches. + /// Find types using a type matching object that contains all search + /// parameters. /// - void - FindTypes(ConstString type_name, bool exact_match, size_t max_matches, - llvm::DenseSet &searched_symbol_files, - TypeList &types); - - /// Find types by name. - /// - /// This behaves like the other FindTypes method but allows to - /// specify a DeclContext and a language for the type being searched - /// for. - /// - /// \param searched_symbol_files - /// Prevents one file from being visited multiple times. - void - FindTypes(llvm::ArrayRef pattern, LanguageSet languages, - llvm::DenseSet &searched_symbol_files, - TypeMap &types); - - lldb::TypeSP FindFirstType(const SymbolContext &sc, ConstString type_name, - bool exact_match); - - /// Find types by name that are in a namespace. This function is used by the - /// expression parser when searches need to happen in an exact namespace - /// scope. + /// \see lldb_private::TypeQuery /// - /// \param[in] type_name - /// The name of a type within a namespace that should not include - /// any qualifying namespaces (just a type basename). + /// \param[in] query + /// A type matching object that contains all of the details of the type + /// search. /// - /// \param[out] type_list - /// A type list gets populated with any matches. - void FindTypesInNamespace(ConstString type_name, - const CompilerDeclContext &parent_decl_ctx, - size_t max_matches, TypeList &type_list); + /// \param[in] results + /// Any matching types will be populated into the \a results object using + /// TypeMap::InsertUnique(...). + void FindTypes(const TypeQuery &query, TypeResults &results); /// Get const accessor for the module architecture. /// @@ -1146,12 +1095,6 @@ private: Module(); // Only used internally by CreateJITModule () - void FindTypes_Impl( - ConstString name, const CompilerDeclContext &parent_decl_ctx, - size_t max_matches, - llvm::DenseSet &searched_symbol_files, - TypeMap &types); - Module(const Module &) = delete; const Module &operator=(const Module &) = delete; }; diff --git a/lldb/include/lldb/Core/ModuleList.h b/lldb/include/lldb/Core/ModuleList.h --- a/lldb/include/lldb/Core/ModuleList.h +++ b/lldb/include/lldb/Core/ModuleList.h @@ -340,26 +340,22 @@ lldb::SymbolType symbol_type, SymbolContextList &sc_list) const; - /// Find types by name. + /// Find types using a type matching object that contains all search + /// parameters. /// /// \param[in] search_first /// If non-null, this module will be searched before any other /// modules. /// - /// \param[in] name - /// The name of the type we are looking for. - /// - /// \param[in] max_matches - /// Allow the number of matches to be limited to \a - /// max_matches. Specify UINT32_MAX to get all possible matches. - /// - /// \param[out] types - /// A type list gets populated with any matches. + /// \param[in] query + /// A type matching object that contains all of the details of the type + /// search. /// - void FindTypes(Module *search_first, ConstString name, - bool name_is_fully_qualified, size_t max_matches, - llvm::DenseSet &searched_symbol_files, - TypeList &types) const; + /// \param[in] results + /// Any matching types will be populated into the \a results object using + /// TypeMap::InsertUnique(...). + void FindTypes(Module *search_first, const TypeQuery &query, + lldb_private::TypeResults &results) const; bool FindSourceFile(const FileSpec &orig_spec, FileSpec &new_spec) const; diff --git a/lldb/include/lldb/Symbol/CompilerDecl.h b/lldb/include/lldb/Symbol/CompilerDecl.h --- a/lldb/include/lldb/Symbol/CompilerDecl.h +++ b/lldb/include/lldb/Symbol/CompilerDecl.h @@ -84,6 +84,14 @@ // based argument index CompilerType GetFunctionArgumentType(size_t arg_idx) const; + /// Populate a valid compiler context from the current declaration. + /// + /// \param context A valid vector of CompilerContext entries that describes + /// this declaration. The first entry in the vector is the parent of + /// the subsequent entry, so the top most entry is the global namespace. + void GetCompilerContext( + llvm::SmallVectorImpl &context) const; + private: TypeSystem *m_type_system = nullptr; void *m_opaque_decl = nullptr; diff --git a/lldb/include/lldb/Symbol/CompilerDeclContext.h b/lldb/include/lldb/Symbol/CompilerDeclContext.h --- a/lldb/include/lldb/Symbol/CompilerDeclContext.h +++ b/lldb/include/lldb/Symbol/CompilerDeclContext.h @@ -11,6 +11,7 @@ #include +#include "lldb/Symbol/Type.h" #include "lldb/Utility/ConstString.h" #include "lldb/lldb-private.h" @@ -56,6 +57,14 @@ return m_type_system != nullptr && m_opaque_decl_ctx != nullptr; } + /// Populate a valid compiler context from the current decl context. + /// + /// \param context A valid vector of CompilerContext entries that describes + /// this declaration context. The first entry in the vector is the parent of + /// the subsequent entry, so the top most entry is the global namespace. + void GetCompilerContext( + llvm::SmallVectorImpl &context) const; + std::vector FindDeclByName(ConstString name, const bool ignore_using_decls); diff --git a/lldb/include/lldb/Symbol/SymbolFile.h b/lldb/include/lldb/Symbol/SymbolFile.h --- a/lldb/include/lldb/Symbol/SymbolFile.h +++ b/lldb/include/lldb/Symbol/SymbolFile.h @@ -284,21 +284,20 @@ bool include_inlines, SymbolContextList &sc_list); virtual void FindFunctions(const RegularExpression ®ex, bool include_inlines, SymbolContextList &sc_list); - virtual void - FindTypes(ConstString name, const CompilerDeclContext &parent_decl_ctx, - uint32_t max_matches, - llvm::DenseSet &searched_symbol_files, - TypeMap &types); - - /// Find types specified by a CompilerContextPattern. - /// \param languages - /// Only return results in these languages. - /// \param searched_symbol_files - /// Prevents one file from being visited multiple times. - virtual void - FindTypes(llvm::ArrayRef pattern, LanguageSet languages, - llvm::DenseSet &searched_symbol_files, - TypeMap &types); + + /// Find types using a type matching object that contains all search + /// parameters. + /// + /// \see lldb_private::TypeQuery + /// + /// \param[in] query + /// A type matching object that contains all of the details of the type + /// search. + /// + /// \param[in] results + /// Any matching types will be populated into the \a results object using + /// TypeMap::InsertUnique(...). + virtual void FindTypes(const TypeQuery &query, TypeResults &results) {} virtual void GetMangledNamesForFunction(const std::string &scope_qualified_name, diff --git a/lldb/include/lldb/Symbol/SymbolFileOnDemand.h b/lldb/include/lldb/Symbol/SymbolFileOnDemand.h --- a/lldb/include/lldb/Symbol/SymbolFileOnDemand.h +++ b/lldb/include/lldb/Symbol/SymbolFileOnDemand.h @@ -151,17 +151,8 @@ const std::string &scope_qualified_name, std::vector &mangled_names) override; - void - FindTypes(lldb_private::ConstString name, - const lldb_private::CompilerDeclContext &parent_decl_ctx, - uint32_t max_matches, - llvm::DenseSet &searched_symbol_files, - lldb_private::TypeMap &types) override; - - void FindTypes(llvm::ArrayRef pattern, - lldb_private::LanguageSet languages, - llvm::DenseSet &searched_symbol_files, - lldb_private::TypeMap &types) override; + void FindTypes(const lldb_private::TypeQuery &query, + lldb_private::TypeResults &results) override; void GetTypes(lldb_private::SymbolContextScope *sc_scope, lldb::TypeClass type_mask, diff --git a/lldb/include/lldb/Symbol/Type.h b/lldb/include/lldb/Symbol/Type.h --- a/lldb/include/lldb/Symbol/Type.h +++ b/lldb/include/lldb/Symbol/Type.h @@ -12,16 +12,38 @@ #include "lldb/Core/Declaration.h" #include "lldb/Symbol/CompilerDecl.h" #include "lldb/Symbol/CompilerType.h" +#include "lldb/Symbol/TypeList.h" +#include "lldb/Symbol/TypeMap.h" +#include "lldb/Symbol/TypeSystem.h" #include "lldb/Utility/ConstString.h" #include "lldb/Utility/UserID.h" #include "lldb/lldb-private.h" #include "llvm/ADT/APSInt.h" +#include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/Optional.h" #include namespace lldb_private { +/// A SmallBitVector that represents a set of source languages (\p +/// lldb::LanguageType). Each lldb::LanguageType is represented by +/// the bit with the position of its enumerator. The largest +/// LanguageType is < 64, so this is space-efficient and on 64-bit +/// architectures a LanguageSet can be completely stack-allocated. +struct LanguageSet { + llvm::SmallBitVector bitvector; + LanguageSet(); + + /// If the set contains a single language only, return it. + llvm::Optional GetSingularLanguage(); + void Insert(lldb::LanguageType language); + bool Empty() const; + size_t Size() const; + bool operator[](unsigned i) const; +}; + /// CompilerContext allows an array of these items to be passed to perform /// detailed lookups in SymbolVendor and SymbolFile functions. struct CompilerContext { @@ -43,6 +65,295 @@ bool contextMatches(llvm::ArrayRef context_chain, llvm::ArrayRef pattern); +/// A class that contains all state required for type lookups. +/// +/// Using a TypeQuery class for matching types simplifies the internal APIs we +/// need to implement type lookups in LLDB. Type lookups can fully specify the +/// exact typename by filling out a complete or partial CompilerContext array. +/// This allows for powerful searches and also allows the SymbolFile classes to +/// use the m_context array to lookup types by basename, then eliminate +/// potential matches without having to resolve types into each TypeSystem. This +/// makes type lookups vastly more efficient and allows the SymbolFile objects +/// to stop looking up types when the type matching is complete, like if we are +/// looking for only a single type in our search. +class TypeQuery { +public: + /// Default constructor. + /// + /// Users will need to call one of the SetMatchContext() functions prior to + /// doing name lookups. + TypeQuery() = delete; + + /// Construct a type match object using a fully or partially qualified name. + /// + /// The specified \a type_name will be chopped up and the m_context will be + /// populated by separating the string by looking for "::". We do this because + /// symbol files have indexes that contain only the type's basename. This also + /// allows symbol files to efficiently not realize types that don't match the + /// specified context. Example of \a type_name values that can be specified + /// include: + /// "foo": Look for any type whose basename matches "foo". + /// If \a exact_match is true, then the type can't be contained in any + /// declaration context like a namespace, class, or other containing + /// scope. + /// If \a exact match is false, then we will find all matches including + /// ones that are contained in other declaration contexts, including top + /// level types. + /// "foo::bar": Look for any type whose basename matches "bar" but make sure + /// its parent declaration context is any named declaration context + /// (namespace, class, struct, etc) whose name matches "foo". + /// If \a exact_match is true, then the "foo" declaration context must + /// appear at the source file level or inside of a function. + /// If \a exact match is false, then the "foo" declaration context can + /// be contained in any other declaration contexts. + /// "class foo": Only match types that are classes whose basename matches + /// "foo". + /// "struct foo": Only match types that are structures whose basename + /// matches "foo". + /// "class foo::bar": Only match types that are classes whose basename + /// matches "bar" and that are contained in any named declaration context + /// named "foo". + /// + /// \param[in] type_name + /// A fully or partially qualified type name. This name will be parsed and + /// broken up and the m_context will be populated with the various parts of + /// the name. This typename can be prefixed with "struct ", "class ", + /// "union", "enum " or "typedef " before the actual type name to limit the + /// results of the types that match. The declaration context can be + /// specified with the "::" string. like "a::b::my_type". + /// + /// \param[in] exact_match + /// If \a exact_match is true, then the typename must match a type's fully + /// qualified name exactly. + /// If \a exact_match is false but \a type_name starts with "::", then an + /// \a exact_match will be set to true internally. + /// If \a exact_match if false, but \a type_name doesn't starts with "::", + /// then an a type name can be partially specfied. For example "b::a", will + /// match: "b::a", "c::b::a", "d::b::a", "e::f::b::a". + TypeQuery(llvm::StringRef name, bool exact_match); + /// Construct a type match object that matches a type basename that exists + /// in the specified declaration context. + /// + /// This allows the m_context to be first populated using a declaration + /// context to exactly identify the containing declaration context of a type. + /// This can be used when you have a forward declaration to a type and you + /// need to search for its complete type. + /// + /// \param[in] decl_ctx + /// A declaration context object that comes from a TypeSystem plug-in. This + /// object will be asked to full the array of CompilerContext objects + /// by adding the top most declaration context first into the array and then + /// adding any containing declaration contexts. + /// + /// \param[in] type_basename + /// The basename of the type to lookup in the specified declaration context. + /// + /// \param[in] module_search True if \a context is a clang module compiler + /// context, false if this is normal type lookup. + TypeQuery(const CompilerDeclContext &decl_ctx, ConstString type_basename, + bool module_search); + /// Construct a type match object using a compiler declaration that specifies + /// a typename and a declaration context to use when doing exact type lookups. + /// + /// This allows the m_context to be first populated using a type declaration. + /// The type declaration might have a declaration context and each TypeSystem + /// plug-in can populate the declaration context needed to perform an exact + /// lookup for a type. + /// This can be used when you have a forward declaration to a type and you + /// need to search for its complete type. + /// + /// \param[in] decl + /// A type declaration context object that comes from a TypeSystem plug-in. + /// This object will be asked to full the array of CompilerContext objects + /// by adding the top most declaration context first into the array and then + /// adding any containing declaration contexts, and ending with the exact + /// typename and the kind of type it is (class, struct, union, enum, etc). + TypeQuery(const CompilerDecl &decl); + + /// Construct a type match object using a CompilerContext array. + /// + /// Clients can manually create compiler contexts and use these to find + /// matches when searching for types. There are two types of contexts that + /// are supported when doing type searchs: type contexts and clang module + /// contexts. Type contexts have contexts that specify the type and its + /// containing declaration context like namespaces and classes. Clang module + /// contexts specify contexts more completely to find exact matches within + /// clang module debug information. They will include the modules that the + /// type is included in and any functions that the type might be defined in. + /// This allows very fine grained type resolution. + /// + /// \param[in] context The compiler context to use when doing the search. + /// + /// \param[in] module_search True if \a context is a clang module compiler + /// context, false if this is normal type lookup. + TypeQuery(const llvm::ArrayRef &context, + bool module_search); + + /// Construct a type match object that duplicates all matching criterea, + /// but not any searched symbol files or the type map for matches. This allows + /// the m_context to be modified prior to performing another search. + TypeQuery(const TypeQuery &rhs); + /// Assign a type match object that duplicates all matching criterea, + /// but not any searched symbol files or the type map for matches. This allows + /// the m_context to be modified prior to performing another search. + void operator=(const TypeQuery &rhs); + + /// Check of a CompilerContext array from matching type from a symbol file + /// matches the \a m_context. + /// + /// \param[in] context + /// A fully qualified CompilerContext array for a potential match that is + /// created by the symbol file prior to trying to actually resolve a type. + /// + /// \returns + /// True if the context matches, false if it doesn't. If \a m_exact_match + /// is true, then \a context must exactly match \a m_context. If + /// \a m_exact_match is false, then the bottom m_context.size() objects in + /// the \a context must match. This allows SymbolFile objects the fill in a + /// potential type basename match from the index into \a context, and see if + /// it matches prior to having to resolve a lldb_private::Type object for + /// the type from the index. This allows type parsing to be as efficient as + /// possible and only realize the types that match the query. + bool ContextMatches(llvm::ArrayRef context) const; + + /// Get the type basename to use when searching the type indexes in each + /// SymbolFile object. + /// + /// Debug information indexes often contain indexes that track the basename + /// of types only, not a fully qualified path. This allows the indexes to be + /// smaller and allows for efficient lookups. + /// + /// \returns + /// The type basename to use when doing lookups as a constant string. + ConstString GetTypeBasename() const; + + /// Returns true if any matching languages have been specified in this type + /// matching object. + bool HasLanguage() const { return m_languages.has_value(); } + + /// Add a language family to the list of languages that should produce a match. + void AddLanguage(lldb::LanguageType language); + + /// Check if the language matches any languages that have been added to this + /// match object. + /// + /// \returns + /// True if no language have been specified, or if some language have been + /// added using AddLanguage(...) and they match. False otherwise. + bool LanguageMatches(lldb::LanguageType language) const; + + /// The \a m_context can be used in two ways: normal types searching with + /// the context containing a stanadard declaration context for a type, or + /// with the context being more complete for exact matches in clang modules. + /// Se this to true if you wish to search for a type in clang module. + bool GetModuleSearch() const { return m_module_search; } + + /// A helper function that sets all of the settings necessary to find a single + /// matching type in a module. + /// + /// \param module The module to find the first type in. + /// + /// \returns A valid TypeSP if a matching type was found, an empty TypeSP if + /// not. + lldb::TypeSP FindFirstType(lldb_private::Module *module); + + /// A helper function that sets all of the settings necessary to find a single + /// matching type in list of modules. + /// + /// \param module_list The module list to linearly search for the first + /// matching type. + /// + /// \param search_first If not NULL, search this module first, and proceed + /// to search the module list linearly if the result was not found in this + /// module. + /// + /// \returns A valid TypeSP if a matching type was found, an empty TypeSP if + /// not. + lldb::TypeSP FindFirstType(const lldb_private::ModuleList &module_list, + lldb_private::Module *search_first = nullptr); + + /// Access the internal compiler context array. + /// + /// Clients can use this to populate the context manually. + llvm::SmallVector &GetContextRef() { return m_context; } + +protected: + /// A full or partial compiler context array where the parent declaration + /// contexts appear at the top of the array starting at index zero and the + /// last entry is contains the type and name of the type we are looking for. + llvm::SmallVector m_context; + /// If this is true, then any matching types must match m_context exactly. If + /// this is false, then only the bottom m_context.size() CompilerContext array + /// entries must match. This allows partial matching to occur. + bool m_exact_match = false; + /// Clang module searches have more entries in the compiler context and are + /// more complete are are used when lookup up types in a clang module's debug + /// information. + bool m_module_search = false; + /// If this has a value, then the language family must match at least one of + /// the specified languages. If this has no value, then the language of the + /// type doesn't need to match any types that are searched. + llvm::Optional m_languages; +}; + +/// This class tracks the state and results of a \ref TypeQuery. +/// +/// Any mutable state required for type lookups and the results are tracked in +/// this object. +class TypeResults { +public: + /// Construct a type results object + /// + /// \param[in] find_one + /// When true, the find types call should stop the query as soon as a single + /// matching type is found. When false, the type query should find all + /// matching types. + TypeResults(bool find_one) : m_find_one(find_one) {} + + /// When types that match a TypeQuery are found, this API is used to insert + /// the matching types. + /// + /// \return + /// True if the type was added, false if the \a type_sp was already in the + /// results. + bool InsertUnique(const lldb::TypeSP &type_sp); + + /// Check if the type matching has found all of the matches that it needs. + bool Done() const; + + /// Check if a SymbolFile object has already been searched by this type match + /// object. + /// + /// Any clients that search for types should first check that the symbol file + /// has not already been searched. If this function returns true, the type + /// search function should early return to avoid duplicating type searchihng + /// efforts. + /// + /// \param[in] sym_file + /// A SymbolFile pointer that will be used to track which symbol files have + /// already been searched. + /// + /// \returns + /// True if the symbol file has been search already, false otherwise. + bool AlreadySearched(lldb_private::SymbolFile *sym_file); + + /// Access the set of searched symbol files. + llvm::DenseSet &GetSearchedSymbolFiles() { + return m_searched_symbol_files; + } + + TypeMap &GetTypeMap() { return m_type_map; } + const TypeMap &GetTypeMap() const { return m_type_map; } +private: + /// Matching types get added to this maps as type search continues. + TypeMap m_type_map; + /// This set is used to track and make sure we only perform lookups in a + /// symbol file one time. + llvm::DenseSet m_searched_symbol_files; + /// If true, just find the first type that matches the specified context. + bool m_find_one; +}; + class SymbolFileType : public std::enable_shared_from_this, public UserID { public: diff --git a/lldb/include/lldb/Symbol/TypeMap.h b/lldb/include/lldb/Symbol/TypeMap.h --- a/lldb/include/lldb/Symbol/TypeMap.h +++ b/lldb/include/lldb/Symbol/TypeMap.h @@ -27,7 +27,7 @@ void Clear(); void Dump(Stream *s, bool show_context, - lldb::DescriptionLevel level = lldb::eDescriptionLevelFull); + lldb::DescriptionLevel level = lldb::eDescriptionLevelFull) const; TypeMap FindTypes(ConstString name); @@ -41,10 +41,12 @@ lldb::TypeSP GetTypeAtIndex(uint32_t idx); + lldb::TypeSP FirstType() const; + typedef std::multimap collection; typedef AdaptedIterable TypeIterable; - TypeIterable Types() { return TypeIterable(m_types); } + TypeIterable Types() const { return TypeIterable(m_types); } void ForEach( std::function const &callback) const; diff --git a/lldb/include/lldb/Symbol/TypeSystem.h b/lldb/include/lldb/Symbol/TypeSystem.h --- a/lldb/include/lldb/Symbol/TypeSystem.h +++ b/lldb/include/lldb/Symbol/TypeSystem.h @@ -25,6 +25,7 @@ #include "lldb/Expression/Expression.h" #include "lldb/Symbol/CompilerDecl.h" #include "lldb/Symbol/CompilerDeclContext.h" +#include "lldb/Symbol/Type.h" #include "lldb/lldb-private.h" class DWARFDIE; @@ -36,22 +37,6 @@ class PdbAstBuilder; } // namespace npdb -/// A SmallBitVector that represents a set of source languages (\p -/// lldb::LanguageType). Each lldb::LanguageType is represented by -/// the bit with the position of its enumerator. The largest -/// LanguageType is < 64, so this is space-efficient and on 64-bit -/// architectures a LanguageSet can be completely stack-allocated. -struct LanguageSet { - llvm::SmallBitVector bitvector; - LanguageSet(); - - /// If the set contains a single language only, return it. - llvm::Optional GetSingularLanguage(); - void Insert(lldb::LanguageType language); - bool Empty() const; - size_t Size() const; - bool operator[](unsigned i) const; -}; /// Interface for representing a type system. /// @@ -112,6 +97,8 @@ virtual CompilerType DeclGetFunctionArgumentType(void *opaque_decl, size_t arg_idx); + virtual void DeclGetCompilerContext(void *opaque_decl, + llvm::SmallVectorImpl &context); virtual CompilerType GetTypeForDecl(void *opaque_decl) = 0; @@ -133,6 +120,8 @@ virtual bool DeclContextIsContainedInLookup(void *opaque_decl_ctx, void *other_opaque_decl_ctx) = 0; + virtual void DeclContextGetCompilerContext(void *opaque_decl_ctx, + llvm::SmallVectorImpl &context); // Tests #ifndef NDEBUG /// Verify the integrity of the type to catch CompilerTypes that mix diff --git a/lldb/include/lldb/lldb-forward.h b/lldb/include/lldb/lldb-forward.h --- a/lldb/include/lldb/lldb-forward.h +++ b/lldb/include/lldb/lldb-forward.h @@ -252,9 +252,11 @@ class TypeList; class TypeListImpl; class TypeMap; +class TypeQuery; class TypeMemberFunctionImpl; class TypeMemberImpl; class TypeNameSpecifierImpl; +class TypeResults; class TypeSummaryImpl; class TypeSummaryOptions; class TypeSystem; diff --git a/lldb/include/lldb/lldb-private-enumerations.h b/lldb/include/lldb/lldb-private-enumerations.h --- a/lldb/include/lldb/lldb-private-enumerations.h +++ b/lldb/include/lldb/lldb-private-enumerations.h @@ -198,12 +198,15 @@ Variable = 1 << 7, Enum = 1 << 8, Typedef = 1 << 9, + Builtin = 1 << 10, Any = 1 << 15, /// Match 0..n nested modules. AnyModule = Any | Module, /// Match any type. - AnyType = Any | Class | Struct | Union | Enum | Typedef + AnyType = Any | Class | Struct | Union | Enum | Typedef | Builtin, + /// Math any declaration context. + AnyDeclContext = Any | Namespace | Class | Struct | Union | Enum | Function }; // Enumerations that can be used to specify the kind of metric we're looking at diff --git a/lldb/source/API/SBModule.cpp b/lldb/source/API/SBModule.cpp --- a/lldb/source/API/SBModule.cpp +++ b/lldb/source/API/SBModule.cpp @@ -437,26 +437,22 @@ LLDB_INSTRUMENT_VA(this, name_cstr); ModuleSP module_sp(GetSP()); - if (!name_cstr || !module_sp) - return {}; - SymbolContext sc; - const bool exact_match = false; - ConstString name(name_cstr); - - SBType sb_type = SBType(module_sp->FindFirstType(sc, name, exact_match)); - - if (sb_type.IsValid()) - return sb_type; + if (name_cstr && module_sp) { + ConstString name(name_cstr); + TypeQuery query(name.GetStringRef(), /*exact_match=*/false); + TypeSP type_sp = query.FindFirstType(module_sp.get()); + if (type_sp) + return SBType(type_sp); + + auto type_system_or_err = module_sp->GetTypeSystemForLanguage(eLanguageTypeC); + if (auto err = type_system_or_err.takeError()) { + llvm::consumeError(std::move(err)); + return {}; + } - auto type_system_or_err = module_sp->GetTypeSystemForLanguage(eLanguageTypeC); - if (auto err = type_system_or_err.takeError()) { - llvm::consumeError(std::move(err)); - return {}; + if (auto ts = *type_system_or_err) + return SBType(ts->GetBuiltinTypeByName(name)); } - - if (auto ts = *type_system_or_err) - return SBType(ts->GetBuiltinTypeByName(name)); - return {}; } @@ -471,7 +467,7 @@ llvm::consumeError(std::move(err)); } else { if (auto ts = *type_system_or_err) - return SBType(ts->GetBasicTypeFromAST(type)); + return SBType(ts->GetBasicTypeFromAST(type)); } } return SBType(); @@ -485,13 +481,11 @@ ModuleSP module_sp(GetSP()); if (type && module_sp) { TypeList type_list; - const bool exact_match = false; - ConstString name(type); - llvm::DenseSet searched_symbol_files; - module_sp->FindTypes(name, exact_match, UINT32_MAX, searched_symbol_files, - type_list); - - if (type_list.Empty()) { + TypeQuery query(type, /*exact_match=*/false); + TypeResults results(/*find_one=*/false); + module_sp->FindTypes(query, results); + if (results.GetTypeMap().Empty()) { + ConstString name(type); auto type_system_or_err = module_sp->GetTypeSystemForLanguage(eLanguageTypeC); if (auto err = type_system_or_err.takeError()) { @@ -502,11 +496,8 @@ retval.Append(SBType(compiler_type)); } } else { - for (size_t idx = 0; idx < type_list.GetSize(); idx++) { - TypeSP type_sp(type_list.GetTypeAtIndex(idx)); - if (type_sp) - retval.Append(SBType(type_sp)); - } + for (const TypeSP &type_sp: results.GetTypeMap().Types()) + retval.Append(SBType(type_sp)); } } return retval; diff --git a/lldb/source/API/SBTarget.cpp b/lldb/source/API/SBTarget.cpp --- a/lldb/source/API/SBTarget.cpp +++ b/lldb/source/API/SBTarget.cpp @@ -1590,7 +1590,7 @@ const char *SBTarget::GetABIName() { LLDB_INSTRUMENT_VA(this); - + TargetSP target_sp(GetSP()); if (target_sp) { std::string abi_name(target_sp->GetABIName().str()); @@ -1751,20 +1751,13 @@ TargetSP target_sp(GetSP()); if (typename_cstr && typename_cstr[0] && target_sp) { ConstString const_typename(typename_cstr); - SymbolContext sc; const bool exact_match = false; - const ModuleList &module_list = target_sp->GetImages(); - size_t count = module_list.GetSize(); - for (size_t idx = 0; idx < count; idx++) { - ModuleSP module_sp(module_list.GetModuleAtIndex(idx)); - if (module_sp) { - TypeSP type_sp( - module_sp->FindFirstType(sc, const_typename, exact_match)); - if (type_sp) - return SBType(type_sp); - } - } + TypeQuery query(const_typename.GetStringRef(), exact_match); + TypeSP type_sp = query.FindFirstType(target_sp->GetImages(), nullptr); + + if (type_sp) + return SBType(type_sp); // Didn't find the type in the symbols; Try the loaded language runtimes. if (auto process_sp = target_sp->GetProcessSP()) { @@ -1806,17 +1799,12 @@ if (typename_cstr && typename_cstr[0] && target_sp) { ModuleList &images = target_sp->GetImages(); ConstString const_typename(typename_cstr); - bool exact_match = false; - TypeList type_list; - llvm::DenseSet searched_symbol_files; - images.FindTypes(nullptr, const_typename, exact_match, UINT32_MAX, - searched_symbol_files, type_list); - - for (size_t idx = 0; idx < type_list.GetSize(); idx++) { - TypeSP type_sp(type_list.GetTypeAtIndex(idx)); - if (type_sp) - sb_type_list.Append(SBType(type_sp)); - } + TypeQuery query(typename_cstr, /*exact_match=*/false); + TypeResults results(/*find_one=*/false); + images.FindTypes(nullptr, query, results); + + for (const TypeSP &type_sp: results.GetTypeMap().Types()) + sb_type_list.Append(SBType(type_sp)); // Try the loaded language runtimes if (auto process_sp = target_sp->GetProcessSP()) { diff --git a/lldb/source/Commands/CommandObjectMemory.cpp b/lldb/source/Commands/CommandObjectMemory.cpp --- a/lldb/source/Commands/CommandObjectMemory.cpp +++ b/lldb/source/Commands/CommandObjectMemory.cpp @@ -372,7 +372,6 @@ // We are viewing memory as a type const bool exact_match = false; - TypeList type_list; uint32_t reference_count = 0; uint32_t pointer_count = 0; size_t idx; @@ -451,18 +450,16 @@ } } - llvm::DenseSet searched_symbol_files; ConstString lookup_type_name(type_str.c_str()); StackFrame *frame = m_exe_ctx.GetFramePtr(); ModuleSP search_first; - if (frame) { + if (frame) search_first = frame->GetSymbolContext(eSymbolContextModule).module_sp; - } - target->GetImages().FindTypes(search_first.get(), lookup_type_name, - exact_match, 1, searched_symbol_files, - type_list); + TypeQuery query(lookup_type_name.GetStringRef(), exact_match); + TypeSP type_sp = query.FindFirstType(target->GetImages(), + search_first.get()); - if (type_list.GetSize() == 0 && lookup_type_name.GetCString()) { + if (!type_sp && lookup_type_name.GetCString()) { LanguageType language_for_type = m_memory_options.m_language_for_type.GetCurrentValue(); std::set languages_to_check; @@ -498,14 +495,13 @@ } if (!compiler_type.IsValid()) { - if (type_list.GetSize() == 0) { + if (!type_sp) { result.AppendErrorWithFormat("unable to find any types that match " "the raw type '%s' for full type '%s'\n", lookup_type_name.GetCString(), view_as_type_cstr); return false; } else { - TypeSP type_sp(type_list.GetTypeAtIndex(0)); compiler_type = type_sp->GetFullCompilerType(); } } diff --git a/lldb/source/Commands/CommandObjectTarget.cpp b/lldb/source/Commands/CommandObjectTarget.cpp --- a/lldb/source/Commands/CommandObjectTarget.cpp +++ b/lldb/source/Commands/CommandObjectTarget.cpp @@ -1623,16 +1623,18 @@ CommandInterpreter &interpreter, Stream &strm, Module *module, const char *name_cstr, bool name_is_regex) { - TypeList type_list; if (module && name_cstr && name_cstr[0]) { - const uint32_t max_num_matches = UINT32_MAX; bool name_is_fully_qualified = false; - ConstString name(name_cstr); - llvm::DenseSet searched_symbol_files; - module->FindTypes(name, name_is_fully_qualified, max_num_matches, - searched_symbol_files, type_list); + TypeQuery query(name_cstr, name_is_fully_qualified); + TypeResults results(/*find_one=*/false); + module->FindTypes(query, results); + TypeList type_list; + SymbolContext sc; + if (module) + sc.module_sp = module->shared_from_this(); + sc.SortTypeList(results.GetTypeMap(), type_list); if (type_list.Empty()) return 0; @@ -1665,22 +1667,21 @@ } strm.EOL(); } + return type_list.GetSize(); } - return type_list.GetSize(); + return 0; } static size_t LookupTypeHere(Target *target, CommandInterpreter &interpreter, Stream &strm, Module &module, const char *name_cstr, bool name_is_regex) { + TypeQuery query(name_cstr, /*exact_match=*/false); + TypeResults results(/*find_one=*/false); + module.FindTypes(query, results); TypeList type_list; - const uint32_t max_num_matches = UINT32_MAX; - bool name_is_fully_qualified = false; - - ConstString name(name_cstr); - llvm::DenseSet searched_symbol_files; - module.FindTypes(name, name_is_fully_qualified, max_num_matches, - searched_symbol_files, type_list); - + SymbolContext sc; + sc.module_sp = module.shared_from_this(); + sc.SortTypeList(results.GetTypeMap(), type_list); if (type_list.Empty()) return 0; diff --git a/lldb/source/Core/Module.cpp b/lldb/source/Core/Module.cpp --- a/lldb/source/Core/Module.cpp +++ b/lldb/source/Core/Module.cpp @@ -955,99 +955,9 @@ } } -void Module::FindTypes_Impl( - ConstString name, const CompilerDeclContext &parent_decl_ctx, - size_t max_matches, - llvm::DenseSet &searched_symbol_files, - TypeMap &types) { +void Module::FindTypes(const TypeQuery &query, TypeResults &results) { if (SymbolFile *symbols = GetSymbolFile()) - symbols->FindTypes(name, parent_decl_ctx, max_matches, - searched_symbol_files, types); -} - -void Module::FindTypesInNamespace(ConstString type_name, - const CompilerDeclContext &parent_decl_ctx, - size_t max_matches, TypeList &type_list) { - TypeMap types_map; - llvm::DenseSet searched_symbol_files; - FindTypes_Impl(type_name, parent_decl_ctx, max_matches, searched_symbol_files, - types_map); - if (types_map.GetSize()) { - SymbolContext sc; - sc.module_sp = shared_from_this(); - sc.SortTypeList(types_map, type_list); - } -} - -lldb::TypeSP Module::FindFirstType(const SymbolContext &sc, ConstString name, - bool exact_match) { - TypeList type_list; - llvm::DenseSet searched_symbol_files; - FindTypes(name, exact_match, 1, searched_symbol_files, type_list); - if (type_list.GetSize()) - return type_list.GetTypeAtIndex(0); - return TypeSP(); -} - -void Module::FindTypes( - ConstString name, bool exact_match, size_t max_matches, - llvm::DenseSet &searched_symbol_files, - TypeList &types) { - const char *type_name_cstr = name.GetCString(); - llvm::StringRef type_scope; - llvm::StringRef type_basename; - TypeClass type_class = eTypeClassAny; - TypeMap typesmap; - - if (Type::GetTypeScopeAndBasename(type_name_cstr, type_scope, type_basename, - type_class)) { - // Check if "name" starts with "::" which means the qualified type starts - // from the root namespace and implies and exact match. The typenames we - // get back from clang do not start with "::" so we need to strip this off - // in order to get the qualified names to match - exact_match = type_scope.consume_front("::"); - - ConstString type_basename_const_str(type_basename); - FindTypes_Impl(type_basename_const_str, CompilerDeclContext(), max_matches, - searched_symbol_files, typesmap); - if (typesmap.GetSize()) - typesmap.RemoveMismatchedTypes(type_scope, type_basename, type_class, - exact_match); - } else { - // The type is not in a namespace/class scope, just search for it by - // basename - if (type_class != eTypeClassAny && !type_basename.empty()) { - // The "type_name_cstr" will have been modified if we have a valid type - // class prefix (like "struct", "class", "union", "typedef" etc). - FindTypes_Impl(ConstString(type_basename), CompilerDeclContext(), - UINT_MAX, searched_symbol_files, typesmap); - typesmap.RemoveMismatchedTypes(type_scope, type_basename, type_class, - exact_match); - } else { - FindTypes_Impl(name, CompilerDeclContext(), UINT_MAX, - searched_symbol_files, typesmap); - if (exact_match) { - typesmap.RemoveMismatchedTypes(type_scope, name.GetStringRef(), - type_class, exact_match); - } - } - } - if (typesmap.GetSize()) { - SymbolContext sc; - sc.module_sp = shared_from_this(); - sc.SortTypeList(typesmap, types); - } -} - -void Module::FindTypes( - llvm::ArrayRef pattern, LanguageSet languages, - llvm::DenseSet &searched_symbol_files, - TypeMap &types) { - // If a scoped timer is needed, place it in a SymbolFile::FindTypes override. - // A timer here is too high volume for some cases, for example when calling - // FindTypes on each object file. - if (SymbolFile *symbols = GetSymbolFile()) - symbols->FindTypes(pattern, languages, searched_symbol_files, types); + symbols->FindTypes(query, results); } SymbolFile *Module::GetSymbolFile(bool can_create, Stream *feedback_strm) { diff --git a/lldb/source/Core/ModuleList.cpp b/lldb/source/Core/ModuleList.cpp --- a/lldb/source/Core/ModuleList.cpp +++ b/lldb/source/Core/ModuleList.cpp @@ -566,36 +566,21 @@ return module_sp; } -void ModuleList::FindTypes(Module *search_first, ConstString name, - bool name_is_fully_qualified, size_t max_matches, - llvm::DenseSet &searched_symbol_files, - TypeList &types) const { +void ModuleList::FindTypes(Module *search_first, const TypeQuery &query, + TypeResults &results) const { std::lock_guard guard(m_modules_mutex); - - collection::const_iterator pos, end = m_modules.end(); if (search_first) { - for (pos = m_modules.begin(); pos != end; ++pos) { - if (search_first == pos->get()) { - search_first->FindTypes(name, name_is_fully_qualified, max_matches, - searched_symbol_files, types); - - if (types.GetSize() >= max_matches) - return; - } - } - } - - for (pos = m_modules.begin(); pos != end; ++pos) { - // Search the module if the module is not equal to the one in the symbol - // context "sc". If "sc" contains a empty module shared pointer, then the - // comparison will always be true (valid_module_ptr != nullptr). - if (search_first != pos->get()) - (*pos)->FindTypes(name, name_is_fully_qualified, max_matches, - searched_symbol_files, types); - - if (types.GetSize() >= max_matches) + search_first->FindTypes(query, results); + if (results.Done()) return; } + for (const auto &module_sp: m_modules) { + if (search_first != module_sp.get()) { + module_sp->FindTypes(query, results); + if (results.Done()) + return; + } + } } bool ModuleList::FindSourceFile(const FileSpec &orig_spec, diff --git a/lldb/source/DataFormatters/TypeFormat.cpp b/lldb/source/DataFormatters/TypeFormat.cpp --- a/lldb/source/DataFormatters/TypeFormat.cpp +++ b/lldb/source/DataFormatters/TypeFormat.cpp @@ -160,13 +160,12 @@ if (!target_sp) return false; const ModuleList &images(target_sp->GetImages()); - TypeList types; - llvm::DenseSet searched_symbol_files; - images.FindTypes(nullptr, m_enum_type, false, UINT32_MAX, - searched_symbol_files, types); - if (types.Empty()) + TypeQuery query(m_enum_type.GetStringRef(), /*exact_match=*/false); + TypeResults results(/*find_one=*/false); + images.FindTypes(nullptr, query, results); + if (results.GetTypeMap().Empty()) return false; - for (lldb::TypeSP type_sp : types.Types()) { + for (lldb::TypeSP type_sp : results.GetTypeMap().Types()) { if (!type_sp) continue; if ((type_sp->GetForwardCompilerType().GetTypeInfo() & diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp @@ -201,19 +201,17 @@ LLDB_LOG(log, " CTD Searching namespace {0} in module {1}", item.second.GetName(), item.first->GetFileSpec().GetFilename()); - TypeList types; - ConstString name(decl->getName()); - item.first->FindTypesInNamespace(name, item.second, UINT32_MAX, types); - - for (uint32_t ti = 0, te = types.GetSize(); ti != te; ++ti) { - lldb::TypeSP type = types.GetTypeAtIndex(ti); - - if (!type) - continue; + // Create a type matcher using the CompilerDeclContext for the namespace + // as the context (item.second) and search for the name inside of this + // context. + TypeQuery query(item.second, name, /*module_search=*/false); + TypeResults results(/*find_one=*/false); + item.first->FindTypes(query, results); - CompilerType clang_type(type->GetFullCompilerType()); + for (const lldb::TypeSP &type_sp: results.GetTypeMap().Types()) { + CompilerType clang_type(type_sp->GetFullCompilerType()); if (!ClangUtil::IsClangType(clang_type)) continue; @@ -233,24 +231,15 @@ } } } else { - TypeList types; - - ConstString name(decl->getName()); - const ModuleList &module_list = m_target->GetImages(); + // Create a type matcher using a CompilerDecl. Each TypeSystem class knows + // how to fill out a CompilerContext array using a CompilerDecl. + TypeQuery query(CompilerDecl(m_clang_ast_context, (void *)decl)); + TypeResults results(/*find_one=*/false); + module_list.FindTypes(nullptr, query, results); + for (const lldb::TypeSP &type_sp: results.GetTypeMap().Types()) { - bool exact_match = false; - llvm::DenseSet searched_symbol_files; - module_list.FindTypes(nullptr, name, exact_match, UINT32_MAX, - searched_symbol_files, types); - - for (uint32_t ti = 0, te = types.GetSize(); ti != te; ++ti) { - lldb::TypeSP type = types.GetTypeAtIndex(ti); - - if (!type) - continue; - - CompilerType clang_type(type->GetFullCompilerType()); + CompilerType clang_type(type_sp->GetFullCompilerType()); if (!ClangUtil::IsClangType(clang_type)) continue; @@ -263,15 +252,8 @@ TagDecl *candidate_tag_decl = const_cast(tag_type->getDecl()); - // We have found a type by basename and we need to make sure the decl - // contexts are the same before we can try to complete this type with - // another - if (!TypeSystemClang::DeclsAreEquivalent(const_cast(decl), - candidate_tag_decl)) - continue; - if (TypeSystemClang::GetCompleteDecl(&candidate_tag_decl->getASTContext(), - candidate_tag_decl)) + candidate_tag_decl)) return candidate_tag_decl; } } @@ -614,41 +596,36 @@ if (context.m_found_type) return; - TypeList types; - const bool exact_match = true; - llvm::DenseSet searched_symbol_files; - if (module_sp && namespace_decl) - module_sp->FindTypesInNamespace(name, namespace_decl, 1, types); - else { - m_target->GetImages().FindTypes(module_sp.get(), name, exact_match, 1, - searched_symbol_files, types); + lldb::TypeSP type_sp; + if (module_sp && namespace_decl) { + // Match the name in the specified decl context. + TypeQuery query(namespace_decl, name, /*module_search=*/false); + type_sp = query.FindFirstType(module_sp.get()); + } else { + // Match the exact name of the type at the root level. + TypeQuery query(name.GetStringRef(), /*exact_match=*/true); + type_sp = query.FindFirstType(m_target->GetImages()); } - if (size_t num_types = types.GetSize()) { - for (size_t ti = 0; ti < num_types; ++ti) { - lldb::TypeSP type_sp = types.GetTypeAtIndex(ti); - - if (log) { - const char *name_string = type_sp->GetName().GetCString(); - - LLDB_LOG(log, " CAS::FEVD Matching type found for \"{0}\": {1}", name, - (name_string ? name_string : "")); - } + if (type_sp) { + if (log) { + const char *name_string = type_sp->GetName().GetCString(); - CompilerType full_type = type_sp->GetFullCompilerType(); + LLDB_LOG(log, " CAS::FEVD Matching type found for \"{0}\": {1}", name, + (name_string ? name_string : "")); + } - CompilerType copied_clang_type(GuardedCopyType(full_type)); + CompilerType full_type = type_sp->GetFullCompilerType(); - if (!copied_clang_type) { - LLDB_LOG(log, " CAS::FEVD - Couldn't export a type"); + CompilerType copied_clang_type(GuardedCopyType(full_type)); - continue; - } + if (!copied_clang_type) { + LLDB_LOG(log, " CAS::FEVD - Couldn't export a type"); + } else { context.AddTypeDecl(copied_clang_type); context.m_found_type = true; - break; } } diff --git a/lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp --- a/lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp +++ b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp @@ -89,24 +89,29 @@ // prefixing it with the root namespace: std::string lookup_name("::"); lookup_name.append(class_name); - + type_info.SetName(class_name); const bool exact_match = true; TypeList class_types; + ConstString const_lookup_name(lookup_name); // First look in the module that the vtable symbol came from and // look for a single exact match. - llvm::DenseSet searched_symbol_files; - if (sc.module_sp) - sc.module_sp->FindTypes(ConstString(lookup_name), exact_match, 1, - searched_symbol_files, class_types); + TypeQuery query(const_lookup_name.GetStringRef(), exact_match); + if (sc.module_sp) { + TypeSP type_sp = query.FindFirstType(sc.module_sp.get()); + if (type_sp) + class_types.Insert(type_sp); + } // If we didn't find a symbol, then move on to the entire module // list in the target and get as many unique matches as possible - if (class_types.Empty()) - target.GetImages().FindTypes(nullptr, ConstString(lookup_name), - exact_match, UINT32_MAX, - searched_symbol_files, class_types); + if (class_types.Empty()) { + TypeResults results(/*find_one=*/false); + target.GetImages().FindTypes(nullptr, query, results); + for (const auto &type_sp: results.GetTypeMap().Types()) + class_types.Insert(type_sp); + } lldb::TypeSP type_sp; if (class_types.Empty()) { diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.cpp --- a/lldb/source/Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.cpp +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.cpp @@ -139,17 +139,10 @@ if (!module_sp) return TypeSP(); - const bool exact_match = true; - const uint32_t max_matches = UINT32_MAX; - TypeList types; - - llvm::DenseSet searched_symbol_files; - module_sp->FindTypes(name, exact_match, max_matches, searched_symbol_files, - types); - - for (uint32_t i = 0; i < types.GetSize(); ++i) { - TypeSP type_sp(types.GetTypeAtIndex(i)); - + TypeQuery query(name.GetStringRef(), /*exact_match=*/true); + TypeResults results(/*find_one=*/false); + module_sp->FindTypes(query, results); + for (const TypeSP &type_sp: results.GetTypeMap().Types()) { if (TypeSystemClang::IsObjCObjectOrInterfaceType( type_sp->GetForwardCompilerType())) { if (TypePayloadClang(type_sp->GetPayload()).IsCompleteObjCClass()) { diff --git a/lldb/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.h b/lldb/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.h --- a/lldb/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.h +++ b/lldb/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.h @@ -117,15 +117,6 @@ void FindFunctions(const RegularExpression ®ex, bool include_inlines, SymbolContextList &sc_list) override; - void FindTypes(ConstString name, const CompilerDeclContext &parent_decl_ctx, - uint32_t max_matches, - llvm::DenseSet &searched_symbol_files, - TypeMap &types) override; - - void FindTypes(llvm::ArrayRef pattern, LanguageSet languages, - llvm::DenseSet &searched_symbol_files, - TypeMap &types) override; - llvm::Expected GetTypeSystemForLanguage(lldb::LanguageType language) override { return llvm::make_error( diff --git a/lldb/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.cpp b/lldb/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.cpp --- a/lldb/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.cpp +++ b/lldb/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.cpp @@ -447,15 +447,6 @@ // TODO } -void SymbolFileBreakpad::FindTypes( - ConstString name, const CompilerDeclContext &parent_decl_ctx, - uint32_t max_matches, llvm::DenseSet &searched_symbol_files, - TypeMap &types) {} - -void SymbolFileBreakpad::FindTypes( - llvm::ArrayRef pattern, LanguageSet languages, - llvm::DenseSet &searched_symbol_files, TypeMap &types) {} - void SymbolFileBreakpad::AddSymbols(Symtab &symtab) { Log *log = GetLog(LLDBLog::Symbols); Module &module = *m_objfile_sp->GetModule(); diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp @@ -139,17 +139,16 @@ // If this type comes from a Clang module, recursively look in the // DWARF section of the .pcm file in the module cache. Clang // generates DWO skeleton units as breadcrumbs to find them. - llvm::SmallVector decl_context; - die.GetDeclContext(decl_context); - TypeMap pcm_types; + llvm::SmallVector die_context; + die.GetDeclContext(die_context); + TypeQuery query(die_context, /*module_search=*/true); + TypeResults results(/*find_one=*/true); // The type in the Clang module must have the same language as the current CU. - LanguageSet languages; - languages.Insert(SymbolFileDWARF::GetLanguageFamily(*die.GetCU())); - llvm::DenseSet searched_symbol_files; - clang_module_sp->GetSymbolFile()->FindTypes(decl_context, languages, - searched_symbol_files, pcm_types); - if (pcm_types.Empty()) { + query.AddLanguage(SymbolFileDWARF::GetLanguageFamily(*die.GetCU())); + clang_module_sp->FindTypes(query, results); + TypeSP pcm_type_sp = results.GetTypeMap().FirstType(); + if (!pcm_type_sp) { // Since this type is defined in one of the Clang modules imported // by this symbol file, search all of them. Instead of calling // sym_file->FindTypes(), which would return this again, go straight @@ -158,24 +157,20 @@ // Well-formed clang modules never form cycles; guard against corrupted // ones by inserting the current file. - searched_symbol_files.insert(&sym_file); + results.AlreadySearched(&sym_file); sym_file.ForEachExternalModule( - *sc.comp_unit, searched_symbol_files, [&](Module &module) { - module.GetSymbolFile()->FindTypes(decl_context, languages, - searched_symbol_files, pcm_types); - return pcm_types.GetSize(); + *sc.comp_unit, results.GetSearchedSymbolFiles(), [&](Module &module) { + module.FindTypes(query, results); + pcm_type_sp = results.GetTypeMap().FirstType(); + return !pcm_type_sp; }); } - if (!pcm_types.GetSize()) + if (!pcm_type_sp) return TypeSP(); // We found a real definition for this type in the Clang module, so lets use // it and cache the fact that we found a complete type for this die. - TypeSP pcm_type_sp = pcm_types.GetTypeAtIndex(0); - if (!pcm_type_sp) - return TypeSP(); - lldb_private::CompilerType pcm_type = pcm_type_sp->GetForwardCompilerType(); lldb_private::CompilerType type = GetClangASTImporter().CopyType(m_ast, pcm_type); diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.h --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.h @@ -71,10 +71,24 @@ std::vector GetDeclContextDIEs() const; /// Return this DIE's decl context as it is needed to look up types - /// in Clang's -gmodules debug info format. + /// in Clang modules. This context will include any modules or functions that + /// the type is declared in so an exact module match can be efficiently made. void GetDeclContext( llvm::SmallVectorImpl &context) const; + /// Get a context to a type so it can be looked up. + /// + /// This function uses the current DIE to fill in a CompilerContext array + /// that is suitable for type lookup for comparison to a TypeQuery's compiler + /// context (TypeQuery::GetContextRef()). If this DIE represents a named type, + /// it should fill out the compiler context with the type itself as the last + /// entry. The declaration context should be above the type and stop at an + /// appropriate time, like either the translation unit or at a function + /// context. This is designed to allow users to efficiently look for types + /// using a full or partial CompilerContext array. + void GetTypeLookupContext( + llvm::SmallVectorImpl &context) const; + // Getting attribute values from the DIE. // // GetAttributeValueAsXXX() functions should only be used if you are diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.cpp --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.cpp @@ -416,6 +416,50 @@ } } +void DWARFDIE::GetTypeLookupContext( + llvm::SmallVectorImpl &context) const { + // If there is no name, then there is no need to look anything up for this DIE. + const char *name = GetName(); + if (!name || !name[0]) + return; + const dw_tag_t tag = Tag(); + if (tag == DW_TAG_compile_unit || tag == DW_TAG_partial_unit) + return; + DWARFDIE parent = GetParent(); + if (parent) + parent.GetTypeLookupContext(context); + switch (tag) { + case DW_TAG_namespace: + context.push_back({CompilerContextKind::Namespace, ConstString(name)}); + break; + case DW_TAG_structure_type: + context.push_back({CompilerContextKind::Struct, ConstString(name)}); + break; + case DW_TAG_union_type: + context.push_back({CompilerContextKind::Union, ConstString(name)}); + break; + case DW_TAG_class_type: + context.push_back({CompilerContextKind::Class, ConstString(name)}); + break; + case DW_TAG_enumeration_type: + context.push_back({CompilerContextKind::Enum, ConstString(name)}); + break; + case DW_TAG_variable: + context.push_back( + {CompilerContextKind::Variable, ConstString(GetPubname())}); + break; + case DW_TAG_typedef: + context.push_back({CompilerContextKind::Typedef, ConstString(name)}); + break; + case DW_TAG_base_type: + context.push_back({CompilerContextKind::Builtin, ConstString(name)}); + break; + default: + break; + } +} + + DWARFDIE DWARFDIE::GetParentDeclContextDIE() const { if (IsValid()) diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h @@ -194,17 +194,8 @@ const std::string &scope_qualified_name, std::vector &mangled_names) override; - void - FindTypes(lldb_private::ConstString name, - const lldb_private::CompilerDeclContext &parent_decl_ctx, - uint32_t max_matches, - llvm::DenseSet &searched_symbol_files, - lldb_private::TypeMap &types) override; - - void FindTypes(llvm::ArrayRef pattern, - lldb_private::LanguageSet languages, - llvm::DenseSet &searched_symbol_files, - lldb_private::TypeMap &types) override; + void FindTypes(const lldb_private::TypeQuery &match, + lldb_private::TypeResults &results) override; void GetTypes(lldb_private::SymbolContextScope *sc_scope, lldb::TypeClass type_mask, diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp @@ -2470,164 +2470,143 @@ } } -void SymbolFileDWARF::FindTypes( - ConstString name, const CompilerDeclContext &parent_decl_ctx, - uint32_t max_matches, - llvm::DenseSet &searched_symbol_files, - TypeMap &types) { - std::lock_guard guard(GetModuleMutex()); - // Make sure we haven't already searched this SymbolFile before. - if (!searched_symbol_files.insert(this).second) - return; - - Log *log = GetLog(DWARFLog::Lookups); - - if (log) { - if (parent_decl_ctx) - GetObjectFile()->GetModule()->LogMessage( - log, - "SymbolFileDWARF::FindTypes (sc, name=\"%s\", parent_decl_ctx = " - "%p (\"%s\"), max_matches=%u, type_list)", - name.GetCString(), static_cast(&parent_decl_ctx), - parent_decl_ctx.GetName().AsCString(""), max_matches); - else - GetObjectFile()->GetModule()->LogMessage( - log, - "SymbolFileDWARF::FindTypes (sc, name=\"%s\", parent_decl_ctx = " - "NULL, max_matches=%u, type_list)", - name.GetCString(), max_matches); - } - - if (!DeclContextMatchesThisSymbolFile(parent_decl_ctx)) - return; - - m_index->GetTypes(name, [&](DWARFDIE die) { - if (!DIEInDeclContext(parent_decl_ctx, die)) - return true; // The containing decl contexts don't match - - Type *matching_type = ResolveType(die, true, true); - if (!matching_type) - return true; - - // We found a type pointer, now find the shared pointer form our type - // list - types.InsertUnique(matching_type->shared_from_this()); - return types.GetSize() < max_matches; - }); - - // With -gsimple-template-names, a templated type's DW_AT_name will not - // contain the template parameters. Try again stripping '<' and anything - // after, filtering out entries with template parameters that don't match. - if (types.GetSize() < max_matches) { - const llvm::StringRef name_ref = name.GetStringRef(); - auto it = name_ref.find('<'); - if (it != llvm::StringRef::npos) { - const llvm::StringRef name_no_template_params = name_ref.slice(0, it); - const llvm::StringRef template_params = name_ref.slice(it, name_ref.size()); - m_index->GetTypes(ConstString(name_no_template_params), [&](DWARFDIE die) { - if (!DIEInDeclContext(parent_decl_ctx, die)) - return true; // The containing decl contexts don't match - - const llvm::StringRef base_name = GetTypeForDIE(die)->GetBaseName().AsCString(); - auto it = base_name.find('<'); - // If the candidate qualified name doesn't have '<', it doesn't have - // template params to compare. - if (it == llvm::StringRef::npos) - return true; - - // Filter out non-matching instantiations by comparing template params. - const llvm::StringRef base_name_template_params = - base_name.slice(it, base_name.size()); - - if (template_params != base_name_template_params) - return true; - - Type *matching_type = ResolveType(die, true, true); - if (!matching_type) - return true; - - // We found a type pointer, now find the shared pointer form our type - // list. - types.InsertUnique(matching_type->shared_from_this()); - return types.GetSize() < max_matches; - }); - } - } - - // Next search through the reachable Clang modules. This only applies for - // DWARF objects compiled with -gmodules that haven't been processed by - // dsymutil. - if (types.GetSize() < max_matches) { - UpdateExternalModuleListIfNeeded(); - - for (const auto &pair : m_external_type_modules) - if (ModuleSP external_module_sp = pair.second) - if (SymbolFile *sym_file = external_module_sp->GetSymbolFile()) - sym_file->FindTypes(name, parent_decl_ctx, max_matches, - searched_symbol_files, types); +/// Split a name up into a basename and template parameters. +static bool SplitTemplateParams(llvm::StringRef fullname, + llvm::StringRef &basename, + llvm::StringRef &template_params) { + auto it = fullname.find('<'); + if (it == llvm::StringRef::npos) { + basename = fullname; + template_params = llvm::StringRef(); + return false; } + basename = fullname.slice(0, it); + template_params = fullname.slice(it, fullname.size()); + return true; +} - if (log && types.GetSize()) { - if (parent_decl_ctx) { - GetObjectFile()->GetModule()->LogMessage( - log, - "SymbolFileDWARF::FindTypes (sc, name=\"%s\", parent_decl_ctx " - "= %p (\"%s\"), max_matches=%u, type_list) => %u", - name.GetCString(), static_cast(&parent_decl_ctx), - parent_decl_ctx.GetName().AsCString(""), max_matches, - types.GetSize()); - } else { - GetObjectFile()->GetModule()->LogMessage( - log, - "SymbolFileDWARF::FindTypes (sc, name=\"%s\", parent_decl_ctx " - "= NULL, max_matches=%u, type_list) => %u", - name.GetCString(), max_matches, types.GetSize()); +static bool UpdateCompilerContextForSimpleTemplateNames(TypeQuery &match) { + // We need to find any names in the context that have template parameters + // and strip them so the context can be matched when -gsimple-template-names + // is being used. Returns true if any of the context items were updated. + bool any_context_updated = false; + for (auto &context: match.GetContextRef()) { + llvm::StringRef basename, params; + if (SplitTemplateParams(context.name.GetStringRef(), basename, params)) { + context.name = ConstString(basename); + any_context_updated = true; } } + return any_context_updated; } -void SymbolFileDWARF::FindTypes( - llvm::ArrayRef pattern, LanguageSet languages, - llvm::DenseSet &searched_symbol_files, TypeMap &types) { +void SymbolFileDWARF::FindTypes(const TypeQuery &query, TypeResults &results) { + // Make sure we haven't already searched this SymbolFile before. - if (!searched_symbol_files.insert(this).second) + if (results.AlreadySearched(this)) return; std::lock_guard guard(GetModuleMutex()); - if (pattern.empty()) - return; - ConstString name = pattern.back().name; + bool have_index_match = false; + m_index->GetTypes(query.GetTypeBasename(), [&](DWARFDIE die) { - if (!name) - return; - - m_index->GetTypes(name, [&](DWARFDIE die) { - if (!languages[GetLanguageFamily(*die.GetCU())]) - return true; + // 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 llvm::SmallVector die_context; - die.GetDeclContext(die_context); - if (!contextMatches(die_context, pattern)) - return true; + if (query.GetModuleSearch()) + die.GetDeclContext(die_context); + else + die.GetTypeLookupContext(die_context); + 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)) { - // We found a type pointer, now find the shared pointer form our type - // list. - types.InsertUnique(matching_type->shared_from_this()); + have_index_match = true; + results.InsertUnique(matching_type->shared_from_this()); } - return true; + return !results.Done(); // Keep iterating if we aren't done. }); + if (results.Done()) + return; + + // With -gsimple-template-names, a templated type's DW_AT_name will not + // contain the template parameters. Try again stripping '<' and anything + // after, filtering out entries with template parameters that don't match. + if (!have_index_match) { + // Create a type matcher with a compiler context that is tuned for + // -gsimple-template-names. We will use this for the index lookup and the + // context matching, but will use the original "match" to insert matches + // into if things match. The "match_simple" has a compiler context with + // all template parameters removed to allow the names and context to match. + // The UpdateCompilerContextForSimpleTemplateNames(...) will return true if + // it trims any context items down by removing template parameter names. + TypeQuery query_simple(query); + if (UpdateCompilerContextForSimpleTemplateNames(query_simple)) { + + // Copy our match's context and update the basename we are looking for + // so we can use this only to compare the context correctly. + m_index->GetTypes(query_simple.GetTypeBasename(), [&](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 + llvm::SmallVector die_context; + if (query.GetModuleSearch()) + die.GetDeclContext(die_context); + else + die.GetTypeLookupContext(die_context); + assert(!die_context.empty()); + if (!query_simple.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)) { + ConstString name = matching_type->GetQualifiedName(); + // We have found a type that still might not match due to template + // parameters. If we create a new TypeQuery that uses the new type's + // fully qualified name, we can find out if this type matches at all + // context levels. We can't use just the "match_simple" context + // because all template parameters were stripped off. The fully + // qualified name of the type will have the template parameters and + // will allow us to make sure it matches correctly. + TypeQuery die_query(name.GetStringRef(), /*exact_match=*/true); + if (!query.ContextMatches(die_query.GetContextRef())) + return true; // Keep iterating over index types, context mismatch. + + results.InsertUnique(matching_type->shared_from_this()); + } + return !results.Done(); // Keep iterating if we aren't done. + }); + if (results.Done()) + return; + } + } + // Next search through the reachable Clang modules. This only applies for // DWARF objects compiled with -gmodules that haven't been processed by // dsymutil. UpdateExternalModuleListIfNeeded(); - for (const auto &pair : m_external_type_modules) - if (ModuleSP external_module_sp = pair.second) - external_module_sp->FindTypes(pattern, languages, searched_symbol_files, - types); + for (const auto &pair : m_external_type_modules) { + if (ModuleSP external_module_sp = pair.second) { + external_module_sp->FindTypes(query, results); + if (results.Done()) + return; + } + } } CompilerDeclContext diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h @@ -121,17 +121,10 @@ void FindFunctions(const lldb_private::RegularExpression ®ex, bool include_inlines, lldb_private::SymbolContextList &sc_list) override; - void - FindTypes(lldb_private::ConstString name, - const lldb_private::CompilerDeclContext &parent_decl_ctx, - uint32_t max_matches, - llvm::DenseSet &searched_symbol_files, - lldb_private::TypeMap &types) override; - void - FindTypes(llvm::ArrayRef context, - lldb_private::LanguageSet languages, - llvm::DenseSet &searched_symbol_files, - lldb_private::TypeMap &types) override; + + void FindTypes(const lldb_private::TypeQuery &match, + lldb_private::TypeResults &results) override; + lldb_private::CompilerDeclContext FindNamespace( lldb_private::ConstString name, const lldb_private::CompilerDeclContext &parent_decl_ctx) override; diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp @@ -1214,27 +1214,12 @@ return TypeSP(); } -void SymbolFileDWARFDebugMap::FindTypes( - ConstString name, const CompilerDeclContext &parent_decl_ctx, - uint32_t max_matches, - llvm::DenseSet &searched_symbol_files, - TypeMap &types) { +void SymbolFileDWARFDebugMap::FindTypes(const TypeQuery &query, + TypeResults &results) { std::lock_guard guard(GetModuleMutex()); ForEachSymbolFile([&](SymbolFileDWARF *oso_dwarf) -> bool { - oso_dwarf->FindTypes(name, parent_decl_ctx, max_matches, - searched_symbol_files, types); - return types.GetSize() >= max_matches; - }); -} - -void SymbolFileDWARFDebugMap::FindTypes( - llvm::ArrayRef context, LanguageSet languages, - llvm::DenseSet &searched_symbol_files, - TypeMap &types) { - LLDB_SCOPED_TIMER(); - ForEachSymbolFile([&](SymbolFileDWARF *oso_dwarf) -> bool { - oso_dwarf->FindTypes(context, languages, searched_symbol_files, types); - return false; + oso_dwarf->FindTypes(query, results); + return !results.Done(); // Keep iterating if we aren't done finding types. }); } diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h --- a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h +++ b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h @@ -139,14 +139,8 @@ llvm::Optional FindSymbolScope(PdbCompilandSymId id); - void FindTypes(ConstString name, const CompilerDeclContext &parent_decl_ctx, - uint32_t max_matches, - llvm::DenseSet &searched_symbol_files, - TypeMap &types) override; - - void FindTypes(llvm::ArrayRef pattern, LanguageSet languages, - llvm::DenseSet &searched_symbol_files, - TypeMap &types) override; + void FindTypes(const lldb_private::TypeQuery &match, + lldb_private::TypeResults &results) override; llvm::Expected GetTypeSystemForLanguage(lldb::LanguageType language) override; diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp --- a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp +++ b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp @@ -1717,24 +1717,33 @@ bool include_inlines, SymbolContextList &sc_list) {} -void SymbolFileNativePDB::FindTypes( - ConstString name, const CompilerDeclContext &parent_decl_ctx, - uint32_t max_matches, llvm::DenseSet &searched_symbol_files, - TypeMap &types) { - std::lock_guard guard(GetModuleMutex()); - if (!name) +void SymbolFileNativePDB::FindTypes(const lldb_private::TypeQuery &match, + lldb_private::TypeResults &results) { + + // Make sure we haven't already searched this SymbolFile before. + if (results.AlreadySearched(this)) return; - searched_symbol_files.clear(); - searched_symbol_files.insert(this); + std::lock_guard guard(GetModuleMutex()); - // There is an assumption 'name' is not a regex - FindTypesByName(name.GetStringRef(), max_matches, types); -} + std::vector matches = + m_index->tpi().findRecordsByName(match.GetTypeBasename().GetStringRef()); -void SymbolFileNativePDB::FindTypes( - llvm::ArrayRef pattern, LanguageSet languages, - llvm::DenseSet &searched_symbol_files, TypeMap &types) {} + for (TypeIndex type_idx : matches) { + TypeSP type_sp = GetOrCreateType(type_idx); + if (!type_sp) + continue; + + // We resolved a type. Get the fully qualified name to ensure it matches. + ConstString name = type_sp->GetQualifiedName(); + TypeQuery type_match(name.GetStringRef(), /*exact_match=*/true); + if (match.ContextMatches(type_match.GetContextRef())) { + results.InsertUnique(type_sp); + if (results.Done()) + return; + } + } +} void SymbolFileNativePDB::FindTypesByName(llvm::StringRef name, uint32_t max_matches, diff --git a/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.h b/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.h --- a/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.h +++ b/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.h @@ -133,19 +133,8 @@ std::vector &mangled_names) override; void AddSymbols(lldb_private::Symtab &symtab) override; - - void - FindTypes(lldb_private::ConstString name, - const lldb_private::CompilerDeclContext &parent_decl_ctx, - uint32_t max_matches, - llvm::DenseSet &searched_symbol_files, - lldb_private::TypeMap &types) override; - - void FindTypes(llvm::ArrayRef pattern, - lldb_private::LanguageSet languages, - llvm::DenseSet &searched_symbol_files, - lldb_private::TypeMap &types) override; - + void FindTypes(const lldb_private::TypeQuery &match, + lldb_private::TypeResults &results) override; void FindTypesByRegex(const lldb_private::RegularExpression ®ex, uint32_t max_matches, lldb_private::TypeMap &types); diff --git a/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp b/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp --- a/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp +++ b/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp @@ -1442,23 +1442,23 @@ symtab.Finalize(); } -void SymbolFilePDB::FindTypes( - lldb_private::ConstString name, const CompilerDeclContext &parent_decl_ctx, - uint32_t max_matches, - llvm::DenseSet &searched_symbol_files, - lldb_private::TypeMap &types) { - std::lock_guard guard(GetModuleMutex()); - if (!name) - return; - if (!DeclContextMatchesThisSymbolFile(parent_decl_ctx)) - return; - - searched_symbol_files.clear(); - searched_symbol_files.insert(this); - - // There is an assumption 'name' is not a regex - FindTypesByName(name.GetStringRef(), parent_decl_ctx, max_matches, types); -} +// void SymbolFilePDB::FindTypes( +// lldb_private::ConstString name, const CompilerDeclContext &parent_decl_ctx, +// uint32_t max_matches, +// llvm::DenseSet &searched_symbol_files, +// lldb_private::TypeMap &types) { +// std::lock_guard guard(GetModuleMutex()); +// if (!name) +// return; +// if (!DeclContextMatchesThisSymbolFile(parent_decl_ctx)) +// return; + +// searched_symbol_files.clear(); +// searched_symbol_files.insert(this); + +// // There is an assumption 'name' is not a regex +// FindTypesByName(name.GetStringRef(), parent_decl_ctx, max_matches, types); +// } void SymbolFilePDB::DumpClangAST(Stream &s) { auto type_system_or_err = @@ -1532,25 +1532,28 @@ } } -void SymbolFilePDB::FindTypesByName( - llvm::StringRef name, - const lldb_private::CompilerDeclContext &parent_decl_ctx, - uint32_t max_matches, lldb_private::TypeMap &types) { +void SymbolFilePDB::FindTypes(const lldb_private::TypeQuery &match, + lldb_private::TypeResults &type_results) { + + // Make sure we haven't already searched this SymbolFile before. + if (type_results.AlreadySearched(this)) + return; + + std::lock_guard guard(GetModuleMutex()); + + std::unique_ptr results; - if (name.empty()) + llvm::StringRef basename = match.GetTypeBasename().GetStringRef(); + if (basename.empty()) return; results = m_global_scope_up->findAllChildren(PDB_SymType::None); if (!results) return; - uint32_t matches = 0; - while (auto result = results->getNext()) { - if (max_matches > 0 && matches >= max_matches) - break; if (MSVCUndecoratedNameParser::DropScope( - result->getRawSymbol().getName()) != name) + result->getRawSymbol().getName()) != basename) continue; switch (result->getSymTag()) { @@ -1569,22 +1572,20 @@ if (!ResolveTypeUID(result->getSymIndexId())) continue; - if (parent_decl_ctx.IsValid() && - GetDeclContextContainingUID(result->getSymIndexId()) != parent_decl_ctx) - continue; - auto iter = m_types.find(result->getSymIndexId()); if (iter == m_types.end()) continue; - types.Insert(iter->second); - ++matches; + // We resolved a type. Get the fully qualified name to ensure it matches. + ConstString name = iter->second->GetQualifiedName(); + TypeQuery type_match(name.GetStringRef(), /*exact_match=*/true); + if (match.ContextMatches(type_match.GetContextRef())) { + type_results.InsertUnique(iter->second); + if (type_results.Done()) + return; + } } } -void SymbolFilePDB::FindTypes( - llvm::ArrayRef pattern, LanguageSet languages, - llvm::DenseSet &searched_symbol_files, - lldb_private::TypeMap &types) {} void SymbolFilePDB::GetTypesForPDBSymbol(const llvm::pdb::PDBSymbol &pdb_symbol, uint32_t type_mask, diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h --- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h +++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h @@ -492,6 +492,9 @@ CompilerType DeclGetFunctionArgumentType(void *opaque_decl, size_t arg_idx) override; + void DeclGetCompilerContext(void *opaque_decl, + llvm::SmallVectorImpl &context) override; + CompilerType GetTypeForDecl(void *opaque_decl) override; // CompilerDeclContext override functions @@ -522,6 +525,9 @@ bool DeclContextIsContainedInLookup(void *opaque_decl_ctx, void *other_opaque_decl_ctx) override; + void DeclContextGetCompilerContext(void *opaque_decl_ctx, + llvm::SmallVectorImpl &context) override; + // Clang specific clang::DeclContext functions static clang::DeclContext * diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp --- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp +++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp @@ -9502,6 +9502,68 @@ return 0; } +static CompilerContextKind GetCompilerKind(clang::Decl::Kind clang_kind, + clang::DeclContext *decl_ctx) { + switch (clang_kind) { + case Decl::TranslationUnit: + return CompilerContextKind::TranslationUnit; + case Decl::Namespace: + return CompilerContextKind::Namespace; + case Decl::Var: + return CompilerContextKind::Variable; + case Decl::Enum: + return CompilerContextKind::Enum; + case Decl::Typedef: + return CompilerContextKind::Typedef; + default: + // Many other kinds have multiple values + if (decl_ctx) { + if (decl_ctx->isFunctionOrMethod()) + return CompilerContextKind::Function; + else if (decl_ctx->isRecord()) + return (CompilerContextKind)( + (uint16_t)CompilerContextKind::Class | + (uint16_t)CompilerContextKind::Struct | + (uint16_t)CompilerContextKind::Union); + } + break; + } + return CompilerContextKind::Any; +} + +static void InsertCompilerContext(TypeSystemClang *ts, + clang::DeclContext *decl_ctx, + llvm::SmallVectorImpl &context) { + if (decl_ctx == nullptr) + return; + InsertCompilerContext(ts, decl_ctx->getParent(), context); + clang::Decl::Kind clang_kind = decl_ctx->getDeclKind(); + if (clang_kind == Decl::TranslationUnit) + return; // Stop at the translation unit. + const CompilerContextKind compiler_kind = GetCompilerKind(clang_kind, decl_ctx); + ConstString decl_ctx_name = ts->DeclContextGetName(decl_ctx); + context.push_back({compiler_kind, decl_ctx_name}); +} + +void TypeSystemClang::DeclGetCompilerContext(void *opaque_decl, + llvm::SmallVectorImpl &context) { + ConstString decl_name = DeclGetName(opaque_decl); + if (!decl_name) { + // If this decl doesn't have a name, we can't make a compiler context for it. + context.clear(); + return; + } + clang::Decl *decl = (clang::Decl *)opaque_decl; + // Add the entire decl context first + clang::DeclContext *decl_ctx = decl->getDeclContext(); + InsertCompilerContext(this, decl_ctx, context); + // Now add the decl information + auto compiler_kind = GetCompilerKind(decl->getKind(), + dyn_cast(decl)); + context.push_back({compiler_kind, decl_name}); +} + + CompilerType TypeSystemClang::DeclGetFunctionArgumentType(void *opaque_decl, size_t idx) { if (clang::FunctionDecl *func_decl = @@ -9762,6 +9824,12 @@ return false; } +void TypeSystemClang::DeclContextGetCompilerContext(void *opaque_decl_ctx, + llvm::SmallVectorImpl &context) { + auto *decl_ctx = (clang::DeclContext *)opaque_decl_ctx; + InsertCompilerContext(this, decl_ctx, context); +} + bool TypeSystemClang::DeclContextIsContainedInLookup( void *opaque_decl_ctx, void *other_opaque_decl_ctx) { auto *decl_ctx = (clang::DeclContext *)opaque_decl_ctx; diff --git a/lldb/source/Symbol/CompilerDecl.cpp b/lldb/source/Symbol/CompilerDecl.cpp --- a/lldb/source/Symbol/CompilerDecl.cpp +++ b/lldb/source/Symbol/CompilerDecl.cpp @@ -47,3 +47,8 @@ return lhs.GetTypeSystem() != rhs.GetTypeSystem() || lhs.GetOpaqueDecl() != rhs.GetOpaqueDecl(); } + +void CompilerDecl::GetCompilerContext( + llvm::SmallVectorImpl &context) const { + return m_type_system->DeclGetCompilerContext(m_opaque_decl, context); +} diff --git a/lldb/source/Symbol/CompilerDeclContext.cpp b/lldb/source/Symbol/CompilerDeclContext.cpp --- a/lldb/source/Symbol/CompilerDeclContext.cpp +++ b/lldb/source/Symbol/CompilerDeclContext.cpp @@ -57,6 +57,14 @@ other.m_opaque_decl_ctx); } +void CompilerDeclContext::GetCompilerContext( + llvm::SmallVectorImpl &context) const { + context.clear(); + if (IsValid()) + return m_type_system->DeclContextGetCompilerContext(m_opaque_decl_ctx, + context); +} + bool lldb_private::operator==(const lldb_private::CompilerDeclContext &lhs, const lldb_private::CompilerDeclContext &rhs) { return lhs.GetTypeSystem() == rhs.GetTypeSystem() && diff --git a/lldb/source/Symbol/SymbolFile.cpp b/lldb/source/Symbol/SymbolFile.cpp --- a/lldb/source/Symbol/SymbolFile.cpp +++ b/lldb/source/Symbol/SymbolFile.cpp @@ -133,17 +133,6 @@ const std::string &scope_qualified_name, std::vector &mangled_names) {} -void SymbolFile::FindTypes( - ConstString name, const CompilerDeclContext &parent_decl_ctx, - uint32_t max_matches, - llvm::DenseSet &searched_symbol_files, - TypeMap &types) {} - -void SymbolFile::FindTypes(llvm::ArrayRef pattern, - LanguageSet languages, - llvm::DenseSet &searched_symbol_files, - TypeMap &types) {} - void SymbolFile::AssertModuleLock() { // The code below is too expensive to leave enabled in release builds. It's // enabled in debug builds or when the correct macro is set. diff --git a/lldb/source/Symbol/SymbolFileOnDemand.cpp b/lldb/source/Symbol/SymbolFileOnDemand.cpp --- a/lldb/source/Symbol/SymbolFileOnDemand.cpp +++ b/lldb/source/Symbol/SymbolFileOnDemand.cpp @@ -430,31 +430,13 @@ mangled_names); } -void SymbolFileOnDemand::FindTypes( - ConstString name, const CompilerDeclContext &parent_decl_ctx, - uint32_t max_matches, - llvm::DenseSet &searched_symbol_files, - TypeMap &types) { - if (!m_debug_info_enabled) { - Log *log = GetLog(); - LLDB_LOG(log, "[{0}] {1}({2}) is skipped", GetSymbolFileName(), - __FUNCTION__, name); - return; - } - return m_sym_file_impl->FindTypes(name, parent_decl_ctx, max_matches, - searched_symbol_files, types); -} - -void SymbolFileOnDemand::FindTypes( - llvm::ArrayRef pattern, LanguageSet languages, - llvm::DenseSet &searched_symbol_files, TypeMap &types) { +void SymbolFileOnDemand::FindTypes(const TypeQuery &match, TypeResults &results) { if (!m_debug_info_enabled) { LLDB_LOG(GetLog(), "[{0}] {1} is skipped", GetSymbolFileName(), __FUNCTION__); return; } - return m_sym_file_impl->FindTypes(pattern, languages, searched_symbol_files, - types); + return m_sym_file_impl->FindTypes(match, results); } void SymbolFileOnDemand::GetTypes(SymbolContextScope *sc_scope, diff --git a/lldb/source/Symbol/Type.cpp b/lldb/source/Symbol/Type.cpp --- a/lldb/source/Symbol/Type.cpp +++ b/lldb/source/Symbol/Type.cpp @@ -63,6 +63,142 @@ return true; } +static CompilerContextKind ConvertTypeClass(lldb::TypeClass type_class) { + if (type_class == eTypeClassAny) + return CompilerContextKind::AnyType; + uint16_t result = 0; + if (type_class & lldb::eTypeClassClass) + result |= (uint16_t)CompilerContextKind::Class; + if (type_class & lldb::eTypeClassStruct) + result |= (uint16_t)CompilerContextKind::Struct; + if (type_class & lldb::eTypeClassUnion) + result |= (uint16_t)CompilerContextKind::Union; + if (type_class & lldb::eTypeClassEnumeration) + result |= (uint16_t)CompilerContextKind::Enum; + if (type_class & lldb::eTypeClassFunction) + result |= (uint16_t)CompilerContextKind::Function; + if (type_class & lldb::eTypeClassTypedef) + result |= (uint16_t)CompilerContextKind::Typedef; + return (CompilerContextKind)result; +} + +TypeQuery::TypeQuery(llvm::StringRef name, bool exact_match) { + llvm::StringRef scope, basename; + lldb::TypeClass type_class = lldb::eTypeClassAny; + if (Type::GetTypeScopeAndBasename(name, scope, basename, type_class)) { + m_exact_match = exact_match | scope.consume_front("::"); + if (!scope.empty()) { + std::pair scope_pair = scope.split("::"); + while (!scope_pair.second.empty()) { + m_context.push_back({CompilerContextKind::AnyDeclContext, + ConstString(scope_pair.first.str())}); + scope_pair = scope_pair.second.split("::"); + } + m_context.push_back({CompilerContextKind::AnyDeclContext, + ConstString(scope_pair.first.str())}); + } + m_context.push_back({ConvertTypeClass(type_class), + ConstString(basename.str())}); + } else { + m_context.push_back({CompilerContextKind::AnyType, + ConstString(name.str())}); + m_exact_match = exact_match; + } +} +TypeQuery::TypeQuery(const CompilerDeclContext &decl_ctx, + ConstString type_basename, bool module_search) { + m_exact_match = true; + m_module_search = module_search; + decl_ctx.GetCompilerContext(m_context); + m_context.push_back({CompilerContextKind::AnyType, type_basename}); +} + +TypeQuery::TypeQuery( + const llvm::ArrayRef &context, + bool module_search) :m_context(context), m_exact_match(true), m_module_search(module_search) {} + +TypeQuery::TypeQuery(const TypeQuery &rhs) : + m_context(rhs.m_context), + m_exact_match(rhs.m_exact_match), + m_module_search(rhs.m_module_search), + m_languages(rhs.m_languages) {} + +void TypeQuery::operator=(const TypeQuery &rhs) { + m_context = rhs.m_context; + m_exact_match = rhs.m_exact_match; + m_module_search = rhs.m_module_search; + m_languages = rhs.m_languages; +} + +TypeQuery::TypeQuery(const CompilerDecl &decl) { + m_exact_match = true; + decl.GetCompilerContext(m_context); +} + +ConstString TypeQuery::GetTypeBasename() const { + if (m_context.empty()) + return ConstString(); + return m_context.back().name; +} + +lldb::TypeSP TypeQuery::FindFirstType(lldb_private::Module *module) { + if (!module) + return TypeSP(); + TypeResults results(/*find_one=*/true); + module->FindTypes(*this, results); + return results.GetTypeMap().FirstType(); +} + +lldb::TypeSP TypeQuery::FindFirstType(const lldb_private::ModuleList &module_list, + lldb_private::Module *search_first) { + TypeResults results(/*find_one=*/true); + module_list.FindTypes(search_first, *this, results); + return results.GetTypeMap().FirstType(); +} + +void TypeQuery::AddLanguage(LanguageType language) { + if (!m_languages) + m_languages = LanguageSet(); + m_languages->Insert(language); +} + +bool TypeQuery::ContextMatches(llvm::ArrayRef context_chain) const { + if (m_exact_match || context_chain.size() == m_context.size()) + return ::contextMatches(context_chain, m_context); + + // We don't have an exact match, we need to bottom m_context.size() items to + // match for a successful lookup. + if (context_chain.size() < m_context.size()) + return false; // Not enough items in context_chain to allow for a match. + + size_t compare_count = context_chain.size() - m_context.size(); + return ::contextMatches( + llvm::ArrayRef(context_chain.data() + compare_count, + m_context.size()), + m_context); +} + +bool TypeQuery::LanguageMatches(lldb::LanguageType language) const { + // If we have no language filterm language always matches. + if (!m_languages.has_value()) + return true; + return (*m_languages)[language]; +} + +bool TypeResults::AlreadySearched(lldb_private::SymbolFile *sym_file) { + return !m_searched_symbol_files.insert(sym_file).second; +} + +bool TypeResults::InsertUnique(const lldb::TypeSP &type_sp) { + return m_type_map.InsertUnique(type_sp); +} + +bool TypeResults::Done() const { + if (m_find_one) + return !m_type_map.Empty(); + return false; +} + void CompilerContext::Dump() const { switch (kind) { default: @@ -676,6 +812,8 @@ if (name.empty()) return false; + // Clear the scope in case we have just a type class and a basename. + scope = llvm::StringRef(); basename = name; if (basename.consume_front("struct ")) type_class = eTypeClassStruct; @@ -689,8 +827,10 @@ type_class = eTypeClassTypedef; size_t namespace_separator = basename.find("::"); - if (namespace_separator == llvm::StringRef::npos) - return false; + if (namespace_separator == llvm::StringRef::npos) { + // If "name" started a type class we need to return true with no scope. + return type_class != eTypeClassAny; + } size_t template_begin = basename.find('<'); while (namespace_separator != llvm::StringRef::npos) { diff --git a/lldb/source/Symbol/TypeMap.cpp b/lldb/source/Symbol/TypeMap.cpp --- a/lldb/source/Symbol/TypeMap.cpp +++ b/lldb/source/Symbol/TypeMap.cpp @@ -91,6 +91,12 @@ return TypeSP(); } +lldb::TypeSP TypeMap::FirstType() const { + if (m_types.empty()) + return TypeSP(); + return m_types.begin()->second; +} + void TypeMap::ForEach( std::function const &callback) const { for (auto pos = m_types.begin(), end = m_types.end(); pos != end; ++pos) { @@ -121,10 +127,10 @@ return false; } -void TypeMap::Dump(Stream *s, bool show_context, lldb::DescriptionLevel level) { - for (iterator pos = m_types.begin(), end = m_types.end(); pos != end; ++pos) { - pos->second->Dump(s, show_context, level); - } +void TypeMap::Dump(Stream *s, bool show_context, + lldb::DescriptionLevel level) const { + for (const auto &pair : m_types) + pair.second->Dump(s, show_context, level); } void TypeMap::RemoveMismatchedTypes(llvm::StringRef type_scope, diff --git a/lldb/source/Symbol/TypeSystem.cpp b/lldb/source/Symbol/TypeSystem.cpp --- a/lldb/source/Symbol/TypeSystem.cpp +++ b/lldb/source/Symbol/TypeSystem.cpp @@ -165,6 +165,16 @@ return CompilerType(); } +void TypeSystem::DeclGetCompilerContext(void *opaque_decl, + llvm::SmallVectorImpl &context) { + context.clear(); +} + + void TypeSystem::DeclContextGetCompilerContext(void *opaque_decl_ctx, + llvm::SmallVectorImpl &context) { + context.clear(); +} + std::vector TypeSystem::DeclContextFindDeclByName(void *opaque_decl_ctx, ConstString name, bool ignore_imported_decls) { diff --git a/lldb/source/Target/Language.cpp b/lldb/source/Target/Language.cpp --- a/lldb/source/Target/Language.cpp +++ b/lldb/source/Target/Language.cpp @@ -399,12 +399,10 @@ Target *target = exe_scope->CalculateTarget().get(); if (target) { const auto &images(target->GetImages()); - ConstString cs_key(key); - llvm::DenseSet searched_sym_files; - TypeList matches; - images.FindTypes(nullptr, cs_key, false, UINT32_MAX, searched_sym_files, - matches); - for (const auto &match : matches.Types()) { + TypeQuery query(key, false); + TypeResults type_results(/*find_one=*/false); + images.FindTypes(nullptr, query, type_results); + for (const auto &match : type_results.GetTypeMap().Types()) { if (match) { CompilerType compiler_type(match->GetFullCompilerType()); compiler_type = AdjustForInclusion(compiler_type); @@ -428,12 +426,12 @@ return false; } -bool Language::DemangledNameContainsPath(llvm::StringRef path, +bool Language::DemangledNameContainsPath(llvm::StringRef path, ConstString demangled) const { // The base implementation does a simple contains comparision: if (path.empty()) return false; - return demangled.GetStringRef().contains(path); + return demangled.GetStringRef().contains(path); } DumpValueObjectOptions::DeclPrintingHelper Language::GetDeclPrintingHelper() { diff --git a/lldb/test/API/functionalities/type_find_first/Makefile b/lldb/test/API/functionalities/type_find_first/Makefile new file mode 100644 --- /dev/null +++ b/lldb/test/API/functionalities/type_find_first/Makefile @@ -0,0 +1,2 @@ +CXX_SOURCES := main.cpp +include Makefile.rules diff --git a/lldb/test/API/functionalities/type_find_first/TestFindFirstType.py b/lldb/test/API/functionalities/type_find_first/TestFindFirstType.py new file mode 100644 --- /dev/null +++ b/lldb/test/API/functionalities/type_find_first/TestFindFirstType.py @@ -0,0 +1,38 @@ +""" +Test the SBModule and SBTarget type lookup APIs. +""" + +import lldb +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil + + +class TypeFindFirstTestCase(TestBase): + + NO_DEBUG_INFO_TESTCASE = True + + def test_find_first_type(self): + """ + Test SBTarget::FindFirstType() and SBModule::FindFirstType() APIs. + + This function had regressed after some past modification of the type + lookup internal code where if we had multiple types with the same + basename, FindFirstType() could end up failing depending on which + type was found first in the debug info indexes. This test will + ensure this doesn't regress in the future. + """ + self.build() + target = self.createTestTarget() + # Test the SBTarget APIs for FindFirstType + integer_type = target.FindFirstType("Integer::Point") + self.assertTrue(integer_type.IsValid()) + float_type = target.FindFirstType("Float::Point") + self.assertTrue(float_type.IsValid()) + + # Test the SBModule APIs for FindFirstType + exe_module = target.GetModuleAtIndex(0) + self.assertTrue(exe_module.IsValid()) + integer_type = exe_module.FindFirstType("Integer::Point") + self.assertTrue(integer_type.IsValid()) + float_type = exe_module.FindFirstType("Float::Point") + self.assertTrue(float_type.IsValid()) diff --git a/lldb/test/API/functionalities/type_find_first/main.cpp b/lldb/test/API/functionalities/type_find_first/main.cpp new file mode 100644 --- /dev/null +++ b/lldb/test/API/functionalities/type_find_first/main.cpp @@ -0,0 +1,17 @@ +namespace Integer { +struct Point { + int x, y; +}; +} // namespace Integer + +namespace Float { +struct Point { + float x, y; +}; +} // namespace Float + +int main(int argc, char const *argv[]) { + Integer::Point ip = {2, 3}; + Float::Point fp = {2.0, 3.0}; + return 0; +} diff --git a/lldb/tools/lldb-test/lldb-test.cpp b/lldb/tools/lldb-test/lldb-test.cpp --- a/lldb/tools/lldb-test/lldb-test.cpp +++ b/lldb/tools/lldb-test/lldb-test.cpp @@ -289,8 +289,8 @@ } // namespace assert } // namespace opts -std::vector parseCompilerContext() { - std::vector result; +llvm::SmallVector parseCompilerContext() { + llvm::SmallVector result; if (opts::symbols::CompilerContext.empty()) return result; @@ -576,29 +576,32 @@ Expected ContextOr = getDeclContext(Symfile); if (!ContextOr) return ContextOr.takeError(); - const CompilerDeclContext &ContextPtr = - ContextOr->IsValid() ? *ContextOr : CompilerDeclContext(); - - LanguageSet languages; - if (!Language.empty()) - languages.Insert(Language::GetLanguageTypeFromString(Language)); - - DenseSet SearchedFiles; - TypeMap Map; - if (!Name.empty()) - Symfile.FindTypes(ConstString(Name), ContextPtr, UINT32_MAX, SearchedFiles, - Map); - else - Module.FindTypes(parseCompilerContext(), languages, SearchedFiles, Map); - outs() << formatv("Found {0} types:\n", Map.GetSize()); + TypeResults results(/*find_one=*/false); + if (!Name.empty()) { + if (ContextOr->IsValid()) { + TypeQuery query(*ContextOr, ConstString(Name), /*module_search=*/true); + if (!Language.empty()) + query.AddLanguage(Language::GetLanguageTypeFromString(Language)); + Symfile.FindTypes(query, results); + } else { + TypeQuery query(Name, /*exact_match=*/false); + if (!Language.empty()) + query.AddLanguage(Language::GetLanguageTypeFromString(Language)); + Symfile.FindTypes(query, results); + } + } else { + TypeQuery query(parseCompilerContext(), /*module_search=*/true); + if (!Language.empty()) + query.AddLanguage(Language::GetLanguageTypeFromString(Language)); + Symfile.FindTypes(query, results); + } + outs() << formatv("Found {0} types:\n", results.GetTypeMap().GetSize()); StreamString Stream; // Resolve types to force-materialize typedef types. - Map.ForEach([&](TypeSP &type) { - type->GetFullCompilerType(); - return false; - }); - Map.Dump(&Stream, false, GetDescriptionLevel()); + for (const auto &type_sp: results.GetTypeMap().Types()) + type_sp->GetFullCompilerType(); + results.GetTypeMap().Dump(&Stream, false, GetDescriptionLevel()); outs() << Stream.GetData() << "\n"; return Error::success(); }