//===-- Type.h --------------------------------------------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #ifndef LLDB_SYMBOL_TYPE_H #define LLDB_SYMBOL_TYPE_H #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 #include namespace lldb_private { class SymbolFileCommon; /// 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. std::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 { CompilerContext(CompilerContextKind t, ConstString n) : kind(t), name(n) {} bool operator==(const CompilerContext &rhs) const { return kind == rhs.kind && name == rhs.name; } bool operator!=(const CompilerContext &rhs) const { return !(*this == rhs); } void Dump(Stream &s) const; CompilerContextKind kind; ConstString name; }; /// Match \p context_chain against \p pattern, which may contain "Any" /// kinds. The \p context_chain should *not* contain any "Any" kinds. bool contextMatches(llvm::ArrayRef context_chain, llvm::ArrayRef pattern); FLAGS_ENUM(TypeQueryOptions){ e_none = 0u, /// If set, TypeQuery::m_context contains an exact context that must match /// the full context. If not set, TypeQuery::m_context can contain a partial /// type match where the full context isn't fully specified. e_exact_match = (1u << 0), /// If set, TypeQuery::m_context is a clang module compiler context. If not /// set TypeQuery::m_context is normal type lookup context. e_module_search = (1u << 1), /// 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. e_find_one = (1u << 2), }; LLDB_MARK_AS_BITMASK_ENUM(TypeQueryOptions) /// 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 technique 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: 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. For example, "a::b::my_type". /// /// \param[in] options A set of boolean enumeration flags from the /// TypeQueryOptions enumerations. \see TypeQueryOptions. TypeQuery(llvm::StringRef name, TypeQueryOptions options = e_none); /// 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 populate 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] options A set of boolean enumeration flags from the /// TypeQueryOptions enumerations. \see TypeQueryOptions. TypeQuery(const CompilerDeclContext &decl_ctx, ConstString type_basename, TypeQueryOptions options = e_none); /// 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). /// /// \param[in] options A set of boolean enumeration flags from the /// TypeQueryOptions enumerations. \see TypeQueryOptions. TypeQuery(const CompilerDecl &decl, TypeQueryOptions options = e_none); /// 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] options A set of boolean enumeration flags from the /// TypeQueryOptions enumerations. \see TypeQueryOptions. TypeQuery(const llvm::ArrayRef &context, TypeQueryOptions options = e_none); /// 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) = default; /// 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. TypeQuery &operator=(const TypeQuery &rhs) = default; /// 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 e_exact_match /// is set in m_options, then \a context must exactly match \a m_context. If /// e_exact_match is not set, then the bottom m_context.size() objects in /// \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); /// Set the list of languages that should produce a match to only the ones /// specified in \ref languages. void SetLanguages(LanguageSet languages); /// 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; bool GetExactMatch() const { return (m_options & e_exact_match) != 0; } /// 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. /// Set this to true if you wish to search for a type in clang module. bool GetModuleSearch() const { return (m_options & e_module_search) != 0; } /// Returns true if the type query is supposed to find only a single matching /// type. Returns false if the type query should find all matches. bool GetFindOne() const { return (m_options & e_find_one) != 0; } void SetFindOne(bool b) { if (b) m_options |= e_find_one; else m_options &= (e_exact_match | e_find_one); } /// Access the internal compiler context array. /// /// Clients can use this to populate the context manually. std::vector &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 contains the type and name of the type we are looking for. std::vector m_context; /// An options bitmask that contains enabled options for the type query. /// \see TypeQueryOptions. TypeQueryOptions m_options; /// If this variable has a value, then the language family must match at least /// one of the specified languages. If this variable has no value, then the /// language of the type doesn't need to match any types that are searched. std::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 TypeResults() = default; /// 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 TypeQuery &query) const; /// Check if a SymbolFile object has already been searched by this type match /// object. /// /// This function will add \a sym_file to the set of SymbolFile objects if it /// isn't already in the set and return \a false. Returns true if \a sym_file /// was already in the set and doesn't need to be searched. /// /// 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; } lldb::TypeSP GetFirstType() const { return m_type_map.FirstType(); } TypeMap &GetTypeMap() { return m_type_map; } const TypeMap &GetTypeMap() const { return m_type_map; } private: /// Matching types get added to this map 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; }; class SymbolFileType : public std::enable_shared_from_this, public UserID { public: SymbolFileType(SymbolFile &symbol_file, lldb::user_id_t uid) : UserID(uid), m_symbol_file(symbol_file) {} SymbolFileType(SymbolFile &symbol_file, const lldb::TypeSP &type_sp); ~SymbolFileType() = default; Type *operator->() { return GetType(); } Type *GetType(); SymbolFile &GetSymbolFile() const { return m_symbol_file; } protected: SymbolFile &m_symbol_file; lldb::TypeSP m_type_sp; }; class Type : public std::enable_shared_from_this, public UserID { public: enum EncodingDataType { /// Invalid encoding. eEncodingInvalid, /// This type is the type whose UID is m_encoding_uid. eEncodingIsUID, /// This type is the type whose UID is m_encoding_uid with the const /// qualifier added. eEncodingIsConstUID, /// This type is the type whose UID is m_encoding_uid with the restrict /// qualifier added. eEncodingIsRestrictUID, /// This type is the type whose UID is m_encoding_uid with the volatile /// qualifier added. eEncodingIsVolatileUID, /// This type is alias to a type whose UID is m_encoding_uid. eEncodingIsTypedefUID, /// This type is pointer to a type whose UID is m_encoding_uid. eEncodingIsPointerUID, /// This type is L value reference to a type whose UID is m_encoding_uid. eEncodingIsLValueReferenceUID, /// This type is R value reference to a type whose UID is m_encoding_uid. eEncodingIsRValueReferenceUID, /// This type is the type whose UID is m_encoding_uid as an atomic type. eEncodingIsAtomicUID, /// This type is the synthetic type whose UID is m_encoding_uid. eEncodingIsSyntheticUID }; enum class ResolveState : unsigned char { Unresolved = 0, Forward = 1, Layout = 2, Full = 3 }; void Dump(Stream *s, bool show_context, lldb::DescriptionLevel level = lldb::eDescriptionLevelFull); void DumpTypeName(Stream *s); /// Since Type instances only keep a "SymbolFile *" internally, other classes /// like TypeImpl need make sure the module is still around before playing /// with /// Type instances. They can store a weak pointer to the Module; lldb::ModuleSP GetModule(); /// GetModule may return module for compile unit's object file. /// GetExeModule returns module for executable object file that contains /// compile unit where type was actually defined. /// GetModule and GetExeModule may return the same value. lldb::ModuleSP GetExeModule(); void GetDescription(Stream *s, lldb::DescriptionLevel level, bool show_name, ExecutionContextScope *exe_scope); SymbolFile *GetSymbolFile() { return m_symbol_file; } const SymbolFile *GetSymbolFile() const { return m_symbol_file; } ConstString GetName(); ConstString GetBaseName(); std::optional GetByteSize(ExecutionContextScope *exe_scope); uint32_t GetNumChildren(bool omit_empty_base_classes); bool IsAggregateType(); // Returns if the type is a templated decl. Does not look through typedefs. bool IsTemplateType(); bool IsValidType() { return m_encoding_uid_type != eEncodingInvalid; } bool IsTypedef() { return m_encoding_uid_type == eEncodingIsTypedefUID; } lldb::TypeSP GetTypedefType(); ConstString GetName() const { return m_name; } ConstString GetQualifiedName(); bool ReadFromMemory(ExecutionContext *exe_ctx, lldb::addr_t address, AddressType address_type, DataExtractor &data); bool WriteToMemory(ExecutionContext *exe_ctx, lldb::addr_t address, AddressType address_type, DataExtractor &data); lldb::Format GetFormat(); lldb::Encoding GetEncoding(uint64_t &count); SymbolContextScope *GetSymbolContextScope() { return m_context; } const SymbolContextScope *GetSymbolContextScope() const { return m_context; } void SetSymbolContextScope(SymbolContextScope *context) { m_context = context; } const lldb_private::Declaration &GetDeclaration() const; // Get the clang type, and resolve definitions for any // class/struct/union/enum types completely. CompilerType GetFullCompilerType(); // Get the clang type, and resolve definitions enough so that the type could // have layout performed. This allows ptrs and refs to // class/struct/union/enum types remain forward declarations. CompilerType GetLayoutCompilerType(); // Get the clang type and leave class/struct/union/enum types as forward // declarations if they haven't already been fully defined. CompilerType GetForwardCompilerType(); static int Compare(const Type &a, const Type &b); // From a fully qualified typename, split the type into the type basename and // the remaining type scope (namespaces/classes). static bool GetTypeScopeAndBasename(llvm::StringRef name, llvm::StringRef &scope, llvm::StringRef &basename, lldb::TypeClass &type_class); void SetEncodingType(Type *encoding_type) { m_encoding_type = encoding_type; } uint32_t GetEncodingMask(); typedef uint32_t Payload; /// Return the language-specific payload. Payload GetPayload() { return m_payload; } /// Return the language-specific payload. void SetPayload(Payload opaque_payload) { m_payload = opaque_payload; } protected: ConstString m_name; SymbolFile *m_symbol_file = nullptr; /// The symbol context in which this type is defined. SymbolContextScope *m_context = nullptr; Type *m_encoding_type = nullptr; lldb::user_id_t m_encoding_uid = LLDB_INVALID_UID; EncodingDataType m_encoding_uid_type = eEncodingInvalid; uint64_t m_byte_size : 63; uint64_t m_byte_size_has_value : 1; Declaration m_decl; CompilerType m_compiler_type; ResolveState m_compiler_type_resolve_state = ResolveState::Unresolved; /// Language-specific flags. Payload m_payload; Type *GetEncodingType(); bool ResolveCompilerType(ResolveState compiler_type_resolve_state); private: /// Only allow Symbol File to create types, as they should own them by keeping /// them in their TypeList. \see SymbolFileCommon::MakeType() reference in the /// header documentation here so users will know what function to use if the /// get a compile error. friend class lldb_private::SymbolFileCommon; Type(lldb::user_id_t uid, SymbolFile *symbol_file, ConstString name, std::optional byte_size, SymbolContextScope *context, lldb::user_id_t encoding_uid, EncodingDataType encoding_uid_type, const Declaration &decl, const CompilerType &compiler_qual_type, ResolveState compiler_type_resolve_state, uint32_t opaque_payload = 0); // This makes an invalid type. Used for functions that return a Type when // they get an error. Type(); Type(Type &t) = default; Type(Type &&t) = default; Type &operator=(const Type &t) = default; Type &operator=(Type &&t) = default; }; // the two classes here are used by the public API as a backend to the SBType // and SBTypeList classes class TypeImpl { public: TypeImpl() = default; ~TypeImpl() = default; TypeImpl(const lldb::TypeSP &type_sp); TypeImpl(const CompilerType &compiler_type); TypeImpl(const lldb::TypeSP &type_sp, const CompilerType &dynamic); TypeImpl(const CompilerType &compiler_type, const CompilerType &dynamic); void SetType(const lldb::TypeSP &type_sp); void SetType(const CompilerType &compiler_type); void SetType(const lldb::TypeSP &type_sp, const CompilerType &dynamic); void SetType(const CompilerType &compiler_type, const CompilerType &dynamic); bool operator==(const TypeImpl &rhs) const; bool operator!=(const TypeImpl &rhs) const; bool IsValid() const; explicit operator bool() const; void Clear(); lldb::ModuleSP GetModule() const; ConstString GetName() const; ConstString GetDisplayTypeName() const; TypeImpl GetPointerType() const; TypeImpl GetPointeeType() const; TypeImpl GetReferenceType() const; TypeImpl GetTypedefedType() const; TypeImpl GetDereferencedType() const; TypeImpl GetUnqualifiedType() const; TypeImpl GetCanonicalType() const; CompilerType GetCompilerType(bool prefer_dynamic); CompilerType::TypeSystemSPWrapper GetTypeSystem(bool prefer_dynamic); bool GetDescription(lldb_private::Stream &strm, lldb::DescriptionLevel description_level); CompilerType FindDirectNestedType(llvm::StringRef name); private: bool CheckModule(lldb::ModuleSP &module_sp) const; bool CheckExeModule(lldb::ModuleSP &module_sp) const; bool CheckModuleCommon(const lldb::ModuleWP &input_module_wp, lldb::ModuleSP &module_sp) const; lldb::ModuleWP m_module_wp; lldb::ModuleWP m_exe_module_wp; CompilerType m_static_type; CompilerType m_dynamic_type; }; class TypeListImpl { public: TypeListImpl() = default; void Append(const lldb::TypeImplSP &type) { m_content.push_back(type); } class AppendVisitor { public: AppendVisitor(TypeListImpl &type_list) : m_type_list(type_list) {} void operator()(const lldb::TypeImplSP &type) { m_type_list.Append(type); } private: TypeListImpl &m_type_list; }; void Append(const lldb_private::TypeList &type_list); lldb::TypeImplSP GetTypeAtIndex(size_t idx) { lldb::TypeImplSP type_sp; if (idx < GetSize()) type_sp = m_content[idx]; return type_sp; } size_t GetSize() { return m_content.size(); } private: std::vector m_content; }; class TypeMemberImpl { public: TypeMemberImpl() = default; TypeMemberImpl(const lldb::TypeImplSP &type_impl_sp, uint64_t bit_offset, ConstString name, uint32_t bitfield_bit_size = 0, bool is_bitfield = false) : m_type_impl_sp(type_impl_sp), m_bit_offset(bit_offset), m_name(name), m_bitfield_bit_size(bitfield_bit_size), m_is_bitfield(is_bitfield) {} TypeMemberImpl(const lldb::TypeImplSP &type_impl_sp, uint64_t bit_offset) : m_type_impl_sp(type_impl_sp), m_bit_offset(bit_offset), m_bitfield_bit_size(0), m_is_bitfield(false) { if (m_type_impl_sp) m_name = m_type_impl_sp->GetName(); } const lldb::TypeImplSP &GetTypeImpl() { return m_type_impl_sp; } ConstString GetName() const { return m_name; } uint64_t GetBitOffset() const { return m_bit_offset; } uint32_t GetBitfieldBitSize() const { return m_bitfield_bit_size; } void SetBitfieldBitSize(uint32_t bitfield_bit_size) { m_bitfield_bit_size = bitfield_bit_size; } bool GetIsBitfield() const { return m_is_bitfield; } void SetIsBitfield(bool is_bitfield) { m_is_bitfield = is_bitfield; } protected: lldb::TypeImplSP m_type_impl_sp; uint64_t m_bit_offset = 0; ConstString m_name; uint32_t m_bitfield_bit_size = 0; // Bit size for bitfield members only bool m_is_bitfield = false; }; /// /// Sometimes you can find the name of the type corresponding to an object, but /// we don't have debug /// information for it. If that is the case, you can return one of these /// objects, and then if it /// has a full type, you can use that, but if not at least you can print the /// name for informational /// purposes. /// class TypeAndOrName { public: TypeAndOrName() = default; TypeAndOrName(lldb::TypeSP &type_sp); TypeAndOrName(const CompilerType &compiler_type); TypeAndOrName(const char *type_str); TypeAndOrName(ConstString &type_const_string); bool operator==(const TypeAndOrName &other) const; bool operator!=(const TypeAndOrName &other) const; ConstString GetName() const; CompilerType GetCompilerType() const { return m_compiler_type; } void SetName(ConstString type_name); void SetName(const char *type_name_cstr); void SetName(llvm::StringRef name); void SetTypeSP(lldb::TypeSP type_sp); void SetCompilerType(CompilerType compiler_type); bool IsEmpty() const; bool HasName() const; bool HasCompilerType() const; bool HasType() const { return HasCompilerType(); } void Clear(); explicit operator bool() { return !IsEmpty(); } private: CompilerType m_compiler_type; ConstString m_type_name; }; class TypeMemberFunctionImpl { public: TypeMemberFunctionImpl() = default; TypeMemberFunctionImpl(const CompilerType &type, const CompilerDecl &decl, const std::string &name, const lldb::MemberFunctionKind &kind) : m_type(type), m_decl(decl), m_name(name), m_kind(kind) {} bool IsValid(); ConstString GetName() const; ConstString GetMangledName() const; CompilerType GetType() const; CompilerType GetReturnType() const; size_t GetNumArguments() const; CompilerType GetArgumentAtIndex(size_t idx) const; lldb::MemberFunctionKind GetKind() const; bool GetDescription(Stream &stream); protected: std::string GetPrintableTypeName(); private: CompilerType m_type; CompilerDecl m_decl; ConstString m_name; lldb::MemberFunctionKind m_kind = lldb::eMemberFunctionKindUnknown; }; class TypeEnumMemberImpl { public: TypeEnumMemberImpl() : m_name("") {} TypeEnumMemberImpl(const lldb::TypeImplSP &integer_type_sp, ConstString name, const llvm::APSInt &value); TypeEnumMemberImpl(const TypeEnumMemberImpl &rhs) = default; TypeEnumMemberImpl &operator=(const TypeEnumMemberImpl &rhs); bool IsValid() { return m_valid; } ConstString GetName() const { return m_name; } const lldb::TypeImplSP &GetIntegerType() const { return m_integer_type_sp; } uint64_t GetValueAsUnsigned() const { return m_value.getZExtValue(); } int64_t GetValueAsSigned() const { return m_value.getSExtValue(); } protected: lldb::TypeImplSP m_integer_type_sp; ConstString m_name; llvm::APSInt m_value; bool m_valid = false; }; class TypeEnumMemberListImpl { public: TypeEnumMemberListImpl() = default; void Append(const lldb::TypeEnumMemberImplSP &type) { m_content.push_back(type); } void Append(const lldb_private::TypeEnumMemberListImpl &type_list); lldb::TypeEnumMemberImplSP GetTypeEnumMemberAtIndex(size_t idx) { lldb::TypeEnumMemberImplSP enum_member; if (idx < GetSize()) enum_member = m_content[idx]; return enum_member; } size_t GetSize() { return m_content.size(); } private: std::vector m_content; }; } // namespace lldb_private #endif // LLDB_SYMBOL_TYPE_H