+++ /dev/null
-//===-- ClangASTImporter.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 liblldb_ClangASTImporter_h_
-#define liblldb_ClangASTImporter_h_
-
-#include <map>
-#include <memory>
-#include <set>
-#include <vector>
-
-#include "clang/AST/ASTImporter.h"
-#include "clang/AST/CharUnits.h"
-#include "clang/AST/Decl.h"
-#include "clang/AST/DeclCXX.h"
-#include "clang/Basic/FileManager.h"
-#include "clang/Basic/FileSystemOptions.h"
-
-#include "lldb/Host/FileSystem.h"
-#include "lldb/Symbol/CompilerDeclContext.h"
-#include "lldb/Symbol/CxxModuleHandler.h"
-#include "lldb/lldb-types.h"
-
-#include "llvm/ADT/DenseMap.h"
-
-namespace lldb_private {
-
-class ClangASTImporter {
-public:
- struct LayoutInfo {
- LayoutInfo() = default;
- typedef llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits>
- OffsetMap;
-
- uint64_t bit_size = 0;
- uint64_t alignment = 0;
- llvm::DenseMap<const clang::FieldDecl *, uint64_t> field_offsets;
- OffsetMap base_offsets;
- OffsetMap vbase_offsets;
- };
-
- ClangASTImporter()
- : m_file_manager(clang::FileSystemOptions(),
- FileSystem::Instance().GetVirtualFileSystem()) {}
-
- CompilerType CopyType(TypeSystemClang &dst, const CompilerType &src_type);
-
- clang::Decl *CopyDecl(clang::ASTContext *dst_ctx, clang::Decl *decl);
-
- CompilerType DeportType(TypeSystemClang &dst, const CompilerType &src_type);
-
- clang::Decl *DeportDecl(clang::ASTContext *dst_ctx, clang::Decl *decl);
-
- /// Sets the layout for the given RecordDecl. The layout will later be
- /// used by Clang's during code generation. Not calling this function for
- /// a RecordDecl will cause that Clang's codegen tries to layout the
- /// record by itself.
- ///
- /// \param decl The RecordDecl to set the layout for.
- /// \param layout The layout for the record.
- void SetRecordLayout(clang::RecordDecl *decl, const LayoutInfo &layout);
-
- bool LayoutRecordType(
- const clang::RecordDecl *record_decl, uint64_t &bit_size,
- uint64_t &alignment,
- llvm::DenseMap<const clang::FieldDecl *, uint64_t> &field_offsets,
- llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits>
- &base_offsets,
- llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits>
- &vbase_offsets);
-
- bool CanImport(const CompilerType &type);
-
- bool Import(const CompilerType &type);
-
- bool CompleteType(const CompilerType &compiler_type);
-
- bool CompleteTagDecl(clang::TagDecl *decl);
-
- bool CompleteTagDeclWithOrigin(clang::TagDecl *decl, clang::TagDecl *origin);
-
- bool CompleteObjCInterfaceDecl(clang::ObjCInterfaceDecl *interface_decl);
-
- bool CompleteAndFetchChildren(clang::QualType type);
-
- bool RequireCompleteType(clang::QualType type);
-
- void SetDeclOrigin(const clang::Decl *decl, clang::Decl *original_decl);
-
- ClangASTMetadata *GetDeclMetadata(const clang::Decl *decl);
-
- //
- // Namespace maps
- //
-
- typedef std::vector<std::pair<lldb::ModuleSP, CompilerDeclContext>>
- NamespaceMap;
- typedef std::shared_ptr<NamespaceMap> NamespaceMapSP;
-
- void RegisterNamespaceMap(const clang::NamespaceDecl *decl,
- NamespaceMapSP &namespace_map);
-
- NamespaceMapSP GetNamespaceMap(const clang::NamespaceDecl *decl);
-
- void BuildNamespaceMap(const clang::NamespaceDecl *decl);
-
- //
- // Completers for maps
- //
-
- class MapCompleter {
- public:
- virtual ~MapCompleter();
-
- virtual void CompleteNamespaceMap(NamespaceMapSP &namespace_map,
- ConstString name,
- NamespaceMapSP &parent_map) const = 0;
- };
-
- void InstallMapCompleter(clang::ASTContext *dst_ctx,
- MapCompleter &completer) {
- ASTContextMetadataSP context_md;
- ContextMetadataMap::iterator context_md_iter = m_metadata_map.find(dst_ctx);
-
- if (context_md_iter == m_metadata_map.end()) {
- context_md = ASTContextMetadataSP(new ASTContextMetadata(dst_ctx));
- m_metadata_map[dst_ctx] = context_md;
- } else {
- context_md = context_md_iter->second;
- }
-
- context_md->m_map_completer = &completer;
- }
-
- void ForgetDestination(clang::ASTContext *dst_ctx);
- void ForgetSource(clang::ASTContext *dst_ctx, clang::ASTContext *src_ctx);
-
-public:
- struct DeclOrigin {
- DeclOrigin() : ctx(nullptr), decl(nullptr) {}
-
- DeclOrigin(clang::ASTContext *_ctx, clang::Decl *_decl)
- : ctx(_ctx), decl(_decl) {}
-
- DeclOrigin(const DeclOrigin &rhs) {
- ctx = rhs.ctx;
- decl = rhs.decl;
- }
-
- void operator=(const DeclOrigin &rhs) {
- ctx = rhs.ctx;
- decl = rhs.decl;
- }
-
- bool Valid() { return (ctx != nullptr || decl != nullptr); }
-
- clang::ASTContext *ctx;
- clang::Decl *decl;
- };
-
- typedef llvm::DenseMap<const clang::Decl *, DeclOrigin> OriginMap;
-
- /// Listener interface used by the ASTImporterDelegate to inform other code
- /// about decls that have been imported the first time.
- struct NewDeclListener {
- virtual ~NewDeclListener() = default;
- /// A decl has been imported for the first time.
- virtual void NewDeclImported(clang::Decl *from, clang::Decl *to) = 0;
- };
-
- /// ASTImporter that intercepts and records the import process of the
- /// underlying ASTImporter.
- ///
- /// This class updates the map from declarations to their original
- /// declarations and can record declarations that have been imported in a
- /// certain interval.
- ///
- /// When intercepting a declaration import, the ASTImporterDelegate uses the
- /// CxxModuleHandler to replace any missing or malformed declarations with
- /// their counterpart from a C++ module.
- struct ASTImporterDelegate : public clang::ASTImporter {
- ASTImporterDelegate(ClangASTImporter &master, clang::ASTContext *target_ctx,
- clang::ASTContext *source_ctx)
- : clang::ASTImporter(*target_ctx, master.m_file_manager, *source_ctx,
- master.m_file_manager, true /*minimal*/),
- m_master(master), m_source_ctx(source_ctx) {
- setODRHandling(clang::ASTImporter::ODRHandlingType::Liberal);
- }
-
- /// Scope guard that attaches a CxxModuleHandler to an ASTImporterDelegate
- /// and deattaches it at the end of the scope. Supports being used multiple
- /// times on the same ASTImporterDelegate instance in nested scopes.
- class CxxModuleScope {
- /// The handler we attach to the ASTImporterDelegate.
- CxxModuleHandler m_handler;
- /// The ASTImporterDelegate we are supposed to attach the handler to.
- ASTImporterDelegate &m_delegate;
- /// True iff we attached the handler to the ASTImporterDelegate.
- bool m_valid = false;
-
- public:
- CxxModuleScope(ASTImporterDelegate &delegate, clang::ASTContext *dst_ctx)
- : m_delegate(delegate) {
- // If the delegate doesn't have a CxxModuleHandler yet, create one
- // and attach it.
- if (!delegate.m_std_handler) {
- m_handler = CxxModuleHandler(delegate, dst_ctx);
- m_valid = true;
- delegate.m_std_handler = &m_handler;
- }
- }
- ~CxxModuleScope() {
- if (m_valid) {
- // Make sure no one messed with the handler we placed.
- assert(m_delegate.m_std_handler == &m_handler);
- m_delegate.m_std_handler = nullptr;
- }
- }
- };
-
- void ImportDefinitionTo(clang::Decl *to, clang::Decl *from);
-
- void Imported(clang::Decl *from, clang::Decl *to) override;
-
- clang::Decl *GetOriginalDecl(clang::Decl *To) override;
-
- void SetImportListener(NewDeclListener *listener) {
- assert(m_new_decl_listener == nullptr && "Already attached a listener?");
- m_new_decl_listener = listener;
- }
- void RemoveImportListener() { m_new_decl_listener = nullptr; }
-
- protected:
- llvm::Expected<clang::Decl *> ImportImpl(clang::Decl *From) override;
-
- private:
- /// Decls we should ignore when mapping decls back to their original
- /// ASTContext. Used by the CxxModuleHandler to mark declarations that
- /// were created from the 'std' C++ module to prevent that the Importer
- /// tries to sync them with the broken equivalent in the debug info AST.
- llvm::SmallPtrSet<clang::Decl *, 16> m_decls_to_ignore;
- ClangASTImporter &m_master;
- clang::ASTContext *m_source_ctx;
- CxxModuleHandler *m_std_handler = nullptr;
- /// The currently attached listener.
- NewDeclListener *m_new_decl_listener = nullptr;
- };
-
- typedef std::shared_ptr<ASTImporterDelegate> ImporterDelegateSP;
- typedef llvm::DenseMap<clang::ASTContext *, ImporterDelegateSP> DelegateMap;
- typedef llvm::DenseMap<const clang::NamespaceDecl *, NamespaceMapSP>
- NamespaceMetaMap;
-
- struct ASTContextMetadata {
- ASTContextMetadata(clang::ASTContext *dst_ctx)
- : m_dst_ctx(dst_ctx), m_delegates(), m_origins(), m_namespace_maps(),
- m_map_completer(nullptr) {}
-
- clang::ASTContext *m_dst_ctx;
- DelegateMap m_delegates;
- OriginMap m_origins;
-
- NamespaceMetaMap m_namespace_maps;
- MapCompleter *m_map_completer;
- };
-
- typedef std::shared_ptr<ASTContextMetadata> ASTContextMetadataSP;
- typedef llvm::DenseMap<const clang::ASTContext *, ASTContextMetadataSP>
- ContextMetadataMap;
-
- ContextMetadataMap m_metadata_map;
-
- ASTContextMetadataSP GetContextMetadata(clang::ASTContext *dst_ctx) {
- ContextMetadataMap::iterator context_md_iter = m_metadata_map.find(dst_ctx);
-
- if (context_md_iter == m_metadata_map.end()) {
- ASTContextMetadataSP context_md =
- ASTContextMetadataSP(new ASTContextMetadata(dst_ctx));
- m_metadata_map[dst_ctx] = context_md;
- return context_md;
- }
- return context_md_iter->second;
- }
-
- ASTContextMetadataSP MaybeGetContextMetadata(clang::ASTContext *dst_ctx) {
- ContextMetadataMap::iterator context_md_iter = m_metadata_map.find(dst_ctx);
-
- if (context_md_iter != m_metadata_map.end())
- return context_md_iter->second;
- return ASTContextMetadataSP();
- }
-
- ImporterDelegateSP GetDelegate(clang::ASTContext *dst_ctx,
- clang::ASTContext *src_ctx) {
- ASTContextMetadataSP context_md = GetContextMetadata(dst_ctx);
-
- DelegateMap &delegates = context_md->m_delegates;
- DelegateMap::iterator delegate_iter = delegates.find(src_ctx);
-
- if (delegate_iter == delegates.end()) {
- ImporterDelegateSP delegate =
- ImporterDelegateSP(new ASTImporterDelegate(*this, dst_ctx, src_ctx));
- delegates[src_ctx] = delegate;
- return delegate;
- }
- return delegate_iter->second;
- }
-
-public:
- DeclOrigin GetDeclOrigin(const clang::Decl *decl);
-
- clang::FileManager m_file_manager;
- typedef llvm::DenseMap<const clang::RecordDecl *, LayoutInfo>
- RecordDeclToLayoutMap;
-
- RecordDeclToLayoutMap m_record_decl_to_layout_map;
-};
-
-} // namespace lldb_private
-
-#endif // liblldb_ClangASTImporter_h_
+++ /dev/null
-//===-- ClangASTMetadata.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 liblldb_ClangASTMetadata_h
-#define liblldb_ClangASTMetadata_h
-
-#include "lldb/Core/dwarf.h"
-#include "lldb/lldb-defines.h"
-#include "lldb/lldb-enumerations.h"
-
-namespace lldb_private {
-
-class ClangASTMetadata {
-public:
- ClangASTMetadata()
- : m_user_id(0), m_union_is_user_id(false), m_union_is_isa_ptr(false),
- m_has_object_ptr(false), m_is_self(false), m_is_dynamic_cxx(true) {}
-
- bool GetIsDynamicCXXType() const { return m_is_dynamic_cxx; }
-
- void SetIsDynamicCXXType(bool b) { m_is_dynamic_cxx = b; }
-
- void SetUserID(lldb::user_id_t user_id) {
- m_user_id = user_id;
- m_union_is_user_id = true;
- m_union_is_isa_ptr = false;
- }
-
- lldb::user_id_t GetUserID() const {
- if (m_union_is_user_id)
- return m_user_id;
- else
- return LLDB_INVALID_UID;
- }
-
- void SetISAPtr(uint64_t isa_ptr) {
- m_isa_ptr = isa_ptr;
- m_union_is_user_id = false;
- m_union_is_isa_ptr = true;
- }
-
- uint64_t GetISAPtr() const {
- if (m_union_is_isa_ptr)
- return m_isa_ptr;
- else
- return 0;
- }
-
- void SetObjectPtrName(const char *name) {
- m_has_object_ptr = true;
- if (strcmp(name, "self") == 0)
- m_is_self = true;
- else if (strcmp(name, "this") == 0)
- m_is_self = false;
- else
- m_has_object_ptr = false;
- }
-
- lldb::LanguageType GetObjectPtrLanguage() const {
- if (m_has_object_ptr) {
- if (m_is_self)
- return lldb::eLanguageTypeObjC;
- else
- return lldb::eLanguageTypeC_plus_plus;
- }
- return lldb::eLanguageTypeUnknown;
- }
-
- const char *GetObjectPtrName() const {
- if (m_has_object_ptr) {
- if (m_is_self)
- return "self";
- else
- return "this";
- } else
- return nullptr;
- }
-
- bool HasObjectPtr() const { return m_has_object_ptr; }
-
- void Dump(Stream *s);
-
-private:
- union {
- lldb::user_id_t m_user_id;
- uint64_t m_isa_ptr;
- };
-
- bool m_union_is_user_id : 1, m_union_is_isa_ptr : 1, m_has_object_ptr : 1,
- m_is_self : 1, m_is_dynamic_cxx : 1;
-};
-
-} // namespace lldb_private
-
-#endif // liblldb_ClangASTMetadata_h
+++ /dev/null
-//===-- ClangExternalASTSourceCallbacks.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 liblldb_ClangExternalASTSourceCallbacks_h_
-#define liblldb_ClangExternalASTSourceCallbacks_h_
-
-#include "lldb/Symbol/TypeSystemClang.h"
-#include "clang/AST/ExternalASTSource.h"
-
-namespace lldb_private {
-
-class TypeSystemClang;
-
-class ClangExternalASTSourceCallbacks : public clang::ExternalASTSource {
-public:
- ClangExternalASTSourceCallbacks(TypeSystemClang &ast) : m_ast(ast) {}
-
- void FindExternalLexicalDecls(
- const clang::DeclContext *DC,
- llvm::function_ref<bool(clang::Decl::Kind)> IsKindWeWant,
- llvm::SmallVectorImpl<clang::Decl *> &Result) override;
-
- void CompleteType(clang::TagDecl *tag_decl) override;
-
- void CompleteType(clang::ObjCInterfaceDecl *objc_decl) override;
-
- bool layoutRecordType(
- const clang::RecordDecl *Record, uint64_t &Size, uint64_t &Alignment,
- llvm::DenseMap<const clang::FieldDecl *, uint64_t> &FieldOffsets,
- llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits>
- &BaseOffsets,
- llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits>
- &VirtualBaseOffsets) override;
-
-private:
- TypeSystemClang &m_ast;
-};
-
-} // namespace lldb_private
-
-#endif // liblldb_ClangExternalASTSourceCallbacks_h_
+++ /dev/null
-//===-- ClangUtil.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
-//
-// A collection of helper methods and data structures for manipulating clang
-// types and decls.
-//===----------------------------------------------------------------------===//
-
-#ifndef LLDB_SYMBOL_CLANGUTIL_H
-#define LLDB_SYMBOL_CLANGUTIL_H
-
-#include "clang/AST/DeclBase.h"
-#include "clang/AST/Type.h"
-
-#include "lldb/Symbol/CompilerType.h"
-
-namespace clang {
-class TagDecl;
-}
-
-namespace lldb_private {
-struct ClangUtil {
- static bool IsClangType(const CompilerType &ct);
-
- /// Returns the clang::Decl of the given CompilerDecl.
- /// CompilerDecl has to be valid and represent a clang::Decl.
- static clang::Decl *GetDecl(const CompilerDecl &decl);
-
- static clang::QualType GetQualType(const CompilerType &ct);
-
- static clang::QualType GetCanonicalQualType(const CompilerType &ct);
-
- static CompilerType RemoveFastQualifiers(const CompilerType &ct);
-
- static clang::TagDecl *GetAsTagDecl(const CompilerType &type);
-
- /// Returns a textual representation of the given Decl's AST. Does not
- /// deserialize any child nodes.
- static std::string DumpDecl(const clang::Decl *d);
- /// Returns a textual representation of the given type.
- static std::string ToString(const clang::Type *t);
- /// Returns a textual representation of the given CompilerType (assuming
- /// its underlying type is a Clang type).
- static std::string ToString(const CompilerType &c);
-};
-}
-
-#endif
+++ /dev/null
-//===-- CxxModuleHandler.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 liblldb_CxxModuleHandler_h_
-#define liblldb_CxxModuleHandler_h_
-
-#include "clang/AST/ASTImporter.h"
-#include "clang/Sema/Sema.h"
-#include "llvm/ADT/StringSet.h"
-
-namespace lldb_private {
-
-/// Handles importing decls into an ASTContext with an attached C++ module.
-///
-/// This class searches a C++ module (which must be attached to the target
-/// ASTContext) for an equivalent decl to the one that should be imported.
-/// If the decl that is found in the module is a suitable replacement
-/// for the decl that should be imported, the module decl will be treated as
-/// the result of the import process.
-///
-/// If the Decl that should be imported is a template specialization
-/// that doesn't exist yet in the target ASTContext (e.g. `std::vector<int>`),
-/// then this class tries to create the template specialization in the target
-/// ASTContext. This is only possible if the CxxModuleHandler can determine
-/// that instantiating this template is safe to do, e.g. because the target
-/// decl is a container class from the STL.
-class CxxModuleHandler {
- /// The ASTImporter that should be used to import any Decls which aren't
- /// directly handled by this class itself.
- clang::ASTImporter *m_importer = nullptr;
-
- /// The Sema instance of the target ASTContext.
- clang::Sema *m_sema = nullptr;
-
- /// List of template names this class currently supports. These are the
- /// template names inside the 'std' namespace such as 'vector' or 'list'.
- llvm::StringSet<> m_supported_templates;
-
- /// Tries to manually instantiate the given foreign template in the target
- /// context (designated by m_sema).
- llvm::Optional<clang::Decl *> tryInstantiateStdTemplate(clang::Decl *d);
-
-public:
- CxxModuleHandler() = default;
- CxxModuleHandler(clang::ASTImporter &importer, clang::ASTContext *target);
-
- /// Attempts to import the given decl into the target ASTContext by
- /// deserializing it from the 'std' module. This function returns a Decl if a
- /// Decl has been deserialized from the 'std' module. Otherwise this function
- /// returns nothing.
- llvm::Optional<clang::Decl *> Import(clang::Decl *d);
-
- /// Returns true iff this instance is capable of importing any declarations
- /// in the target ASTContext.
- bool isValid() const { return m_sema != nullptr; }
-};
-
-} // namespace lldb_private
-
-#endif // liblldb_CxxModuleHandler_h_
+++ /dev/null
-//===-- TypeSystemClang.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 liblldb_TypeSystemClang_h_
-#define liblldb_TypeSystemClang_h_
-
-#include <stdint.h>
-
-#include <functional>
-#include <initializer_list>
-#include <map>
-#include <memory>
-#include <set>
-#include <string>
-#include <utility>
-#include <vector>
-
-#include "clang/AST/ASTContext.h"
-#include "clang/AST/ASTFwd.h"
-#include "clang/AST/TemplateBase.h"
-#include "llvm/ADT/APSInt.h"
-#include "llvm/ADT/SmallVector.h"
-
-#include "Plugins/ExpressionParser/Clang/ClangPersistentVariables.h"
-#include "lldb/Core/ClangForward.h"
-#include "lldb/Expression/ExpressionVariable.h"
-#include "lldb/Symbol/CompilerType.h"
-#include "lldb/Symbol/TypeSystem.h"
-#include "lldb/Target/Target.h"
-#include "lldb/Utility/ConstString.h"
-#include "lldb/Utility/Log.h"
-#include "lldb/Utility/Logging.h"
-#include "lldb/lldb-enumerations.h"
-
-class DWARFASTParserClang;
-class PDBASTParser;
-
-namespace lldb_private {
-
-class Declaration;
-
-class TypeSystemClang : public TypeSystem {
- // LLVM RTTI support
- static char ID;
-
-public:
- typedef void (*CompleteTagDeclCallback)(void *baton, clang::TagDecl *);
- typedef void (*CompleteObjCInterfaceDeclCallback)(void *baton,
- clang::ObjCInterfaceDecl *);
-
- // llvm casting support
- bool isA(const void *ClassID) const override { return ClassID == &ID; }
- static bool classof(const TypeSystem *ts) { return ts->isA(&ID); }
-
- /// Constructs a TypeSystemClang with an ASTContext using the given triple.
- ///
- /// \param name The name for the TypeSystemClang (for logging purposes)
- /// \param triple The llvm::Triple used for the ASTContext. The triple defines
- /// certain characteristics of the ASTContext and its types
- /// (e.g., whether certain primitive types exist or what their
- /// signedness is).
- explicit TypeSystemClang(llvm::StringRef name, llvm::Triple triple);
-
- /// Constructs a TypeSystemClang that uses an existing ASTContext internally.
- /// Useful when having an existing ASTContext created by Clang.
- ///
- /// \param name The name for the TypeSystemClang (for logging purposes)
- /// \param existing_ctxt An existing ASTContext.
- explicit TypeSystemClang(llvm::StringRef name,
- clang::ASTContext &existing_ctxt);
-
- ~TypeSystemClang() override;
-
- void Finalize() override;
-
- // PluginInterface functions
- ConstString GetPluginName() override;
-
- uint32_t GetPluginVersion() override;
-
- static ConstString GetPluginNameStatic();
-
- static lldb::TypeSystemSP CreateInstance(lldb::LanguageType language,
- Module *module, Target *target);
-
- static LanguageSet GetSupportedLanguagesForTypes();
- static LanguageSet GetSupportedLanguagesForExpressions();
-
- static void Initialize();
-
- static void Terminate();
-
- static TypeSystemClang *GetASTContext(clang::ASTContext *ast_ctx);
-
- static TypeSystemClang *GetScratch(Target &target,
- bool create_on_demand = true) {
- auto type_system_or_err = target.GetScratchTypeSystemForLanguage(
- lldb::eLanguageTypeC, create_on_demand);
- if (auto err = type_system_or_err.takeError()) {
- LLDB_LOG_ERROR(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_TARGET),
- std::move(err), "Couldn't get scratch TypeSystemClang");
- return nullptr;
- }
- return llvm::dyn_cast<TypeSystemClang>(&type_system_or_err.get());
- }
-
- /// Returns the display name of this TypeSystemClang that indicates what
- /// purpose it serves in LLDB. Used for example in logs.
- llvm::StringRef getDisplayName() const { return m_display_name; }
-
- clang::ASTContext &getASTContext();
-
- clang::MangleContext *getMangleContext();
-
- std::shared_ptr<clang::TargetOptions> &getTargetOptions();
-
- clang::TargetInfo *getTargetInfo();
-
- void setSema(clang::Sema *s);
- clang::Sema *getSema() { return m_sema; }
-
- const char *GetTargetTriple();
-
- void SetExternalSource(
- llvm::IntrusiveRefCntPtr<clang::ExternalASTSource> &ast_source_up);
-
- bool GetCompleteDecl(clang::Decl *decl) {
- return TypeSystemClang::GetCompleteDecl(&getASTContext(), decl);
- }
-
- static void DumpDeclHiearchy(clang::Decl *decl);
-
- static void DumpDeclContextHiearchy(clang::DeclContext *decl_ctx);
-
- static bool DeclsAreEquivalent(clang::Decl *lhs_decl, clang::Decl *rhs_decl);
-
- static bool GetCompleteDecl(clang::ASTContext *ast, clang::Decl *decl);
-
- void SetMetadataAsUserID(const clang::Decl *decl, lldb::user_id_t user_id);
- void SetMetadataAsUserID(const clang::Type *type, lldb::user_id_t user_id);
-
- void SetMetadata(const clang::Decl *object, ClangASTMetadata &meta_data);
-
- void SetMetadata(const clang::Type *object, ClangASTMetadata &meta_data);
- ClangASTMetadata *GetMetadata(const clang::Decl *object);
- ClangASTMetadata *GetMetadata(const clang::Type *object);
-
- // Basic Types
- CompilerType GetBuiltinTypeForEncodingAndBitSize(lldb::Encoding encoding,
- size_t bit_size) override;
-
- CompilerType GetBasicType(lldb::BasicType type);
-
- static lldb::BasicType GetBasicTypeEnumeration(ConstString name);
-
- CompilerType
- GetBuiltinTypeForDWARFEncodingAndBitSize(llvm::StringRef type_name,
- uint32_t dw_ate, uint32_t bit_size);
-
- CompilerType GetCStringType(bool is_const);
-
- static clang::DeclContext *GetDeclContextForType(clang::QualType type);
-
- static clang::DeclContext *GetDeclContextForType(const CompilerType &type);
-
- uint32_t GetPointerByteSize() override;
-
- clang::TranslationUnitDecl *GetTranslationUnitDecl() {
- return getASTContext().getTranslationUnitDecl();
- }
-
- static bool AreTypesSame(CompilerType type1, CompilerType type2,
- bool ignore_qualifiers = false);
-
- /// Creates a CompilerType form the given QualType with the current
- /// TypeSystemClang instance as the CompilerType's typesystem.
- /// \param qt The QualType for a type that belongs to the ASTContext of this
- /// TypeSystemClang.
- /// \return The CompilerType representing the given QualType. If the
- /// QualType's type pointer is a nullptr then the function returns an
- /// invalid CompilerType.
- CompilerType GetType(clang::QualType qt) {
- if (qt.getTypePtrOrNull() == nullptr)
- return CompilerType();
- // Check that the type actually belongs to this TypeSystemClang.
- assert(qt->getAsTagDecl() == nullptr ||
- &qt->getAsTagDecl()->getASTContext() == &getASTContext());
- return CompilerType(this, qt.getAsOpaquePtr());
- }
-
- CompilerType GetTypeForDecl(clang::NamedDecl *decl);
-
- CompilerType GetTypeForDecl(clang::TagDecl *decl);
-
- CompilerType GetTypeForDecl(clang::ObjCInterfaceDecl *objc_decl);
-
- template <typename RecordDeclType>
- CompilerType
- GetTypeForIdentifier(ConstString type_name,
- clang::DeclContext *decl_context = nullptr) {
- CompilerType compiler_type;
-
- if (type_name.GetLength()) {
- clang::ASTContext &ast = getASTContext();
- if (!decl_context)
- decl_context = ast.getTranslationUnitDecl();
-
- clang::IdentifierInfo &myIdent = ast.Idents.get(type_name.GetCString());
- clang::DeclarationName myName =
- ast.DeclarationNames.getIdentifier(&myIdent);
-
- clang::DeclContext::lookup_result result = decl_context->lookup(myName);
-
- if (!result.empty()) {
- clang::NamedDecl *named_decl = result[0];
- if (const RecordDeclType *record_decl =
- llvm::dyn_cast<RecordDeclType>(named_decl))
- compiler_type.SetCompilerType(
- this, clang::QualType(record_decl->getTypeForDecl(), 0)
- .getAsOpaquePtr());
- }
- }
-
- return compiler_type;
- }
-
- CompilerType CreateStructForIdentifier(
- ConstString type_name,
- const std::initializer_list<std::pair<const char *, CompilerType>>
- &type_fields,
- bool packed = false);
-
- CompilerType GetOrCreateStructForIdentifier(
- ConstString type_name,
- const std::initializer_list<std::pair<const char *, CompilerType>>
- &type_fields,
- bool packed = false);
-
- static bool IsOperator(llvm::StringRef name,
- clang::OverloadedOperatorKind &op_kind);
-
- // Structure, Unions, Classes
-
- static clang::AccessSpecifier
- ConvertAccessTypeToAccessSpecifier(lldb::AccessType access);
-
- static clang::AccessSpecifier
- UnifyAccessSpecifiers(clang::AccessSpecifier lhs, clang::AccessSpecifier rhs);
-
- static uint32_t GetNumBaseClasses(const clang::CXXRecordDecl *cxx_record_decl,
- bool omit_empty_base_classes);
-
- CompilerType CreateRecordType(clang::DeclContext *decl_ctx,
- lldb::AccessType access_type,
- llvm::StringRef name, int kind,
- lldb::LanguageType language,
- ClangASTMetadata *metadata = nullptr,
- bool exports_symbols = false);
-
- class TemplateParameterInfos {
- public:
- bool IsValid() const {
- if (args.empty())
- return false;
- return args.size() == names.size() &&
- ((bool)pack_name == (bool)packed_args) &&
- (!packed_args || !packed_args->packed_args);
- }
-
- llvm::SmallVector<const char *, 2> names;
- llvm::SmallVector<clang::TemplateArgument, 2> args;
-
- const char * pack_name = nullptr;
- std::unique_ptr<TemplateParameterInfos> packed_args;
- };
-
- clang::FunctionTemplateDecl *
- CreateFunctionTemplateDecl(clang::DeclContext *decl_ctx,
- clang::FunctionDecl *func_decl, const char *name,
- const TemplateParameterInfos &infos);
-
- void CreateFunctionTemplateSpecializationInfo(
- clang::FunctionDecl *func_decl, clang::FunctionTemplateDecl *Template,
- const TemplateParameterInfos &infos);
-
- clang::ClassTemplateDecl *
- CreateClassTemplateDecl(clang::DeclContext *decl_ctx,
- lldb::AccessType access_type, const char *class_name,
- int kind, const TemplateParameterInfos &infos);
-
- clang::TemplateTemplateParmDecl *
- CreateTemplateTemplateParmDecl(const char *template_name);
-
- clang::ClassTemplateSpecializationDecl *CreateClassTemplateSpecializationDecl(
- clang::DeclContext *decl_ctx,
- clang::ClassTemplateDecl *class_template_decl, int kind,
- const TemplateParameterInfos &infos);
-
- CompilerType
- CreateClassTemplateSpecializationType(clang::ClassTemplateSpecializationDecl *
- class_template_specialization_decl);
-
- static clang::DeclContext *
- GetAsDeclContext(clang::FunctionDecl *function_decl);
-
- static bool CheckOverloadedOperatorKindParameterCount(
- bool is_method, clang::OverloadedOperatorKind op_kind,
- uint32_t num_params);
-
- bool FieldIsBitfield(clang::FieldDecl *field, uint32_t &bitfield_bit_size);
-
- static bool RecordHasFields(const clang::RecordDecl *record_decl);
-
- CompilerType CreateObjCClass(llvm::StringRef name,
- clang::DeclContext *decl_ctx, bool isForwardDecl,
- bool isInternal,
- ClangASTMetadata *metadata = nullptr);
-
- bool SetTagTypeKind(clang::QualType type, int kind) const;
-
- bool SetDefaultAccessForRecordFields(clang::RecordDecl *record_decl,
- int default_accessibility,
- int *assigned_accessibilities,
- size_t num_assigned_accessibilities);
-
- // Returns a mask containing bits from the TypeSystemClang::eTypeXXX
- // enumerations
-
- // Namespace Declarations
-
- clang::NamespaceDecl *
- GetUniqueNamespaceDeclaration(const char *name, clang::DeclContext *decl_ctx,
- bool is_inline = false);
-
- // Function Types
-
- clang::FunctionDecl *
- CreateFunctionDeclaration(clang::DeclContext *decl_ctx, const char *name,
- const CompilerType &function_Type, int storage,
- bool is_inline);
-
- CompilerType CreateFunctionType(const CompilerType &result_type,
- const CompilerType *args, unsigned num_args,
- bool is_variadic, unsigned type_quals,
- clang::CallingConv cc);
-
- CompilerType CreateFunctionType(const CompilerType &result_type,
- const CompilerType *args, unsigned num_args,
- bool is_variadic, unsigned type_quals) {
- return CreateFunctionType(result_type, args, num_args, is_variadic,
- type_quals, clang::CC_C);
- }
-
- clang::ParmVarDecl *CreateParameterDeclaration(clang::DeclContext *decl_ctx,
- const char *name,
- const CompilerType ¶m_type,
- int storage,
- bool add_decl=false);
-
- void SetFunctionParameters(clang::FunctionDecl *function_decl,
- clang::ParmVarDecl **params, unsigned num_params);
-
- CompilerType CreateBlockPointerType(const CompilerType &function_type);
-
- // Array Types
-
- CompilerType CreateArrayType(const CompilerType &element_type,
- size_t element_count, bool is_vector);
-
- // Enumeration Types
- CompilerType CreateEnumerationType(const char *name,
- clang::DeclContext *decl_ctx,
- const Declaration &decl,
- const CompilerType &integer_qual_type,
- bool is_scoped);
-
- // Integer type functions
-
- CompilerType GetIntTypeFromBitSize(size_t bit_size, bool is_signed);
-
- CompilerType GetPointerSizedIntType(bool is_signed);
-
- // Floating point functions
-
- static CompilerType GetFloatTypeFromBitSize(clang::ASTContext *ast,
- size_t bit_size);
-
- // TypeSystem methods
- DWARFASTParser *GetDWARFParser() override;
- PDBASTParser *GetPDBParser() override;
-
- // TypeSystemClang callbacks for external source lookups.
- void CompleteTagDecl(clang::TagDecl *);
-
- void CompleteObjCInterfaceDecl(clang::ObjCInterfaceDecl *);
-
- bool LayoutRecordType(
- const clang::RecordDecl *record_decl, uint64_t &size, uint64_t &alignment,
- llvm::DenseMap<const clang::FieldDecl *, uint64_t> &field_offsets,
- llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits>
- &base_offsets,
- llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits>
- &vbase_offsets);
-
- /// Creates a CompilerDecl from the given Decl with the current
- /// TypeSystemClang instance as its typesystem.
- /// The Decl has to come from the ASTContext of this
- /// TypeSystemClang.
- CompilerDecl GetCompilerDecl(clang::Decl *decl) {
- assert(&decl->getASTContext() == &getASTContext() &&
- "CreateCompilerDecl for Decl from wrong ASTContext?");
- return CompilerDecl(this, decl);
- }
-
- // CompilerDecl override functions
- ConstString DeclGetName(void *opaque_decl) override;
-
- ConstString DeclGetMangledName(void *opaque_decl) override;
-
- CompilerDeclContext DeclGetDeclContext(void *opaque_decl) override;
-
- CompilerType DeclGetFunctionReturnType(void *opaque_decl) override;
-
- size_t DeclGetFunctionNumArguments(void *opaque_decl) override;
-
- CompilerType DeclGetFunctionArgumentType(void *opaque_decl,
- size_t arg_idx) override;
-
- CompilerType GetTypeForDecl(void *opaque_decl) override;
-
- // CompilerDeclContext override functions
-
- /// Creates a CompilerDeclContext from the given DeclContext
- /// with the current TypeSystemClang instance as its typesystem.
- /// The DeclContext has to come from the ASTContext of this
- /// TypeSystemClang.
- CompilerDeclContext CreateDeclContext(clang::DeclContext *ctx);
-
- std::vector<CompilerDecl>
- DeclContextFindDeclByName(void *opaque_decl_ctx, ConstString name,
- const bool ignore_using_decls) override;
-
- ConstString DeclContextGetName(void *opaque_decl_ctx) override;
-
- ConstString DeclContextGetScopeQualifiedName(void *opaque_decl_ctx) override;
-
- bool DeclContextIsClassMethod(void *opaque_decl_ctx,
- lldb::LanguageType *language_ptr,
- bool *is_instance_method_ptr,
- ConstString *language_object_name_ptr) override;
-
- bool DeclContextIsContainedInLookup(void *opaque_decl_ctx,
- void *other_opaque_decl_ctx) override;
-
- // Clang specific clang::DeclContext functions
-
- static clang::DeclContext *
- DeclContextGetAsDeclContext(const CompilerDeclContext &dc);
-
- static clang::ObjCMethodDecl *
- DeclContextGetAsObjCMethodDecl(const CompilerDeclContext &dc);
-
- static clang::CXXMethodDecl *
- DeclContextGetAsCXXMethodDecl(const CompilerDeclContext &dc);
-
- static clang::FunctionDecl *
- DeclContextGetAsFunctionDecl(const CompilerDeclContext &dc);
-
- static clang::NamespaceDecl *
- DeclContextGetAsNamespaceDecl(const CompilerDeclContext &dc);
-
- static ClangASTMetadata *DeclContextGetMetaData(const CompilerDeclContext &dc,
- const clang::Decl *object);
-
- static clang::ASTContext *
- DeclContextGetTypeSystemClang(const CompilerDeclContext &dc);
-
- // Tests
-
- bool IsArrayType(lldb::opaque_compiler_type_t type,
- CompilerType *element_type, uint64_t *size,
- bool *is_incomplete) override;
-
- bool IsVectorType(lldb::opaque_compiler_type_t type,
- CompilerType *element_type, uint64_t *size) override;
-
- bool IsAggregateType(lldb::opaque_compiler_type_t type) override;
-
- bool IsAnonymousType(lldb::opaque_compiler_type_t type) override;
-
- bool IsBeingDefined(lldb::opaque_compiler_type_t type) override;
-
- bool IsCharType(lldb::opaque_compiler_type_t type) override;
-
- bool IsCompleteType(lldb::opaque_compiler_type_t type) override;
-
- bool IsConst(lldb::opaque_compiler_type_t type) override;
-
- bool IsCStringType(lldb::opaque_compiler_type_t type,
- uint32_t &length) override;
-
- static bool IsCXXClassType(const CompilerType &type);
-
- bool IsDefined(lldb::opaque_compiler_type_t type) override;
-
- bool IsFloatingPointType(lldb::opaque_compiler_type_t type, uint32_t &count,
- bool &is_complex) override;
-
- bool IsFunctionType(lldb::opaque_compiler_type_t type,
- bool *is_variadic_ptr) override;
-
- uint32_t IsHomogeneousAggregate(lldb::opaque_compiler_type_t type,
- CompilerType *base_type_ptr) override;
-
- size_t
- GetNumberOfFunctionArguments(lldb::opaque_compiler_type_t type) override;
-
- CompilerType GetFunctionArgumentAtIndex(lldb::opaque_compiler_type_t type,
- const size_t index) override;
-
- bool IsFunctionPointerType(lldb::opaque_compiler_type_t type) override;
-
- bool IsBlockPointerType(lldb::opaque_compiler_type_t type,
- CompilerType *function_pointer_type_ptr) override;
-
- bool IsIntegerType(lldb::opaque_compiler_type_t type,
- bool &is_signed) override;
-
- bool IsEnumerationType(lldb::opaque_compiler_type_t type,
- bool &is_signed) override;
-
- static bool IsObjCClassType(const CompilerType &type);
-
- static bool IsObjCClassTypeAndHasIVars(const CompilerType &type,
- bool check_superclass);
-
- static bool IsObjCObjectOrInterfaceType(const CompilerType &type);
-
- static bool IsObjCObjectPointerType(const CompilerType &type,
- CompilerType *target_type = nullptr);
-
- bool IsPolymorphicClass(lldb::opaque_compiler_type_t type) override;
-
- static bool IsClassType(lldb::opaque_compiler_type_t type);
-
- static bool IsEnumType(lldb::opaque_compiler_type_t type);
-
- bool IsPossibleDynamicType(lldb::opaque_compiler_type_t type,
- CompilerType *target_type, // Can pass nullptr
- bool check_cplusplus, bool check_objc) override;
-
- bool IsRuntimeGeneratedType(lldb::opaque_compiler_type_t type) override;
-
- bool IsPointerType(lldb::opaque_compiler_type_t type,
- CompilerType *pointee_type) override;
-
- bool IsPointerOrReferenceType(lldb::opaque_compiler_type_t type,
- CompilerType *pointee_type) override;
-
- bool IsReferenceType(lldb::opaque_compiler_type_t type,
- CompilerType *pointee_type, bool *is_rvalue) override;
-
- bool IsScalarType(lldb::opaque_compiler_type_t type) override;
-
- bool IsTypedefType(lldb::opaque_compiler_type_t type) override;
-
- bool IsVoidType(lldb::opaque_compiler_type_t type) override;
-
- bool CanPassInRegisters(const CompilerType &type) override;
-
- bool SupportsLanguage(lldb::LanguageType language) override;
-
- static llvm::Optional<std::string> GetCXXClassName(const CompilerType &type);
-
- // Type Completion
-
- bool GetCompleteType(lldb::opaque_compiler_type_t type) override;
-
- // Accessors
-
- ConstString GetTypeName(lldb::opaque_compiler_type_t type) override;
-
- uint32_t GetTypeInfo(lldb::opaque_compiler_type_t type,
- CompilerType *pointee_or_element_compiler_type) override;
-
- lldb::LanguageType
- GetMinimumLanguage(lldb::opaque_compiler_type_t type) override;
-
- lldb::TypeClass GetTypeClass(lldb::opaque_compiler_type_t type) override;
-
- unsigned GetTypeQualifiers(lldb::opaque_compiler_type_t type) override;
-
- // Creating related types
-
- // Using the current type, create a new typedef to that type using
- // "typedef_name" as the name and "decl_ctx" as the decl context.
- static CompilerType
- CreateTypedefType(const CompilerType &type, const char *typedef_name,
- const CompilerDeclContext &compiler_decl_ctx);
-
- CompilerType GetArrayElementType(lldb::opaque_compiler_type_t type,
- uint64_t *stride) override;
-
- CompilerType GetArrayType(lldb::opaque_compiler_type_t type,
- uint64_t size) override;
-
- CompilerType GetCanonicalType(lldb::opaque_compiler_type_t type) override;
-
- CompilerType
- GetFullyUnqualifiedType(lldb::opaque_compiler_type_t type) override;
-
- // Returns -1 if this isn't a function of if the function doesn't have a
- // prototype Returns a value >= 0 if there is a prototype.
- int GetFunctionArgumentCount(lldb::opaque_compiler_type_t type) override;
-
- CompilerType GetFunctionArgumentTypeAtIndex(lldb::opaque_compiler_type_t type,
- size_t idx) override;
-
- CompilerType
- GetFunctionReturnType(lldb::opaque_compiler_type_t type) override;
-
- size_t GetNumMemberFunctions(lldb::opaque_compiler_type_t type) override;
-
- TypeMemberFunctionImpl
- GetMemberFunctionAtIndex(lldb::opaque_compiler_type_t type,
- size_t idx) override;
-
- CompilerType GetNonReferenceType(lldb::opaque_compiler_type_t type) override;
-
- CompilerType GetPointeeType(lldb::opaque_compiler_type_t type) override;
-
- CompilerType GetPointerType(lldb::opaque_compiler_type_t type) override;
-
- CompilerType
- GetLValueReferenceType(lldb::opaque_compiler_type_t type) override;
-
- CompilerType
- GetRValueReferenceType(lldb::opaque_compiler_type_t type) override;
-
- CompilerType GetAtomicType(lldb::opaque_compiler_type_t type) override;
-
- CompilerType AddConstModifier(lldb::opaque_compiler_type_t type) override;
-
- CompilerType AddVolatileModifier(lldb::opaque_compiler_type_t type) override;
-
- CompilerType AddRestrictModifier(lldb::opaque_compiler_type_t type) override;
-
- CompilerType CreateTypedef(lldb::opaque_compiler_type_t type,
- const char *name,
- const CompilerDeclContext &decl_ctx) override;
-
- // If the current object represents a typedef type, get the underlying type
- CompilerType GetTypedefedType(lldb::opaque_compiler_type_t type) override;
-
- // Create related types using the current type's AST
- CompilerType GetBasicTypeFromAST(lldb::BasicType basic_type) override;
-
- // Exploring the type
-
- const llvm::fltSemantics &GetFloatTypeSemantics(size_t byte_size) override;
-
- llvm::Optional<uint64_t> GetByteSize(lldb::opaque_compiler_type_t type,
- ExecutionContextScope *exe_scope) {
- if (llvm::Optional<uint64_t> bit_size = GetBitSize(type, exe_scope))
- return (*bit_size + 7) / 8;
- return llvm::None;
- }
-
- llvm::Optional<uint64_t>
- GetBitSize(lldb::opaque_compiler_type_t type,
- ExecutionContextScope *exe_scope) override;
-
- lldb::Encoding GetEncoding(lldb::opaque_compiler_type_t type,
- uint64_t &count) override;
-
- lldb::Format GetFormat(lldb::opaque_compiler_type_t type) override;
-
- llvm::Optional<size_t>
- GetTypeBitAlign(lldb::opaque_compiler_type_t type,
- ExecutionContextScope *exe_scope) override;
-
- uint32_t GetNumChildren(lldb::opaque_compiler_type_t type,
- bool omit_empty_base_classes,
- const ExecutionContext *exe_ctx) override;
-
- CompilerType GetBuiltinTypeByName(ConstString name) override;
-
- lldb::BasicType
- GetBasicTypeEnumeration(lldb::opaque_compiler_type_t type) override;
-
- static lldb::BasicType
- GetBasicTypeEnumeration(lldb::opaque_compiler_type_t type,
- ConstString name);
-
- void ForEachEnumerator(
- lldb::opaque_compiler_type_t type,
- std::function<bool(const CompilerType &integer_type,
- ConstString name,
- const llvm::APSInt &value)> const &callback) override;
-
- uint32_t GetNumFields(lldb::opaque_compiler_type_t type) override;
-
- CompilerType GetFieldAtIndex(lldb::opaque_compiler_type_t type, size_t idx,
- std::string &name, uint64_t *bit_offset_ptr,
- uint32_t *bitfield_bit_size_ptr,
- bool *is_bitfield_ptr) override;
-
- uint32_t GetNumDirectBaseClasses(lldb::opaque_compiler_type_t type) override;
-
- uint32_t GetNumVirtualBaseClasses(lldb::opaque_compiler_type_t type) override;
-
- CompilerType GetDirectBaseClassAtIndex(lldb::opaque_compiler_type_t type,
- size_t idx,
- uint32_t *bit_offset_ptr) override;
-
- CompilerType GetVirtualBaseClassAtIndex(lldb::opaque_compiler_type_t type,
- size_t idx,
- uint32_t *bit_offset_ptr) override;
-
- static uint32_t GetNumPointeeChildren(clang::QualType type);
-
- CompilerType GetChildCompilerTypeAtIndex(
- lldb::opaque_compiler_type_t type, ExecutionContext *exe_ctx, size_t idx,
- bool transparent_pointers, bool omit_empty_base_classes,
- bool ignore_array_bounds, std::string &child_name,
- uint32_t &child_byte_size, int32_t &child_byte_offset,
- uint32_t &child_bitfield_bit_size, uint32_t &child_bitfield_bit_offset,
- bool &child_is_base_class, bool &child_is_deref_of_parent,
- ValueObject *valobj, uint64_t &language_flags) override;
-
- // Lookup a child given a name. This function will match base class names and
- // member member names in "clang_type" only, not descendants.
- uint32_t GetIndexOfChildWithName(lldb::opaque_compiler_type_t type,
- const char *name,
- bool omit_empty_base_classes) override;
-
- // Lookup a child member given a name. This function will match member names
- // only and will descend into "clang_type" children in search for the first
- // member in this class, or any base class that matches "name".
- // TODO: Return all matches for a given name by returning a
- // vector<vector<uint32_t>>
- // so we catch all names that match a given child name, not just the first.
- size_t
- GetIndexOfChildMemberWithName(lldb::opaque_compiler_type_t type,
- const char *name, bool omit_empty_base_classes,
- std::vector<uint32_t> &child_indexes) override;
-
- size_t GetNumTemplateArguments(lldb::opaque_compiler_type_t type) override;
-
- lldb::TemplateArgumentKind
- GetTemplateArgumentKind(lldb::opaque_compiler_type_t type,
- size_t idx) override;
- CompilerType GetTypeTemplateArgument(lldb::opaque_compiler_type_t type,
- size_t idx) override;
- llvm::Optional<CompilerType::IntegralTemplateArgument>
- GetIntegralTemplateArgument(lldb::opaque_compiler_type_t type,
- size_t idx) override;
-
- CompilerType GetTypeForFormatters(void *type) override;
-
-#define LLDB_INVALID_DECL_LEVEL UINT32_MAX
- // LLDB_INVALID_DECL_LEVEL is returned by CountDeclLevels if child_decl_ctx
- // could not be found in decl_ctx.
- uint32_t CountDeclLevels(clang::DeclContext *frame_decl_ctx,
- clang::DeclContext *child_decl_ctx,
- ConstString *child_name = nullptr,
- CompilerType *child_type = nullptr);
-
- // Modifying RecordType
- static clang::FieldDecl *AddFieldToRecordType(const CompilerType &type,
- llvm::StringRef name,
- const CompilerType &field_type,
- lldb::AccessType access,
- uint32_t bitfield_bit_size);
-
- static void BuildIndirectFields(const CompilerType &type);
-
- static void SetIsPacked(const CompilerType &type);
-
- static clang::VarDecl *AddVariableToRecordType(const CompilerType &type,
- llvm::StringRef name,
- const CompilerType &var_type,
- lldb::AccessType access);
-
- clang::CXXMethodDecl *AddMethodToCXXRecordType(
- lldb::opaque_compiler_type_t type, llvm::StringRef name,
- const char *mangled_name, const CompilerType &method_type,
- lldb::AccessType access, bool is_virtual, bool is_static, bool is_inline,
- bool is_explicit, bool is_attr_used, bool is_artificial);
-
- void AddMethodOverridesForCXXRecordType(lldb::opaque_compiler_type_t type);
-
- // C++ Base Classes
- std::unique_ptr<clang::CXXBaseSpecifier>
- CreateBaseClassSpecifier(lldb::opaque_compiler_type_t type,
- lldb::AccessType access, bool is_virtual,
- bool base_of_class);
-
- bool TransferBaseClasses(
- lldb::opaque_compiler_type_t type,
- std::vector<std::unique_ptr<clang::CXXBaseSpecifier>> bases);
-
- static bool SetObjCSuperClass(const CompilerType &type,
- const CompilerType &superclass_compiler_type);
-
- static bool AddObjCClassProperty(const CompilerType &type,
- const char *property_name,
- const CompilerType &property_compiler_type,
- clang::ObjCIvarDecl *ivar_decl,
- const char *property_setter_name,
- const char *property_getter_name,
- uint32_t property_attributes,
- ClangASTMetadata *metadata);
-
- static clang::ObjCMethodDecl *AddMethodToObjCObjectType(
- const CompilerType &type,
- const char *name, // the full symbol name as seen in the symbol table
- // (lldb::opaque_compiler_type_t type, "-[NString
- // stringWithCString:]")
- const CompilerType &method_compiler_type, lldb::AccessType access,
- bool is_artificial, bool is_variadic, bool is_objc_direct_call);
-
- static bool SetHasExternalStorage(lldb::opaque_compiler_type_t type,
- bool has_extern);
-
- // Tag Declarations
- static bool StartTagDeclarationDefinition(const CompilerType &type);
-
- static bool CompleteTagDeclarationDefinition(const CompilerType &type);
-
- // Modifying Enumeration types
- clang::EnumConstantDecl *AddEnumerationValueToEnumerationType(
- const CompilerType &enum_type, const Declaration &decl, const char *name,
- int64_t enum_value, uint32_t enum_value_bit_size);
- clang::EnumConstantDecl *AddEnumerationValueToEnumerationType(
- const CompilerType &enum_type, const Declaration &decl, const char *name,
- const llvm::APSInt &value);
-
- CompilerType GetEnumerationIntegerType(lldb::opaque_compiler_type_t type);
-
- // Pointers & References
-
- // Call this function using the class type when you want to make a member
- // pointer type to pointee_type.
- static CompilerType CreateMemberPointerType(const CompilerType &type,
- const CompilerType &pointee_type);
-
- // Dumping types
-#ifndef NDEBUG
- /// Convenience LLVM-style dump method for use in the debugger only.
- /// In contrast to the other \p Dump() methods this directly invokes
- /// \p clang::QualType::dump().
- LLVM_DUMP_METHOD void dump(lldb::opaque_compiler_type_t type) const override;
-#endif
-
- void Dump(Stream &s);
-
- /// Dump clang AST types from the symbol file.
- ///
- /// \param[in] s
- /// A stream to send the dumped AST node(s) to
- /// \param[in] symbol_name
- /// The name of the symbol to dump, if it is empty dump all the symbols
- void DumpFromSymbolFile(Stream &s, llvm::StringRef symbol_name);
-
- void DumpValue(lldb::opaque_compiler_type_t type, ExecutionContext *exe_ctx,
- Stream *s, lldb::Format format, const DataExtractor &data,
- lldb::offset_t data_offset, size_t data_byte_size,
- uint32_t bitfield_bit_size, uint32_t bitfield_bit_offset,
- bool show_types, bool show_summary, bool verbose,
- uint32_t depth) override;
-
- bool DumpTypeValue(lldb::opaque_compiler_type_t type, Stream *s,
- lldb::Format format, const DataExtractor &data,
- lldb::offset_t data_offset, size_t data_byte_size,
- uint32_t bitfield_bit_size, uint32_t bitfield_bit_offset,
- ExecutionContextScope *exe_scope) override;
-
- void DumpSummary(lldb::opaque_compiler_type_t type, ExecutionContext *exe_ctx,
- Stream *s, const DataExtractor &data,
- lldb::offset_t data_offset, size_t data_byte_size) override;
-
- void DumpTypeDescription(
- lldb::opaque_compiler_type_t type) override; // Dump to stdout
-
- void DumpTypeDescription(lldb::opaque_compiler_type_t type,
- Stream *s) override;
-
- static void DumpTypeName(const CompilerType &type);
-
- static clang::EnumDecl *GetAsEnumDecl(const CompilerType &type);
-
- static clang::RecordDecl *GetAsRecordDecl(const CompilerType &type);
-
- static clang::TagDecl *GetAsTagDecl(const CompilerType &type);
-
- static clang::TypedefNameDecl *GetAsTypedefDecl(const CompilerType &type);
-
- static clang::CXXRecordDecl *
- GetAsCXXRecordDecl(lldb::opaque_compiler_type_t type);
-
- static clang::ObjCInterfaceDecl *
- GetAsObjCInterfaceDecl(const CompilerType &type);
-
- clang::ClassTemplateDecl *ParseClassTemplateDecl(
- clang::DeclContext *decl_ctx, lldb::AccessType access_type,
- const char *parent_name, int tag_decl_kind,
- const TypeSystemClang::TemplateParameterInfos &template_param_infos);
-
- clang::BlockDecl *CreateBlockDeclaration(clang::DeclContext *ctx);
-
- clang::UsingDirectiveDecl *
- CreateUsingDirectiveDeclaration(clang::DeclContext *decl_ctx,
- clang::NamespaceDecl *ns_decl);
-
- clang::UsingDecl *CreateUsingDeclaration(clang::DeclContext *current_decl_ctx,
- clang::NamedDecl *target);
-
- clang::VarDecl *CreateVariableDeclaration(clang::DeclContext *decl_context,
- const char *name,
- clang::QualType type);
-
- static lldb::opaque_compiler_type_t
- GetOpaqueCompilerType(clang::ASTContext *ast, lldb::BasicType basic_type);
-
- static clang::QualType GetQualType(lldb::opaque_compiler_type_t type) {
- if (type)
- return clang::QualType::getFromOpaquePtr(type);
- return clang::QualType();
- }
-
- static clang::QualType
- GetCanonicalQualType(lldb::opaque_compiler_type_t type) {
- if (type)
- return clang::QualType::getFromOpaquePtr(type).getCanonicalType();
- return clang::QualType();
- }
-
- clang::DeclarationName
- GetDeclarationName(const char *name, const CompilerType &function_clang_type);
-
-private:
- const clang::ClassTemplateSpecializationDecl *
- GetAsTemplateSpecialization(lldb::opaque_compiler_type_t type);
-
- // Classes that inherit from TypeSystemClang can see and modify these
- std::string m_target_triple;
- std::unique_ptr<clang::ASTContext> m_ast_up;
- std::unique_ptr<clang::LangOptions> m_language_options_up;
- std::unique_ptr<clang::FileManager> m_file_manager_up;
- std::unique_ptr<clang::SourceManager> m_source_manager_up;
- std::unique_ptr<clang::DiagnosticsEngine> m_diagnostics_engine_up;
- std::unique_ptr<clang::DiagnosticConsumer> m_diagnostic_consumer_up;
- std::shared_ptr<clang::TargetOptions> m_target_options_rp;
- std::unique_ptr<clang::TargetInfo> m_target_info_up;
- std::unique_ptr<clang::IdentifierTable> m_identifier_table_up;
- std::unique_ptr<clang::SelectorTable> m_selector_table_up;
- std::unique_ptr<clang::Builtin::Context> m_builtins_up;
- std::unique_ptr<DWARFASTParserClang> m_dwarf_ast_parser_up;
- std::unique_ptr<PDBASTParser> m_pdb_ast_parser_up;
- std::unique_ptr<clang::MangleContext> m_mangle_ctx_up;
- uint32_t m_pointer_byte_size = 0;
- bool m_ast_owned = false;
- /// A string describing what this TypeSystemClang represents (e.g.,
- /// AST for debug information, an expression, some other utility ClangAST).
- /// Useful for logging and debugging.
- std::string m_display_name;
-
- typedef llvm::DenseMap<const clang::Decl *, ClangASTMetadata> DeclMetadataMap;
- /// Maps Decls to their associated ClangASTMetadata.
- DeclMetadataMap m_decl_metadata;
-
- typedef llvm::DenseMap<const clang::Type *, ClangASTMetadata> TypeMetadataMap;
- /// Maps Types to their associated ClangASTMetadata.
- TypeMetadataMap m_type_metadata;
-
- /// The sema associated that is currently used to build this ASTContext.
- /// May be null if we are already done parsing this ASTContext or the
- /// ASTContext wasn't created by parsing source code.
- clang::Sema *m_sema = nullptr;
-
- // For TypeSystemClang only
- TypeSystemClang(const TypeSystemClang &);
- const TypeSystemClang &operator=(const TypeSystemClang &);
- /// Creates the internal ASTContext.
- void CreateASTContext();
- void SetTargetTriple(llvm::StringRef target_triple);
-};
-
-class TypeSystemClangForExpressions : public TypeSystemClang {
-public:
- TypeSystemClangForExpressions(Target &target, llvm::Triple triple);
-
- ~TypeSystemClangForExpressions() override = default;
-
- void Finalize() override;
-
- UserExpression *
- GetUserExpression(llvm::StringRef expr, llvm::StringRef prefix,
- lldb::LanguageType language,
- Expression::ResultType desired_type,
- const EvaluateExpressionOptions &options,
- ValueObject *ctx_obj) override;
-
- FunctionCaller *GetFunctionCaller(const CompilerType &return_type,
- const Address &function_address,
- const ValueList &arg_value_list,
- const char *name) override;
-
- UtilityFunction *GetUtilityFunction(const char *text,
- const char *name) override;
-
- PersistentExpressionState *GetPersistentExpressionState() override;
-private:
- lldb::TargetWP m_target_wp;
- std::unique_ptr<ClangPersistentVariables>
- m_persistent_variables; // These are the persistent variables associated
- // with this process for the expression parser
- std::unique_ptr<ClangASTSource> m_scratch_ast_source_up;
-};
-
-} // namespace lldb_private
-
-#endif // liblldb_TypeSystemClang_h_
#include "lldb/Host/Host.h"
#include "lldb/Initialization/SystemInitializerCommon.h"
#include "lldb/Interpreter/CommandInterpreter.h"
-#include "lldb/Symbol/TypeSystemClang.h"
#include "lldb/Utility/Timer.h"
#include "Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.h"
#include "Plugins/SymbolVendor/ELF/SymbolVendorELF.h"
#include "Plugins/SymbolVendor/wasm/SymbolVendorWasm.h"
#include "Plugins/SystemRuntime/MacOSX/SystemRuntimeMacOSX.h"
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
#include "Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.h"
#include "Plugins/UnwindAssembly/x86/UnwindAssembly-x86.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/Triple.h"
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
#include "Utility/PPC64LE_DWARF_Registers.h"
#include "Utility/PPC64_DWARF_Registers.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/ValueObjectConstResult.h"
#include "lldb/Core/ValueObjectMemory.h"
#include "lldb/Core/ValueObjectRegister.h"
-#include "lldb/Symbol/TypeSystemClang.h"
#include "lldb/Symbol/UnwindPlan.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/RegisterContext.h"
lldbCore
lldbSymbol
lldbTarget
+ lldbPluginTypeSystemClang
LINK_COMPONENTS
Support
)
add_subdirectory(SymbolFile)
add_subdirectory(SystemRuntime)
add_subdirectory(SymbolVendor)
+add_subdirectory(TypeSystem)
add_subdirectory(UnwindAssembly)
lldbSymbol
lldbTarget
lldbUtility
+ lldbPluginTypeSystemClang
LINK_COMPONENTS
Support
)
#include "lldb/Core/Section.h"
#include "lldb/Expression/DiagnosticManager.h"
#include "lldb/Host/FileSystem.h"
-#include "lldb/Symbol/TypeSystemClang.h"
#include "lldb/Symbol/Function.h"
#include "lldb/Symbol/ObjectFile.h"
#include "lldb/Target/ABI.h"
#include "lldb/Utility/State.h"
#include "Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h"
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
//#define ENABLE_DEBUG_PRINTF // COMMENT THIS LINE OUT PRIOR TO CHECKIN
#ifdef ENABLE_DEBUG_PRINTF
#include "lldb/Core/Module.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Core/Section.h"
-#include "lldb/Symbol/TypeSystemClang.h"
#include "lldb/Symbol/ObjectFile.h"
#include "lldb/Symbol/SymbolVendor.h"
#include "lldb/Target/ABI.h"
#include "DynamicLoaderDarwin.h"
#include "DynamicLoaderMacOS.h"
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
+
using namespace lldb;
using namespace lldb_private;
#include "lldb/Core/ModuleSpec.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Core/Section.h"
-#include "lldb/Symbol/TypeSystemClang.h"
#include "lldb/Symbol/Function.h"
#include "lldb/Symbol/ObjectFile.h"
#include "lldb/Target/ABI.h"
#include "DynamicLoaderMacOSXDYLD.h"
#include "Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h"
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
//#define ENABLE_DEBUG_PRINTF // COMMENT THIS LINE OUT PRIOR TO CHECKIN
#ifdef ENABLE_DEBUG_PRINTF
#include "ASTResultSynthesizer.h"
+#include "ClangASTImporter.h"
#include "ClangPersistentVariables.h"
-#include "lldb/Symbol/TypeSystemClang.h"
-#include "lldb/Symbol/ClangASTImporter.h"
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
#include "lldb/Target/Target.h"
#include "lldb/Utility/LLDBAssert.h"
#include "lldb/Utility/Log.h"
ASTResultSynthesizer.cpp
ASTStructExtractor.cpp
ASTUtils.cpp
+ ClangASTImporter.cpp
+ ClangASTMetadata.cpp
ClangASTSource.cpp
ClangDeclVendor.cpp
ClangExpressionDeclMap.cpp
ClangExpressionParser.cpp
ClangExpressionSourceCode.cpp
ClangExpressionVariable.cpp
+ ClangExternalASTSourceCallbacks.cpp
ClangFunctionCaller.cpp
ClangHost.cpp
ClangModulesDeclVendor.cpp
ClangPersistentVariables.cpp
ClangUserExpression.cpp
+ ClangUtil.cpp
ClangUtilityFunction.cpp
CppModuleConfiguration.cpp
+ CxxModuleHandler.cpp
IRForTarget.cpp
IRDynamicChecks.cpp
lldbUtility
lldbPluginCPlusPlusLanguage
lldbPluginCPPRuntime
+ lldbPluginObjCRuntime
+ lldbPluginTypeSystemClang
CLANG_LIBS
clangAST
clangCodeGen
--- /dev/null
+//===-- ClangASTImporter.cpp ----------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Core/Module.h"
+#include "lldb/Utility/LLDBAssert.h"
+#include "lldb/Utility/Log.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/Sema/Lookup.h"
+#include "clang/Sema/Sema.h"
+#include "llvm/Support/raw_ostream.h"
+
+#include "Plugins/ExpressionParser/Clang/ClangASTImporter.h"
+#include "Plugins/ExpressionParser/Clang/ClangASTMetadata.h"
+#include "Plugins/ExpressionParser/Clang/ClangUtil.h"
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
+
+#include <memory>
+
+using namespace lldb_private;
+using namespace clang;
+
+CompilerType ClangASTImporter::CopyType(TypeSystemClang &dst_ast,
+ const CompilerType &src_type) {
+ clang::ASTContext &dst_clang_ast = dst_ast.getASTContext();
+
+ TypeSystemClang *src_ast =
+ llvm::dyn_cast_or_null<TypeSystemClang>(src_type.GetTypeSystem());
+ if (!src_ast)
+ return CompilerType();
+
+ clang::ASTContext &src_clang_ast = src_ast->getASTContext();
+
+ clang::QualType src_qual_type = ClangUtil::GetQualType(src_type);
+
+ ImporterDelegateSP delegate_sp(GetDelegate(&dst_clang_ast, &src_clang_ast));
+ if (!delegate_sp)
+ return CompilerType();
+
+ ASTImporterDelegate::CxxModuleScope std_scope(*delegate_sp, &dst_clang_ast);
+
+ llvm::Expected<QualType> ret_or_error = delegate_sp->Import(src_qual_type);
+ if (!ret_or_error) {
+ Log *log =
+ lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS);
+ LLDB_LOG_ERROR(log, ret_or_error.takeError(),
+ "Couldn't import type: {0}");
+ return CompilerType();
+ }
+
+ lldb::opaque_compiler_type_t dst_clang_type = ret_or_error->getAsOpaquePtr();
+
+ if (dst_clang_type)
+ return CompilerType(&dst_ast, dst_clang_type);
+ return CompilerType();
+}
+
+clang::Decl *ClangASTImporter::CopyDecl(clang::ASTContext *dst_ast,
+ clang::Decl *decl) {
+ ImporterDelegateSP delegate_sp;
+
+ clang::ASTContext *src_ast = &decl->getASTContext();
+ delegate_sp = GetDelegate(dst_ast, src_ast);
+
+ ASTImporterDelegate::CxxModuleScope std_scope(*delegate_sp, dst_ast);
+
+ if (!delegate_sp)
+ return nullptr;
+
+ llvm::Expected<clang::Decl *> result = delegate_sp->Import(decl);
+ if (!result) {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
+ LLDB_LOG_ERROR(log, result.takeError(), "Couldn't import decl: {0}");
+ if (log) {
+ lldb::user_id_t user_id = LLDB_INVALID_UID;
+ ClangASTMetadata *metadata = GetDeclMetadata(decl);
+ if (metadata)
+ user_id = metadata->GetUserID();
+
+ if (NamedDecl *named_decl = dyn_cast<NamedDecl>(decl))
+ LLDB_LOG(log,
+ " [ClangASTImporter] WARNING: Failed to import a {0} "
+ "'{1}', metadata {2}",
+ decl->getDeclKindName(), named_decl->getNameAsString(),
+ user_id);
+ else
+ LLDB_LOG(log,
+ " [ClangASTImporter] WARNING: Failed to import a {0}, "
+ "metadata {1}",
+ decl->getDeclKindName(), user_id);
+ }
+ return nullptr;
+ }
+
+ return *result;
+}
+
+class DeclContextOverride {
+private:
+ struct Backup {
+ clang::DeclContext *decl_context;
+ clang::DeclContext *lexical_decl_context;
+ };
+
+ llvm::DenseMap<clang::Decl *, Backup> m_backups;
+
+ void OverrideOne(clang::Decl *decl) {
+ if (m_backups.find(decl) != m_backups.end()) {
+ return;
+ }
+
+ m_backups[decl] = {decl->getDeclContext(), decl->getLexicalDeclContext()};
+
+ decl->setDeclContext(decl->getASTContext().getTranslationUnitDecl());
+ decl->setLexicalDeclContext(decl->getASTContext().getTranslationUnitDecl());
+ }
+
+ bool ChainPassesThrough(
+ clang::Decl *decl, clang::DeclContext *base,
+ clang::DeclContext *(clang::Decl::*contextFromDecl)(),
+ clang::DeclContext *(clang::DeclContext::*contextFromContext)()) {
+ for (DeclContext *decl_ctx = (decl->*contextFromDecl)(); decl_ctx;
+ decl_ctx = (decl_ctx->*contextFromContext)()) {
+ if (decl_ctx == base) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ clang::Decl *GetEscapedChild(clang::Decl *decl,
+ clang::DeclContext *base = nullptr) {
+ if (base) {
+ // decl's DeclContext chains must pass through base.
+
+ if (!ChainPassesThrough(decl, base, &clang::Decl::getDeclContext,
+ &clang::DeclContext::getParent) ||
+ !ChainPassesThrough(decl, base, &clang::Decl::getLexicalDeclContext,
+ &clang::DeclContext::getLexicalParent)) {
+ return decl;
+ }
+ } else {
+ base = clang::dyn_cast<clang::DeclContext>(decl);
+
+ if (!base) {
+ return nullptr;
+ }
+ }
+
+ if (clang::DeclContext *context =
+ clang::dyn_cast<clang::DeclContext>(decl)) {
+ for (clang::Decl *decl : context->decls()) {
+ if (clang::Decl *escaped_child = GetEscapedChild(decl)) {
+ return escaped_child;
+ }
+ }
+ }
+
+ return nullptr;
+ }
+
+ void Override(clang::Decl *decl) {
+ if (clang::Decl *escaped_child = GetEscapedChild(decl)) {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
+
+ LLDB_LOG(log,
+ " [ClangASTImporter] DeclContextOverride couldn't "
+ "override ({0}Decl*){1} - its child ({2}Decl*){3} escapes",
+ decl->getDeclKindName(), decl, escaped_child->getDeclKindName(),
+ escaped_child);
+ lldbassert(0 && "Couldn't override!");
+ }
+
+ OverrideOne(decl);
+ }
+
+public:
+ DeclContextOverride() {}
+
+ void OverrideAllDeclsFromContainingFunction(clang::Decl *decl) {
+ for (DeclContext *decl_context = decl->getLexicalDeclContext();
+ decl_context; decl_context = decl_context->getLexicalParent()) {
+ DeclContext *redecl_context = decl_context->getRedeclContext();
+
+ if (llvm::isa<FunctionDecl>(redecl_context) &&
+ llvm::isa<TranslationUnitDecl>(redecl_context->getLexicalParent())) {
+ for (clang::Decl *child_decl : decl_context->decls()) {
+ Override(child_decl);
+ }
+ }
+ }
+ }
+
+ ~DeclContextOverride() {
+ for (const std::pair<clang::Decl *, Backup> &backup : m_backups) {
+ backup.first->setDeclContext(backup.second.decl_context);
+ backup.first->setLexicalDeclContext(backup.second.lexical_decl_context);
+ }
+ }
+};
+
+namespace {
+/// Completes all imported TagDecls at the end of the scope.
+///
+/// While in a CompleteTagDeclsScope, every decl that could be completed will
+/// be completed at the end of the scope (including all Decls that are
+/// imported while completing the original Decls).
+class CompleteTagDeclsScope : public ClangASTImporter::NewDeclListener {
+ ClangASTImporter::ImporterDelegateSP m_delegate;
+ llvm::SmallVector<NamedDecl *, 32> m_decls_to_complete;
+ llvm::SmallPtrSet<NamedDecl *, 32> m_decls_already_completed;
+ clang::ASTContext *m_dst_ctx;
+ clang::ASTContext *m_src_ctx;
+ ClangASTImporter &importer;
+
+public:
+ /// Constructs a CompleteTagDeclsScope.
+ /// \param importer The ClangASTImporter that we should observe.
+ /// \param dst_ctx The ASTContext to which Decls are imported.
+ /// \param src_ctx The ASTContext from which Decls are imported.
+ explicit CompleteTagDeclsScope(ClangASTImporter &importer,
+ clang::ASTContext *dst_ctx,
+ clang::ASTContext *src_ctx)
+ : m_delegate(importer.GetDelegate(dst_ctx, src_ctx)), m_dst_ctx(dst_ctx),
+ m_src_ctx(src_ctx), importer(importer) {
+ m_delegate->SetImportListener(this);
+ }
+
+ virtual ~CompleteTagDeclsScope() {
+ ClangASTImporter::ASTContextMetadataSP to_context_md =
+ importer.GetContextMetadata(m_dst_ctx);
+
+ // Complete all decls we collected until now.
+ while (!m_decls_to_complete.empty()) {
+ NamedDecl *decl = m_decls_to_complete.pop_back_val();
+ m_decls_already_completed.insert(decl);
+
+ // We should only complete decls coming from the source context.
+ assert(to_context_md->m_origins[decl].ctx == m_src_ctx);
+
+ Decl *original_decl = to_context_md->m_origins[decl].decl;
+
+ // Complete the decl now.
+ TypeSystemClang::GetCompleteDecl(m_src_ctx, original_decl);
+ if (auto *tag_decl = dyn_cast<TagDecl>(decl)) {
+ if (auto *original_tag_decl = dyn_cast<TagDecl>(original_decl)) {
+ if (original_tag_decl->isCompleteDefinition()) {
+ m_delegate->ImportDefinitionTo(tag_decl, original_tag_decl);
+ tag_decl->setCompleteDefinition(true);
+ }
+ }
+
+ tag_decl->setHasExternalLexicalStorage(false);
+ tag_decl->setHasExternalVisibleStorage(false);
+ } else if (auto *container_decl = dyn_cast<ObjCContainerDecl>(decl)) {
+ container_decl->setHasExternalLexicalStorage(false);
+ container_decl->setHasExternalVisibleStorage(false);
+ }
+
+ to_context_md->m_origins.erase(decl);
+ }
+
+ // Stop listening to imported decls. We do this after clearing the
+ // Decls we needed to import to catch all Decls they might have pulled in.
+ m_delegate->RemoveImportListener();
+ }
+
+ void NewDeclImported(clang::Decl *from, clang::Decl *to) override {
+ // Filter out decls that we can't complete later.
+ if (!isa<TagDecl>(to) && !isa<ObjCInterfaceDecl>(to))
+ return;
+ RecordDecl *from_record_decl = dyn_cast<RecordDecl>(from);
+ // We don't need to complete injected class name decls.
+ if (from_record_decl && from_record_decl->isInjectedClassName())
+ return;
+
+ NamedDecl *to_named_decl = dyn_cast<NamedDecl>(to);
+ // Check if we already completed this type.
+ if (m_decls_already_completed.count(to_named_decl) != 0)
+ return;
+ m_decls_to_complete.push_back(to_named_decl);
+ }
+};
+} // namespace
+
+CompilerType ClangASTImporter::DeportType(TypeSystemClang &dst,
+ const CompilerType &src_type) {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
+
+ TypeSystemClang *src_ctxt =
+ llvm::cast<TypeSystemClang>(src_type.GetTypeSystem());
+
+ LLDB_LOG(log,
+ " [ClangASTImporter] DeportType called on ({0}Type*){1} "
+ "from (ASTContext*){2} to (ASTContext*){3}",
+ src_type.GetTypeName(), src_type.GetOpaqueQualType(),
+ &src_ctxt->getASTContext(), &dst.getASTContext());
+
+ DeclContextOverride decl_context_override;
+
+ if (auto *t = ClangUtil::GetQualType(src_type)->getAs<TagType>())
+ decl_context_override.OverrideAllDeclsFromContainingFunction(t->getDecl());
+
+ CompleteTagDeclsScope complete_scope(*this, &dst.getASTContext(),
+ &src_ctxt->getASTContext());
+ return CopyType(dst, src_type);
+}
+
+clang::Decl *ClangASTImporter::DeportDecl(clang::ASTContext *dst_ctx,
+ clang::Decl *decl) {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
+
+ clang::ASTContext *src_ctx = &decl->getASTContext();
+ LLDB_LOG(log,
+ " [ClangASTImporter] DeportDecl called on ({0}Decl*){1} from "
+ "(ASTContext*){2} to (ASTContext*){3}",
+ decl->getDeclKindName(), decl, src_ctx, dst_ctx);
+
+ DeclContextOverride decl_context_override;
+
+ decl_context_override.OverrideAllDeclsFromContainingFunction(decl);
+
+ clang::Decl *result;
+ {
+ CompleteTagDeclsScope complete_scope(*this, dst_ctx, src_ctx);
+ result = CopyDecl(dst_ctx, decl);
+ }
+
+ if (!result)
+ return nullptr;
+
+ LLDB_LOG(log,
+ " [ClangASTImporter] DeportDecl deported ({0}Decl*){1} to "
+ "({2}Decl*){3}",
+ decl->getDeclKindName(), decl, result->getDeclKindName(), result);
+
+ return result;
+}
+
+bool ClangASTImporter::CanImport(const CompilerType &type) {
+ if (!ClangUtil::IsClangType(type))
+ return false;
+
+ // TODO: remove external completion BOOL
+ // CompleteAndFetchChildren should get the Decl out and check for the
+
+ clang::QualType qual_type(
+ ClangUtil::GetCanonicalQualType(ClangUtil::RemoveFastQualifiers(type)));
+
+ const clang::Type::TypeClass type_class = qual_type->getTypeClass();
+ switch (type_class) {
+ case clang::Type::Record: {
+ const clang::CXXRecordDecl *cxx_record_decl =
+ qual_type->getAsCXXRecordDecl();
+ if (cxx_record_decl) {
+ if (GetDeclOrigin(cxx_record_decl).Valid())
+ return true;
+ }
+ } break;
+
+ case clang::Type::Enum: {
+ clang::EnumDecl *enum_decl =
+ llvm::cast<clang::EnumType>(qual_type)->getDecl();
+ if (enum_decl) {
+ if (GetDeclOrigin(enum_decl).Valid())
+ return true;
+ }
+ } break;
+
+ case clang::Type::ObjCObject:
+ case clang::Type::ObjCInterface: {
+ const clang::ObjCObjectType *objc_class_type =
+ llvm::dyn_cast<clang::ObjCObjectType>(qual_type);
+ if (objc_class_type) {
+ clang::ObjCInterfaceDecl *class_interface_decl =
+ objc_class_type->getInterface();
+ // We currently can't complete objective C types through the newly added
+ // ASTContext because it only supports TagDecl objects right now...
+ if (class_interface_decl) {
+ if (GetDeclOrigin(class_interface_decl).Valid())
+ return true;
+ }
+ }
+ } break;
+
+ case clang::Type::Typedef:
+ return CanImport(CompilerType(type.GetTypeSystem(),
+ llvm::cast<clang::TypedefType>(qual_type)
+ ->getDecl()
+ ->getUnderlyingType()
+ .getAsOpaquePtr()));
+
+ case clang::Type::Auto:
+ return CanImport(CompilerType(type.GetTypeSystem(),
+ llvm::cast<clang::AutoType>(qual_type)
+ ->getDeducedType()
+ .getAsOpaquePtr()));
+
+ case clang::Type::Elaborated:
+ return CanImport(CompilerType(type.GetTypeSystem(),
+ llvm::cast<clang::ElaboratedType>(qual_type)
+ ->getNamedType()
+ .getAsOpaquePtr()));
+
+ case clang::Type::Paren:
+ return CanImport(CompilerType(
+ type.GetTypeSystem(),
+ llvm::cast<clang::ParenType>(qual_type)->desugar().getAsOpaquePtr()));
+
+ default:
+ break;
+ }
+
+ return false;
+}
+
+bool ClangASTImporter::Import(const CompilerType &type) {
+ if (!ClangUtil::IsClangType(type))
+ return false;
+ // TODO: remove external completion BOOL
+ // CompleteAndFetchChildren should get the Decl out and check for the
+
+ clang::QualType qual_type(
+ ClangUtil::GetCanonicalQualType(ClangUtil::RemoveFastQualifiers(type)));
+
+ const clang::Type::TypeClass type_class = qual_type->getTypeClass();
+ switch (type_class) {
+ case clang::Type::Record: {
+ const clang::CXXRecordDecl *cxx_record_decl =
+ qual_type->getAsCXXRecordDecl();
+ if (cxx_record_decl) {
+ if (GetDeclOrigin(cxx_record_decl).Valid())
+ return CompleteAndFetchChildren(qual_type);
+ }
+ } break;
+
+ case clang::Type::Enum: {
+ clang::EnumDecl *enum_decl =
+ llvm::cast<clang::EnumType>(qual_type)->getDecl();
+ if (enum_decl) {
+ if (GetDeclOrigin(enum_decl).Valid())
+ return CompleteAndFetchChildren(qual_type);
+ }
+ } break;
+
+ case clang::Type::ObjCObject:
+ case clang::Type::ObjCInterface: {
+ const clang::ObjCObjectType *objc_class_type =
+ llvm::dyn_cast<clang::ObjCObjectType>(qual_type);
+ if (objc_class_type) {
+ clang::ObjCInterfaceDecl *class_interface_decl =
+ objc_class_type->getInterface();
+ // We currently can't complete objective C types through the newly added
+ // ASTContext because it only supports TagDecl objects right now...
+ if (class_interface_decl) {
+ if (GetDeclOrigin(class_interface_decl).Valid())
+ return CompleteAndFetchChildren(qual_type);
+ }
+ }
+ } break;
+
+ case clang::Type::Typedef:
+ return Import(CompilerType(type.GetTypeSystem(),
+ llvm::cast<clang::TypedefType>(qual_type)
+ ->getDecl()
+ ->getUnderlyingType()
+ .getAsOpaquePtr()));
+
+ case clang::Type::Auto:
+ return Import(CompilerType(type.GetTypeSystem(),
+ llvm::cast<clang::AutoType>(qual_type)
+ ->getDeducedType()
+ .getAsOpaquePtr()));
+
+ case clang::Type::Elaborated:
+ return Import(CompilerType(type.GetTypeSystem(),
+ llvm::cast<clang::ElaboratedType>(qual_type)
+ ->getNamedType()
+ .getAsOpaquePtr()));
+
+ case clang::Type::Paren:
+ return Import(CompilerType(
+ type.GetTypeSystem(),
+ llvm::cast<clang::ParenType>(qual_type)->desugar().getAsOpaquePtr()));
+
+ default:
+ break;
+ }
+ return false;
+}
+
+bool ClangASTImporter::CompleteType(const CompilerType &compiler_type) {
+ if (!CanImport(compiler_type))
+ return false;
+
+ if (Import(compiler_type)) {
+ TypeSystemClang::CompleteTagDeclarationDefinition(compiler_type);
+ return true;
+ }
+
+ TypeSystemClang::SetHasExternalStorage(compiler_type.GetOpaqueQualType(),
+ false);
+ return false;
+}
+
+bool ClangASTImporter::LayoutRecordType(
+ const clang::RecordDecl *record_decl, uint64_t &bit_size,
+ uint64_t &alignment,
+ llvm::DenseMap<const clang::FieldDecl *, uint64_t> &field_offsets,
+ llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits>
+ &base_offsets,
+ llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits>
+ &vbase_offsets) {
+ RecordDeclToLayoutMap::iterator pos =
+ m_record_decl_to_layout_map.find(record_decl);
+ bool success = false;
+ base_offsets.clear();
+ vbase_offsets.clear();
+ if (pos != m_record_decl_to_layout_map.end()) {
+ bit_size = pos->second.bit_size;
+ alignment = pos->second.alignment;
+ field_offsets.swap(pos->second.field_offsets);
+ base_offsets.swap(pos->second.base_offsets);
+ vbase_offsets.swap(pos->second.vbase_offsets);
+ m_record_decl_to_layout_map.erase(pos);
+ success = true;
+ } else {
+ bit_size = 0;
+ alignment = 0;
+ field_offsets.clear();
+ }
+ return success;
+}
+
+void ClangASTImporter::SetRecordLayout(clang::RecordDecl *decl,
+ const LayoutInfo &layout) {
+ m_record_decl_to_layout_map.insert(std::make_pair(decl, layout));
+}
+
+bool ClangASTImporter::CompleteTagDecl(clang::TagDecl *decl) {
+ DeclOrigin decl_origin = GetDeclOrigin(decl);
+
+ if (!decl_origin.Valid())
+ return false;
+
+ if (!TypeSystemClang::GetCompleteDecl(decl_origin.ctx, decl_origin.decl))
+ return false;
+
+ ImporterDelegateSP delegate_sp(
+ GetDelegate(&decl->getASTContext(), decl_origin.ctx));
+
+ ASTImporterDelegate::CxxModuleScope std_scope(*delegate_sp,
+ &decl->getASTContext());
+ if (delegate_sp)
+ delegate_sp->ImportDefinitionTo(decl, decl_origin.decl);
+
+ return true;
+}
+
+bool ClangASTImporter::CompleteTagDeclWithOrigin(clang::TagDecl *decl,
+ clang::TagDecl *origin_decl) {
+ clang::ASTContext *origin_ast_ctx = &origin_decl->getASTContext();
+
+ if (!TypeSystemClang::GetCompleteDecl(origin_ast_ctx, origin_decl))
+ return false;
+
+ ImporterDelegateSP delegate_sp(
+ GetDelegate(&decl->getASTContext(), origin_ast_ctx));
+
+ if (delegate_sp)
+ delegate_sp->ImportDefinitionTo(decl, origin_decl);
+
+ ASTContextMetadataSP context_md = GetContextMetadata(&decl->getASTContext());
+
+ OriginMap &origins = context_md->m_origins;
+
+ origins[decl] = DeclOrigin(origin_ast_ctx, origin_decl);
+
+ return true;
+}
+
+bool ClangASTImporter::CompleteObjCInterfaceDecl(
+ clang::ObjCInterfaceDecl *interface_decl) {
+ DeclOrigin decl_origin = GetDeclOrigin(interface_decl);
+
+ if (!decl_origin.Valid())
+ return false;
+
+ if (!TypeSystemClang::GetCompleteDecl(decl_origin.ctx, decl_origin.decl))
+ return false;
+
+ ImporterDelegateSP delegate_sp(
+ GetDelegate(&interface_decl->getASTContext(), decl_origin.ctx));
+
+ if (delegate_sp)
+ delegate_sp->ImportDefinitionTo(interface_decl, decl_origin.decl);
+
+ if (ObjCInterfaceDecl *super_class = interface_decl->getSuperClass())
+ RequireCompleteType(clang::QualType(super_class->getTypeForDecl(), 0));
+
+ return true;
+}
+
+bool ClangASTImporter::CompleteAndFetchChildren(clang::QualType type) {
+ if (!RequireCompleteType(type))
+ return false;
+
+ Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS);
+
+ if (const TagType *tag_type = type->getAs<TagType>()) {
+ TagDecl *tag_decl = tag_type->getDecl();
+
+ DeclOrigin decl_origin = GetDeclOrigin(tag_decl);
+
+ if (!decl_origin.Valid())
+ return false;
+
+ ImporterDelegateSP delegate_sp(
+ GetDelegate(&tag_decl->getASTContext(), decl_origin.ctx));
+
+ ASTImporterDelegate::CxxModuleScope std_scope(*delegate_sp,
+ &tag_decl->getASTContext());
+
+ TagDecl *origin_tag_decl = llvm::dyn_cast<TagDecl>(decl_origin.decl);
+
+ for (Decl *origin_child_decl : origin_tag_decl->decls()) {
+ llvm::Expected<Decl *> imported_or_err =
+ delegate_sp->Import(origin_child_decl);
+ if (!imported_or_err) {
+ LLDB_LOG_ERROR(log, imported_or_err.takeError(),
+ "Couldn't import decl: {0}");
+ return false;
+ }
+ }
+
+ if (RecordDecl *record_decl = dyn_cast<RecordDecl>(origin_tag_decl))
+ record_decl->setHasLoadedFieldsFromExternalStorage(true);
+
+ return true;
+ }
+
+ if (const ObjCObjectType *objc_object_type = type->getAs<ObjCObjectType>()) {
+ if (ObjCInterfaceDecl *objc_interface_decl =
+ objc_object_type->getInterface()) {
+ DeclOrigin decl_origin = GetDeclOrigin(objc_interface_decl);
+
+ if (!decl_origin.Valid())
+ return false;
+
+ ImporterDelegateSP delegate_sp(
+ GetDelegate(&objc_interface_decl->getASTContext(), decl_origin.ctx));
+
+ ObjCInterfaceDecl *origin_interface_decl =
+ llvm::dyn_cast<ObjCInterfaceDecl>(decl_origin.decl);
+
+ for (Decl *origin_child_decl : origin_interface_decl->decls()) {
+ llvm::Expected<Decl *> imported_or_err =
+ delegate_sp->Import(origin_child_decl);
+ if (!imported_or_err) {
+ LLDB_LOG_ERROR(log, imported_or_err.takeError(),
+ "Couldn't import decl: {0}");
+ return false;
+ }
+ }
+
+ return true;
+ }
+ return false;
+ }
+
+ return true;
+}
+
+bool ClangASTImporter::RequireCompleteType(clang::QualType type) {
+ if (type.isNull())
+ return false;
+
+ if (const TagType *tag_type = type->getAs<TagType>()) {
+ TagDecl *tag_decl = tag_type->getDecl();
+
+ if (tag_decl->getDefinition() || tag_decl->isBeingDefined())
+ return true;
+
+ return CompleteTagDecl(tag_decl);
+ }
+ if (const ObjCObjectType *objc_object_type = type->getAs<ObjCObjectType>()) {
+ if (ObjCInterfaceDecl *objc_interface_decl =
+ objc_object_type->getInterface())
+ return CompleteObjCInterfaceDecl(objc_interface_decl);
+ return false;
+ }
+ if (const ArrayType *array_type = type->getAsArrayTypeUnsafe())
+ return RequireCompleteType(array_type->getElementType());
+ if (const AtomicType *atomic_type = type->getAs<AtomicType>())
+ return RequireCompleteType(atomic_type->getPointeeType());
+
+ return true;
+}
+
+ClangASTMetadata *ClangASTImporter::GetDeclMetadata(const clang::Decl *decl) {
+ DeclOrigin decl_origin = GetDeclOrigin(decl);
+
+ if (decl_origin.Valid()) {
+ TypeSystemClang *ast = TypeSystemClang::GetASTContext(decl_origin.ctx);
+ return ast->GetMetadata(decl_origin.decl);
+ }
+ TypeSystemClang *ast = TypeSystemClang::GetASTContext(&decl->getASTContext());
+ return ast->GetMetadata(decl);
+}
+
+ClangASTImporter::DeclOrigin
+ClangASTImporter::GetDeclOrigin(const clang::Decl *decl) {
+ ASTContextMetadataSP context_md = GetContextMetadata(&decl->getASTContext());
+
+ OriginMap &origins = context_md->m_origins;
+
+ OriginMap::iterator iter = origins.find(decl);
+
+ if (iter != origins.end())
+ return iter->second;
+ return DeclOrigin();
+}
+
+void ClangASTImporter::SetDeclOrigin(const clang::Decl *decl,
+ clang::Decl *original_decl) {
+ ASTContextMetadataSP context_md = GetContextMetadata(&decl->getASTContext());
+
+ OriginMap &origins = context_md->m_origins;
+
+ OriginMap::iterator iter = origins.find(decl);
+
+ if (iter != origins.end()) {
+ iter->second.decl = original_decl;
+ iter->second.ctx = &original_decl->getASTContext();
+ return;
+ }
+ origins[decl] = DeclOrigin(&original_decl->getASTContext(), original_decl);
+}
+
+void ClangASTImporter::RegisterNamespaceMap(const clang::NamespaceDecl *decl,
+ NamespaceMapSP &namespace_map) {
+ ASTContextMetadataSP context_md = GetContextMetadata(&decl->getASTContext());
+
+ context_md->m_namespace_maps[decl] = namespace_map;
+}
+
+ClangASTImporter::NamespaceMapSP
+ClangASTImporter::GetNamespaceMap(const clang::NamespaceDecl *decl) {
+ ASTContextMetadataSP context_md = GetContextMetadata(&decl->getASTContext());
+
+ NamespaceMetaMap &namespace_maps = context_md->m_namespace_maps;
+
+ NamespaceMetaMap::iterator iter = namespace_maps.find(decl);
+
+ if (iter != namespace_maps.end())
+ return iter->second;
+ return NamespaceMapSP();
+}
+
+void ClangASTImporter::BuildNamespaceMap(const clang::NamespaceDecl *decl) {
+ assert(decl);
+ ASTContextMetadataSP context_md = GetContextMetadata(&decl->getASTContext());
+
+ const DeclContext *parent_context = decl->getDeclContext();
+ const NamespaceDecl *parent_namespace =
+ dyn_cast<NamespaceDecl>(parent_context);
+ NamespaceMapSP parent_map;
+
+ if (parent_namespace)
+ parent_map = GetNamespaceMap(parent_namespace);
+
+ NamespaceMapSP new_map;
+
+ new_map = std::make_shared<NamespaceMap>();
+
+ if (context_md->m_map_completer) {
+ std::string namespace_string = decl->getDeclName().getAsString();
+
+ context_md->m_map_completer->CompleteNamespaceMap(
+ new_map, ConstString(namespace_string.c_str()), parent_map);
+ }
+
+ context_md->m_namespace_maps[decl] = new_map;
+}
+
+void ClangASTImporter::ForgetDestination(clang::ASTContext *dst_ast) {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
+
+ LLDB_LOG(log,
+ " [ClangASTImporter] Forgetting destination (ASTContext*){0}",
+ dst_ast);
+
+ m_metadata_map.erase(dst_ast);
+}
+
+void ClangASTImporter::ForgetSource(clang::ASTContext *dst_ast,
+ clang::ASTContext *src_ast) {
+ ASTContextMetadataSP md = MaybeGetContextMetadata(dst_ast);
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
+
+ LLDB_LOG(log,
+ " [ClangASTImporter] Forgetting source->dest "
+ "(ASTContext*){0}->(ASTContext*){1}",
+ src_ast, dst_ast);
+
+ if (!md)
+ return;
+
+ md->m_delegates.erase(src_ast);
+
+ for (OriginMap::iterator iter = md->m_origins.begin();
+ iter != md->m_origins.end();) {
+ if (iter->second.ctx == src_ast)
+ md->m_origins.erase(iter++);
+ else
+ ++iter;
+ }
+}
+
+ClangASTImporter::MapCompleter::~MapCompleter() { return; }
+
+llvm::Expected<Decl *>
+ClangASTImporter::ASTImporterDelegate::ImportImpl(Decl *From) {
+ if (m_std_handler) {
+ llvm::Optional<Decl *> D = m_std_handler->Import(From);
+ if (D) {
+ // Make sure we don't use this decl later to map it back to it's original
+ // decl. The decl the CxxModuleHandler created has nothing to do with
+ // the one from debug info, and linking those two would just cause the
+ // ASTImporter to try 'updating' the module decl with the minimal one from
+ // the debug info.
+ m_decls_to_ignore.insert(*D);
+ return *D;
+ }
+ }
+
+ // Check which ASTContext this declaration originally came from.
+ DeclOrigin origin = m_master.GetDeclOrigin(From);
+ // If it originally came from the target ASTContext then we can just
+ // pretend that the original is the one we imported. This can happen for
+ // example when inspecting a persistent declaration from the scratch
+ // ASTContext (which will provide the declaration when parsing the
+ // expression and then we later try to copy the declaration back to the
+ // scratch ASTContext to store the result).
+ // Without this check we would ask the ASTImporter to import a declaration
+ // into the same ASTContext where it came from (which doesn't make a lot of
+ // sense).
+ if (origin.Valid() && origin.ctx == &getToContext()) {
+ RegisterImportedDecl(From, origin.decl);
+ return origin.decl;
+ }
+
+ // This declaration came originally from another ASTContext. Instead of
+ // copying our potentially incomplete 'From' Decl we instead go to the
+ // original ASTContext and copy the original to the target. This is not
+ // only faster than first completing our current decl and then copying it
+ // to the target, but it also prevents that indirectly copying the same
+ // declaration to the same target requires the ASTImporter to merge all
+ // the different decls that appear to come from different ASTContexts (even
+ // though all these different source ASTContexts just got a copy from
+ // one source AST).
+ if (origin.Valid()) {
+ auto R = m_master.CopyDecl(&getToContext(), origin.decl);
+ if (R) {
+ RegisterImportedDecl(From, R);
+ return R;
+ }
+ }
+
+ return ASTImporter::ImportImpl(From);
+}
+
+void ClangASTImporter::ASTImporterDelegate::ImportDefinitionTo(
+ clang::Decl *to, clang::Decl *from) {
+ // We might have a forward declaration from a shared library that we
+ // gave external lexical storage so that Clang asks us about the full
+ // definition when it needs it. In this case the ASTImporter isn't aware
+ // that the forward decl from the shared library is the actual import
+ // target but would create a second declaration that would then be defined.
+ // We want that 'to' is actually complete after this function so let's
+ // tell the ASTImporter that 'to' was imported from 'from'.
+ MapImported(from, to);
+ ASTImporter::Imported(from, to);
+
+ /*
+ if (to_objc_interface)
+ to_objc_interface->startDefinition();
+
+ CXXRecordDecl *to_cxx_record = dyn_cast<CXXRecordDecl>(to);
+
+ if (to_cxx_record)
+ to_cxx_record->startDefinition();
+ */
+
+ Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS);
+
+ if (llvm::Error err = ImportDefinition(from)) {
+ LLDB_LOG_ERROR(log, std::move(err),
+ "[ClangASTImporter] Error during importing definition: {0}");
+ return;
+ }
+
+ if (clang::TagDecl *to_tag = dyn_cast<clang::TagDecl>(to)) {
+ if (clang::TagDecl *from_tag = dyn_cast<clang::TagDecl>(from)) {
+ to_tag->setCompleteDefinition(from_tag->isCompleteDefinition());
+
+ if (Log *log_ast =
+ lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_AST)) {
+ std::string name_string;
+ if (NamedDecl *from_named_decl = dyn_cast<clang::NamedDecl>(from)) {
+ llvm::raw_string_ostream name_stream(name_string);
+ from_named_decl->printName(name_stream);
+ name_stream.flush();
+ }
+ LLDB_LOG(log_ast, "==== [ClangASTImporter][TUDecl: {0}] Imported "
+ "({1}Decl*){2}, named {3} (from "
+ "(Decl*){4})",
+ static_cast<void *>(to->getTranslationUnitDecl()),
+ from->getDeclKindName(), static_cast<void *>(to), name_string,
+ static_cast<void *>(from));
+
+ // Log the AST of the TU.
+ std::string ast_string;
+ llvm::raw_string_ostream ast_stream(ast_string);
+ to->getTranslationUnitDecl()->dump(ast_stream);
+ LLDB_LOG(log_ast, "{0}", ast_string);
+ }
+ }
+ }
+
+ // If we're dealing with an Objective-C class, ensure that the inheritance
+ // has been set up correctly. The ASTImporter may not do this correctly if
+ // the class was originally sourced from symbols.
+
+ if (ObjCInterfaceDecl *to_objc_interface = dyn_cast<ObjCInterfaceDecl>(to)) {
+ do {
+ ObjCInterfaceDecl *to_superclass = to_objc_interface->getSuperClass();
+
+ if (to_superclass)
+ break; // we're not going to override it if it's set
+
+ ObjCInterfaceDecl *from_objc_interface =
+ dyn_cast<ObjCInterfaceDecl>(from);
+
+ if (!from_objc_interface)
+ break;
+
+ ObjCInterfaceDecl *from_superclass = from_objc_interface->getSuperClass();
+
+ if (!from_superclass)
+ break;
+
+ llvm::Expected<Decl *> imported_from_superclass_decl =
+ Import(from_superclass);
+
+ if (!imported_from_superclass_decl) {
+ LLDB_LOG_ERROR(log, imported_from_superclass_decl.takeError(),
+ "Couldn't import decl: {0}");
+ break;
+ }
+
+ ObjCInterfaceDecl *imported_from_superclass =
+ dyn_cast<ObjCInterfaceDecl>(*imported_from_superclass_decl);
+
+ if (!imported_from_superclass)
+ break;
+
+ if (!to_objc_interface->hasDefinition())
+ to_objc_interface->startDefinition();
+
+ to_objc_interface->setSuperClass(m_source_ctx->getTrivialTypeSourceInfo(
+ m_source_ctx->getObjCInterfaceType(imported_from_superclass)));
+ } while (false);
+ }
+}
+
+/// Takes a CXXMethodDecl and completes the return type if necessary. This
+/// is currently only necessary for virtual functions with covariant return
+/// types where Clang's CodeGen expects that the underlying records are already
+/// completed.
+static void MaybeCompleteReturnType(ClangASTImporter &importer,
+ CXXMethodDecl *to_method) {
+ if (!to_method->isVirtual())
+ return;
+ QualType return_type = to_method->getReturnType();
+ if (!return_type->isPointerType() && !return_type->isReferenceType())
+ return;
+
+ clang::RecordDecl *rd = return_type->getPointeeType()->getAsRecordDecl();
+ if (!rd)
+ return;
+
+ importer.CompleteTagDecl(rd);
+}
+
+void ClangASTImporter::ASTImporterDelegate::Imported(clang::Decl *from,
+ clang::Decl *to) {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
+
+ // Some decls shouldn't be tracked here because they were not created by
+ // copying 'from' to 'to'. Just exit early for those.
+ if (m_decls_to_ignore.find(to) != m_decls_to_ignore.end())
+ return clang::ASTImporter::Imported(from, to);
+
+ lldb::user_id_t user_id = LLDB_INVALID_UID;
+ ClangASTMetadata *metadata = m_master.GetDeclMetadata(from);
+ if (metadata)
+ user_id = metadata->GetUserID();
+
+ if (log) {
+ if (NamedDecl *from_named_decl = dyn_cast<clang::NamedDecl>(from)) {
+ std::string name_string;
+ llvm::raw_string_ostream name_stream(name_string);
+ from_named_decl->printName(name_stream);
+ name_stream.flush();
+
+ LLDB_LOG(log,
+ " [ClangASTImporter] Imported ({0}Decl*){1}, named {2} (from "
+ "(Decl*){3}), metadata {4}",
+ from->getDeclKindName(), to, name_string, from, user_id);
+ } else {
+ LLDB_LOG(log,
+ " [ClangASTImporter] Imported ({0}Decl*){1} (from "
+ "(Decl*){2}), metadata {3}",
+ from->getDeclKindName(), to, from, user_id);
+ }
+ }
+
+ ASTContextMetadataSP to_context_md =
+ m_master.GetContextMetadata(&to->getASTContext());
+ ASTContextMetadataSP from_context_md =
+ m_master.MaybeGetContextMetadata(m_source_ctx);
+
+ if (from_context_md) {
+ OriginMap &origins = from_context_md->m_origins;
+
+ OriginMap::iterator origin_iter = origins.find(from);
+
+ if (origin_iter != origins.end()) {
+ if (to_context_md->m_origins.find(to) == to_context_md->m_origins.end() ||
+ user_id != LLDB_INVALID_UID) {
+ if (origin_iter->second.ctx != &to->getASTContext())
+ to_context_md->m_origins[to] = origin_iter->second;
+ }
+
+ ImporterDelegateSP direct_completer =
+ m_master.GetDelegate(&to->getASTContext(), origin_iter->second.ctx);
+
+ if (direct_completer.get() != this)
+ direct_completer->ASTImporter::Imported(origin_iter->second.decl, to);
+
+ LLDB_LOG(log,
+ " [ClangASTImporter] Propagated origin "
+ "(Decl*){0}/(ASTContext*){1} from (ASTContext*){2} to "
+ "(ASTContext*){3}",
+ origin_iter->second.decl, origin_iter->second.ctx,
+ &from->getASTContext(), &to->getASTContext());
+ } else {
+ if (m_new_decl_listener)
+ m_new_decl_listener->NewDeclImported(from, to);
+
+ if (to_context_md->m_origins.find(to) == to_context_md->m_origins.end() ||
+ user_id != LLDB_INVALID_UID) {
+ to_context_md->m_origins[to] = DeclOrigin(m_source_ctx, from);
+ }
+
+ LLDB_LOG(log,
+ " [ClangASTImporter] Decl has no origin information in "
+ "(ASTContext*){0}",
+ &from->getASTContext());
+ }
+
+ if (auto *to_namespace = dyn_cast<clang::NamespaceDecl>(to)) {
+ auto *from_namespace = cast<clang::NamespaceDecl>(from);
+
+ NamespaceMetaMap &namespace_maps = from_context_md->m_namespace_maps;
+
+ NamespaceMetaMap::iterator namespace_map_iter =
+ namespace_maps.find(from_namespace);
+
+ if (namespace_map_iter != namespace_maps.end())
+ to_context_md->m_namespace_maps[to_namespace] =
+ namespace_map_iter->second;
+ }
+ } else {
+ to_context_md->m_origins[to] = DeclOrigin(m_source_ctx, from);
+
+ LLDB_LOG(log,
+ " [ClangASTImporter] Sourced origin "
+ "(Decl*){0}/(ASTContext*){1} into (ASTContext*){2}",
+ from, m_source_ctx, &to->getASTContext());
+ }
+
+ if (auto *to_tag_decl = dyn_cast<TagDecl>(to)) {
+ to_tag_decl->setHasExternalLexicalStorage();
+ to_tag_decl->getPrimaryContext()->setMustBuildLookupTable();
+ auto from_tag_decl = cast<TagDecl>(from);
+
+ LLDB_LOG(
+ log,
+ " [ClangASTImporter] To is a TagDecl - attributes {0}{1} [{2}->{3}]",
+ (to_tag_decl->hasExternalLexicalStorage() ? " Lexical" : ""),
+ (to_tag_decl->hasExternalVisibleStorage() ? " Visible" : ""),
+ (from_tag_decl->isCompleteDefinition() ? "complete" : "incomplete"),
+ (to_tag_decl->isCompleteDefinition() ? "complete" : "incomplete"));
+ }
+
+ if (auto *to_namespace_decl = dyn_cast<NamespaceDecl>(to)) {
+ m_master.BuildNamespaceMap(to_namespace_decl);
+ to_namespace_decl->setHasExternalVisibleStorage();
+ }
+
+ if (auto *to_container_decl = dyn_cast<ObjCContainerDecl>(to)) {
+ to_container_decl->setHasExternalLexicalStorage();
+ to_container_decl->setHasExternalVisibleStorage();
+
+ if (log) {
+ if (ObjCInterfaceDecl *to_interface_decl =
+ llvm::dyn_cast<ObjCInterfaceDecl>(to_container_decl)) {
+ LLDB_LOG(
+ log,
+ " [ClangASTImporter] To is an ObjCInterfaceDecl - attributes "
+ "{0}{1}{2}",
+ (to_interface_decl->hasExternalLexicalStorage() ? " Lexical" : ""),
+ (to_interface_decl->hasExternalVisibleStorage() ? " Visible" : ""),
+ (to_interface_decl->hasDefinition() ? " HasDefinition" : ""));
+ } else {
+ LLDB_LOG(
+ log, " [ClangASTImporter] To is an {0}Decl - attributes {1}{2}",
+ ((Decl *)to_container_decl)->getDeclKindName(),
+ (to_container_decl->hasExternalLexicalStorage() ? " Lexical" : ""),
+ (to_container_decl->hasExternalVisibleStorage() ? " Visible" : ""));
+ }
+ }
+ }
+
+ if (clang::CXXMethodDecl *to_method = dyn_cast<CXXMethodDecl>(to))
+ MaybeCompleteReturnType(m_master, to_method);
+}
+
+clang::Decl *
+ClangASTImporter::ASTImporterDelegate::GetOriginalDecl(clang::Decl *To) {
+ return m_master.GetDeclOrigin(To).decl;
+}
--- /dev/null
+//===-- ClangASTImporter.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 liblldb_ClangASTImporter_h_
+#define liblldb_ClangASTImporter_h_
+
+#include <map>
+#include <memory>
+#include <set>
+#include <vector>
+
+#include "clang/AST/ASTImporter.h"
+#include "clang/AST/CharUnits.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Basic/FileSystemOptions.h"
+
+#include "lldb/Host/FileSystem.h"
+#include "lldb/Symbol/CompilerDeclContext.h"
+#include "lldb/lldb-types.h"
+
+#include "Plugins/ExpressionParser/Clang/CxxModuleHandler.h"
+
+#include "llvm/ADT/DenseMap.h"
+
+namespace lldb_private {
+
+class ClangASTImporter {
+public:
+ struct LayoutInfo {
+ LayoutInfo() = default;
+ typedef llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits>
+ OffsetMap;
+
+ uint64_t bit_size = 0;
+ uint64_t alignment = 0;
+ llvm::DenseMap<const clang::FieldDecl *, uint64_t> field_offsets;
+ OffsetMap base_offsets;
+ OffsetMap vbase_offsets;
+ };
+
+ ClangASTImporter()
+ : m_file_manager(clang::FileSystemOptions(),
+ FileSystem::Instance().GetVirtualFileSystem()) {}
+
+ CompilerType CopyType(TypeSystemClang &dst, const CompilerType &src_type);
+
+ clang::Decl *CopyDecl(clang::ASTContext *dst_ctx, clang::Decl *decl);
+
+ CompilerType DeportType(TypeSystemClang &dst, const CompilerType &src_type);
+
+ clang::Decl *DeportDecl(clang::ASTContext *dst_ctx, clang::Decl *decl);
+
+ /// Sets the layout for the given RecordDecl. The layout will later be
+ /// used by Clang's during code generation. Not calling this function for
+ /// a RecordDecl will cause that Clang's codegen tries to layout the
+ /// record by itself.
+ ///
+ /// \param decl The RecordDecl to set the layout for.
+ /// \param layout The layout for the record.
+ void SetRecordLayout(clang::RecordDecl *decl, const LayoutInfo &layout);
+
+ bool LayoutRecordType(
+ const clang::RecordDecl *record_decl, uint64_t &bit_size,
+ uint64_t &alignment,
+ llvm::DenseMap<const clang::FieldDecl *, uint64_t> &field_offsets,
+ llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits>
+ &base_offsets,
+ llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits>
+ &vbase_offsets);
+
+ bool CanImport(const CompilerType &type);
+
+ bool Import(const CompilerType &type);
+
+ bool CompleteType(const CompilerType &compiler_type);
+
+ bool CompleteTagDecl(clang::TagDecl *decl);
+
+ bool CompleteTagDeclWithOrigin(clang::TagDecl *decl, clang::TagDecl *origin);
+
+ bool CompleteObjCInterfaceDecl(clang::ObjCInterfaceDecl *interface_decl);
+
+ bool CompleteAndFetchChildren(clang::QualType type);
+
+ bool RequireCompleteType(clang::QualType type);
+
+ void SetDeclOrigin(const clang::Decl *decl, clang::Decl *original_decl);
+
+ ClangASTMetadata *GetDeclMetadata(const clang::Decl *decl);
+
+ //
+ // Namespace maps
+ //
+
+ typedef std::vector<std::pair<lldb::ModuleSP, CompilerDeclContext>>
+ NamespaceMap;
+ typedef std::shared_ptr<NamespaceMap> NamespaceMapSP;
+
+ void RegisterNamespaceMap(const clang::NamespaceDecl *decl,
+ NamespaceMapSP &namespace_map);
+
+ NamespaceMapSP GetNamespaceMap(const clang::NamespaceDecl *decl);
+
+ void BuildNamespaceMap(const clang::NamespaceDecl *decl);
+
+ //
+ // Completers for maps
+ //
+
+ class MapCompleter {
+ public:
+ virtual ~MapCompleter();
+
+ virtual void CompleteNamespaceMap(NamespaceMapSP &namespace_map,
+ ConstString name,
+ NamespaceMapSP &parent_map) const = 0;
+ };
+
+ void InstallMapCompleter(clang::ASTContext *dst_ctx,
+ MapCompleter &completer) {
+ ASTContextMetadataSP context_md;
+ ContextMetadataMap::iterator context_md_iter = m_metadata_map.find(dst_ctx);
+
+ if (context_md_iter == m_metadata_map.end()) {
+ context_md = ASTContextMetadataSP(new ASTContextMetadata(dst_ctx));
+ m_metadata_map[dst_ctx] = context_md;
+ } else {
+ context_md = context_md_iter->second;
+ }
+
+ context_md->m_map_completer = &completer;
+ }
+
+ void ForgetDestination(clang::ASTContext *dst_ctx);
+ void ForgetSource(clang::ASTContext *dst_ctx, clang::ASTContext *src_ctx);
+
+public:
+ struct DeclOrigin {
+ DeclOrigin() : ctx(nullptr), decl(nullptr) {}
+
+ DeclOrigin(clang::ASTContext *_ctx, clang::Decl *_decl)
+ : ctx(_ctx), decl(_decl) {}
+
+ DeclOrigin(const DeclOrigin &rhs) {
+ ctx = rhs.ctx;
+ decl = rhs.decl;
+ }
+
+ void operator=(const DeclOrigin &rhs) {
+ ctx = rhs.ctx;
+ decl = rhs.decl;
+ }
+
+ bool Valid() { return (ctx != nullptr || decl != nullptr); }
+
+ clang::ASTContext *ctx;
+ clang::Decl *decl;
+ };
+
+ typedef llvm::DenseMap<const clang::Decl *, DeclOrigin> OriginMap;
+
+ /// Listener interface used by the ASTImporterDelegate to inform other code
+ /// about decls that have been imported the first time.
+ struct NewDeclListener {
+ virtual ~NewDeclListener() = default;
+ /// A decl has been imported for the first time.
+ virtual void NewDeclImported(clang::Decl *from, clang::Decl *to) = 0;
+ };
+
+ /// ASTImporter that intercepts and records the import process of the
+ /// underlying ASTImporter.
+ ///
+ /// This class updates the map from declarations to their original
+ /// declarations and can record declarations that have been imported in a
+ /// certain interval.
+ ///
+ /// When intercepting a declaration import, the ASTImporterDelegate uses the
+ /// CxxModuleHandler to replace any missing or malformed declarations with
+ /// their counterpart from a C++ module.
+ struct ASTImporterDelegate : public clang::ASTImporter {
+ ASTImporterDelegate(ClangASTImporter &master, clang::ASTContext *target_ctx,
+ clang::ASTContext *source_ctx)
+ : clang::ASTImporter(*target_ctx, master.m_file_manager, *source_ctx,
+ master.m_file_manager, true /*minimal*/),
+ m_master(master), m_source_ctx(source_ctx) {
+ setODRHandling(clang::ASTImporter::ODRHandlingType::Liberal);
+ }
+
+ /// Scope guard that attaches a CxxModuleHandler to an ASTImporterDelegate
+ /// and deattaches it at the end of the scope. Supports being used multiple
+ /// times on the same ASTImporterDelegate instance in nested scopes.
+ class CxxModuleScope {
+ /// The handler we attach to the ASTImporterDelegate.
+ CxxModuleHandler m_handler;
+ /// The ASTImporterDelegate we are supposed to attach the handler to.
+ ASTImporterDelegate &m_delegate;
+ /// True iff we attached the handler to the ASTImporterDelegate.
+ bool m_valid = false;
+
+ public:
+ CxxModuleScope(ASTImporterDelegate &delegate, clang::ASTContext *dst_ctx)
+ : m_delegate(delegate) {
+ // If the delegate doesn't have a CxxModuleHandler yet, create one
+ // and attach it.
+ if (!delegate.m_std_handler) {
+ m_handler = CxxModuleHandler(delegate, dst_ctx);
+ m_valid = true;
+ delegate.m_std_handler = &m_handler;
+ }
+ }
+ ~CxxModuleScope() {
+ if (m_valid) {
+ // Make sure no one messed with the handler we placed.
+ assert(m_delegate.m_std_handler == &m_handler);
+ m_delegate.m_std_handler = nullptr;
+ }
+ }
+ };
+
+ void ImportDefinitionTo(clang::Decl *to, clang::Decl *from);
+
+ void Imported(clang::Decl *from, clang::Decl *to) override;
+
+ clang::Decl *GetOriginalDecl(clang::Decl *To) override;
+
+ void SetImportListener(NewDeclListener *listener) {
+ assert(m_new_decl_listener == nullptr && "Already attached a listener?");
+ m_new_decl_listener = listener;
+ }
+ void RemoveImportListener() { m_new_decl_listener = nullptr; }
+
+ protected:
+ llvm::Expected<clang::Decl *> ImportImpl(clang::Decl *From) override;
+
+ private:
+ /// Decls we should ignore when mapping decls back to their original
+ /// ASTContext. Used by the CxxModuleHandler to mark declarations that
+ /// were created from the 'std' C++ module to prevent that the Importer
+ /// tries to sync them with the broken equivalent in the debug info AST.
+ llvm::SmallPtrSet<clang::Decl *, 16> m_decls_to_ignore;
+ ClangASTImporter &m_master;
+ clang::ASTContext *m_source_ctx;
+ CxxModuleHandler *m_std_handler = nullptr;
+ /// The currently attached listener.
+ NewDeclListener *m_new_decl_listener = nullptr;
+ };
+
+ typedef std::shared_ptr<ASTImporterDelegate> ImporterDelegateSP;
+ typedef llvm::DenseMap<clang::ASTContext *, ImporterDelegateSP> DelegateMap;
+ typedef llvm::DenseMap<const clang::NamespaceDecl *, NamespaceMapSP>
+ NamespaceMetaMap;
+
+ struct ASTContextMetadata {
+ ASTContextMetadata(clang::ASTContext *dst_ctx)
+ : m_dst_ctx(dst_ctx), m_delegates(), m_origins(), m_namespace_maps(),
+ m_map_completer(nullptr) {}
+
+ clang::ASTContext *m_dst_ctx;
+ DelegateMap m_delegates;
+ OriginMap m_origins;
+
+ NamespaceMetaMap m_namespace_maps;
+ MapCompleter *m_map_completer;
+ };
+
+ typedef std::shared_ptr<ASTContextMetadata> ASTContextMetadataSP;
+ typedef llvm::DenseMap<const clang::ASTContext *, ASTContextMetadataSP>
+ ContextMetadataMap;
+
+ ContextMetadataMap m_metadata_map;
+
+ ASTContextMetadataSP GetContextMetadata(clang::ASTContext *dst_ctx) {
+ ContextMetadataMap::iterator context_md_iter = m_metadata_map.find(dst_ctx);
+
+ if (context_md_iter == m_metadata_map.end()) {
+ ASTContextMetadataSP context_md =
+ ASTContextMetadataSP(new ASTContextMetadata(dst_ctx));
+ m_metadata_map[dst_ctx] = context_md;
+ return context_md;
+ }
+ return context_md_iter->second;
+ }
+
+ ASTContextMetadataSP MaybeGetContextMetadata(clang::ASTContext *dst_ctx) {
+ ContextMetadataMap::iterator context_md_iter = m_metadata_map.find(dst_ctx);
+
+ if (context_md_iter != m_metadata_map.end())
+ return context_md_iter->second;
+ return ASTContextMetadataSP();
+ }
+
+ ImporterDelegateSP GetDelegate(clang::ASTContext *dst_ctx,
+ clang::ASTContext *src_ctx) {
+ ASTContextMetadataSP context_md = GetContextMetadata(dst_ctx);
+
+ DelegateMap &delegates = context_md->m_delegates;
+ DelegateMap::iterator delegate_iter = delegates.find(src_ctx);
+
+ if (delegate_iter == delegates.end()) {
+ ImporterDelegateSP delegate =
+ ImporterDelegateSP(new ASTImporterDelegate(*this, dst_ctx, src_ctx));
+ delegates[src_ctx] = delegate;
+ return delegate;
+ }
+ return delegate_iter->second;
+ }
+
+public:
+ DeclOrigin GetDeclOrigin(const clang::Decl *decl);
+
+ clang::FileManager m_file_manager;
+ typedef llvm::DenseMap<const clang::RecordDecl *, LayoutInfo>
+ RecordDeclToLayoutMap;
+
+ RecordDeclToLayoutMap m_record_decl_to_layout_map;
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_ClangASTImporter_h_
--- /dev/null
+//===-- ClangASTMetadata.cpp ----------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "Plugins/ExpressionParser/Clang/ClangASTMetadata.h"
+#include "lldb/Utility/Stream.h"
+
+using namespace lldb_private;
+
+void ClangASTMetadata::Dump(Stream *s) {
+ lldb::user_id_t uid = GetUserID();
+
+ if (uid != LLDB_INVALID_UID) {
+ s->Printf("uid=0x%" PRIx64, uid);
+ }
+
+ uint64_t isa_ptr = GetISAPtr();
+ if (isa_ptr != 0) {
+ s->Printf("isa_ptr=0x%" PRIx64, isa_ptr);
+ }
+
+ const char *obj_ptr_name = GetObjectPtrName();
+ if (obj_ptr_name) {
+ s->Printf("obj_ptr_name=\"%s\" ", obj_ptr_name);
+ }
+
+ if (m_is_dynamic_cxx) {
+ s->Printf("is_dynamic_cxx=%i ", m_is_dynamic_cxx);
+ }
+ s->EOL();
+}
--- /dev/null
+//===-- ClangASTMetadata.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 liblldb_ClangASTMetadata_h
+#define liblldb_ClangASTMetadata_h
+
+#include "lldb/Core/dwarf.h"
+#include "lldb/lldb-defines.h"
+#include "lldb/lldb-enumerations.h"
+
+namespace lldb_private {
+
+class ClangASTMetadata {
+public:
+ ClangASTMetadata()
+ : m_user_id(0), m_union_is_user_id(false), m_union_is_isa_ptr(false),
+ m_has_object_ptr(false), m_is_self(false), m_is_dynamic_cxx(true) {}
+
+ bool GetIsDynamicCXXType() const { return m_is_dynamic_cxx; }
+
+ void SetIsDynamicCXXType(bool b) { m_is_dynamic_cxx = b; }
+
+ void SetUserID(lldb::user_id_t user_id) {
+ m_user_id = user_id;
+ m_union_is_user_id = true;
+ m_union_is_isa_ptr = false;
+ }
+
+ lldb::user_id_t GetUserID() const {
+ if (m_union_is_user_id)
+ return m_user_id;
+ else
+ return LLDB_INVALID_UID;
+ }
+
+ void SetISAPtr(uint64_t isa_ptr) {
+ m_isa_ptr = isa_ptr;
+ m_union_is_user_id = false;
+ m_union_is_isa_ptr = true;
+ }
+
+ uint64_t GetISAPtr() const {
+ if (m_union_is_isa_ptr)
+ return m_isa_ptr;
+ else
+ return 0;
+ }
+
+ void SetObjectPtrName(const char *name) {
+ m_has_object_ptr = true;
+ if (strcmp(name, "self") == 0)
+ m_is_self = true;
+ else if (strcmp(name, "this") == 0)
+ m_is_self = false;
+ else
+ m_has_object_ptr = false;
+ }
+
+ lldb::LanguageType GetObjectPtrLanguage() const {
+ if (m_has_object_ptr) {
+ if (m_is_self)
+ return lldb::eLanguageTypeObjC;
+ else
+ return lldb::eLanguageTypeC_plus_plus;
+ }
+ return lldb::eLanguageTypeUnknown;
+ }
+
+ const char *GetObjectPtrName() const {
+ if (m_has_object_ptr) {
+ if (m_is_self)
+ return "self";
+ else
+ return "this";
+ } else
+ return nullptr;
+ }
+
+ bool HasObjectPtr() const { return m_has_object_ptr; }
+
+ void Dump(Stream *s);
+
+private:
+ union {
+ lldb::user_id_t m_user_id;
+ uint64_t m_isa_ptr;
+ };
+
+ bool m_union_is_user_id : 1, m_union_is_isa_ptr : 1, m_has_object_ptr : 1,
+ m_is_self : 1, m_is_dynamic_cxx : 1;
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_ClangASTMetadata_h
#include "lldb/Core/Module.h"
#include "lldb/Core/ModuleList.h"
-#include "lldb/Symbol/TypeSystemClang.h"
-#include "lldb/Symbol/ClangUtil.h"
#include "lldb/Symbol/CompilerDeclContext.h"
#include "lldb/Symbol/Function.h"
#include "lldb/Symbol/SymbolFile.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/RecordLayout.h"
+#include "Plugins/ExpressionParser/Clang/ClangUtil.h"
#include "Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h"
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
#include <memory>
#include <vector>
#include <set>
-#include "lldb/Symbol/ClangASTImporter.h"
+#include "Plugins/ExpressionParser/Clang/ClangASTImporter.h"
#include "lldb/Symbol/CompilerType.h"
#include "lldb/Target/Target.h"
#include "clang/AST/ExternalASTSource.h"
//===----------------------------------------------------------------------===//
#include "Plugins/ExpressionParser/Clang/ClangDeclVendor.h"
+#include "Plugins/ExpressionParser/Clang/ClangUtil.h"
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
-#include "lldb/Symbol/ClangUtil.h"
-#include "lldb/Symbol/TypeSystemClang.h"
#include "lldb/Utility/ConstString.h"
using namespace lldb_private;
#include "ClangASTSource.h"
#include "ClangModulesDeclVendor.h"
#include "ClangPersistentVariables.h"
+#include "ClangUtil.h"
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
#include "lldb/Core/Address.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/ModuleSpec.h"
#include "lldb/Core/ValueObjectConstResult.h"
#include "lldb/Core/ValueObjectVariable.h"
#include "lldb/Expression/Materializer.h"
-#include "lldb/Symbol/TypeSystemClang.h"
-#include "lldb/Symbol/ClangUtil.h"
#include "lldb/Symbol/CompileUnit.h"
#include "lldb/Symbol/CompilerDecl.h"
#include "lldb/Symbol/CompilerDeclContext.h"
#include "IRForTarget.h"
#include "ModuleDependencyCollector.h"
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
#include "lldb/Core/Debugger.h"
#include "lldb/Core/Disassembler.h"
#include "lldb/Core/Module.h"
#include "lldb/Expression/IRInterpreter.h"
#include "lldb/Host/File.h"
#include "lldb/Host/HostInfo.h"
-#include "lldb/Symbol/TypeSystemClang.h"
#include "lldb/Symbol/SymbolVendor.h"
#include "lldb/Target/ExecutionContext.h"
#include "lldb/Target/Language.h"
--- /dev/null
+//===-- ClangExternalASTSourceCallbacks.cpp -------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "Plugins/ExpressionParser/Clang/ClangExternalASTSourceCallbacks.h"
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
+
+#include "clang/AST/Decl.h"
+
+using namespace lldb_private;
+
+void ClangExternalASTSourceCallbacks::CompleteType(clang::TagDecl *tag_decl) {
+ m_ast.CompleteTagDecl(tag_decl);
+}
+
+void ClangExternalASTSourceCallbacks::CompleteType(
+ clang::ObjCInterfaceDecl *objc_decl) {
+ m_ast.CompleteObjCInterfaceDecl(objc_decl);
+}
+
+bool ClangExternalASTSourceCallbacks::layoutRecordType(
+ const clang::RecordDecl *Record, uint64_t &Size, uint64_t &Alignment,
+ llvm::DenseMap<const clang::FieldDecl *, uint64_t> &FieldOffsets,
+ llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits> &BaseOffsets,
+ llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits>
+ &VirtualBaseOffsets) {
+ return m_ast.LayoutRecordType(Record, Size, Alignment, FieldOffsets,
+ BaseOffsets, VirtualBaseOffsets);
+}
+
+void ClangExternalASTSourceCallbacks::FindExternalLexicalDecls(
+ const clang::DeclContext *decl_ctx,
+ llvm::function_ref<bool(clang::Decl::Kind)> IsKindWeWant,
+ llvm::SmallVectorImpl<clang::Decl *> &decls) {
+ if (decl_ctx) {
+ clang::TagDecl *tag_decl = llvm::dyn_cast<clang::TagDecl>(
+ const_cast<clang::DeclContext *>(decl_ctx));
+ if (tag_decl)
+ CompleteType(tag_decl);
+ }
+}
--- /dev/null
+//===-- ClangExternalASTSourceCallbacks.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 liblldb_ClangExternalASTSourceCallbacks_h_
+#define liblldb_ClangExternalASTSourceCallbacks_h_
+
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
+#include "clang/AST/ExternalASTSource.h"
+
+namespace lldb_private {
+
+class TypeSystemClang;
+
+class ClangExternalASTSourceCallbacks : public clang::ExternalASTSource {
+public:
+ ClangExternalASTSourceCallbacks(TypeSystemClang &ast) : m_ast(ast) {}
+
+ void FindExternalLexicalDecls(
+ const clang::DeclContext *DC,
+ llvm::function_ref<bool(clang::Decl::Kind)> IsKindWeWant,
+ llvm::SmallVectorImpl<clang::Decl *> &Result) override;
+
+ void CompleteType(clang::TagDecl *tag_decl) override;
+
+ void CompleteType(clang::ObjCInterfaceDecl *objc_decl) override;
+
+ bool layoutRecordType(
+ const clang::RecordDecl *Record, uint64_t &Size, uint64_t &Alignment,
+ llvm::DenseMap<const clang::FieldDecl *, uint64_t> &FieldOffsets,
+ llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits>
+ &BaseOffsets,
+ llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits>
+ &VirtualBaseOffsets) override;
+
+private:
+ TypeSystemClang &m_ast;
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_ClangExternalASTSourceCallbacks_h_
#include "llvm/ExecutionEngine/ExecutionEngine.h"
#include "llvm/IR/Module.h"
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/ValueObject.h"
#include "lldb/Core/ValueObjectList.h"
#include "lldb/Expression/IRExecutionUnit.h"
#include "lldb/Interpreter/CommandReturnObject.h"
-#include "lldb/Symbol/TypeSystemClang.h"
#include "lldb/Symbol/Function.h"
#include "lldb/Symbol/Type.h"
#include "lldb/Target/ExecutionContext.h"
#include "ClangModulesDeclVendor.h"
#include "ModuleDependencyCollector.h"
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
#include "lldb/Core/ModuleList.h"
#include "lldb/Host/Host.h"
#include "lldb/Host/HostInfo.h"
-#include "lldb/Symbol/TypeSystemClang.h"
#include "lldb/Symbol/CompileUnit.h"
#include "lldb/Symbol/SourceModule.h"
#include "lldb/Target/Target.h"
//===----------------------------------------------------------------------===//
#include "ClangPersistentVariables.h"
+#include "ClangASTImporter.h"
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
#include "lldb/Core/Value.h"
-#include "lldb/Symbol/ClangASTImporter.h"
-#include "lldb/Symbol/TypeSystemClang.h"
#include "lldb/Target/Target.h"
#include "lldb/Utility/DataExtractor.h"
#include "lldb/Utility/Log.h"
#include "ClangUserExpression.h"
#include "ASTResultSynthesizer.h"
+#include "ClangASTMetadata.h"
#include "ClangDiagnostic.h"
#include "ClangExpressionDeclMap.h"
#include "ClangExpressionParser.h"
#include "ClangPersistentVariables.h"
#include "CppModuleConfiguration.h"
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
#include "lldb/Core/Debugger.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/StreamFile.h"
#include "lldb/Expression/Materializer.h"
#include "lldb/Host/HostInfo.h"
#include "lldb/Symbol/Block.h"
-#include "lldb/Symbol/TypeSystemClang.h"
-#include "lldb/Symbol/ClangASTMetadata.h"
#include "lldb/Symbol/CompileUnit.h"
#include "lldb/Symbol/Function.h"
#include "lldb/Symbol/ObjectFile.h"
--- /dev/null
+//===-- ClangUtil.cpp -----------------------------------------------------===//
+//
+// 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
+//
+// A collection of helper methods and data structures for manipulating clang
+// types and decls.
+//===----------------------------------------------------------------------===//
+
+#include "Plugins/ExpressionParser/Clang/ClangUtil.h"
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
+
+using namespace clang;
+using namespace lldb_private;
+
+bool ClangUtil::IsClangType(const CompilerType &ct) {
+ // Invalid types are never Clang types.
+ if (!ct)
+ return false;
+
+ if (llvm::dyn_cast_or_null<TypeSystemClang>(ct.GetTypeSystem()) == nullptr)
+ return false;
+
+ if (!ct.GetOpaqueQualType())
+ return false;
+
+ return true;
+}
+
+clang::Decl *ClangUtil::GetDecl(const CompilerDecl &decl) {
+ assert(llvm::isa<TypeSystemClang>(decl.GetTypeSystem()));
+ return static_cast<clang::Decl *>(decl.GetOpaqueDecl());
+}
+
+QualType ClangUtil::GetQualType(const CompilerType &ct) {
+ // Make sure we have a clang type before making a clang::QualType
+ if (!IsClangType(ct))
+ return QualType();
+
+ return QualType::getFromOpaquePtr(ct.GetOpaqueQualType());
+}
+
+QualType ClangUtil::GetCanonicalQualType(const CompilerType &ct) {
+ if (!IsClangType(ct))
+ return QualType();
+
+ return GetQualType(ct).getCanonicalType();
+}
+
+CompilerType ClangUtil::RemoveFastQualifiers(const CompilerType &ct) {
+ if (!IsClangType(ct))
+ return ct;
+
+ QualType qual_type(GetQualType(ct));
+ qual_type.removeLocalFastQualifiers();
+ return CompilerType(ct.GetTypeSystem(), qual_type.getAsOpaquePtr());
+}
+
+clang::TagDecl *ClangUtil::GetAsTagDecl(const CompilerType &type) {
+ clang::QualType qual_type = ClangUtil::GetCanonicalQualType(type);
+ if (qual_type.isNull())
+ return nullptr;
+
+ return qual_type->getAsTagDecl();
+}
+
+std::string ClangUtil::DumpDecl(const clang::Decl *d) {
+ if (!d)
+ return "nullptr";
+
+ std::string result;
+ llvm::raw_string_ostream stream(result);
+ bool deserialize = false;
+ d->dump(stream, deserialize);
+
+ stream.flush();
+ return result;
+}
+
+std::string ClangUtil::ToString(const clang::Type *t) {
+ return clang::QualType(t, 0).getAsString();
+}
+
+std::string ClangUtil::ToString(const CompilerType &c) {
+ return ClangUtil::GetQualType(c).getAsString();
+}
--- /dev/null
+//===-- ClangUtil.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
+//
+// A collection of helper methods and data structures for manipulating clang
+// types and decls.
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SYMBOL_CLANGUTIL_H
+#define LLDB_SYMBOL_CLANGUTIL_H
+
+#include "clang/AST/DeclBase.h"
+#include "clang/AST/Type.h"
+
+#include "lldb/Symbol/CompilerType.h"
+
+namespace clang {
+class TagDecl;
+}
+
+namespace lldb_private {
+struct ClangUtil {
+ static bool IsClangType(const CompilerType &ct);
+
+ /// Returns the clang::Decl of the given CompilerDecl.
+ /// CompilerDecl has to be valid and represent a clang::Decl.
+ static clang::Decl *GetDecl(const CompilerDecl &decl);
+
+ static clang::QualType GetQualType(const CompilerType &ct);
+
+ static clang::QualType GetCanonicalQualType(const CompilerType &ct);
+
+ static CompilerType RemoveFastQualifiers(const CompilerType &ct);
+
+ static clang::TagDecl *GetAsTagDecl(const CompilerType &type);
+
+ /// Returns a textual representation of the given Decl's AST. Does not
+ /// deserialize any child nodes.
+ static std::string DumpDecl(const clang::Decl *d);
+ /// Returns a textual representation of the given type.
+ static std::string ToString(const clang::Type *t);
+ /// Returns a textual representation of the given CompilerType (assuming
+ /// its underlying type is a Clang type).
+ static std::string ToString(const CompilerType &c);
+};
+}
+
+#endif
--- /dev/null
+//===-- CxxModuleHandler.cpp ----------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "Plugins/ExpressionParser/Clang/CxxModuleHandler.h"
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
+
+#include "lldb/Utility/Log.h"
+#include "clang/Sema/Lookup.h"
+#include "llvm/Support/Error.h"
+
+using namespace lldb_private;
+using namespace clang;
+
+CxxModuleHandler::CxxModuleHandler(ASTImporter &importer, ASTContext *target)
+ : m_importer(&importer),
+ m_sema(TypeSystemClang::GetASTContext(target)->getSema()) {
+
+ std::initializer_list<const char *> supported_names = {
+ // containers
+ "deque",
+ "forward_list",
+ "list",
+ "queue",
+ "stack",
+ "vector",
+ // pointers
+ "shared_ptr",
+ "unique_ptr",
+ "weak_ptr",
+ // utility
+ "allocator",
+ };
+ m_supported_templates.insert(supported_names.begin(), supported_names.end());
+}
+
+/// Builds a list of scopes that point into the given context.
+///
+/// \param sema The sema that will be using the scopes.
+/// \param ctxt The context that the scope should look into.
+/// \param result A list of scopes. The scopes need to be freed by the caller
+/// (except the TUScope which is owned by the sema).
+static void makeScopes(Sema &sema, DeclContext *ctxt,
+ std::vector<Scope *> &result) {
+ // FIXME: The result should be a list of unique_ptrs, but the TUScope makes
+ // this currently impossible as it's owned by the Sema.
+
+ if (auto parent = ctxt->getParent()) {
+ makeScopes(sema, parent, result);
+
+ Scope *scope =
+ new Scope(result.back(), Scope::DeclScope, sema.getDiagnostics());
+ scope->setEntity(ctxt);
+ result.push_back(scope);
+ } else
+ result.push_back(sema.TUScope);
+}
+
+/// Uses the Sema to look up the given name in the given DeclContext.
+static std::unique_ptr<LookupResult>
+emulateLookupInCtxt(Sema &sema, llvm::StringRef name, DeclContext *ctxt) {
+ IdentifierInfo &ident = sema.getASTContext().Idents.get(name);
+
+ std::unique_ptr<LookupResult> lookup_result;
+ lookup_result.reset(new LookupResult(sema, DeclarationName(&ident),
+ SourceLocation(),
+ Sema::LookupOrdinaryName));
+
+ // Usually during parsing we already encountered the scopes we would use. But
+ // here don't have these scopes so we have to emulate the behavior of the
+ // Sema during parsing.
+ std::vector<Scope *> scopes;
+ makeScopes(sema, ctxt, scopes);
+
+ // Now actually perform the lookup with the sema.
+ sema.LookupName(*lookup_result, scopes.back());
+
+ // Delete all the allocated scopes beside the translation unit scope (which
+ // has depth 0).
+ for (Scope *s : scopes)
+ if (s->getDepth() != 0)
+ delete s;
+
+ return lookup_result;
+}
+
+/// Error class for handling problems when finding a certain DeclContext.
+struct MissingDeclContext : public llvm::ErrorInfo<MissingDeclContext> {
+
+ static char ID;
+
+ MissingDeclContext(DeclContext *context, std::string error)
+ : m_context(context), m_error(error) {}
+
+ DeclContext *m_context;
+ std::string m_error;
+
+ void log(llvm::raw_ostream &OS) const override {
+ OS << llvm::formatv("error when reconstructing context of kind {0}:{1}",
+ m_context->getDeclKindName(), m_error);
+ }
+
+ std::error_code convertToErrorCode() const override {
+ return llvm::inconvertibleErrorCode();
+ }
+};
+
+char MissingDeclContext::ID = 0;
+
+/// Given a foreign decl context, this function finds the equivalent local
+/// decl context in the ASTContext of the given Sema. Potentially deserializes
+/// decls from the 'std' module if necessary.
+static llvm::Expected<DeclContext *>
+getEqualLocalDeclContext(Sema &sema, DeclContext *foreign_ctxt) {
+
+ // Inline namespaces don't matter for lookups, so let's skip them.
+ while (foreign_ctxt && foreign_ctxt->isInlineNamespace())
+ foreign_ctxt = foreign_ctxt->getParent();
+
+ // If the foreign context is the TU, we just return the local TU.
+ if (foreign_ctxt->isTranslationUnit())
+ return sema.getASTContext().getTranslationUnitDecl();
+
+ // Recursively find/build the parent DeclContext.
+ llvm::Expected<DeclContext *> parent =
+ getEqualLocalDeclContext(sema, foreign_ctxt->getParent());
+ if (!parent)
+ return parent;
+
+ // We currently only support building namespaces.
+ if (foreign_ctxt->isNamespace()) {
+ NamedDecl *ns = llvm::dyn_cast<NamedDecl>(foreign_ctxt);
+ llvm::StringRef ns_name = ns->getName();
+
+ auto lookup_result = emulateLookupInCtxt(sema, ns_name, *parent);
+ for (NamedDecl *named_decl : *lookup_result) {
+ if (DeclContext *DC = llvm::dyn_cast<DeclContext>(named_decl))
+ return DC->getPrimaryContext();
+ }
+ return llvm::make_error<MissingDeclContext>(
+ foreign_ctxt,
+ "Couldn't find namespace " + ns->getQualifiedNameAsString());
+ }
+
+ return llvm::make_error<MissingDeclContext>(foreign_ctxt, "Unknown context ");
+}
+
+/// Returns true iff tryInstantiateStdTemplate supports instantiating a template
+/// with the given template arguments.
+static bool templateArgsAreSupported(ArrayRef<TemplateArgument> a) {
+ for (const TemplateArgument &arg : a) {
+ switch (arg.getKind()) {
+ case TemplateArgument::Type:
+ case TemplateArgument::Integral:
+ break;
+ default:
+ // TemplateArgument kind hasn't been handled yet.
+ return false;
+ }
+ }
+ return true;
+}
+
+/// Constructor function for Clang declarations. Ensures that the created
+/// declaration is registered with the ASTImporter.
+template <typename T, typename... Args>
+T *createDecl(ASTImporter &importer, Decl *from_d, Args &&... args) {
+ T *to_d = T::Create(std::forward<Args>(args)...);
+ importer.RegisterImportedDecl(from_d, to_d);
+ return to_d;
+}
+
+llvm::Optional<Decl *> CxxModuleHandler::tryInstantiateStdTemplate(Decl *d) {
+ Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS);
+
+ // If we don't have a template to instiantiate, then there is nothing to do.
+ auto td = dyn_cast<ClassTemplateSpecializationDecl>(d);
+ if (!td)
+ return {};
+
+ // We only care about templates in the std namespace.
+ if (!td->getDeclContext()->isStdNamespace())
+ return {};
+
+ // We have a whitelist of supported template names.
+ if (m_supported_templates.find(td->getName()) == m_supported_templates.end())
+ return {};
+
+ // Early check if we even support instantiating this template. We do this
+ // before we import anything into the target AST.
+ auto &foreign_args = td->getTemplateInstantiationArgs();
+ if (!templateArgsAreSupported(foreign_args.asArray()))
+ return {};
+
+ // Find the local DeclContext that corresponds to the DeclContext of our
+ // decl we want to import.
+ llvm::Expected<DeclContext *> to_context =
+ getEqualLocalDeclContext(*m_sema, td->getDeclContext());
+ if (!to_context) {
+ LLDB_LOG_ERROR(log, to_context.takeError(),
+ "Got error while searching equal local DeclContext for decl "
+ "'{1}':\n{0}",
+ td->getName());
+ return {};
+ }
+
+ // Look up the template in our local context.
+ std::unique_ptr<LookupResult> lookup =
+ emulateLookupInCtxt(*m_sema, td->getName(), *to_context);
+
+ ClassTemplateDecl *new_class_template = nullptr;
+ for (auto LD : *lookup) {
+ if ((new_class_template = dyn_cast<ClassTemplateDecl>(LD)))
+ break;
+ }
+ if (!new_class_template)
+ return {};
+
+ // Import the foreign template arguments.
+ llvm::SmallVector<TemplateArgument, 4> imported_args;
+
+ // If this logic is changed, also update templateArgsAreSupported.
+ for (const TemplateArgument &arg : foreign_args.asArray()) {
+ switch (arg.getKind()) {
+ case TemplateArgument::Type: {
+ llvm::Expected<QualType> type = m_importer->Import(arg.getAsType());
+ if (!type) {
+ LLDB_LOG_ERROR(log, type.takeError(), "Couldn't import type: {0}");
+ return {};
+ }
+ imported_args.push_back(TemplateArgument(*type));
+ break;
+ }
+ case TemplateArgument::Integral: {
+ llvm::APSInt integral = arg.getAsIntegral();
+ llvm::Expected<QualType> type =
+ m_importer->Import(arg.getIntegralType());
+ if (!type) {
+ LLDB_LOG_ERROR(log, type.takeError(), "Couldn't import type: {0}");
+ return {};
+ }
+ imported_args.push_back(
+ TemplateArgument(d->getASTContext(), integral, *type));
+ break;
+ }
+ default:
+ assert(false && "templateArgsAreSupported not updated?");
+ }
+ }
+
+ // Find the class template specialization declaration that
+ // corresponds to these arguments.
+ void *InsertPos = nullptr;
+ ClassTemplateSpecializationDecl *result =
+ new_class_template->findSpecialization(imported_args, InsertPos);
+
+ if (result) {
+ // We found an existing specialization in the module that fits our arguments
+ // so we can treat it as the result and register it with the ASTImporter.
+ m_importer->RegisterImportedDecl(d, result);
+ return result;
+ }
+
+ // Instantiate the template.
+ result = createDecl<ClassTemplateSpecializationDecl>(
+ *m_importer, d, m_sema->getASTContext(),
+ new_class_template->getTemplatedDecl()->getTagKind(),
+ new_class_template->getDeclContext(),
+ new_class_template->getTemplatedDecl()->getLocation(),
+ new_class_template->getLocation(), new_class_template, imported_args,
+ nullptr);
+
+ new_class_template->AddSpecialization(result, InsertPos);
+ if (new_class_template->isOutOfLine())
+ result->setLexicalDeclContext(
+ new_class_template->getLexicalDeclContext());
+ return result;
+}
+
+llvm::Optional<Decl *> CxxModuleHandler::Import(Decl *d) {
+ if (!isValid())
+ return {};
+
+ return tryInstantiateStdTemplate(d);
+}
--- /dev/null
+//===-- CxxModuleHandler.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 liblldb_CxxModuleHandler_h_
+#define liblldb_CxxModuleHandler_h_
+
+#include "clang/AST/ASTImporter.h"
+#include "clang/Sema/Sema.h"
+#include "llvm/ADT/StringSet.h"
+
+namespace lldb_private {
+
+/// Handles importing decls into an ASTContext with an attached C++ module.
+///
+/// This class searches a C++ module (which must be attached to the target
+/// ASTContext) for an equivalent decl to the one that should be imported.
+/// If the decl that is found in the module is a suitable replacement
+/// for the decl that should be imported, the module decl will be treated as
+/// the result of the import process.
+///
+/// If the Decl that should be imported is a template specialization
+/// that doesn't exist yet in the target ASTContext (e.g. `std::vector<int>`),
+/// then this class tries to create the template specialization in the target
+/// ASTContext. This is only possible if the CxxModuleHandler can determine
+/// that instantiating this template is safe to do, e.g. because the target
+/// decl is a container class from the STL.
+class CxxModuleHandler {
+ /// The ASTImporter that should be used to import any Decls which aren't
+ /// directly handled by this class itself.
+ clang::ASTImporter *m_importer = nullptr;
+
+ /// The Sema instance of the target ASTContext.
+ clang::Sema *m_sema = nullptr;
+
+ /// List of template names this class currently supports. These are the
+ /// template names inside the 'std' namespace such as 'vector' or 'list'.
+ llvm::StringSet<> m_supported_templates;
+
+ /// Tries to manually instantiate the given foreign template in the target
+ /// context (designated by m_sema).
+ llvm::Optional<clang::Decl *> tryInstantiateStdTemplate(clang::Decl *d);
+
+public:
+ CxxModuleHandler() = default;
+ CxxModuleHandler(clang::ASTImporter &importer, clang::ASTContext *target);
+
+ /// Attempts to import the given decl into the target ASTContext by
+ /// deserializing it from the 'std' module. This function returns a Decl if a
+ /// Decl has been deserialized from the 'std' module. Otherwise this function
+ /// returns nothing.
+ llvm::Optional<clang::Decl *> Import(clang::Decl *d);
+
+ /// Returns true iff this instance is capable of importing any declarations
+ /// in the target ASTContext.
+ bool isValid() const { return m_sema != nullptr; }
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_CxxModuleHandler_h_
#include "IRForTarget.h"
#include "ClangExpressionDeclMap.h"
+#include "ClangUtil.h"
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/InstrTypes.h"
#include "lldb/Core/dwarf.h"
#include "lldb/Expression/IRExecutionUnit.h"
#include "lldb/Expression/IRInterpreter.h"
-#include "lldb/Symbol/TypeSystemClang.h"
-#include "lldb/Symbol/ClangUtil.h"
#include "lldb/Symbol/CompilerType.h"
#include "lldb/Utility/ConstString.h"
#include "lldb/Utility/DataBufferHeap.h"
#include "BlockPointer.h"
+#include "Plugins/ExpressionParser/Clang/ClangASTImporter.h"
#include "Plugins/ExpressionParser/Clang/ClangPersistentVariables.h"
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
#include "lldb/Core/ValueObject.h"
#include "lldb/DataFormatters/FormattersHelpers.h"
-#include "lldb/Symbol/ClangASTImporter.h"
#include "lldb/Symbol/CompilerType.h"
#include "lldb/Symbol/TypeSystem.h"
-#include "lldb/Symbol/TypeSystemClang.h"
#include "lldb/Target/Target.h"
#include "lldb/Utility/LLDBAssert.h"
#include "lldb/Utility/Log.h"
lldbUtility
lldbPluginClangCommon
lldbPluginCPPRuntime
+ lldbPluginTypeSystemClang
LINK_COMPONENTS
Support
#include "llvm/Support/ConvertUTF.h"
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
#include "lldb/Core/ValueObject.h"
#include "lldb/Core/ValueObjectConstResult.h"
#include "lldb/DataFormatters/FormattersHelpers.h"
#include "lldb/DataFormatters/StringPrinter.h"
#include "lldb/DataFormatters/TypeSummary.h"
#include "lldb/Host/Time.h"
-#include "lldb/Symbol/TypeSystemClang.h"
#include "lldb/Target/ProcessStructReader.h"
#include "lldb/Target/SectionLoadList.h"
#include "lldb/Target/Target.h"
#include "lldb/DataFormatters/StringPrinter.h"
#include "lldb/DataFormatters/TypeSummary.h"
#include "lldb/DataFormatters/VectorIterator.h"
-#include "lldb/Symbol/TypeSystemClang.h"
#include "lldb/Target/ProcessStructReader.h"
#include "lldb/Target/SectionLoadList.h"
#include "lldb/Target/Target.h"
#include "lldb/Utility/Stream.h"
#include "Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.h"
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
using namespace lldb;
using namespace lldb_private;
//===----------------------------------------------------------------------===//
#include "LibCxx.h"
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
#include "lldb/DataFormatters/FormattersHelpers.h"
-#include "lldb/Symbol/TypeSystemClang.h"
#include "lldb/Target/Target.h"
using namespace lldb;
#include "LibCxx.h"
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
#include "lldb/Core/ValueObject.h"
#include "lldb/Core/ValueObjectConstResult.h"
#include "lldb/DataFormatters/FormattersHelpers.h"
-#include "lldb/Symbol/TypeSystemClang.h"
#include "lldb/Target/Target.h"
#include "lldb/Utility/DataBufferHeap.h"
#include "lldb/Utility/Endian.h"
#include "LibCxx.h"
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
#include "lldb/Core/ValueObject.h"
#include "lldb/Core/ValueObjectConstResult.h"
#include "lldb/DataFormatters/FormattersHelpers.h"
-#include "lldb/Symbol/TypeSystemClang.h"
#include "lldb/Target/Target.h"
#include "lldb/Utility/DataBufferHeap.h"
#include "lldb/Utility/Endian.h"
#include "LibCxx.h"
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
#include "lldb/Core/ValueObject.h"
#include "lldb/Core/ValueObjectConstResult.h"
#include "lldb/DataFormatters/FormattersHelpers.h"
-#include "lldb/Symbol/TypeSystemClang.h"
#include "lldb/Target/Target.h"
#include "lldb/Utility/DataBufferHeap.h"
#include "lldb/Utility/Endian.h"
#include "LibStdcpp.h"
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
#include "lldb/Core/ValueObject.h"
#include "lldb/Core/ValueObjectConstResult.h"
#include "lldb/DataFormatters/StringPrinter.h"
#include "lldb/DataFormatters/VectorIterator.h"
-#include "lldb/Symbol/TypeSystemClang.h"
#include "lldb/Target/Target.h"
#include "lldb/Utility/DataBufferHeap.h"
#include "lldb/Utility/Endian.h"
#include "CF.h"
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
#include "lldb/Core/ValueObject.h"
#include "lldb/Core/ValueObjectConstResult.h"
#include "lldb/DataFormatters/FormattersHelpers.h"
-#include "lldb/Symbol/TypeSystemClang.h"
#include "lldb/Target/Language.h"
#include "lldb/Target/StackFrame.h"
#include "lldb/Target/Target.h"
lldbUtility
lldbPluginAppleObjCRuntime
lldbPluginClangCommon
+ lldbPluginTypeSystemClang
CLANG_LIBS
clangAST
#include "Cocoa.h"
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
#include "lldb/Core/Mangled.h"
#include "lldb/Core/ValueObject.h"
#include "lldb/Core/ValueObjectConstResult.h"
#include "lldb/DataFormatters/StringPrinter.h"
#include "lldb/DataFormatters/TypeSummary.h"
#include "lldb/Host/Time.h"
-#include "lldb/Symbol/TypeSystemClang.h"
#include "lldb/Target/Language.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/ProcessStructReader.h"
#include "Cocoa.h"
#include "Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h"
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
#include "lldb/Core/ValueObject.h"
#include "lldb/Core/ValueObjectConstResult.h"
#include "lldb/DataFormatters/FormattersHelpers.h"
#include "lldb/Expression/FunctionCaller.h"
-#include "lldb/Symbol/TypeSystemClang.h"
#include "lldb/Target/Language.h"
#include "lldb/Target/Target.h"
#include "lldb/Utility/DataBufferHeap.h"
#include "NSDictionary.h"
#include "Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h"
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
#include "lldb/Core/ValueObject.h"
#include "lldb/Core/ValueObjectConstResult.h"
#include "lldb/DataFormatters/FormattersHelpers.h"
-#include "lldb/Symbol/TypeSystemClang.h"
#include "lldb/Target/Language.h"
#include "lldb/Target/StackFrame.h"
#include "lldb/Target/Target.h"
#include "Cocoa.h"
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
#include "lldb/Core/ValueObject.h"
#include "lldb/Core/ValueObjectConstResult.h"
#include "lldb/DataFormatters/FormattersHelpers.h"
-#include "lldb/Symbol/TypeSystemClang.h"
#include "lldb/Target/ProcessStructReader.h"
#include "lldb/Target/Target.h"
#include "lldb/Utility/DataBufferHeap.h"
#include "lldb/Core/ValueObject.h"
#include "lldb/Core/ValueObjectConstResult.h"
#include "lldb/DataFormatters/FormattersHelpers.h"
-#include "lldb/Symbol/TypeSystemClang.h"
#include "lldb/Target/ProcessStructReader.h"
#include "lldb/Target/Target.h"
#include "lldb/Utility/DataBufferHeap.h"
#include "Plugins/Language/ObjC/NSString.h"
#include "Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h"
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
using namespace lldb;
using namespace lldb_private;
#include "Cocoa.h"
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
#include "lldb/Core/ValueObject.h"
#include "lldb/Core/ValueObjectConstResult.h"
#include "lldb/DataFormatters/FormattersHelpers.h"
#include "lldb/DataFormatters/TypeSynthetic.h"
-#include "lldb/Symbol/TypeSystemClang.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/Target.h"
#include "NSSet.h"
#include "Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h"
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
#include "lldb/Core/ValueObject.h"
#include "lldb/Core/ValueObjectConstResult.h"
#include "lldb/DataFormatters/FormattersHelpers.h"
-#include "lldb/Symbol/TypeSystemClang.h"
#include "lldb/Target/Language.h"
#include "lldb/Target/Target.h"
#include "lldb/Utility/DataBufferHeap.h"
#include "NSString.h"
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
#include "lldb/Core/ValueObject.h"
#include "lldb/Core/ValueObjectConstResult.h"
#include "lldb/DataFormatters/FormattersHelpers.h"
#include "lldb/DataFormatters/StringPrinter.h"
-#include "lldb/Symbol/TypeSystemClang.h"
#include "lldb/Target/Language.h"
#include "lldb/Target/ProcessStructReader.h"
#include "lldb/Target/Target.h"
#include "ObjCLanguage.h"
+#include "Plugins/ExpressionParser/Clang/ClangUtil.h"
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Core/ValueObject.h"
#include "lldb/DataFormatters/DataVisualization.h"
#include "lldb/DataFormatters/FormattersHelpers.h"
-#include "lldb/Symbol/TypeSystemClang.h"
-#include "lldb/Symbol/ClangUtil.h"
#include "lldb/Symbol/CompilerType.h"
#include "lldb/Target/Target.h"
#include "lldb/Utility/ConstString.h"
lldbCore
lldbSymbol
lldbTarget
+ lldbPluginTypeSystemClang
)
add_subdirectory(ItaniumABI)
#include "lldb/Symbol/Variable.h"
#include "lldb/Symbol/VariableList.h"
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Core/UniqueCStringMap.h"
-#include "lldb/Symbol/TypeSystemClang.h"
#include "lldb/Symbol/CompileUnit.h"
#include "lldb/Target/ABI.h"
#include "lldb/Target/ExecutionContext.h"
lldbSymbol
lldbTarget
lldbPluginCPPRuntime
+ lldbPluginTypeSystemClang
)
#include "ItaniumABILanguageRuntime.h"
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
#include "lldb/Breakpoint/BreakpointLocation.h"
#include "lldb/Core/Mangled.h"
#include "lldb/Core/Module.h"
#include "lldb/Interpreter/CommandObject.h"
#include "lldb/Interpreter/CommandObjectMultiword.h"
#include "lldb/Interpreter/CommandReturnObject.h"
-#include "lldb/Symbol/TypeSystemClang.h"
#include "lldb/Symbol/Symbol.h"
#include "lldb/Symbol/SymbolFile.h"
#include "lldb/Symbol/TypeList.h"
#include "AppleObjCDeclVendor.h"
+#include "Plugins/ExpressionParser/Clang/ClangASTMetadata.h"
+#include "Plugins/ExpressionParser/Clang/ClangUtil.h"
#include "Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h"
#include "lldb/Core/Module.h"
-#include "lldb/Symbol/ClangASTMetadata.h"
-#include "lldb/Symbol/ClangUtil.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/Target.h"
#include "lldb/Utility/Log.h"
#ifndef liblldb_AppleObjCDeclVendor_h_
#define liblldb_AppleObjCDeclVendor_h_
-#include "lldb/Symbol/TypeSystemClang.h"
#include "lldb/lldb-private.h"
#include "Plugins/ExpressionParser/Clang/ClangDeclVendor.h"
#include "Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h"
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
namespace lldb_private {
#include "lldb/DataFormatters/FormattersHelpers.h"
#include "lldb/Expression/DiagnosticManager.h"
#include "lldb/Expression/FunctionCaller.h"
-#include "lldb/Symbol/TypeSystemClang.h"
#include "lldb/Symbol/ObjectFile.h"
#include "lldb/Target/ExecutionContext.h"
#include "lldb/Target/Process.h"
#include "lldb/Utility/StreamString.h"
#include "clang/AST/Type.h"
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
+
#include <vector>
using namespace lldb;
#include "clang/AST/Type.h"
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
#include "lldb/Breakpoint/BreakpointLocation.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Expression/FunctionCaller.h"
#include "lldb/Expression/UtilityFunction.h"
-#include "lldb/Symbol/TypeSystemClang.h"
#include "lldb/Symbol/Symbol.h"
#include "lldb/Target/ExecutionContext.h"
#include "lldb/Target/Process.h"
#include "lldb/Symbol/CompilerType.h"
#include "lldb/lldb-enumerations.h"
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
#include "lldb/Core/ClangForward.h"
#include "lldb/Core/Debugger.h"
#include "lldb/Core/Module.h"
#include "lldb/Interpreter/CommandReturnObject.h"
#include "lldb/Interpreter/OptionArgParser.h"
#include "lldb/Interpreter/OptionValueBoolean.h"
-#include "lldb/Symbol/TypeSystemClang.h"
#include "lldb/Symbol/ObjectFile.h"
#include "lldb/Symbol/Symbol.h"
#include "lldb/Symbol/TypeList.h"
#include "AppleObjCTrampolineHandler.h"
#include "AppleThreadPlanStepThroughObjCTrampoline.h"
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
#include "lldb/Breakpoint/StoppointCallbackContext.h"
#include "lldb/Core/Debugger.h"
#include "lldb/Core/Module.h"
#include "lldb/Expression/FunctionCaller.h"
#include "lldb/Expression/UserExpression.h"
#include "lldb/Expression/UtilityFunction.h"
-#include "lldb/Symbol/TypeSystemClang.h"
#include "lldb/Symbol/Symbol.h"
#include "lldb/Target/ABI.h"
#include "lldb/Target/ExecutionContext.h"
#include "AppleObjCTypeEncodingParser.h"
-#include "lldb/Symbol/TypeSystemClang.h"
-#include "lldb/Symbol/ClangUtil.h"
+#include "Plugins/ExpressionParser/Clang/ClangUtil.h"
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
#include "lldb/Symbol/CompilerType.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/Target.h"
lldbUtility
lldbPluginExpressionParserClang
lldbPluginCPPRuntime
+ lldbPluginTypeSystemClang
CLANG_LIBS
clangAST
LINK_COMPONENTS
#include "ObjCLanguageRuntime.h"
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
#include "lldb/Core/MappedHash.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Core/ValueObject.h"
-#include "lldb/Symbol/TypeSystemClang.h"
#include "lldb/Symbol/SymbolContext.h"
#include "lldb/Symbol/SymbolFile.h"
#include "lldb/Symbol/Type.h"
lldbHost
lldbInterpreter
lldbTarget
+ lldbPluginTypeSystemClang
)
#include "PlatformPOSIX.h"
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
#include "lldb/Core/Debugger.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/ModuleSpec.h"
#include "lldb/Host/Host.h"
#include "lldb/Host/HostInfo.h"
#include "lldb/Host/ProcessLaunchInfo.h"
-#include "lldb/Symbol/TypeSystemClang.h"
#include "lldb/Target/DynamicLoader.h"
#include "lldb/Target/ExecutionContext.h"
#include "lldb/Target/Process.h"
lldbPluginObjCLanguage
lldbPluginCPlusPlusLanguage
lldbPluginExpressionParserClang
+ lldbPluginTypeSystemClang
CLANG_LIBS
clangAST
clangBasic
#include "SymbolFileDWARFDebugMap.h"
#include "UniqueDWARFASTType.h"
+#include "Plugins/ExpressionParser/Clang/ClangASTImporter.h"
+#include "Plugins/ExpressionParser/Clang/ClangASTMetadata.h"
+#include "Plugins/ExpressionParser/Clang/ClangUtil.h"
#include "Plugins/Language/ObjC/ObjCLanguage.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/Value.h"
#include "lldb/Host/Host.h"
-#include "lldb/Symbol/ClangASTImporter.h"
-#include "lldb/Symbol/ClangASTMetadata.h"
-#include "lldb/Symbol/ClangUtil.h"
#include "lldb/Symbol/CompileUnit.h"
#include "lldb/Symbol/Function.h"
#include "lldb/Symbol/ObjectFile.h"
#include "LogChannelDWARF.h"
#include "lldb/Core/ClangForward.h"
#include "lldb/Core/PluginInterface.h"
-#include "lldb/Symbol/TypeSystemClang.h"
-#include "lldb/Symbol/ClangASTImporter.h"
+
+#include "Plugins/ExpressionParser/Clang/ClangASTImporter.h"
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
#include <vector>
#include "lldb/Interpreter/OptionValueFileSpecList.h"
#include "lldb/Interpreter/OptionValueProperties.h"
+#include "Plugins/ExpressionParser/Clang/ClangUtil.h"
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
#include "lldb/Symbol/Block.h"
-#include "lldb/Symbol/TypeSystemClang.h"
-#include "lldb/Symbol/ClangUtil.h"
#include "lldb/Symbol/CompileUnit.h"
#include "lldb/Symbol/CompilerDecl.h"
#include "lldb/Symbol/CompilerDeclContext.h"
lldbCore
lldbSymbol
lldbUtility
+ lldbPluginTypeSystemClang
CLANG_LIBS
clangAST
clangLex
#include "llvm/DebugInfo/PDB/Native/TpiStream.h"
#include "llvm/Demangle/MicrosoftDemangle.h"
+#include "Plugins/ExpressionParser/Clang/ClangASTMetadata.h"
+#include "Plugins/ExpressionParser/Clang/ClangUtil.h"
#include "Plugins/Language/CPlusPlus/MSVCUndecoratedNameParser.h"
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
#include "lldb/Core/Module.h"
-#include "lldb/Symbol/TypeSystemClang.h"
-#include "lldb/Symbol/ClangASTMetadata.h"
-#include "lldb/Symbol/ClangUtil.h"
#include "lldb/Symbol/ObjectFile.h"
#include "lldb/Utility/LLDBAssert.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/StringRef.h"
-#include "lldb/Symbol/ClangASTImporter.h"
+#include "Plugins/ExpressionParser/Clang/ClangASTImporter.h"
#include "PdbIndex.h"
#include "PdbSymUid.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/Type.h"
+#include "Plugins/ExpressionParser/Clang/ClangUtil.h"
#include "Plugins/Language/CPlusPlus/MSVCUndecoratedNameParser.h"
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Core/StreamBuffer.h"
#include "lldb/Core/StreamFile.h"
-#include "lldb/Symbol/TypeSystemClang.h"
-#include "lldb/Symbol/ClangUtil.h"
#include "lldb/Symbol/CompileUnit.h"
#include "lldb/Symbol/LineTable.h"
#include "lldb/Symbol/ObjectFile.h"
#include "PdbSymUid.h"
#include "PdbUtil.h"
-#include "lldb/Symbol/TypeSystemClang.h"
-#include "lldb/Symbol/ClangASTImporter.h"
+#include "Plugins/ExpressionParser/Clang/ClangASTImporter.h"
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
#include "lldb/Symbol/Type.h"
#include "lldb/Utility/LLDBAssert.h"
#include "lldb/lldb-enumerations.h"
#ifndef LLDB_PLUGINS_SYMBOLFILE_NATIVEPDB_UDTRECORDCOMPLETER_H
#define LLDB_PLUGINS_SYMBOLFILE_NATIVEPDB_UDTRECORDCOMPLETER_H
-#include "lldb/Symbol/ClangASTImporter.h"
+#include "Plugins/ExpressionParser/Clang/ClangASTImporter.h"
#include "llvm/DebugInfo/CodeView/CVRecord.h"
#include "llvm/DebugInfo/CodeView/TypeRecord.h"
#include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h"
lldbPluginSymbolFileNativePDB
lldbSymbol
lldbUtility
+ lldbPluginTypeSystemClang
CLANG_LIBS
clangAST
clangLex
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
+#include "Plugins/ExpressionParser/Clang/ClangASTMetadata.h"
+#include "Plugins/ExpressionParser/Clang/ClangUtil.h"
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
#include "lldb/Core/Module.h"
-#include "lldb/Symbol/TypeSystemClang.h"
-#include "lldb/Symbol/ClangASTMetadata.h"
-#include "lldb/Symbol/ClangUtil.h"
#include "lldb/Symbol/Declaration.h"
#include "lldb/Symbol/SymbolFile.h"
#include "lldb/Symbol/TypeMap.h"
#include "lldb/lldb-forward.h"
-#include "lldb/Symbol/ClangASTImporter.h"
+#include "Plugins/ExpressionParser/Clang/ClangASTImporter.h"
class SymbolFilePDB;
#include "clang/Lex/Lexer.h"
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/PluginManager.h"
-#include "lldb/Symbol/TypeSystemClang.h"
#include "lldb/Symbol/CompileUnit.h"
#include "lldb/Symbol/LineTable.h"
#include "lldb/Symbol/ObjectFile.h"
#include "AppleGetItemInfoHandler.h"
-
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/Value.h"
#include "lldb/Expression/DiagnosticManager.h"
#include "lldb/Expression/FunctionCaller.h"
#include "lldb/Expression/UtilityFunction.h"
-#include "lldb/Symbol/TypeSystemClang.h"
#include "lldb/Symbol/Symbol.h"
#include "lldb/Target/ExecutionContext.h"
#include "lldb/Target/Process.h"
#include "AppleGetPendingItemsHandler.h"
-
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/Value.h"
#include "lldb/Expression/DiagnosticManager.h"
#include "lldb/Expression/FunctionCaller.h"
#include "lldb/Expression/UtilityFunction.h"
-#include "lldb/Symbol/TypeSystemClang.h"
#include "lldb/Symbol/Symbol.h"
#include "lldb/Target/ExecutionContext.h"
#include "lldb/Target/Process.h"
#include "AppleGetQueuesHandler.h"
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/Value.h"
#include "lldb/Expression/DiagnosticManager.h"
#include "lldb/Expression/FunctionCaller.h"
#include "lldb/Expression/UtilityFunction.h"
-#include "lldb/Symbol/TypeSystemClang.h"
#include "lldb/Symbol/Symbol.h"
#include "lldb/Target/ExecutionContext.h"
#include "lldb/Target/Process.h"
#include "AppleGetThreadItemInfoHandler.h"
-
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/Value.h"
#include "lldb/Expression/DiagnosticManager.h"
#include "lldb/Expression/Expression.h"
#include "lldb/Expression/FunctionCaller.h"
#include "lldb/Expression/UtilityFunction.h"
-#include "lldb/Symbol/TypeSystemClang.h"
#include "lldb/Symbol/Symbol.h"
#include "lldb/Target/ExecutionContext.h"
#include "lldb/Target/Process.h"
lldbTarget
lldbUtility
lldbPluginProcessUtility
+ lldbPluginTypeSystemClang
)
//===----------------------------------------------------------------------===//
#include "Plugins/Process/Utility/HistoryThread.h"
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
#include "lldb/Breakpoint/StoppointCallbackContext.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/ModuleSpec.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Core/Section.h"
-#include "lldb/Symbol/TypeSystemClang.h"
#include "lldb/Symbol/ObjectFile.h"
#include "lldb/Symbol/SymbolContext.h"
#include "lldb/Target/Process.h"
--- /dev/null
+add_subdirectory(Clang)
--- /dev/null
+add_lldb_library(lldbPluginTypeSystemClang PLUGIN
+ TypeSystemClang.cpp
+
+ LINK_LIBS
+ lldbCore
+ lldbSymbol
+ lldbTarget
+ lldbUtility
+ lldbPluginExpressionParserClang
+ lldbPluginSymbolFileDWARF
+ lldbPluginSymbolFilePDB
+ lldbPluginObjCRuntime
+ CLANG_LIBS
+ clangAST
+ clangBasic
+ clangFrontend
+ clangSema
+ LINK_COMPONENTS
+ Support
+)
--- /dev/null
+//===-- TypeSystemClang.cpp -----------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "TypeSystemClang.h"
+
+#include "llvm/Support/FormatAdapters.h"
+#include "llvm/Support/FormatVariadic.h"
+
+#include <mutex>
+#include <string>
+#include <vector>
+
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTImporter.h"
+#include "clang/AST/Attr.h"
+#include "clang/AST/CXXInheritance.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/Mangle.h"
+#include "clang/AST/RecordLayout.h"
+#include "clang/AST/Type.h"
+#include "clang/AST/VTableBuilder.h"
+#include "clang/Basic/Builtins.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Basic/FileSystemOptions.h"
+#include "clang/Basic/LangStandard.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/TargetInfo.h"
+#include "clang/Basic/TargetOptions.h"
+#include "clang/Frontend/FrontendOptions.h"
+#include "clang/Sema/Sema.h"
+
+#include "llvm/Support/Signals.h"
+#include "llvm/Support/Threading.h"
+
+#include "Plugins/ExpressionParser/Clang/ClangASTImporter.h"
+#include "Plugins/ExpressionParser/Clang/ClangASTMetadata.h"
+#include "Plugins/ExpressionParser/Clang/ClangExternalASTSourceCallbacks.h"
+#include "Plugins/ExpressionParser/Clang/ClangFunctionCaller.h"
+#include "Plugins/ExpressionParser/Clang/ClangPersistentVariables.h"
+#include "Plugins/ExpressionParser/Clang/ClangUserExpression.h"
+#include "Plugins/ExpressionParser/Clang/ClangUtil.h"
+#include "Plugins/ExpressionParser/Clang/ClangUtilityFunction.h"
+#include "lldb/Utility/ArchSpec.h"
+#include "lldb/Utility/Flags.h"
+
+#include "lldb/Core/DumpDataExtractor.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/StreamFile.h"
+#include "lldb/Core/ThreadSafeDenseMap.h"
+#include "lldb/Core/UniqueCStringMap.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Symbol/SymbolFile.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Language.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Utility/DataExtractor.h"
+#include "lldb/Utility/LLDBAssert.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/RegularExpression.h"
+#include "lldb/Utility/Scalar.h"
+
+#include "Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h"
+#include "Plugins/SymbolFile/DWARF/DWARFASTParserClang.h"
+#include "Plugins/SymbolFile/PDB/PDBASTParser.h"
+
+#include <stdio.h>
+
+#include <mutex>
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace clang;
+using llvm::StringSwitch;
+
+namespace {
+#ifdef LLDB_CONFIGURATION_DEBUG
+static void VerifyDecl(clang::Decl *decl) {
+ assert(decl && "VerifyDecl called with nullptr?");
+ decl->getAccess();
+}
+#endif
+
+static inline bool
+TypeSystemClangSupportsLanguage(lldb::LanguageType language) {
+ return language == eLanguageTypeUnknown || // Clang is the default type system
+ lldb_private::Language::LanguageIsC(language) ||
+ lldb_private::Language::LanguageIsCPlusPlus(language) ||
+ lldb_private::Language::LanguageIsObjC(language) ||
+ lldb_private::Language::LanguageIsPascal(language) ||
+ // Use Clang for Rust until there is a proper language plugin for it
+ language == eLanguageTypeRust ||
+ language == eLanguageTypeExtRenderScript ||
+ // Use Clang for D until there is a proper language plugin for it
+ language == eLanguageTypeD ||
+ // Open Dylan compiler debug info is designed to be Clang-compatible
+ language == eLanguageTypeDylan;
+}
+
+// Checks whether m1 is an overload of m2 (as opposed to an override). This is
+// called by addOverridesForMethod to distinguish overrides (which share a
+// vtable entry) from overloads (which require distinct entries).
+bool isOverload(clang::CXXMethodDecl *m1, clang::CXXMethodDecl *m2) {
+ // FIXME: This should detect covariant return types, but currently doesn't.
+ lldbassert(&m1->getASTContext() == &m2->getASTContext() &&
+ "Methods should have the same AST context");
+ clang::ASTContext &context = m1->getASTContext();
+
+ const auto *m1Type = llvm::cast<clang::FunctionProtoType>(
+ context.getCanonicalType(m1->getType()));
+
+ const auto *m2Type = llvm::cast<clang::FunctionProtoType>(
+ context.getCanonicalType(m2->getType()));
+
+ auto compareArgTypes = [&context](const clang::QualType &m1p,
+ const clang::QualType &m2p) {
+ return context.hasSameType(m1p.getUnqualifiedType(),
+ m2p.getUnqualifiedType());
+ };
+
+ // FIXME: In C++14 and later, we can just pass m2Type->param_type_end()
+ // as a fourth parameter to std::equal().
+ return (m1->getNumParams() != m2->getNumParams()) ||
+ !std::equal(m1Type->param_type_begin(), m1Type->param_type_end(),
+ m2Type->param_type_begin(), compareArgTypes);
+}
+
+// If decl is a virtual method, walk the base classes looking for methods that
+// decl overrides. This table of overridden methods is used by IRGen to
+// determine the vtable layout for decl's parent class.
+void addOverridesForMethod(clang::CXXMethodDecl *decl) {
+ if (!decl->isVirtual())
+ return;
+
+ clang::CXXBasePaths paths;
+
+ auto find_overridden_methods =
+ [decl](const clang::CXXBaseSpecifier *specifier,
+ clang::CXXBasePath &path) {
+ if (auto *base_record = llvm::dyn_cast<clang::CXXRecordDecl>(
+ specifier->getType()->getAs<clang::RecordType>()->getDecl())) {
+
+ clang::DeclarationName name = decl->getDeclName();
+
+ // If this is a destructor, check whether the base class destructor is
+ // virtual.
+ if (name.getNameKind() == clang::DeclarationName::CXXDestructorName)
+ if (auto *baseDtorDecl = base_record->getDestructor()) {
+ if (baseDtorDecl->isVirtual()) {
+ path.Decls = baseDtorDecl;
+ return true;
+ } else
+ return false;
+ }
+
+ // Otherwise, search for name in the base class.
+ for (path.Decls = base_record->lookup(name); !path.Decls.empty();
+ path.Decls = path.Decls.slice(1)) {
+ if (auto *method_decl =
+ llvm::dyn_cast<clang::CXXMethodDecl>(path.Decls.front()))
+ if (method_decl->isVirtual() && !isOverload(decl, method_decl)) {
+ path.Decls = method_decl;
+ return true;
+ }
+ }
+ }
+
+ return false;
+ };
+
+ if (decl->getParent()->lookupInBases(find_overridden_methods, paths)) {
+ for (auto *overridden_decl : paths.found_decls())
+ decl->addOverriddenMethod(
+ llvm::cast<clang::CXXMethodDecl>(overridden_decl));
+ }
+}
+}
+
+static lldb::addr_t GetVTableAddress(Process &process,
+ VTableContextBase &vtable_ctx,
+ ValueObject &valobj,
+ const ASTRecordLayout &record_layout) {
+ // Retrieve type info
+ CompilerType pointee_type;
+ CompilerType this_type(valobj.GetCompilerType());
+ uint32_t type_info = this_type.GetTypeInfo(&pointee_type);
+ if (!type_info)
+ return LLDB_INVALID_ADDRESS;
+
+ // Check if it's a pointer or reference
+ bool ptr_or_ref = false;
+ if (type_info & (eTypeIsPointer | eTypeIsReference)) {
+ ptr_or_ref = true;
+ type_info = pointee_type.GetTypeInfo();
+ }
+
+ // We process only C++ classes
+ const uint32_t cpp_class = eTypeIsClass | eTypeIsCPlusPlus;
+ if ((type_info & cpp_class) != cpp_class)
+ return LLDB_INVALID_ADDRESS;
+
+ // Calculate offset to VTable pointer
+ lldb::offset_t vbtable_ptr_offset =
+ vtable_ctx.isMicrosoft() ? record_layout.getVBPtrOffset().getQuantity()
+ : 0;
+
+ if (ptr_or_ref) {
+ // We have a pointer / ref to object, so read
+ // VTable pointer from process memory
+
+ if (valobj.GetAddressTypeOfChildren() != eAddressTypeLoad)
+ return LLDB_INVALID_ADDRESS;
+
+ auto vbtable_ptr_addr = valobj.GetValueAsUnsigned(LLDB_INVALID_ADDRESS);
+ if (vbtable_ptr_addr == LLDB_INVALID_ADDRESS)
+ return LLDB_INVALID_ADDRESS;
+
+ vbtable_ptr_addr += vbtable_ptr_offset;
+
+ Status err;
+ return process.ReadPointerFromMemory(vbtable_ptr_addr, err);
+ }
+
+ // We have an object already read from process memory,
+ // so just extract VTable pointer from it
+
+ DataExtractor data;
+ Status err;
+ auto size = valobj.GetData(data, err);
+ if (err.Fail() || vbtable_ptr_offset + data.GetAddressByteSize() > size)
+ return LLDB_INVALID_ADDRESS;
+
+ return data.GetPointer(&vbtable_ptr_offset);
+}
+
+static int64_t ReadVBaseOffsetFromVTable(Process &process,
+ VTableContextBase &vtable_ctx,
+ lldb::addr_t vtable_ptr,
+ const CXXRecordDecl *cxx_record_decl,
+ const CXXRecordDecl *base_class_decl) {
+ if (vtable_ctx.isMicrosoft()) {
+ clang::MicrosoftVTableContext &msoft_vtable_ctx =
+ static_cast<clang::MicrosoftVTableContext &>(vtable_ctx);
+
+ // Get the index into the virtual base table. The
+ // index is the index in uint32_t from vbtable_ptr
+ const unsigned vbtable_index =
+ msoft_vtable_ctx.getVBTableIndex(cxx_record_decl, base_class_decl);
+ const lldb::addr_t base_offset_addr = vtable_ptr + vbtable_index * 4;
+ Status err;
+ return process.ReadSignedIntegerFromMemory(base_offset_addr, 4, INT64_MAX,
+ err);
+ }
+
+ clang::ItaniumVTableContext &itanium_vtable_ctx =
+ static_cast<clang::ItaniumVTableContext &>(vtable_ctx);
+
+ clang::CharUnits base_offset_offset =
+ itanium_vtable_ctx.getVirtualBaseOffsetOffset(cxx_record_decl,
+ base_class_decl);
+ const lldb::addr_t base_offset_addr =
+ vtable_ptr + base_offset_offset.getQuantity();
+ const uint32_t base_offset_size = process.GetAddressByteSize();
+ Status err;
+ return process.ReadSignedIntegerFromMemory(base_offset_addr, base_offset_size,
+ INT64_MAX, err);
+}
+
+static bool GetVBaseBitOffset(VTableContextBase &vtable_ctx,
+ ValueObject &valobj,
+ const ASTRecordLayout &record_layout,
+ const CXXRecordDecl *cxx_record_decl,
+ const CXXRecordDecl *base_class_decl,
+ int32_t &bit_offset) {
+ ExecutionContext exe_ctx(valobj.GetExecutionContextRef());
+ Process *process = exe_ctx.GetProcessPtr();
+ if (!process)
+ return false;
+
+ lldb::addr_t vtable_ptr =
+ GetVTableAddress(*process, vtable_ctx, valobj, record_layout);
+ if (vtable_ptr == LLDB_INVALID_ADDRESS)
+ return false;
+
+ auto base_offset = ReadVBaseOffsetFromVTable(
+ *process, vtable_ctx, vtable_ptr, cxx_record_decl, base_class_decl);
+ if (base_offset == INT64_MAX)
+ return false;
+
+ bit_offset = base_offset * 8;
+
+ return true;
+}
+
+typedef lldb_private::ThreadSafeDenseMap<clang::ASTContext *, TypeSystemClang *>
+ ClangASTMap;
+
+static ClangASTMap &GetASTMap() {
+ static ClangASTMap *g_map_ptr = nullptr;
+ static llvm::once_flag g_once_flag;
+ llvm::call_once(g_once_flag, []() {
+ g_map_ptr = new ClangASTMap(); // leaked on purpose to avoid spins
+ });
+ return *g_map_ptr;
+}
+
+char TypeSystemClang::ID;
+
+bool TypeSystemClang::IsOperator(llvm::StringRef name,
+ clang::OverloadedOperatorKind &op_kind) {
+ // All operators have to start with "operator".
+ if (!name.consume_front("operator"))
+ return false;
+
+ // Remember if there was a space after "operator". This is necessary to
+ // check for collisions with strangely named functions like "operatorint()".
+ bool space_after_operator = name.consume_front(" ");
+
+ op_kind = StringSwitch<clang::OverloadedOperatorKind>(name)
+ .Case("+", clang::OO_Plus)
+ .Case("+=", clang::OO_PlusEqual)
+ .Case("++", clang::OO_PlusPlus)
+ .Case("-", clang::OO_Minus)
+ .Case("-=", clang::OO_MinusEqual)
+ .Case("--", clang::OO_MinusMinus)
+ .Case("->", clang::OO_Arrow)
+ .Case("->*", clang::OO_ArrowStar)
+ .Case("*", clang::OO_Star)
+ .Case("*=", clang::OO_StarEqual)
+ .Case("/", clang::OO_Slash)
+ .Case("/=", clang::OO_SlashEqual)
+ .Case("%", clang::OO_Percent)
+ .Case("%=", clang::OO_PercentEqual)
+ .Case("^", clang::OO_Caret)
+ .Case("^=", clang::OO_CaretEqual)
+ .Case("&", clang::OO_Amp)
+ .Case("&=", clang::OO_AmpEqual)
+ .Case("&&", clang::OO_AmpAmp)
+ .Case("|", clang::OO_Pipe)
+ .Case("|=", clang::OO_PipeEqual)
+ .Case("||", clang::OO_PipePipe)
+ .Case("~", clang::OO_Tilde)
+ .Case("!", clang::OO_Exclaim)
+ .Case("!=", clang::OO_ExclaimEqual)
+ .Case("=", clang::OO_Equal)
+ .Case("==", clang::OO_EqualEqual)
+ .Case("<", clang::OO_Less)
+ .Case("<<", clang::OO_LessLess)
+ .Case("<<=", clang::OO_LessLessEqual)
+ .Case("<=", clang::OO_LessEqual)
+ .Case(">", clang::OO_Greater)
+ .Case(">>", clang::OO_GreaterGreater)
+ .Case(">>=", clang::OO_GreaterGreaterEqual)
+ .Case(">=", clang::OO_GreaterEqual)
+ .Case("()", clang::OO_Call)
+ .Case("[]", clang::OO_Subscript)
+ .Case(",", clang::OO_Comma)
+ .Default(clang::NUM_OVERLOADED_OPERATORS);
+
+ // We found a fitting operator, so we can exit now.
+ if (op_kind != clang::NUM_OVERLOADED_OPERATORS)
+ return true;
+
+ // After the "operator " or "operator" part is something unknown. This means
+ // it's either one of the named operators (new/delete), a conversion operator
+ // (e.g. operator bool) or a function which name starts with "operator"
+ // (e.g. void operatorbool).
+
+ // If it's a function that starts with operator it can't have a space after
+ // "operator" because identifiers can't contain spaces.
+ // E.g. "operator int" (conversion operator)
+ // vs. "operatorint" (function with colliding name).
+ if (!space_after_operator)
+ return false; // not an operator.
+
+ // Now the operator is either one of the named operators or a conversion
+ // operator.
+ op_kind = StringSwitch<clang::OverloadedOperatorKind>(name)
+ .Case("new", clang::OO_New)
+ .Case("new[]", clang::OO_Array_New)
+ .Case("delete", clang::OO_Delete)
+ .Case("delete[]", clang::OO_Array_Delete)
+ // conversion operators hit this case.
+ .Default(clang::NUM_OVERLOADED_OPERATORS);
+
+ return true;
+}
+
+clang::AccessSpecifier
+TypeSystemClang::ConvertAccessTypeToAccessSpecifier(AccessType access) {
+ switch (access) {
+ default:
+ break;
+ case eAccessNone:
+ return AS_none;
+ case eAccessPublic:
+ return AS_public;
+ case eAccessPrivate:
+ return AS_private;
+ case eAccessProtected:
+ return AS_protected;
+ }
+ return AS_none;
+}
+
+static void ParseLangArgs(LangOptions &Opts, InputKind IK, const char *triple) {
+ // FIXME: Cleanup per-file based stuff.
+
+ // Set some properties which depend solely on the input kind; it would be
+ // nice to move these to the language standard, and have the driver resolve
+ // the input kind + language standard.
+ if (IK.getLanguage() == clang::Language::Asm) {
+ Opts.AsmPreprocessor = 1;
+ } else if (IK.isObjectiveC()) {
+ Opts.ObjC = 1;
+ }
+
+ LangStandard::Kind LangStd = LangStandard::lang_unspecified;
+
+ if (LangStd == LangStandard::lang_unspecified) {
+ // Based on the base language, pick one.
+ switch (IK.getLanguage()) {
+ case clang::Language::Unknown:
+ case clang::Language::LLVM_IR:
+ case clang::Language::RenderScript:
+ llvm_unreachable("Invalid input kind!");
+ case clang::Language::OpenCL:
+ LangStd = LangStandard::lang_opencl10;
+ break;
+ case clang::Language::CUDA:
+ LangStd = LangStandard::lang_cuda;
+ break;
+ case clang::Language::Asm:
+ case clang::Language::C:
+ case clang::Language::ObjC:
+ LangStd = LangStandard::lang_gnu99;
+ break;
+ case clang::Language::CXX:
+ case clang::Language::ObjCXX:
+ LangStd = LangStandard::lang_gnucxx98;
+ break;
+ case clang::Language::HIP:
+ LangStd = LangStandard::lang_hip;
+ break;
+ }
+ }
+
+ const LangStandard &Std = LangStandard::getLangStandardForKind(LangStd);
+ Opts.LineComment = Std.hasLineComments();
+ Opts.C99 = Std.isC99();
+ Opts.CPlusPlus = Std.isCPlusPlus();
+ Opts.CPlusPlus11 = Std.isCPlusPlus11();
+ Opts.Digraphs = Std.hasDigraphs();
+ Opts.GNUMode = Std.isGNUMode();
+ Opts.GNUInline = !Std.isC99();
+ Opts.HexFloats = Std.hasHexFloats();
+ Opts.ImplicitInt = Std.hasImplicitInt();
+
+ Opts.WChar = true;
+
+ // OpenCL has some additional defaults.
+ if (LangStd == LangStandard::lang_opencl10) {
+ Opts.OpenCL = 1;
+ Opts.AltiVec = 1;
+ Opts.CXXOperatorNames = 1;
+ Opts.setLaxVectorConversions(LangOptions::LaxVectorConversionKind::All);
+ }
+
+ // OpenCL and C++ both have bool, true, false keywords.
+ Opts.Bool = Opts.OpenCL || Opts.CPlusPlus;
+
+ Opts.setValueVisibilityMode(DefaultVisibility);
+
+ // Mimicing gcc's behavior, trigraphs are only enabled if -trigraphs is
+ // specified, or -std is set to a conforming mode.
+ Opts.Trigraphs = !Opts.GNUMode;
+ Opts.CharIsSigned = ArchSpec(triple).CharIsSignedByDefault();
+ Opts.OptimizeSize = 0;
+
+ // FIXME: Eliminate this dependency.
+ // unsigned Opt =
+ // Args.hasArg(OPT_Os) ? 2 : getLastArgIntValue(Args, OPT_O, 0, Diags);
+ // Opts.Optimize = Opt != 0;
+ unsigned Opt = 0;
+
+ // This is the __NO_INLINE__ define, which just depends on things like the
+ // optimization level and -fno-inline, not actually whether the backend has
+ // inlining enabled.
+ //
+ // FIXME: This is affected by other options (-fno-inline).
+ Opts.NoInlineDefine = !Opt;
+}
+
+TypeSystemClang::TypeSystemClang(llvm::StringRef name,
+ llvm::Triple target_triple) {
+ m_display_name = name.str();
+ if (!target_triple.str().empty())
+ SetTargetTriple(target_triple.str());
+ // The caller didn't pass an ASTContext so create a new one for this
+ // TypeSystemClang.
+ CreateASTContext();
+}
+
+TypeSystemClang::TypeSystemClang(llvm::StringRef name,
+ ASTContext &existing_ctxt) {
+ m_display_name = name.str();
+ SetTargetTriple(existing_ctxt.getTargetInfo().getTriple().str());
+
+ m_ast_up.reset(&existing_ctxt);
+ GetASTMap().Insert(&existing_ctxt, this);
+}
+
+// Destructor
+TypeSystemClang::~TypeSystemClang() { Finalize(); }
+
+ConstString TypeSystemClang::GetPluginNameStatic() {
+ return ConstString("clang");
+}
+
+ConstString TypeSystemClang::GetPluginName() {
+ return TypeSystemClang::GetPluginNameStatic();
+}
+
+uint32_t TypeSystemClang::GetPluginVersion() { return 1; }
+
+lldb::TypeSystemSP TypeSystemClang::CreateInstance(lldb::LanguageType language,
+ lldb_private::Module *module,
+ Target *target) {
+ if (!TypeSystemClangSupportsLanguage(language))
+ return lldb::TypeSystemSP();
+ ArchSpec arch;
+ if (module)
+ arch = module->GetArchitecture();
+ else if (target)
+ arch = target->GetArchitecture();
+
+ if (!arch.IsValid())
+ return lldb::TypeSystemSP();
+
+ llvm::Triple triple = arch.GetTriple();
+ // LLVM wants this to be set to iOS or MacOSX; if we're working on
+ // a bare-boards type image, change the triple for llvm's benefit.
+ if (triple.getVendor() == llvm::Triple::Apple &&
+ triple.getOS() == llvm::Triple::UnknownOS) {
+ if (triple.getArch() == llvm::Triple::arm ||
+ triple.getArch() == llvm::Triple::aarch64 ||
+ triple.getArch() == llvm::Triple::aarch64_32 ||
+ triple.getArch() == llvm::Triple::thumb) {
+ triple.setOS(llvm::Triple::IOS);
+ } else {
+ triple.setOS(llvm::Triple::MacOSX);
+ }
+ }
+
+ if (module) {
+ std::string ast_name =
+ "ASTContext for '" + module->GetFileSpec().GetPath() + "'";
+ return std::make_shared<TypeSystemClang>(ast_name, triple);
+ } else if (target && target->IsValid())
+ return std::make_shared<TypeSystemClangForExpressions>(*target, triple);
+ return lldb::TypeSystemSP();
+}
+
+LanguageSet TypeSystemClang::GetSupportedLanguagesForTypes() {
+ LanguageSet languages;
+ languages.Insert(lldb::eLanguageTypeC89);
+ languages.Insert(lldb::eLanguageTypeC);
+ languages.Insert(lldb::eLanguageTypeC11);
+ languages.Insert(lldb::eLanguageTypeC_plus_plus);
+ languages.Insert(lldb::eLanguageTypeC99);
+ languages.Insert(lldb::eLanguageTypeObjC);
+ languages.Insert(lldb::eLanguageTypeObjC_plus_plus);
+ languages.Insert(lldb::eLanguageTypeC_plus_plus_03);
+ languages.Insert(lldb::eLanguageTypeC_plus_plus_11);
+ languages.Insert(lldb::eLanguageTypeC11);
+ languages.Insert(lldb::eLanguageTypeC_plus_plus_14);
+ return languages;
+}
+
+LanguageSet TypeSystemClang::GetSupportedLanguagesForExpressions() {
+ LanguageSet languages;
+ languages.Insert(lldb::eLanguageTypeC_plus_plus);
+ languages.Insert(lldb::eLanguageTypeObjC_plus_plus);
+ languages.Insert(lldb::eLanguageTypeC_plus_plus_03);
+ languages.Insert(lldb::eLanguageTypeC_plus_plus_11);
+ languages.Insert(lldb::eLanguageTypeC_plus_plus_14);
+ return languages;
+}
+
+void TypeSystemClang::Initialize() {
+ PluginManager::RegisterPlugin(
+ GetPluginNameStatic(), "clang base AST context plug-in", CreateInstance,
+ GetSupportedLanguagesForTypes(), GetSupportedLanguagesForExpressions());
+}
+
+void TypeSystemClang::Terminate() {
+ PluginManager::UnregisterPlugin(CreateInstance);
+}
+
+void TypeSystemClang::Finalize() {
+ assert(m_ast_up);
+ GetASTMap().Erase(m_ast_up.get());
+ if (!m_ast_owned)
+ m_ast_up.release();
+
+ m_builtins_up.reset();
+ m_selector_table_up.reset();
+ m_identifier_table_up.reset();
+ m_target_info_up.reset();
+ m_target_options_rp.reset();
+ m_diagnostics_engine_up.reset();
+ m_source_manager_up.reset();
+ m_language_options_up.reset();
+}
+
+void TypeSystemClang::setSema(Sema *s) {
+ // Ensure that the new sema actually belongs to our ASTContext.
+ assert(s == nullptr || &s->getASTContext() == m_ast_up.get());
+ m_sema = s;
+}
+
+const char *TypeSystemClang::GetTargetTriple() {
+ return m_target_triple.c_str();
+}
+
+void TypeSystemClang::SetTargetTriple(llvm::StringRef target_triple) {
+ m_target_triple = target_triple.str();
+}
+
+void TypeSystemClang::SetExternalSource(
+ llvm::IntrusiveRefCntPtr<ExternalASTSource> &ast_source_up) {
+ ASTContext &ast = getASTContext();
+ ast.setExternalSource(ast_source_up);
+ ast.getTranslationUnitDecl()->setHasExternalLexicalStorage(true);
+}
+
+ASTContext &TypeSystemClang::getASTContext() {
+ assert(m_ast_up);
+ return *m_ast_up;
+}
+
+class NullDiagnosticConsumer : public DiagnosticConsumer {
+public:
+ NullDiagnosticConsumer() {
+ m_log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS);
+ }
+
+ void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
+ const clang::Diagnostic &info) override {
+ if (m_log) {
+ llvm::SmallVector<char, 32> diag_str(10);
+ info.FormatDiagnostic(diag_str);
+ diag_str.push_back('\0');
+ LLDB_LOGF(m_log, "Compiler diagnostic: %s\n", diag_str.data());
+ }
+ }
+
+ DiagnosticConsumer *clone(DiagnosticsEngine &Diags) const {
+ return new NullDiagnosticConsumer();
+ }
+
+private:
+ Log *m_log;
+};
+
+void TypeSystemClang::CreateASTContext() {
+ assert(!m_ast_up);
+ m_ast_owned = true;
+
+ m_language_options_up.reset(new LangOptions());
+ ParseLangArgs(*m_language_options_up, clang::Language::ObjCXX,
+ GetTargetTriple());
+
+ m_identifier_table_up.reset(
+ new IdentifierTable(*m_language_options_up, nullptr));
+ m_builtins_up.reset(new Builtin::Context());
+
+ m_selector_table_up.reset(new SelectorTable());
+
+ clang::FileSystemOptions file_system_options;
+ m_file_manager_up.reset(new clang::FileManager(
+ file_system_options, FileSystem::Instance().GetVirtualFileSystem()));
+
+ llvm::IntrusiveRefCntPtr<DiagnosticIDs> diag_id_sp(new DiagnosticIDs());
+ m_diagnostics_engine_up.reset(
+ new DiagnosticsEngine(diag_id_sp, new DiagnosticOptions()));
+
+ m_source_manager_up.reset(
+ new clang::SourceManager(*m_diagnostics_engine_up, *m_file_manager_up));
+ m_ast_up.reset(new ASTContext(*m_language_options_up, *m_source_manager_up,
+ *m_identifier_table_up, *m_selector_table_up,
+ *m_builtins_up));
+
+ m_diagnostic_consumer_up.reset(new NullDiagnosticConsumer);
+ m_ast_up->getDiagnostics().setClient(m_diagnostic_consumer_up.get(), false);
+
+ // This can be NULL if we don't know anything about the architecture or if
+ // the target for an architecture isn't enabled in the llvm/clang that we
+ // built
+ TargetInfo *target_info = getTargetInfo();
+ if (target_info)
+ m_ast_up->InitBuiltinTypes(*target_info);
+
+ GetASTMap().Insert(m_ast_up.get(), this);
+
+ llvm::IntrusiveRefCntPtr<clang::ExternalASTSource> ast_source_up(
+ new ClangExternalASTSourceCallbacks(*this));
+ SetExternalSource(ast_source_up);
+}
+
+TypeSystemClang *TypeSystemClang::GetASTContext(clang::ASTContext *ast) {
+ TypeSystemClang *clang_ast = GetASTMap().Lookup(ast);
+ return clang_ast;
+}
+
+clang::MangleContext *TypeSystemClang::getMangleContext() {
+ if (m_mangle_ctx_up == nullptr)
+ m_mangle_ctx_up.reset(getASTContext().createMangleContext());
+ return m_mangle_ctx_up.get();
+}
+
+std::shared_ptr<clang::TargetOptions> &TypeSystemClang::getTargetOptions() {
+ if (m_target_options_rp == nullptr && !m_target_triple.empty()) {
+ m_target_options_rp = std::make_shared<clang::TargetOptions>();
+ if (m_target_options_rp != nullptr)
+ m_target_options_rp->Triple = m_target_triple;
+ }
+ return m_target_options_rp;
+}
+
+TargetInfo *TypeSystemClang::getTargetInfo() {
+ // target_triple should be something like "x86_64-apple-macosx"
+ if (m_target_info_up == nullptr && !m_target_triple.empty())
+ m_target_info_up.reset(TargetInfo::CreateTargetInfo(
+ getASTContext().getDiagnostics(), getTargetOptions()));
+ return m_target_info_up.get();
+}
+
+#pragma mark Basic Types
+
+static inline bool QualTypeMatchesBitSize(const uint64_t bit_size,
+ ASTContext &ast, QualType qual_type) {
+ uint64_t qual_type_bit_size = ast.getTypeSize(qual_type);
+ return qual_type_bit_size == bit_size;
+}
+
+CompilerType
+TypeSystemClang::GetBuiltinTypeForEncodingAndBitSize(Encoding encoding,
+ size_t bit_size) {
+ ASTContext &ast = getASTContext();
+ switch (encoding) {
+ case eEncodingInvalid:
+ if (QualTypeMatchesBitSize(bit_size, ast, ast.VoidPtrTy))
+ return GetType(ast.VoidPtrTy);
+ break;
+
+ case eEncodingUint:
+ if (QualTypeMatchesBitSize(bit_size, ast, ast.UnsignedCharTy))
+ return GetType(ast.UnsignedCharTy);
+ if (QualTypeMatchesBitSize(bit_size, ast, ast.UnsignedShortTy))
+ return GetType(ast.UnsignedShortTy);
+ if (QualTypeMatchesBitSize(bit_size, ast, ast.UnsignedIntTy))
+ return GetType(ast.UnsignedIntTy);
+ if (QualTypeMatchesBitSize(bit_size, ast, ast.UnsignedLongTy))
+ return GetType(ast.UnsignedLongTy);
+ if (QualTypeMatchesBitSize(bit_size, ast, ast.UnsignedLongLongTy))
+ return GetType(ast.UnsignedLongLongTy);
+ if (QualTypeMatchesBitSize(bit_size, ast, ast.UnsignedInt128Ty))
+ return GetType(ast.UnsignedInt128Ty);
+ break;
+
+ case eEncodingSint:
+ if (QualTypeMatchesBitSize(bit_size, ast, ast.SignedCharTy))
+ return GetType(ast.SignedCharTy);
+ if (QualTypeMatchesBitSize(bit_size, ast, ast.ShortTy))
+ return GetType(ast.ShortTy);
+ if (QualTypeMatchesBitSize(bit_size, ast, ast.IntTy))
+ return GetType(ast.IntTy);
+ if (QualTypeMatchesBitSize(bit_size, ast, ast.LongTy))
+ return GetType(ast.LongTy);
+ if (QualTypeMatchesBitSize(bit_size, ast, ast.LongLongTy))
+ return GetType(ast.LongLongTy);
+ if (QualTypeMatchesBitSize(bit_size, ast, ast.Int128Ty))
+ return GetType(ast.Int128Ty);
+ break;
+
+ case eEncodingIEEE754:
+ if (QualTypeMatchesBitSize(bit_size, ast, ast.FloatTy))
+ return GetType(ast.FloatTy);
+ if (QualTypeMatchesBitSize(bit_size, ast, ast.DoubleTy))
+ return GetType(ast.DoubleTy);
+ if (QualTypeMatchesBitSize(bit_size, ast, ast.LongDoubleTy))
+ return GetType(ast.LongDoubleTy);
+ if (QualTypeMatchesBitSize(bit_size, ast, ast.HalfTy))
+ return GetType(ast.HalfTy);
+ break;
+
+ case eEncodingVector:
+ // Sanity check that bit_size is a multiple of 8's.
+ if (bit_size && !(bit_size & 0x7u))
+ return GetType(ast.getExtVectorType(ast.UnsignedCharTy, bit_size / 8));
+ break;
+ }
+
+ return CompilerType();
+}
+
+lldb::BasicType
+TypeSystemClang::GetBasicTypeEnumeration(ConstString name) {
+ if (name) {
+ typedef UniqueCStringMap<lldb::BasicType> TypeNameToBasicTypeMap;
+ static TypeNameToBasicTypeMap g_type_map;
+ static llvm::once_flag g_once_flag;
+ llvm::call_once(g_once_flag, []() {
+ // "void"
+ g_type_map.Append(ConstString("void"), eBasicTypeVoid);
+
+ // "char"
+ g_type_map.Append(ConstString("char"), eBasicTypeChar);
+ g_type_map.Append(ConstString("signed char"), eBasicTypeSignedChar);
+ g_type_map.Append(ConstString("unsigned char"), eBasicTypeUnsignedChar);
+ g_type_map.Append(ConstString("wchar_t"), eBasicTypeWChar);
+ g_type_map.Append(ConstString("signed wchar_t"), eBasicTypeSignedWChar);
+ g_type_map.Append(ConstString("unsigned wchar_t"),
+ eBasicTypeUnsignedWChar);
+ // "short"
+ g_type_map.Append(ConstString("short"), eBasicTypeShort);
+ g_type_map.Append(ConstString("short int"), eBasicTypeShort);
+ g_type_map.Append(ConstString("unsigned short"), eBasicTypeUnsignedShort);
+ g_type_map.Append(ConstString("unsigned short int"),
+ eBasicTypeUnsignedShort);
+
+ // "int"
+ g_type_map.Append(ConstString("int"), eBasicTypeInt);
+ g_type_map.Append(ConstString("signed int"), eBasicTypeInt);
+ g_type_map.Append(ConstString("unsigned int"), eBasicTypeUnsignedInt);
+ g_type_map.Append(ConstString("unsigned"), eBasicTypeUnsignedInt);
+
+ // "long"
+ g_type_map.Append(ConstString("long"), eBasicTypeLong);
+ g_type_map.Append(ConstString("long int"), eBasicTypeLong);
+ g_type_map.Append(ConstString("unsigned long"), eBasicTypeUnsignedLong);
+ g_type_map.Append(ConstString("unsigned long int"),
+ eBasicTypeUnsignedLong);
+
+ // "long long"
+ g_type_map.Append(ConstString("long long"), eBasicTypeLongLong);
+ g_type_map.Append(ConstString("long long int"), eBasicTypeLongLong);
+ g_type_map.Append(ConstString("unsigned long long"),
+ eBasicTypeUnsignedLongLong);
+ g_type_map.Append(ConstString("unsigned long long int"),
+ eBasicTypeUnsignedLongLong);
+
+ // "int128"
+ g_type_map.Append(ConstString("__int128_t"), eBasicTypeInt128);
+ g_type_map.Append(ConstString("__uint128_t"), eBasicTypeUnsignedInt128);
+
+ // Miscellaneous
+ g_type_map.Append(ConstString("bool"), eBasicTypeBool);
+ g_type_map.Append(ConstString("float"), eBasicTypeFloat);
+ g_type_map.Append(ConstString("double"), eBasicTypeDouble);
+ g_type_map.Append(ConstString("long double"), eBasicTypeLongDouble);
+ g_type_map.Append(ConstString("id"), eBasicTypeObjCID);
+ g_type_map.Append(ConstString("SEL"), eBasicTypeObjCSel);
+ g_type_map.Append(ConstString("nullptr"), eBasicTypeNullPtr);
+ g_type_map.Sort();
+ });
+
+ return g_type_map.Find(name, eBasicTypeInvalid);
+ }
+ return eBasicTypeInvalid;
+}
+
+uint32_t TypeSystemClang::GetPointerByteSize() {
+ if (m_pointer_byte_size == 0)
+ if (auto size = GetBasicType(lldb::eBasicTypeVoid)
+ .GetPointerType()
+ .GetByteSize(nullptr))
+ m_pointer_byte_size = *size;
+ return m_pointer_byte_size;
+}
+
+CompilerType TypeSystemClang::GetBasicType(lldb::BasicType basic_type) {
+ clang::ASTContext &ast = getASTContext();
+
+ lldb::opaque_compiler_type_t clang_type =
+ GetOpaqueCompilerType(&ast, basic_type);
+
+ if (clang_type)
+ return CompilerType(this, clang_type);
+ return CompilerType();
+}
+
+CompilerType TypeSystemClang::GetBuiltinTypeForDWARFEncodingAndBitSize(
+ llvm::StringRef type_name, uint32_t dw_ate, uint32_t bit_size) {
+ ASTContext &ast = getASTContext();
+
+ switch (dw_ate) {
+ default:
+ break;
+
+ case DW_ATE_address:
+ if (QualTypeMatchesBitSize(bit_size, ast, ast.VoidPtrTy))
+ return GetType(ast.VoidPtrTy);
+ break;
+
+ case DW_ATE_boolean:
+ if (QualTypeMatchesBitSize(bit_size, ast, ast.BoolTy))
+ return GetType(ast.BoolTy);
+ if (QualTypeMatchesBitSize(bit_size, ast, ast.UnsignedCharTy))
+ return GetType(ast.UnsignedCharTy);
+ if (QualTypeMatchesBitSize(bit_size, ast, ast.UnsignedShortTy))
+ return GetType(ast.UnsignedShortTy);
+ if (QualTypeMatchesBitSize(bit_size, ast, ast.UnsignedIntTy))
+ return GetType(ast.UnsignedIntTy);
+ break;
+
+ case DW_ATE_lo_user:
+ // This has been seen to mean DW_AT_complex_integer
+ if (type_name.contains("complex")) {
+ CompilerType complex_int_clang_type =
+ GetBuiltinTypeForDWARFEncodingAndBitSize("int", DW_ATE_signed,
+ bit_size / 2);
+ return GetType(
+ ast.getComplexType(ClangUtil::GetQualType(complex_int_clang_type)));
+ }
+ break;
+
+ case DW_ATE_complex_float:
+ if (QualTypeMatchesBitSize(bit_size, ast, ast.FloatComplexTy))
+ return GetType(ast.FloatComplexTy);
+ else if (QualTypeMatchesBitSize(bit_size, ast, ast.DoubleComplexTy))
+ return GetType(ast.DoubleComplexTy);
+ else if (QualTypeMatchesBitSize(bit_size, ast, ast.LongDoubleComplexTy))
+ return GetType(ast.LongDoubleComplexTy);
+ else {
+ CompilerType complex_float_clang_type =
+ GetBuiltinTypeForDWARFEncodingAndBitSize("float", DW_ATE_float,
+ bit_size / 2);
+ return GetType(
+ ast.getComplexType(ClangUtil::GetQualType(complex_float_clang_type)));
+ }
+ break;
+
+ case DW_ATE_float:
+ if (type_name == "float" &&
+ QualTypeMatchesBitSize(bit_size, ast, ast.FloatTy))
+ return GetType(ast.FloatTy);
+ if (type_name == "double" &&
+ QualTypeMatchesBitSize(bit_size, ast, ast.DoubleTy))
+ return GetType(ast.DoubleTy);
+ if (type_name == "long double" &&
+ QualTypeMatchesBitSize(bit_size, ast, ast.LongDoubleTy))
+ return GetType(ast.LongDoubleTy);
+ // Fall back to not requiring a name match
+ if (QualTypeMatchesBitSize(bit_size, ast, ast.FloatTy))
+ return GetType(ast.FloatTy);
+ if (QualTypeMatchesBitSize(bit_size, ast, ast.DoubleTy))
+ return GetType(ast.DoubleTy);
+ if (QualTypeMatchesBitSize(bit_size, ast, ast.LongDoubleTy))
+ return GetType(ast.LongDoubleTy);
+ if (QualTypeMatchesBitSize(bit_size, ast, ast.HalfTy))
+ return GetType(ast.HalfTy);
+ break;
+
+ case DW_ATE_signed:
+ if (!type_name.empty()) {
+ if (type_name == "wchar_t" &&
+ QualTypeMatchesBitSize(bit_size, ast, ast.WCharTy) &&
+ (getTargetInfo() &&
+ TargetInfo::isTypeSigned(getTargetInfo()->getWCharType())))
+ return GetType(ast.WCharTy);
+ if (type_name == "void" &&
+ QualTypeMatchesBitSize(bit_size, ast, ast.VoidTy))
+ return GetType(ast.VoidTy);
+ if (type_name.contains("long long") &&
+ QualTypeMatchesBitSize(bit_size, ast, ast.LongLongTy))
+ return GetType(ast.LongLongTy);
+ if (type_name.contains("long") &&
+ QualTypeMatchesBitSize(bit_size, ast, ast.LongTy))
+ return GetType(ast.LongTy);
+ if (type_name.contains("short") &&
+ QualTypeMatchesBitSize(bit_size, ast, ast.ShortTy))
+ return GetType(ast.ShortTy);
+ if (type_name.contains("char")) {
+ if (QualTypeMatchesBitSize(bit_size, ast, ast.CharTy))
+ return GetType(ast.CharTy);
+ if (QualTypeMatchesBitSize(bit_size, ast, ast.SignedCharTy))
+ return GetType(ast.SignedCharTy);
+ }
+ if (type_name.contains("int")) {
+ if (QualTypeMatchesBitSize(bit_size, ast, ast.IntTy))
+ return GetType(ast.IntTy);
+ if (QualTypeMatchesBitSize(bit_size, ast, ast.Int128Ty))
+ return GetType(ast.Int128Ty);
+ }
+ }
+ // We weren't able to match up a type name, just search by size
+ if (QualTypeMatchesBitSize(bit_size, ast, ast.CharTy))
+ return GetType(ast.CharTy);
+ if (QualTypeMatchesBitSize(bit_size, ast, ast.ShortTy))
+ return GetType(ast.ShortTy);
+ if (QualTypeMatchesBitSize(bit_size, ast, ast.IntTy))
+ return GetType(ast.IntTy);
+ if (QualTypeMatchesBitSize(bit_size, ast, ast.LongTy))
+ return GetType(ast.LongTy);
+ if (QualTypeMatchesBitSize(bit_size, ast, ast.LongLongTy))
+ return GetType(ast.LongLongTy);
+ if (QualTypeMatchesBitSize(bit_size, ast, ast.Int128Ty))
+ return GetType(ast.Int128Ty);
+ break;
+
+ case DW_ATE_signed_char:
+ if (ast.getLangOpts().CharIsSigned && type_name == "char") {
+ if (QualTypeMatchesBitSize(bit_size, ast, ast.CharTy))
+ return GetType(ast.CharTy);
+ }
+ if (QualTypeMatchesBitSize(bit_size, ast, ast.SignedCharTy))
+ return GetType(ast.SignedCharTy);
+ break;
+
+ case DW_ATE_unsigned:
+ if (!type_name.empty()) {
+ if (type_name == "wchar_t") {
+ if (QualTypeMatchesBitSize(bit_size, ast, ast.WCharTy)) {
+ if (!(getTargetInfo() &&
+ TargetInfo::isTypeSigned(getTargetInfo()->getWCharType())))
+ return GetType(ast.WCharTy);
+ }
+ }
+ if (type_name.contains("long long")) {
+ if (QualTypeMatchesBitSize(bit_size, ast, ast.UnsignedLongLongTy))
+ return GetType(ast.UnsignedLongLongTy);
+ } else if (type_name.contains("long")) {
+ if (QualTypeMatchesBitSize(bit_size, ast, ast.UnsignedLongTy))
+ return GetType(ast.UnsignedLongTy);
+ } else if (type_name.contains("short")) {
+ if (QualTypeMatchesBitSize(bit_size, ast, ast.UnsignedShortTy))
+ return GetType(ast.UnsignedShortTy);
+ } else if (type_name.contains("char")) {
+ if (QualTypeMatchesBitSize(bit_size, ast, ast.UnsignedCharTy))
+ return GetType(ast.UnsignedCharTy);
+ } else if (type_name.contains("int")) {
+ if (QualTypeMatchesBitSize(bit_size, ast, ast.UnsignedIntTy))
+ return GetType(ast.UnsignedIntTy);
+ if (QualTypeMatchesBitSize(bit_size, ast, ast.UnsignedInt128Ty))
+ return GetType(ast.UnsignedInt128Ty);
+ }
+ }
+ // We weren't able to match up a type name, just search by size
+ if (QualTypeMatchesBitSize(bit_size, ast, ast.UnsignedCharTy))
+ return GetType(ast.UnsignedCharTy);
+ if (QualTypeMatchesBitSize(bit_size, ast, ast.UnsignedShortTy))
+ return GetType(ast.UnsignedShortTy);
+ if (QualTypeMatchesBitSize(bit_size, ast, ast.UnsignedIntTy))
+ return GetType(ast.UnsignedIntTy);
+ if (QualTypeMatchesBitSize(bit_size, ast, ast.UnsignedLongTy))
+ return GetType(ast.UnsignedLongTy);
+ if (QualTypeMatchesBitSize(bit_size, ast, ast.UnsignedLongLongTy))
+ return GetType(ast.UnsignedLongLongTy);
+ if (QualTypeMatchesBitSize(bit_size, ast, ast.UnsignedInt128Ty))
+ return GetType(ast.UnsignedInt128Ty);
+ break;
+
+ case DW_ATE_unsigned_char:
+ if (!ast.getLangOpts().CharIsSigned && type_name == "char") {
+ if (QualTypeMatchesBitSize(bit_size, ast, ast.CharTy))
+ return GetType(ast.CharTy);
+ }
+ if (QualTypeMatchesBitSize(bit_size, ast, ast.UnsignedCharTy))
+ return GetType(ast.UnsignedCharTy);
+ if (QualTypeMatchesBitSize(bit_size, ast, ast.UnsignedShortTy))
+ return GetType(ast.UnsignedShortTy);
+ break;
+
+ case DW_ATE_imaginary_float:
+ break;
+
+ case DW_ATE_UTF:
+ if (!type_name.empty()) {
+ if (type_name == "char16_t")
+ return GetType(ast.Char16Ty);
+ if (type_name == "char32_t")
+ return GetType(ast.Char32Ty);
+ if (type_name == "char8_t")
+ return GetType(ast.Char8Ty);
+ }
+ break;
+ }
+ // This assert should fire for anything that we don't catch above so we know
+ // to fix any issues we run into.
+ if (!type_name.empty()) {
+ std::string type_name_str = type_name.str();
+ Host::SystemLog(Host::eSystemLogError,
+ "error: need to add support for DW_TAG_base_type '%s' "
+ "encoded with DW_ATE = 0x%x, bit_size = %u\n",
+ type_name_str.c_str(), dw_ate, bit_size);
+ } else {
+ Host::SystemLog(Host::eSystemLogError, "error: need to add support for "
+ "DW_TAG_base_type encoded with "
+ "DW_ATE = 0x%x, bit_size = %u\n",
+ dw_ate, bit_size);
+ }
+ return CompilerType();
+}
+
+CompilerType TypeSystemClang::GetCStringType(bool is_const) {
+ ASTContext &ast = getASTContext();
+ QualType char_type(ast.CharTy);
+
+ if (is_const)
+ char_type.addConst();
+
+ return GetType(ast.getPointerType(char_type));
+}
+
+bool TypeSystemClang::AreTypesSame(CompilerType type1, CompilerType type2,
+ bool ignore_qualifiers) {
+ TypeSystemClang *ast =
+ llvm::dyn_cast_or_null<TypeSystemClang>(type1.GetTypeSystem());
+ if (!ast || ast != type2.GetTypeSystem())
+ return false;
+
+ if (type1.GetOpaqueQualType() == type2.GetOpaqueQualType())
+ return true;
+
+ QualType type1_qual = ClangUtil::GetQualType(type1);
+ QualType type2_qual = ClangUtil::GetQualType(type2);
+
+ if (ignore_qualifiers) {
+ type1_qual = type1_qual.getUnqualifiedType();
+ type2_qual = type2_qual.getUnqualifiedType();
+ }
+
+ return ast->getASTContext().hasSameType(type1_qual, type2_qual);
+}
+
+CompilerType TypeSystemClang::GetTypeForDecl(void *opaque_decl) {
+ if (!opaque_decl)
+ return CompilerType();
+
+ clang::Decl *decl = static_cast<clang::Decl *>(opaque_decl);
+ if (auto *named_decl = llvm::dyn_cast<clang::NamedDecl>(decl))
+ return GetTypeForDecl(named_decl);
+ return CompilerType();
+}
+
+CompilerDeclContext TypeSystemClang::CreateDeclContext(DeclContext *ctx) {
+ // Check that the DeclContext actually belongs to this ASTContext.
+ assert(&ctx->getParentASTContext() == &getASTContext());
+ return CompilerDeclContext(this, ctx);
+}
+
+CompilerType TypeSystemClang::GetTypeForDecl(clang::NamedDecl *decl) {
+ if (clang::ObjCInterfaceDecl *interface_decl =
+ llvm::dyn_cast<clang::ObjCInterfaceDecl>(decl))
+ return GetTypeForDecl(interface_decl);
+ if (clang::TagDecl *tag_decl = llvm::dyn_cast<clang::TagDecl>(decl))
+ return GetTypeForDecl(tag_decl);
+ return CompilerType();
+}
+
+CompilerType TypeSystemClang::GetTypeForDecl(TagDecl *decl) {
+ return GetType(getASTContext().getTagDeclType(decl));
+}
+
+CompilerType TypeSystemClang::GetTypeForDecl(ObjCInterfaceDecl *decl) {
+ return GetType(getASTContext().getObjCInterfaceType(decl));
+}
+
+#pragma mark Structure, Unions, Classes
+
+CompilerType TypeSystemClang::CreateRecordType(DeclContext *decl_ctx,
+ AccessType access_type,
+ llvm::StringRef name, int kind,
+ LanguageType language,
+ ClangASTMetadata *metadata,
+ bool exports_symbols) {
+ ASTContext &ast = getASTContext();
+
+ if (decl_ctx == nullptr)
+ decl_ctx = ast.getTranslationUnitDecl();
+
+ if (language == eLanguageTypeObjC ||
+ language == eLanguageTypeObjC_plus_plus) {
+ bool isForwardDecl = true;
+ bool isInternal = false;
+ return CreateObjCClass(name, decl_ctx, isForwardDecl, isInternal, metadata);
+ }
+
+ // NOTE: Eventually CXXRecordDecl will be merged back into RecordDecl and
+ // we will need to update this code. I was told to currently always use the
+ // CXXRecordDecl class since we often don't know from debug information if
+ // something is struct or a class, so we default to always use the more
+ // complete definition just in case.
+
+ bool has_name = !name.empty();
+
+ CXXRecordDecl *decl = CXXRecordDecl::Create(
+ ast, (TagDecl::TagKind)kind, decl_ctx, SourceLocation(), SourceLocation(),
+ has_name ? &ast.Idents.get(name) : nullptr);
+
+ if (!has_name) {
+ // In C++ a lambda is also represented as an unnamed class. This is
+ // different from an *anonymous class* that the user wrote:
+ //
+ // struct A {
+ // // anonymous class (GNU/MSVC extension)
+ // struct {
+ // int x;
+ // };
+ // // unnamed class within a class
+ // struct {
+ // int y;
+ // } B;
+ // };
+ //
+ // void f() {
+ // // unammed class outside of a class
+ // struct {
+ // int z;
+ // } C;
+ // }
+ //
+ // Anonymous classes is a GNU/MSVC extension that clang supports. It
+ // requires the anonymous class be embedded within a class. So the new
+ // heuristic verifies this condition.
+ if (isa<CXXRecordDecl>(decl_ctx) && exports_symbols)
+ decl->setAnonymousStructOrUnion(true);
+ }
+
+ if (decl) {
+ if (metadata)
+ SetMetadata(decl, *metadata);
+
+ if (access_type != eAccessNone)
+ decl->setAccess(ConvertAccessTypeToAccessSpecifier(access_type));
+
+ if (decl_ctx)
+ decl_ctx->addDecl(decl);
+
+ return GetType(ast.getTagDeclType(decl));
+ }
+ return CompilerType();
+}
+
+namespace {
+ bool IsValueParam(const clang::TemplateArgument &argument) {
+ return argument.getKind() == TemplateArgument::Integral;
+ }
+}
+
+static TemplateParameterList *CreateTemplateParameterList(
+ ASTContext *ast,
+ const TypeSystemClang::TemplateParameterInfos &template_param_infos,
+ llvm::SmallVector<NamedDecl *, 8> &template_param_decls) {
+ const bool parameter_pack = false;
+ const bool is_typename = false;
+ const unsigned depth = 0;
+ const size_t num_template_params = template_param_infos.args.size();
+ DeclContext *const decl_context =
+ ast->getTranslationUnitDecl(); // Is this the right decl context?,
+ for (size_t i = 0; i < num_template_params; ++i) {
+ const char *name = template_param_infos.names[i];
+
+ IdentifierInfo *identifier_info = nullptr;
+ if (name && name[0])
+ identifier_info = &ast->Idents.get(name);
+ if (IsValueParam(template_param_infos.args[i])) {
+ template_param_decls.push_back(NonTypeTemplateParmDecl::Create(
+ *ast, decl_context,
+ SourceLocation(), SourceLocation(), depth, i, identifier_info,
+ template_param_infos.args[i].getIntegralType(), parameter_pack,
+ nullptr));
+
+ } else {
+ template_param_decls.push_back(TemplateTypeParmDecl::Create(
+ *ast, decl_context,
+ SourceLocation(), SourceLocation(), depth, i, identifier_info,
+ is_typename, parameter_pack));
+ }
+ }
+
+ if (template_param_infos.packed_args) {
+ IdentifierInfo *identifier_info = nullptr;
+ if (template_param_infos.pack_name && template_param_infos.pack_name[0])
+ identifier_info = &ast->Idents.get(template_param_infos.pack_name);
+ const bool parameter_pack_true = true;
+
+ if (!template_param_infos.packed_args->args.empty() &&
+ IsValueParam(template_param_infos.packed_args->args[0])) {
+ template_param_decls.push_back(NonTypeTemplateParmDecl::Create(
+ *ast, decl_context, SourceLocation(), SourceLocation(), depth,
+ num_template_params, identifier_info,
+ template_param_infos.packed_args->args[0].getIntegralType(),
+ parameter_pack_true, nullptr));
+ } else {
+ template_param_decls.push_back(TemplateTypeParmDecl::Create(
+ *ast, decl_context, SourceLocation(), SourceLocation(), depth,
+ num_template_params, identifier_info, is_typename,
+ parameter_pack_true));
+ }
+ }
+ clang::Expr *const requires_clause = nullptr; // TODO: Concepts
+ TemplateParameterList *template_param_list = TemplateParameterList::Create(
+ *ast, SourceLocation(), SourceLocation(), template_param_decls,
+ SourceLocation(), requires_clause);
+ return template_param_list;
+}
+
+clang::FunctionTemplateDecl *TypeSystemClang::CreateFunctionTemplateDecl(
+ clang::DeclContext *decl_ctx, clang::FunctionDecl *func_decl,
+ const char *name, const TemplateParameterInfos &template_param_infos) {
+ // /// Create a function template node.
+ ASTContext &ast = getASTContext();
+
+ llvm::SmallVector<NamedDecl *, 8> template_param_decls;
+
+ TemplateParameterList *template_param_list = CreateTemplateParameterList(
+ &ast, template_param_infos, template_param_decls);
+ FunctionTemplateDecl *func_tmpl_decl = FunctionTemplateDecl::Create(
+ ast, decl_ctx, func_decl->getLocation(), func_decl->getDeclName(),
+ template_param_list, func_decl);
+
+ for (size_t i = 0, template_param_decl_count = template_param_decls.size();
+ i < template_param_decl_count; ++i) {
+ // TODO: verify which decl context we should put template_param_decls into..
+ template_param_decls[i]->setDeclContext(func_decl);
+ }
+ // Function templates inside a record need to have an access specifier.
+ // It doesn't matter what access specifier we give the template as LLDB
+ // anyway allows accessing everything inside a record.
+ if (decl_ctx->isRecord())
+ func_tmpl_decl->setAccess(clang::AccessSpecifier::AS_public);
+
+ return func_tmpl_decl;
+}
+
+void TypeSystemClang::CreateFunctionTemplateSpecializationInfo(
+ FunctionDecl *func_decl, clang::FunctionTemplateDecl *func_tmpl_decl,
+ const TemplateParameterInfos &infos) {
+ TemplateArgumentList *template_args_ptr =
+ TemplateArgumentList::CreateCopy(func_decl->getASTContext(), infos.args);
+
+ func_decl->setFunctionTemplateSpecialization(func_tmpl_decl,
+ template_args_ptr, nullptr);
+}
+
+ClassTemplateDecl *TypeSystemClang::CreateClassTemplateDecl(
+ DeclContext *decl_ctx, lldb::AccessType access_type, const char *class_name,
+ int kind, const TemplateParameterInfos &template_param_infos) {
+ ASTContext &ast = getASTContext();
+
+ ClassTemplateDecl *class_template_decl = nullptr;
+ if (decl_ctx == nullptr)
+ decl_ctx = ast.getTranslationUnitDecl();
+
+ IdentifierInfo &identifier_info = ast.Idents.get(class_name);
+ DeclarationName decl_name(&identifier_info);
+
+ clang::DeclContext::lookup_result result = decl_ctx->lookup(decl_name);
+
+ for (NamedDecl *decl : result) {
+ class_template_decl = dyn_cast<clang::ClassTemplateDecl>(decl);
+ if (class_template_decl)
+ return class_template_decl;
+ }
+
+ llvm::SmallVector<NamedDecl *, 8> template_param_decls;
+
+ TemplateParameterList *template_param_list = CreateTemplateParameterList(
+ &ast, template_param_infos, template_param_decls);
+
+ CXXRecordDecl *template_cxx_decl = CXXRecordDecl::Create(
+ ast, (TagDecl::TagKind)kind,
+ decl_ctx, // What decl context do we use here? TU? The actual decl
+ // context?
+ SourceLocation(), SourceLocation(), &identifier_info);
+
+ for (size_t i = 0, template_param_decl_count = template_param_decls.size();
+ i < template_param_decl_count; ++i) {
+ template_param_decls[i]->setDeclContext(template_cxx_decl);
+ }
+
+ // With templated classes, we say that a class is templated with
+ // specializations, but that the bare class has no functions.
+ // template_cxx_decl->startDefinition();
+ // template_cxx_decl->completeDefinition();
+
+ class_template_decl = ClassTemplateDecl::Create(
+ ast,
+ decl_ctx, // What decl context do we use here? TU? The actual decl
+ // context?
+ SourceLocation(), decl_name, template_param_list, template_cxx_decl);
+ template_cxx_decl->setDescribedClassTemplate(class_template_decl);
+
+ if (class_template_decl) {
+ if (access_type != eAccessNone)
+ class_template_decl->setAccess(
+ ConvertAccessTypeToAccessSpecifier(access_type));
+
+ // if (TagDecl *ctx_tag_decl = dyn_cast<TagDecl>(decl_ctx))
+ // CompleteTagDeclarationDefinition(GetTypeForDecl(ctx_tag_decl));
+
+ decl_ctx->addDecl(class_template_decl);
+
+#ifdef LLDB_CONFIGURATION_DEBUG
+ VerifyDecl(class_template_decl);
+#endif
+ }
+
+ return class_template_decl;
+}
+
+TemplateTemplateParmDecl *
+TypeSystemClang::CreateTemplateTemplateParmDecl(const char *template_name) {
+ ASTContext &ast = getASTContext();
+
+ auto *decl_ctx = ast.getTranslationUnitDecl();
+
+ IdentifierInfo &identifier_info = ast.Idents.get(template_name);
+ llvm::SmallVector<NamedDecl *, 8> template_param_decls;
+
+ TypeSystemClang::TemplateParameterInfos template_param_infos;
+ TemplateParameterList *template_param_list = CreateTemplateParameterList(
+ &ast, template_param_infos, template_param_decls);
+
+ // LLDB needs to create those decls only to be able to display a
+ // type that includes a template template argument. Only the name matters for
+ // this purpose, so we use dummy values for the other characterisitcs of the
+ // type.
+ return TemplateTemplateParmDecl::Create(
+ ast, decl_ctx, SourceLocation(),
+ /*Depth*/ 0, /*Position*/ 0,
+ /*IsParameterPack*/ false, &identifier_info, template_param_list);
+}
+
+ClassTemplateSpecializationDecl *
+TypeSystemClang::CreateClassTemplateSpecializationDecl(
+ DeclContext *decl_ctx, ClassTemplateDecl *class_template_decl, int kind,
+ const TemplateParameterInfos &template_param_infos) {
+ ASTContext &ast = getASTContext();
+ llvm::SmallVector<clang::TemplateArgument, 2> args(
+ template_param_infos.args.size() +
+ (template_param_infos.packed_args ? 1 : 0));
+ std::copy(template_param_infos.args.begin(), template_param_infos.args.end(),
+ args.begin());
+ if (template_param_infos.packed_args) {
+ args[args.size() - 1] = TemplateArgument::CreatePackCopy(
+ ast, template_param_infos.packed_args->args);
+ }
+ ClassTemplateSpecializationDecl *class_template_specialization_decl =
+ ClassTemplateSpecializationDecl::Create(
+ ast, (TagDecl::TagKind)kind, decl_ctx, SourceLocation(),
+ SourceLocation(), class_template_decl, args, nullptr);
+
+ class_template_specialization_decl->setSpecializationKind(
+ TSK_ExplicitSpecialization);
+
+ return class_template_specialization_decl;
+}
+
+CompilerType TypeSystemClang::CreateClassTemplateSpecializationType(
+ ClassTemplateSpecializationDecl *class_template_specialization_decl) {
+ if (class_template_specialization_decl) {
+ ASTContext &ast = getASTContext();
+ return GetType(ast.getTagDeclType(class_template_specialization_decl));
+ }
+ return CompilerType();
+}
+
+static inline bool check_op_param(bool is_method,
+ clang::OverloadedOperatorKind op_kind,
+ bool unary, bool binary,
+ uint32_t num_params) {
+ // Special-case call since it can take any number of operands
+ if (op_kind == OO_Call)
+ return true;
+
+ // The parameter count doesn't include "this"
+ if (is_method)
+ ++num_params;
+ if (num_params == 1)
+ return unary;
+ if (num_params == 2)
+ return binary;
+ else
+ return false;
+}
+
+bool TypeSystemClang::CheckOverloadedOperatorKindParameterCount(
+ bool is_method, clang::OverloadedOperatorKind op_kind,
+ uint32_t num_params) {
+ switch (op_kind) {
+ default:
+ break;
+ // C++ standard allows any number of arguments to new/delete
+ case OO_New:
+ case OO_Array_New:
+ case OO_Delete:
+ case OO_Array_Delete:
+ return true;
+ }
+
+#define OVERLOADED_OPERATOR(Name, Spelling, Token, Unary, Binary, MemberOnly) \
+ case OO_##Name: \
+ return check_op_param(is_method, op_kind, Unary, Binary, num_params);
+ switch (op_kind) {
+#include "clang/Basic/OperatorKinds.def"
+ default:
+ break;
+ }
+ return false;
+}
+
+clang::AccessSpecifier
+TypeSystemClang::UnifyAccessSpecifiers(clang::AccessSpecifier lhs,
+ clang::AccessSpecifier rhs) {
+ // Make the access equal to the stricter of the field and the nested field's
+ // access
+ if (lhs == AS_none || rhs == AS_none)
+ return AS_none;
+ if (lhs == AS_private || rhs == AS_private)
+ return AS_private;
+ if (lhs == AS_protected || rhs == AS_protected)
+ return AS_protected;
+ return AS_public;
+}
+
+bool TypeSystemClang::FieldIsBitfield(FieldDecl *field,
+ uint32_t &bitfield_bit_size) {
+ ASTContext &ast = getASTContext();
+ if (field == nullptr)
+ return false;
+
+ if (field->isBitField()) {
+ Expr *bit_width_expr = field->getBitWidth();
+ if (bit_width_expr) {
+ llvm::APSInt bit_width_apsint;
+ if (bit_width_expr->isIntegerConstantExpr(bit_width_apsint, ast)) {
+ bitfield_bit_size = bit_width_apsint.getLimitedValue(UINT32_MAX);
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+bool TypeSystemClang::RecordHasFields(const RecordDecl *record_decl) {
+ if (record_decl == nullptr)
+ return false;
+
+ if (!record_decl->field_empty())
+ return true;
+
+ // No fields, lets check this is a CXX record and check the base classes
+ const CXXRecordDecl *cxx_record_decl = dyn_cast<CXXRecordDecl>(record_decl);
+ if (cxx_record_decl) {
+ CXXRecordDecl::base_class_const_iterator base_class, base_class_end;
+ for (base_class = cxx_record_decl->bases_begin(),
+ base_class_end = cxx_record_decl->bases_end();
+ base_class != base_class_end; ++base_class) {
+ const CXXRecordDecl *base_class_decl = cast<CXXRecordDecl>(
+ base_class->getType()->getAs<RecordType>()->getDecl());
+ if (RecordHasFields(base_class_decl))
+ return true;
+ }
+ }
+ return false;
+}
+
+#pragma mark Objective-C Classes
+
+CompilerType TypeSystemClang::CreateObjCClass(llvm::StringRef name,
+ DeclContext *decl_ctx,
+ bool isForwardDecl,
+ bool isInternal,
+ ClangASTMetadata *metadata) {
+ ASTContext &ast = getASTContext();
+ assert(!name.empty());
+ if (decl_ctx == nullptr)
+ decl_ctx = ast.getTranslationUnitDecl();
+
+ ObjCInterfaceDecl *decl = ObjCInterfaceDecl::Create(
+ ast, decl_ctx, SourceLocation(), &ast.Idents.get(name), nullptr, nullptr,
+ SourceLocation(),
+ /*isForwardDecl,*/
+ isInternal);
+
+ if (decl && metadata)
+ SetMetadata(decl, *metadata);
+
+ return GetType(ast.getObjCInterfaceType(decl));
+}
+
+static inline bool BaseSpecifierIsEmpty(const CXXBaseSpecifier *b) {
+ return !TypeSystemClang::RecordHasFields(b->getType()->getAsCXXRecordDecl());
+}
+
+uint32_t
+TypeSystemClang::GetNumBaseClasses(const CXXRecordDecl *cxx_record_decl,
+ bool omit_empty_base_classes) {
+ uint32_t num_bases = 0;
+ if (cxx_record_decl) {
+ if (omit_empty_base_classes) {
+ CXXRecordDecl::base_class_const_iterator base_class, base_class_end;
+ for (base_class = cxx_record_decl->bases_begin(),
+ base_class_end = cxx_record_decl->bases_end();
+ base_class != base_class_end; ++base_class) {
+ // Skip empty base classes
+ if (omit_empty_base_classes) {
+ if (BaseSpecifierIsEmpty(base_class))
+ continue;
+ }
+ ++num_bases;
+ }
+ } else
+ num_bases = cxx_record_decl->getNumBases();
+ }
+ return num_bases;
+}
+
+#pragma mark Namespace Declarations
+
+NamespaceDecl *TypeSystemClang::GetUniqueNamespaceDeclaration(
+ const char *name, DeclContext *decl_ctx, bool is_inline) {
+ NamespaceDecl *namespace_decl = nullptr;
+ ASTContext &ast = getASTContext();
+ TranslationUnitDecl *translation_unit_decl = ast.getTranslationUnitDecl();
+ if (decl_ctx == nullptr)
+ decl_ctx = translation_unit_decl;
+
+ if (name) {
+ IdentifierInfo &identifier_info = ast.Idents.get(name);
+ DeclarationName decl_name(&identifier_info);
+ clang::DeclContext::lookup_result result = decl_ctx->lookup(decl_name);
+ for (NamedDecl *decl : result) {
+ namespace_decl = dyn_cast<clang::NamespaceDecl>(decl);
+ if (namespace_decl)
+ return namespace_decl;
+ }
+
+ namespace_decl =
+ NamespaceDecl::Create(ast, decl_ctx, is_inline, SourceLocation(),
+ SourceLocation(), &identifier_info, nullptr);
+
+ decl_ctx->addDecl(namespace_decl);
+ } else {
+ if (decl_ctx == translation_unit_decl) {
+ namespace_decl = translation_unit_decl->getAnonymousNamespace();
+ if (namespace_decl)
+ return namespace_decl;
+
+ namespace_decl =
+ NamespaceDecl::Create(ast, decl_ctx, false, SourceLocation(),
+ SourceLocation(), nullptr, nullptr);
+ translation_unit_decl->setAnonymousNamespace(namespace_decl);
+ translation_unit_decl->addDecl(namespace_decl);
+ assert(namespace_decl == translation_unit_decl->getAnonymousNamespace());
+ } else {
+ NamespaceDecl *parent_namespace_decl = cast<NamespaceDecl>(decl_ctx);
+ if (parent_namespace_decl) {
+ namespace_decl = parent_namespace_decl->getAnonymousNamespace();
+ if (namespace_decl)
+ return namespace_decl;
+ namespace_decl =
+ NamespaceDecl::Create(ast, decl_ctx, false, SourceLocation(),
+ SourceLocation(), nullptr, nullptr);
+ parent_namespace_decl->setAnonymousNamespace(namespace_decl);
+ parent_namespace_decl->addDecl(namespace_decl);
+ assert(namespace_decl ==
+ parent_namespace_decl->getAnonymousNamespace());
+ } else {
+ assert(false && "GetUniqueNamespaceDeclaration called with no name and "
+ "no namespace as decl_ctx");
+ }
+ }
+ }
+#ifdef LLDB_CONFIGURATION_DEBUG
+ VerifyDecl(namespace_decl);
+#endif
+ return namespace_decl;
+}
+
+clang::BlockDecl *
+TypeSystemClang::CreateBlockDeclaration(clang::DeclContext *ctx) {
+ if (ctx != nullptr) {
+ clang::BlockDecl *decl =
+ clang::BlockDecl::Create(getASTContext(), ctx, clang::SourceLocation());
+ ctx->addDecl(decl);
+ return decl;
+ }
+ return nullptr;
+}
+
+clang::DeclContext *FindLCABetweenDecls(clang::DeclContext *left,
+ clang::DeclContext *right,
+ clang::DeclContext *root) {
+ if (root == nullptr)
+ return nullptr;
+
+ std::set<clang::DeclContext *> path_left;
+ for (clang::DeclContext *d = left; d != nullptr; d = d->getParent())
+ path_left.insert(d);
+
+ for (clang::DeclContext *d = right; d != nullptr; d = d->getParent())
+ if (path_left.find(d) != path_left.end())
+ return d;
+
+ return nullptr;
+}
+
+clang::UsingDirectiveDecl *TypeSystemClang::CreateUsingDirectiveDeclaration(
+ clang::DeclContext *decl_ctx, clang::NamespaceDecl *ns_decl) {
+ if (decl_ctx != nullptr && ns_decl != nullptr) {
+ auto *translation_unit = getASTContext().getTranslationUnitDecl();
+ clang::UsingDirectiveDecl *using_decl = clang::UsingDirectiveDecl::Create(
+ getASTContext(), decl_ctx, clang::SourceLocation(),
+ clang::SourceLocation(), clang::NestedNameSpecifierLoc(),
+ clang::SourceLocation(), ns_decl,
+ FindLCABetweenDecls(decl_ctx, ns_decl, translation_unit));
+ decl_ctx->addDecl(using_decl);
+ return using_decl;
+ }
+ return nullptr;
+}
+
+clang::UsingDecl *
+TypeSystemClang::CreateUsingDeclaration(clang::DeclContext *current_decl_ctx,
+ clang::NamedDecl *target) {
+ if (current_decl_ctx != nullptr && target != nullptr) {
+ clang::UsingDecl *using_decl = clang::UsingDecl::Create(
+ getASTContext(), current_decl_ctx, clang::SourceLocation(),
+ clang::NestedNameSpecifierLoc(), clang::DeclarationNameInfo(), false);
+ clang::UsingShadowDecl *shadow_decl = clang::UsingShadowDecl::Create(
+ getASTContext(), current_decl_ctx, clang::SourceLocation(), using_decl,
+ target);
+ using_decl->addShadowDecl(shadow_decl);
+ current_decl_ctx->addDecl(using_decl);
+ return using_decl;
+ }
+ return nullptr;
+}
+
+clang::VarDecl *TypeSystemClang::CreateVariableDeclaration(
+ clang::DeclContext *decl_context, const char *name, clang::QualType type) {
+ if (decl_context != nullptr) {
+ clang::VarDecl *var_decl = clang::VarDecl::Create(
+ getASTContext(), decl_context, clang::SourceLocation(),
+ clang::SourceLocation(),
+ name && name[0] ? &getASTContext().Idents.getOwn(name) : nullptr, type,
+ nullptr, clang::SC_None);
+ var_decl->setAccess(clang::AS_public);
+ decl_context->addDecl(var_decl);
+ return var_decl;
+ }
+ return nullptr;
+}
+
+lldb::opaque_compiler_type_t
+TypeSystemClang::GetOpaqueCompilerType(clang::ASTContext *ast,
+ lldb::BasicType basic_type) {
+ switch (basic_type) {
+ case eBasicTypeVoid:
+ return ast->VoidTy.getAsOpaquePtr();
+ case eBasicTypeChar:
+ return ast->CharTy.getAsOpaquePtr();
+ case eBasicTypeSignedChar:
+ return ast->SignedCharTy.getAsOpaquePtr();
+ case eBasicTypeUnsignedChar:
+ return ast->UnsignedCharTy.getAsOpaquePtr();
+ case eBasicTypeWChar:
+ return ast->getWCharType().getAsOpaquePtr();
+ case eBasicTypeSignedWChar:
+ return ast->getSignedWCharType().getAsOpaquePtr();
+ case eBasicTypeUnsignedWChar:
+ return ast->getUnsignedWCharType().getAsOpaquePtr();
+ case eBasicTypeChar16:
+ return ast->Char16Ty.getAsOpaquePtr();
+ case eBasicTypeChar32:
+ return ast->Char32Ty.getAsOpaquePtr();
+ case eBasicTypeShort:
+ return ast->ShortTy.getAsOpaquePtr();
+ case eBasicTypeUnsignedShort:
+ return ast->UnsignedShortTy.getAsOpaquePtr();
+ case eBasicTypeInt:
+ return ast->IntTy.getAsOpaquePtr();
+ case eBasicTypeUnsignedInt:
+ return ast->UnsignedIntTy.getAsOpaquePtr();
+ case eBasicTypeLong:
+ return ast->LongTy.getAsOpaquePtr();
+ case eBasicTypeUnsignedLong:
+ return ast->UnsignedLongTy.getAsOpaquePtr();
+ case eBasicTypeLongLong:
+ return ast->LongLongTy.getAsOpaquePtr();
+ case eBasicTypeUnsignedLongLong:
+ return ast->UnsignedLongLongTy.getAsOpaquePtr();
+ case eBasicTypeInt128:
+ return ast->Int128Ty.getAsOpaquePtr();
+ case eBasicTypeUnsignedInt128:
+ return ast->UnsignedInt128Ty.getAsOpaquePtr();
+ case eBasicTypeBool:
+ return ast->BoolTy.getAsOpaquePtr();
+ case eBasicTypeHalf:
+ return ast->HalfTy.getAsOpaquePtr();
+ case eBasicTypeFloat:
+ return ast->FloatTy.getAsOpaquePtr();
+ case eBasicTypeDouble:
+ return ast->DoubleTy.getAsOpaquePtr();
+ case eBasicTypeLongDouble:
+ return ast->LongDoubleTy.getAsOpaquePtr();
+ case eBasicTypeFloatComplex:
+ return ast->FloatComplexTy.getAsOpaquePtr();
+ case eBasicTypeDoubleComplex:
+ return ast->DoubleComplexTy.getAsOpaquePtr();
+ case eBasicTypeLongDoubleComplex:
+ return ast->LongDoubleComplexTy.getAsOpaquePtr();
+ case eBasicTypeObjCID:
+ return ast->getObjCIdType().getAsOpaquePtr();
+ case eBasicTypeObjCClass:
+ return ast->getObjCClassType().getAsOpaquePtr();
+ case eBasicTypeObjCSel:
+ return ast->getObjCSelType().getAsOpaquePtr();
+ case eBasicTypeNullPtr:
+ return ast->NullPtrTy.getAsOpaquePtr();
+ default:
+ return nullptr;
+ }
+}
+
+#pragma mark Function Types
+
+clang::DeclarationName
+TypeSystemClang::GetDeclarationName(const char *name,
+ const CompilerType &function_clang_type) {
+ if (!name || !name[0])
+ return clang::DeclarationName();
+
+ clang::OverloadedOperatorKind op_kind = clang::NUM_OVERLOADED_OPERATORS;
+ if (!IsOperator(name, op_kind) || op_kind == clang::NUM_OVERLOADED_OPERATORS)
+ return DeclarationName(&getASTContext().Idents.get(
+ name)); // Not operator, but a regular function.
+
+ // Check the number of operator parameters. Sometimes we have seen bad DWARF
+ // that doesn't correctly describe operators and if we try to create a method
+ // and add it to the class, clang will assert and crash, so we need to make
+ // sure things are acceptable.
+ clang::QualType method_qual_type(ClangUtil::GetQualType(function_clang_type));
+ const clang::FunctionProtoType *function_type =
+ llvm::dyn_cast<clang::FunctionProtoType>(method_qual_type.getTypePtr());
+ if (function_type == nullptr)
+ return clang::DeclarationName();
+
+ const bool is_method = false;
+ const unsigned int num_params = function_type->getNumParams();
+ if (!TypeSystemClang::CheckOverloadedOperatorKindParameterCount(
+ is_method, op_kind, num_params))
+ return clang::DeclarationName();
+
+ return getASTContext().DeclarationNames.getCXXOperatorName(op_kind);
+}
+
+FunctionDecl *TypeSystemClang::CreateFunctionDeclaration(
+ DeclContext *decl_ctx, const char *name,
+ const CompilerType &function_clang_type, int storage, bool is_inline) {
+ FunctionDecl *func_decl = nullptr;
+ ASTContext &ast = getASTContext();
+ if (decl_ctx == nullptr)
+ decl_ctx = ast.getTranslationUnitDecl();
+
+ const bool hasWrittenPrototype = true;
+ const bool isConstexprSpecified = false;
+
+ clang::DeclarationName declarationName =
+ GetDeclarationName(name, function_clang_type);
+ func_decl = FunctionDecl::Create(
+ ast, decl_ctx, SourceLocation(), SourceLocation(), declarationName,
+ ClangUtil::GetQualType(function_clang_type), nullptr,
+ (clang::StorageClass)storage, is_inline, hasWrittenPrototype,
+ isConstexprSpecified ? CSK_constexpr : CSK_unspecified);
+ if (func_decl)
+ decl_ctx->addDecl(func_decl);
+
+#ifdef LLDB_CONFIGURATION_DEBUG
+ VerifyDecl(func_decl);
+#endif
+
+ return func_decl;
+}
+
+CompilerType
+TypeSystemClang::CreateFunctionType(const CompilerType &result_type,
+ const CompilerType *args, unsigned num_args,
+ bool is_variadic, unsigned type_quals,
+ clang::CallingConv cc) {
+ if (!result_type || !ClangUtil::IsClangType(result_type))
+ return CompilerType(); // invalid return type
+
+ std::vector<QualType> qual_type_args;
+ if (num_args > 0 && args == nullptr)
+ return CompilerType(); // invalid argument array passed in
+
+ // Verify that all arguments are valid and the right type
+ for (unsigned i = 0; i < num_args; ++i) {
+ if (args[i]) {
+ // Make sure we have a clang type in args[i] and not a type from another
+ // language whose name might match
+ const bool is_clang_type = ClangUtil::IsClangType(args[i]);
+ lldbassert(is_clang_type);
+ if (is_clang_type)
+ qual_type_args.push_back(ClangUtil::GetQualType(args[i]));
+ else
+ return CompilerType(); // invalid argument type (must be a clang type)
+ } else
+ return CompilerType(); // invalid argument type (empty)
+ }
+
+ // TODO: Detect calling convention in DWARF?
+ FunctionProtoType::ExtProtoInfo proto_info;
+ proto_info.ExtInfo = cc;
+ proto_info.Variadic = is_variadic;
+ proto_info.ExceptionSpec = EST_None;
+ proto_info.TypeQuals = clang::Qualifiers::fromFastMask(type_quals);
+ proto_info.RefQualifier = RQ_None;
+
+ return GetType(getASTContext().getFunctionType(
+ ClangUtil::GetQualType(result_type), qual_type_args, proto_info));
+}
+
+ParmVarDecl *TypeSystemClang::CreateParameterDeclaration(
+ clang::DeclContext *decl_ctx, const char *name,
+ const CompilerType ¶m_type, int storage, bool add_decl) {
+ ASTContext &ast = getASTContext();
+ auto *decl =
+ ParmVarDecl::Create(ast, decl_ctx, SourceLocation(), SourceLocation(),
+ name && name[0] ? &ast.Idents.get(name) : nullptr,
+ ClangUtil::GetQualType(param_type), nullptr,
+ (clang::StorageClass)storage, nullptr);
+ if (add_decl)
+ decl_ctx->addDecl(decl);
+
+ return decl;
+}
+
+void TypeSystemClang::SetFunctionParameters(FunctionDecl *function_decl,
+ ParmVarDecl **params,
+ unsigned num_params) {
+ if (function_decl)
+ function_decl->setParams(ArrayRef<ParmVarDecl *>(params, num_params));
+}
+
+CompilerType
+TypeSystemClang::CreateBlockPointerType(const CompilerType &function_type) {
+ QualType block_type = m_ast_up->getBlockPointerType(
+ clang::QualType::getFromOpaquePtr(function_type.GetOpaqueQualType()));
+
+ return GetType(block_type);
+}
+
+#pragma mark Array Types
+
+CompilerType TypeSystemClang::CreateArrayType(const CompilerType &element_type,
+ size_t element_count,
+ bool is_vector) {
+ if (element_type.IsValid()) {
+ ASTContext &ast = getASTContext();
+
+ if (is_vector) {
+ return GetType(ast.getExtVectorType(ClangUtil::GetQualType(element_type),
+ element_count));
+ } else {
+
+ llvm::APInt ap_element_count(64, element_count);
+ if (element_count == 0) {
+ return GetType(ast.getIncompleteArrayType(
+ ClangUtil::GetQualType(element_type), clang::ArrayType::Normal, 0));
+ } else {
+ return GetType(ast.getConstantArrayType(
+ ClangUtil::GetQualType(element_type), ap_element_count, nullptr,
+ clang::ArrayType::Normal, 0));
+ }
+ }
+ }
+ return CompilerType();
+}
+
+CompilerType TypeSystemClang::CreateStructForIdentifier(
+ ConstString type_name,
+ const std::initializer_list<std::pair<const char *, CompilerType>>
+ &type_fields,
+ bool packed) {
+ CompilerType type;
+ if (!type_name.IsEmpty() &&
+ (type = GetTypeForIdentifier<clang::CXXRecordDecl>(type_name))
+ .IsValid()) {
+ lldbassert(0 && "Trying to create a type for an existing name");
+ return type;
+ }
+
+ type = CreateRecordType(nullptr, lldb::eAccessPublic, type_name.GetCString(),
+ clang::TTK_Struct, lldb::eLanguageTypeC);
+ StartTagDeclarationDefinition(type);
+ for (const auto &field : type_fields)
+ AddFieldToRecordType(type, field.first, field.second, lldb::eAccessPublic,
+ 0);
+ if (packed)
+ SetIsPacked(type);
+ CompleteTagDeclarationDefinition(type);
+ return type;
+}
+
+CompilerType TypeSystemClang::GetOrCreateStructForIdentifier(
+ ConstString type_name,
+ const std::initializer_list<std::pair<const char *, CompilerType>>
+ &type_fields,
+ bool packed) {
+ CompilerType type;
+ if ((type = GetTypeForIdentifier<clang::CXXRecordDecl>(type_name)).IsValid())
+ return type;
+
+ return CreateStructForIdentifier(type_name, type_fields, packed);
+}
+
+#pragma mark Enumeration Types
+
+CompilerType
+TypeSystemClang::CreateEnumerationType(const char *name, DeclContext *decl_ctx,
+ const Declaration &decl,
+ const CompilerType &integer_clang_type,
+ bool is_scoped) {
+ // TODO: Do something intelligent with the Declaration object passed in
+ // like maybe filling in the SourceLocation with it...
+ ASTContext &ast = getASTContext();
+
+ // TODO: ask about these...
+ // const bool IsFixed = false;
+
+ EnumDecl *enum_decl = EnumDecl::Create(
+ ast, decl_ctx, SourceLocation(), SourceLocation(),
+ name && name[0] ? &ast.Idents.get(name) : nullptr, nullptr,
+ is_scoped, // IsScoped
+ is_scoped, // IsScopedUsingClassTag
+ false); // IsFixed
+
+ if (enum_decl) {
+ if (decl_ctx)
+ decl_ctx->addDecl(enum_decl);
+
+ // TODO: check if we should be setting the promotion type too?
+ enum_decl->setIntegerType(ClangUtil::GetQualType(integer_clang_type));
+
+ enum_decl->setAccess(AS_public); // TODO respect what's in the debug info
+
+ return GetType(ast.getTagDeclType(enum_decl));
+ }
+ return CompilerType();
+}
+
+CompilerType TypeSystemClang::GetIntTypeFromBitSize(size_t bit_size,
+ bool is_signed) {
+ clang::ASTContext &ast = getASTContext();
+
+ if (is_signed) {
+ if (bit_size == ast.getTypeSize(ast.SignedCharTy))
+ return GetType(ast.SignedCharTy);
+
+ if (bit_size == ast.getTypeSize(ast.ShortTy))
+ return GetType(ast.ShortTy);
+
+ if (bit_size == ast.getTypeSize(ast.IntTy))
+ return GetType(ast.IntTy);
+
+ if (bit_size == ast.getTypeSize(ast.LongTy))
+ return GetType(ast.LongTy);
+
+ if (bit_size == ast.getTypeSize(ast.LongLongTy))
+ return GetType(ast.LongLongTy);
+
+ if (bit_size == ast.getTypeSize(ast.Int128Ty))
+ return GetType(ast.Int128Ty);
+ } else {
+ if (bit_size == ast.getTypeSize(ast.UnsignedCharTy))
+ return GetType(ast.UnsignedCharTy);
+
+ if (bit_size == ast.getTypeSize(ast.UnsignedShortTy))
+ return GetType(ast.UnsignedShortTy);
+
+ if (bit_size == ast.getTypeSize(ast.UnsignedIntTy))
+ return GetType(ast.UnsignedIntTy);
+
+ if (bit_size == ast.getTypeSize(ast.UnsignedLongTy))
+ return GetType(ast.UnsignedLongTy);
+
+ if (bit_size == ast.getTypeSize(ast.UnsignedLongLongTy))
+ return GetType(ast.UnsignedLongLongTy);
+
+ if (bit_size == ast.getTypeSize(ast.UnsignedInt128Ty))
+ return GetType(ast.UnsignedInt128Ty);
+ }
+ return CompilerType();
+}
+
+CompilerType TypeSystemClang::GetPointerSizedIntType(bool is_signed) {
+ return GetIntTypeFromBitSize(
+ getASTContext().getTypeSize(getASTContext().VoidPtrTy), is_signed);
+}
+
+void TypeSystemClang::DumpDeclContextHiearchy(clang::DeclContext *decl_ctx) {
+ if (decl_ctx) {
+ DumpDeclContextHiearchy(decl_ctx->getParent());
+
+ clang::NamedDecl *named_decl = llvm::dyn_cast<clang::NamedDecl>(decl_ctx);
+ if (named_decl) {
+ printf("%20s: %s\n", decl_ctx->getDeclKindName(),
+ named_decl->getDeclName().getAsString().c_str());
+ } else {
+ printf("%20s\n", decl_ctx->getDeclKindName());
+ }
+ }
+}
+
+void TypeSystemClang::DumpDeclHiearchy(clang::Decl *decl) {
+ if (decl == nullptr)
+ return;
+ DumpDeclContextHiearchy(decl->getDeclContext());
+
+ clang::RecordDecl *record_decl = llvm::dyn_cast<clang::RecordDecl>(decl);
+ if (record_decl) {
+ printf("%20s: %s%s\n", decl->getDeclKindName(),
+ record_decl->getDeclName().getAsString().c_str(),
+ record_decl->isInjectedClassName() ? " (injected class name)" : "");
+
+ } else {
+ clang::NamedDecl *named_decl = llvm::dyn_cast<clang::NamedDecl>(decl);
+ if (named_decl) {
+ printf("%20s: %s\n", decl->getDeclKindName(),
+ named_decl->getDeclName().getAsString().c_str());
+ } else {
+ printf("%20s\n", decl->getDeclKindName());
+ }
+ }
+}
+
+bool TypeSystemClang::DeclsAreEquivalent(clang::Decl *lhs_decl,
+ clang::Decl *rhs_decl) {
+ if (lhs_decl && rhs_decl) {
+ // Make sure the decl kinds match first
+ const clang::Decl::Kind lhs_decl_kind = lhs_decl->getKind();
+ const clang::Decl::Kind rhs_decl_kind = rhs_decl->getKind();
+
+ if (lhs_decl_kind == rhs_decl_kind) {
+ // Now check that the decl contexts kinds are all equivalent before we
+ // have to check any names of the decl contexts...
+ clang::DeclContext *lhs_decl_ctx = lhs_decl->getDeclContext();
+ clang::DeclContext *rhs_decl_ctx = rhs_decl->getDeclContext();
+ if (lhs_decl_ctx && rhs_decl_ctx) {
+ while (true) {
+ if (lhs_decl_ctx && rhs_decl_ctx) {
+ const clang::Decl::Kind lhs_decl_ctx_kind =
+ lhs_decl_ctx->getDeclKind();
+ const clang::Decl::Kind rhs_decl_ctx_kind =
+ rhs_decl_ctx->getDeclKind();
+ if (lhs_decl_ctx_kind == rhs_decl_ctx_kind) {
+ lhs_decl_ctx = lhs_decl_ctx->getParent();
+ rhs_decl_ctx = rhs_decl_ctx->getParent();
+
+ if (lhs_decl_ctx == nullptr && rhs_decl_ctx == nullptr)
+ break;
+ } else
+ return false;
+ } else
+ return false;
+ }
+
+ // Now make sure the name of the decls match
+ clang::NamedDecl *lhs_named_decl =
+ llvm::dyn_cast<clang::NamedDecl>(lhs_decl);
+ clang::NamedDecl *rhs_named_decl =
+ llvm::dyn_cast<clang::NamedDecl>(rhs_decl);
+ if (lhs_named_decl && rhs_named_decl) {
+ clang::DeclarationName lhs_decl_name = lhs_named_decl->getDeclName();
+ clang::DeclarationName rhs_decl_name = rhs_named_decl->getDeclName();
+ if (lhs_decl_name.getNameKind() == rhs_decl_name.getNameKind()) {
+ if (lhs_decl_name.getAsString() != rhs_decl_name.getAsString())
+ return false;
+ } else
+ return false;
+ } else
+ return false;
+
+ // We know that the decl context kinds all match, so now we need to
+ // make sure the names match as well
+ lhs_decl_ctx = lhs_decl->getDeclContext();
+ rhs_decl_ctx = rhs_decl->getDeclContext();
+ while (true) {
+ switch (lhs_decl_ctx->getDeclKind()) {
+ case clang::Decl::TranslationUnit:
+ // We don't care about the translation unit names
+ return true;
+ default: {
+ clang::NamedDecl *lhs_named_decl =
+ llvm::dyn_cast<clang::NamedDecl>(lhs_decl_ctx);
+ clang::NamedDecl *rhs_named_decl =
+ llvm::dyn_cast<clang::NamedDecl>(rhs_decl_ctx);
+ if (lhs_named_decl && rhs_named_decl) {
+ clang::DeclarationName lhs_decl_name =
+ lhs_named_decl->getDeclName();
+ clang::DeclarationName rhs_decl_name =
+ rhs_named_decl->getDeclName();
+ if (lhs_decl_name.getNameKind() == rhs_decl_name.getNameKind()) {
+ if (lhs_decl_name.getAsString() != rhs_decl_name.getAsString())
+ return false;
+ } else
+ return false;
+ } else
+ return false;
+ } break;
+ }
+ lhs_decl_ctx = lhs_decl_ctx->getParent();
+ rhs_decl_ctx = rhs_decl_ctx->getParent();
+ }
+ }
+ }
+ }
+ return false;
+}
+bool TypeSystemClang::GetCompleteDecl(clang::ASTContext *ast,
+ clang::Decl *decl) {
+ if (!decl)
+ return false;
+
+ ExternalASTSource *ast_source = ast->getExternalSource();
+
+ if (!ast_source)
+ return false;
+
+ if (clang::TagDecl *tag_decl = llvm::dyn_cast<clang::TagDecl>(decl)) {
+ if (tag_decl->isCompleteDefinition())
+ return true;
+
+ if (!tag_decl->hasExternalLexicalStorage())
+ return false;
+
+ ast_source->CompleteType(tag_decl);
+
+ return !tag_decl->getTypeForDecl()->isIncompleteType();
+ } else if (clang::ObjCInterfaceDecl *objc_interface_decl =
+ llvm::dyn_cast<clang::ObjCInterfaceDecl>(decl)) {
+ if (objc_interface_decl->getDefinition())
+ return true;
+
+ if (!objc_interface_decl->hasExternalLexicalStorage())
+ return false;
+
+ ast_source->CompleteType(objc_interface_decl);
+
+ return !objc_interface_decl->getTypeForDecl()->isIncompleteType();
+ } else {
+ return false;
+ }
+}
+
+void TypeSystemClang::SetMetadataAsUserID(const clang::Decl *decl,
+ user_id_t user_id) {
+ ClangASTMetadata meta_data;
+ meta_data.SetUserID(user_id);
+ SetMetadata(decl, meta_data);
+}
+
+void TypeSystemClang::SetMetadataAsUserID(const clang::Type *type,
+ user_id_t user_id) {
+ ClangASTMetadata meta_data;
+ meta_data.SetUserID(user_id);
+ SetMetadata(type, meta_data);
+}
+
+void TypeSystemClang::SetMetadata(const clang::Decl *object,
+ ClangASTMetadata &metadata) {
+ m_decl_metadata[object] = metadata;
+}
+
+void TypeSystemClang::SetMetadata(const clang::Type *object,
+ ClangASTMetadata &metadata) {
+ m_type_metadata[object] = metadata;
+}
+
+ClangASTMetadata *TypeSystemClang::GetMetadata(const clang::Decl *object) {
+ auto It = m_decl_metadata.find(object);
+ if (It != m_decl_metadata.end())
+ return &It->second;
+ return nullptr;
+}
+
+ClangASTMetadata *TypeSystemClang::GetMetadata(const clang::Type *object) {
+ auto It = m_type_metadata.find(object);
+ if (It != m_type_metadata.end())
+ return &It->second;
+ return nullptr;
+}
+
+bool TypeSystemClang::SetTagTypeKind(clang::QualType tag_qual_type,
+ int kind) const {
+ const clang::Type *clang_type = tag_qual_type.getTypePtr();
+ if (clang_type) {
+ const clang::TagType *tag_type = llvm::dyn_cast<clang::TagType>(clang_type);
+ if (tag_type) {
+ clang::TagDecl *tag_decl =
+ llvm::dyn_cast<clang::TagDecl>(tag_type->getDecl());
+ if (tag_decl) {
+ tag_decl->setTagKind((clang::TagDecl::TagKind)kind);
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+bool TypeSystemClang::SetDefaultAccessForRecordFields(
+ clang::RecordDecl *record_decl, int default_accessibility,
+ int *assigned_accessibilities, size_t num_assigned_accessibilities) {
+ if (record_decl) {
+ uint32_t field_idx;
+ clang::RecordDecl::field_iterator field, field_end;
+ for (field = record_decl->field_begin(),
+ field_end = record_decl->field_end(), field_idx = 0;
+ field != field_end; ++field, ++field_idx) {
+ // If no accessibility was assigned, assign the correct one
+ if (field_idx < num_assigned_accessibilities &&
+ assigned_accessibilities[field_idx] == clang::AS_none)
+ field->setAccess((clang::AccessSpecifier)default_accessibility);
+ }
+ return true;
+ }
+ return false;
+}
+
+clang::DeclContext *
+TypeSystemClang::GetDeclContextForType(const CompilerType &type) {
+ return GetDeclContextForType(ClangUtil::GetQualType(type));
+}
+
+/// Aggressively desugar the provided type, skipping past various kinds of
+/// syntactic sugar and other constructs one typically wants to ignore.
+/// The \p mask argument allows one to skip certain kinds of simplifications,
+/// when one wishes to handle a certain kind of type directly.
+static QualType
+RemoveWrappingTypes(QualType type, ArrayRef<clang::Type::TypeClass> mask = {}) {
+ while (true) {
+ if (find(mask, type->getTypeClass()) != mask.end())
+ return type;
+ switch (type->getTypeClass()) {
+ // This is not fully correct as _Atomic is more than sugar, but it is
+ // sufficient for the purposes we care about.
+ case clang::Type::Atomic:
+ type = cast<clang::AtomicType>(type)->getValueType();
+ break;
+ case clang::Type::Auto:
+ case clang::Type::Decltype:
+ case clang::Type::Elaborated:
+ case clang::Type::Paren:
+ case clang::Type::Typedef:
+ case clang::Type::TypeOf:
+ case clang::Type::TypeOfExpr:
+ type = type->getLocallyUnqualifiedSingleStepDesugaredType();
+ break;
+ default:
+ return type;
+ }
+ }
+}
+
+clang::DeclContext *
+TypeSystemClang::GetDeclContextForType(clang::QualType type) {
+ if (type.isNull())
+ return nullptr;
+
+ clang::QualType qual_type = RemoveWrappingTypes(type.getCanonicalType());
+ const clang::Type::TypeClass type_class = qual_type->getTypeClass();
+ switch (type_class) {
+ case clang::Type::ObjCInterface:
+ return llvm::cast<clang::ObjCObjectType>(qual_type.getTypePtr())
+ ->getInterface();
+ case clang::Type::ObjCObjectPointer:
+ return GetDeclContextForType(
+ llvm::cast<clang::ObjCObjectPointerType>(qual_type.getTypePtr())
+ ->getPointeeType());
+ case clang::Type::Record:
+ return llvm::cast<clang::RecordType>(qual_type)->getDecl();
+ case clang::Type::Enum:
+ return llvm::cast<clang::EnumType>(qual_type)->getDecl();
+ default:
+ break;
+ }
+ // No DeclContext in this type...
+ return nullptr;
+}
+
+static bool GetCompleteQualType(clang::ASTContext *ast,
+ clang::QualType qual_type,
+ bool allow_completion = true) {
+ qual_type = RemoveWrappingTypes(qual_type);
+ const clang::Type::TypeClass type_class = qual_type->getTypeClass();
+ switch (type_class) {
+ case clang::Type::ConstantArray:
+ case clang::Type::IncompleteArray:
+ case clang::Type::VariableArray: {
+ const clang::ArrayType *array_type =
+ llvm::dyn_cast<clang::ArrayType>(qual_type.getTypePtr());
+
+ if (array_type)
+ return GetCompleteQualType(ast, array_type->getElementType(),
+ allow_completion);
+ } break;
+ case clang::Type::Record: {
+ clang::CXXRecordDecl *cxx_record_decl = qual_type->getAsCXXRecordDecl();
+ if (cxx_record_decl) {
+ if (cxx_record_decl->hasExternalLexicalStorage()) {
+ const bool is_complete = cxx_record_decl->isCompleteDefinition();
+ const bool fields_loaded =
+ cxx_record_decl->hasLoadedFieldsFromExternalStorage();
+ if (is_complete && fields_loaded)
+ return true;
+
+ if (!allow_completion)
+ return false;
+
+ // Call the field_begin() accessor to for it to use the external source
+ // to load the fields...
+ clang::ExternalASTSource *external_ast_source =
+ ast->getExternalSource();
+ if (external_ast_source) {
+ external_ast_source->CompleteType(cxx_record_decl);
+ if (cxx_record_decl->isCompleteDefinition()) {
+ cxx_record_decl->field_begin();
+ cxx_record_decl->setHasLoadedFieldsFromExternalStorage(true);
+ }
+ }
+ }
+ }
+ const clang::TagType *tag_type =
+ llvm::cast<clang::TagType>(qual_type.getTypePtr());
+ return !tag_type->isIncompleteType();
+ } break;
+
+ case clang::Type::Enum: {
+ const clang::TagType *tag_type =
+ llvm::dyn_cast<clang::TagType>(qual_type.getTypePtr());
+ if (tag_type) {
+ clang::TagDecl *tag_decl = tag_type->getDecl();
+ if (tag_decl) {
+ if (tag_decl->getDefinition())
+ return true;
+
+ if (!allow_completion)
+ return false;
+
+ if (tag_decl->hasExternalLexicalStorage()) {
+ if (ast) {
+ clang::ExternalASTSource *external_ast_source =
+ ast->getExternalSource();
+ if (external_ast_source) {
+ external_ast_source->CompleteType(tag_decl);
+ return !tag_type->isIncompleteType();
+ }
+ }
+ }
+ return false;
+ }
+ }
+
+ } break;
+ case clang::Type::ObjCObject:
+ case clang::Type::ObjCInterface: {
+ const clang::ObjCObjectType *objc_class_type =
+ llvm::dyn_cast<clang::ObjCObjectType>(qual_type);
+ if (objc_class_type) {
+ clang::ObjCInterfaceDecl *class_interface_decl =
+ objc_class_type->getInterface();
+ // We currently can't complete objective C types through the newly added
+ // ASTContext because it only supports TagDecl objects right now...
+ if (class_interface_decl) {
+ if (class_interface_decl->getDefinition())
+ return true;
+
+ if (!allow_completion)
+ return false;
+
+ if (class_interface_decl->hasExternalLexicalStorage()) {
+ if (ast) {
+ clang::ExternalASTSource *external_ast_source =
+ ast->getExternalSource();
+ if (external_ast_source) {
+ external_ast_source->CompleteType(class_interface_decl);
+ return !objc_class_type->isIncompleteType();
+ }
+ }
+ }
+ return false;
+ }
+ }
+ } break;
+
+ case clang::Type::Attributed:
+ return GetCompleteQualType(
+ ast, llvm::cast<clang::AttributedType>(qual_type)->getModifiedType(),
+ allow_completion);
+
+ default:
+ break;
+ }
+
+ return true;
+}
+
+static clang::ObjCIvarDecl::AccessControl
+ConvertAccessTypeToObjCIvarAccessControl(AccessType access) {
+ switch (access) {
+ case eAccessNone:
+ return clang::ObjCIvarDecl::None;
+ case eAccessPublic:
+ return clang::ObjCIvarDecl::Public;
+ case eAccessPrivate:
+ return clang::ObjCIvarDecl::Private;
+ case eAccessProtected:
+ return clang::ObjCIvarDecl::Protected;
+ case eAccessPackage:
+ return clang::ObjCIvarDecl::Package;
+ }
+ return clang::ObjCIvarDecl::None;
+}
+
+// Tests
+
+bool TypeSystemClang::IsAggregateType(lldb::opaque_compiler_type_t type) {
+ clang::QualType qual_type(RemoveWrappingTypes(GetCanonicalQualType(type)));
+
+ const clang::Type::TypeClass type_class = qual_type->getTypeClass();
+ switch (type_class) {
+ case clang::Type::IncompleteArray:
+ case clang::Type::VariableArray:
+ case clang::Type::ConstantArray:
+ case clang::Type::ExtVector:
+ case clang::Type::Vector:
+ case clang::Type::Record:
+ case clang::Type::ObjCObject:
+ case clang::Type::ObjCInterface:
+ return true;
+ default:
+ break;
+ }
+ // The clang type does have a value
+ return false;
+}
+
+bool TypeSystemClang::IsAnonymousType(lldb::opaque_compiler_type_t type) {
+ clang::QualType qual_type(RemoveWrappingTypes(GetCanonicalQualType(type)));
+
+ const clang::Type::TypeClass type_class = qual_type->getTypeClass();
+ switch (type_class) {
+ case clang::Type::Record: {
+ if (const clang::RecordType *record_type =
+ llvm::dyn_cast_or_null<clang::RecordType>(
+ qual_type.getTypePtrOrNull())) {
+ if (const clang::RecordDecl *record_decl = record_type->getDecl()) {
+ return record_decl->isAnonymousStructOrUnion();
+ }
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ // The clang type does have a value
+ return false;
+}
+
+bool TypeSystemClang::IsArrayType(lldb::opaque_compiler_type_t type,
+ CompilerType *element_type_ptr,
+ uint64_t *size, bool *is_incomplete) {
+ clang::QualType qual_type(RemoveWrappingTypes(GetCanonicalQualType(type)));
+
+ const clang::Type::TypeClass type_class = qual_type->getTypeClass();
+ switch (type_class) {
+ default:
+ break;
+
+ case clang::Type::ConstantArray:
+ if (element_type_ptr)
+ element_type_ptr->SetCompilerType(
+ this, llvm::cast<clang::ConstantArrayType>(qual_type)
+ ->getElementType()
+ .getAsOpaquePtr());
+ if (size)
+ *size = llvm::cast<clang::ConstantArrayType>(qual_type)
+ ->getSize()
+ .getLimitedValue(ULLONG_MAX);
+ if (is_incomplete)
+ *is_incomplete = false;
+ return true;
+
+ case clang::Type::IncompleteArray:
+ if (element_type_ptr)
+ element_type_ptr->SetCompilerType(
+ this, llvm::cast<clang::IncompleteArrayType>(qual_type)
+ ->getElementType()
+ .getAsOpaquePtr());
+ if (size)
+ *size = 0;
+ if (is_incomplete)
+ *is_incomplete = true;
+ return true;
+
+ case clang::Type::VariableArray:
+ if (element_type_ptr)
+ element_type_ptr->SetCompilerType(
+ this, llvm::cast<clang::VariableArrayType>(qual_type)
+ ->getElementType()
+ .getAsOpaquePtr());
+ if (size)
+ *size = 0;
+ if (is_incomplete)
+ *is_incomplete = false;
+ return true;
+
+ case clang::Type::DependentSizedArray:
+ if (element_type_ptr)
+ element_type_ptr->SetCompilerType(
+ this, llvm::cast<clang::DependentSizedArrayType>(qual_type)
+ ->getElementType()
+ .getAsOpaquePtr());
+ if (size)
+ *size = 0;
+ if (is_incomplete)
+ *is_incomplete = false;
+ return true;
+ }
+ if (element_type_ptr)
+ element_type_ptr->Clear();
+ if (size)
+ *size = 0;
+ if (is_incomplete)
+ *is_incomplete = false;
+ return false;
+}
+
+bool TypeSystemClang::IsVectorType(lldb::opaque_compiler_type_t type,
+ CompilerType *element_type, uint64_t *size) {
+ clang::QualType qual_type(GetCanonicalQualType(type));
+
+ const clang::Type::TypeClass type_class = qual_type->getTypeClass();
+ switch (type_class) {
+ case clang::Type::Vector: {
+ const clang::VectorType *vector_type =
+ qual_type->getAs<clang::VectorType>();
+ if (vector_type) {
+ if (size)
+ *size = vector_type->getNumElements();
+ if (element_type)
+ *element_type = GetType(vector_type->getElementType());
+ }
+ return true;
+ } break;
+ case clang::Type::ExtVector: {
+ const clang::ExtVectorType *ext_vector_type =
+ qual_type->getAs<clang::ExtVectorType>();
+ if (ext_vector_type) {
+ if (size)
+ *size = ext_vector_type->getNumElements();
+ if (element_type)
+ *element_type =
+ CompilerType(this, ext_vector_type->getElementType().getAsOpaquePtr());
+ }
+ return true;
+ }
+ default:
+ break;
+ }
+ return false;
+}
+
+bool TypeSystemClang::IsRuntimeGeneratedType(
+ lldb::opaque_compiler_type_t type) {
+ clang::DeclContext *decl_ctx = GetDeclContextForType(GetQualType(type));
+ if (!decl_ctx)
+ return false;
+
+ if (!llvm::isa<clang::ObjCInterfaceDecl>(decl_ctx))
+ return false;
+
+ clang::ObjCInterfaceDecl *result_iface_decl =
+ llvm::dyn_cast<clang::ObjCInterfaceDecl>(decl_ctx);
+
+ ClangASTMetadata *ast_metadata = GetMetadata(result_iface_decl);
+ if (!ast_metadata)
+ return false;
+ return (ast_metadata->GetISAPtr() != 0);
+}
+
+bool TypeSystemClang::IsCharType(lldb::opaque_compiler_type_t type) {
+ return GetQualType(type).getUnqualifiedType()->isCharType();
+}
+
+bool TypeSystemClang::IsCompleteType(lldb::opaque_compiler_type_t type) {
+ const bool allow_completion = false;
+ return GetCompleteQualType(&getASTContext(), GetQualType(type),
+ allow_completion);
+}
+
+bool TypeSystemClang::IsConst(lldb::opaque_compiler_type_t type) {
+ return GetQualType(type).isConstQualified();
+}
+
+bool TypeSystemClang::IsCStringType(lldb::opaque_compiler_type_t type,
+ uint32_t &length) {
+ CompilerType pointee_or_element_clang_type;
+ length = 0;
+ Flags type_flags(GetTypeInfo(type, &pointee_or_element_clang_type));
+
+ if (!pointee_or_element_clang_type.IsValid())
+ return false;
+
+ if (type_flags.AnySet(eTypeIsArray | eTypeIsPointer)) {
+ if (pointee_or_element_clang_type.IsCharType()) {
+ if (type_flags.Test(eTypeIsArray)) {
+ // We know the size of the array and it could be a C string since it is
+ // an array of characters
+ length = llvm::cast<clang::ConstantArrayType>(
+ GetCanonicalQualType(type).getTypePtr())
+ ->getSize()
+ .getLimitedValue();
+ }
+ return true;
+ }
+ }
+ return false;
+}
+
+bool TypeSystemClang::IsFunctionType(lldb::opaque_compiler_type_t type,
+ bool *is_variadic_ptr) {
+ if (type) {
+ clang::QualType qual_type = RemoveWrappingTypes(GetCanonicalQualType(type));
+
+ if (qual_type->isFunctionType()) {
+ if (is_variadic_ptr) {
+ const clang::FunctionProtoType *function_proto_type =
+ llvm::dyn_cast<clang::FunctionProtoType>(qual_type.getTypePtr());
+ if (function_proto_type)
+ *is_variadic_ptr = function_proto_type->isVariadic();
+ else
+ *is_variadic_ptr = false;
+ }
+ return true;
+ }
+
+ const clang::Type::TypeClass type_class = qual_type->getTypeClass();
+ switch (type_class) {
+ default:
+ break;
+ case clang::Type::LValueReference:
+ case clang::Type::RValueReference: {
+ const clang::ReferenceType *reference_type =
+ llvm::cast<clang::ReferenceType>(qual_type.getTypePtr());
+ if (reference_type)
+ return IsFunctionType(reference_type->getPointeeType().getAsOpaquePtr(),
+ nullptr);
+ } break;
+ }
+ }
+ return false;
+}
+
+// Used to detect "Homogeneous Floating-point Aggregates"
+uint32_t
+TypeSystemClang::IsHomogeneousAggregate(lldb::opaque_compiler_type_t type,
+ CompilerType *base_type_ptr) {
+ if (!type)
+ return 0;
+
+ clang::QualType qual_type(RemoveWrappingTypes(GetCanonicalQualType(type)));
+ const clang::Type::TypeClass type_class = qual_type->getTypeClass();
+ switch (type_class) {
+ case clang::Type::Record:
+ if (GetCompleteType(type)) {
+ const clang::CXXRecordDecl *cxx_record_decl =
+ qual_type->getAsCXXRecordDecl();
+ if (cxx_record_decl) {
+ if (cxx_record_decl->getNumBases() || cxx_record_decl->isDynamicClass())
+ return 0;
+ }
+ const clang::RecordType *record_type =
+ llvm::cast<clang::RecordType>(qual_type.getTypePtr());
+ if (record_type) {
+ const clang::RecordDecl *record_decl = record_type->getDecl();
+ if (record_decl) {
+ // We are looking for a structure that contains only floating point
+ // types
+ clang::RecordDecl::field_iterator field_pos,
+ field_end = record_decl->field_end();
+ uint32_t num_fields = 0;
+ bool is_hva = false;
+ bool is_hfa = false;
+ clang::QualType base_qual_type;
+ uint64_t base_bitwidth = 0;
+ for (field_pos = record_decl->field_begin(); field_pos != field_end;
+ ++field_pos) {
+ clang::QualType field_qual_type = field_pos->getType();
+ uint64_t field_bitwidth = getASTContext().getTypeSize(qual_type);
+ if (field_qual_type->isFloatingType()) {
+ if (field_qual_type->isComplexType())
+ return 0;
+ else {
+ if (num_fields == 0)
+ base_qual_type = field_qual_type;
+ else {
+ if (is_hva)
+ return 0;
+ is_hfa = true;
+ if (field_qual_type.getTypePtr() !=
+ base_qual_type.getTypePtr())
+ return 0;
+ }
+ }
+ } else if (field_qual_type->isVectorType() ||
+ field_qual_type->isExtVectorType()) {
+ if (num_fields == 0) {
+ base_qual_type = field_qual_type;
+ base_bitwidth = field_bitwidth;
+ } else {
+ if (is_hfa)
+ return 0;
+ is_hva = true;
+ if (base_bitwidth != field_bitwidth)
+ return 0;
+ if (field_qual_type.getTypePtr() != base_qual_type.getTypePtr())
+ return 0;
+ }
+ } else
+ return 0;
+ ++num_fields;
+ }
+ if (base_type_ptr)
+ *base_type_ptr = CompilerType(this, base_qual_type.getAsOpaquePtr());
+ return num_fields;
+ }
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+ return 0;
+}
+
+size_t TypeSystemClang::GetNumberOfFunctionArguments(
+ lldb::opaque_compiler_type_t type) {
+ if (type) {
+ clang::QualType qual_type(GetCanonicalQualType(type));
+ const clang::FunctionProtoType *func =
+ llvm::dyn_cast<clang::FunctionProtoType>(qual_type.getTypePtr());
+ if (func)
+ return func->getNumParams();
+ }
+ return 0;
+}
+
+CompilerType
+TypeSystemClang::GetFunctionArgumentAtIndex(lldb::opaque_compiler_type_t type,
+ const size_t index) {
+ if (type) {
+ clang::QualType qual_type(GetQualType(type));
+ const clang::FunctionProtoType *func =
+ llvm::dyn_cast<clang::FunctionProtoType>(qual_type.getTypePtr());
+ if (func) {
+ if (index < func->getNumParams())
+ return CompilerType(this, func->getParamType(index).getAsOpaquePtr());
+ }
+ }
+ return CompilerType();
+}
+
+bool TypeSystemClang::IsFunctionPointerType(lldb::opaque_compiler_type_t type) {
+ if (type) {
+ clang::QualType qual_type = RemoveWrappingTypes(GetCanonicalQualType(type));
+
+ if (qual_type->isFunctionPointerType())
+ return true;
+
+ const clang::Type::TypeClass type_class = qual_type->getTypeClass();
+ switch (type_class) {
+ default:
+ break;
+
+ case clang::Type::LValueReference:
+ case clang::Type::RValueReference: {
+ const clang::ReferenceType *reference_type =
+ llvm::cast<clang::ReferenceType>(qual_type.getTypePtr());
+ if (reference_type)
+ return IsFunctionPointerType(
+ reference_type->getPointeeType().getAsOpaquePtr());
+ } break;
+ }
+ }
+ return false;
+}
+
+bool TypeSystemClang::IsBlockPointerType(
+ lldb::opaque_compiler_type_t type,
+ CompilerType *function_pointer_type_ptr) {
+ if (type) {
+ clang::QualType qual_type = RemoveWrappingTypes(GetCanonicalQualType(type));
+
+ if (qual_type->isBlockPointerType()) {
+ if (function_pointer_type_ptr) {
+ const clang::BlockPointerType *block_pointer_type =
+ qual_type->getAs<clang::BlockPointerType>();
+ QualType pointee_type = block_pointer_type->getPointeeType();
+ QualType function_pointer_type = m_ast_up->getPointerType(pointee_type);
+ *function_pointer_type_ptr =
+ CompilerType(this, function_pointer_type.getAsOpaquePtr());
+ }
+ return true;
+ }
+
+ const clang::Type::TypeClass type_class = qual_type->getTypeClass();
+ switch (type_class) {
+ default:
+ break;
+
+ case clang::Type::LValueReference:
+ case clang::Type::RValueReference: {
+ const clang::ReferenceType *reference_type =
+ llvm::cast<clang::ReferenceType>(qual_type.getTypePtr());
+ if (reference_type)
+ return IsBlockPointerType(
+ reference_type->getPointeeType().getAsOpaquePtr(),
+ function_pointer_type_ptr);
+ } break;
+ }
+ }
+ return false;
+}
+
+bool TypeSystemClang::IsIntegerType(lldb::opaque_compiler_type_t type,
+ bool &is_signed) {
+ if (!type)
+ return false;
+
+ clang::QualType qual_type(GetCanonicalQualType(type));
+ const clang::BuiltinType *builtin_type =
+ llvm::dyn_cast<clang::BuiltinType>(qual_type->getCanonicalTypeInternal());
+
+ if (builtin_type) {
+ if (builtin_type->isInteger()) {
+ is_signed = builtin_type->isSignedInteger();
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool TypeSystemClang::IsEnumerationType(lldb::opaque_compiler_type_t type,
+ bool &is_signed) {
+ if (type) {
+ const clang::EnumType *enum_type = llvm::dyn_cast<clang::EnumType>(
+ GetCanonicalQualType(type)->getCanonicalTypeInternal());
+
+ if (enum_type) {
+ IsIntegerType(enum_type->getDecl()->getIntegerType().getAsOpaquePtr(),
+ is_signed);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool TypeSystemClang::IsPointerType(lldb::opaque_compiler_type_t type,
+ CompilerType *pointee_type) {
+ if (type) {
+ clang::QualType qual_type = RemoveWrappingTypes(GetCanonicalQualType(type));
+ const clang::Type::TypeClass type_class = qual_type->getTypeClass();
+ switch (type_class) {
+ case clang::Type::Builtin:
+ switch (llvm::cast<clang::BuiltinType>(qual_type)->getKind()) {
+ default:
+ break;
+ case clang::BuiltinType::ObjCId:
+ case clang::BuiltinType::ObjCClass:
+ return true;
+ }
+ return false;
+ case clang::Type::ObjCObjectPointer:
+ if (pointee_type)
+ pointee_type->SetCompilerType(
+ this, llvm::cast<clang::ObjCObjectPointerType>(qual_type)
+ ->getPointeeType()
+ .getAsOpaquePtr());
+ return true;
+ case clang::Type::BlockPointer:
+ if (pointee_type)
+ pointee_type->SetCompilerType(
+ this, llvm::cast<clang::BlockPointerType>(qual_type)
+ ->getPointeeType()
+ .getAsOpaquePtr());
+ return true;
+ case clang::Type::Pointer:
+ if (pointee_type)
+ pointee_type->SetCompilerType(this,
+ llvm::cast<clang::PointerType>(qual_type)
+ ->getPointeeType()
+ .getAsOpaquePtr());
+ return true;
+ case clang::Type::MemberPointer:
+ if (pointee_type)
+ pointee_type->SetCompilerType(
+ this, llvm::cast<clang::MemberPointerType>(qual_type)
+ ->getPointeeType()
+ .getAsOpaquePtr());
+ return true;
+ default:
+ break;
+ }
+ }
+ if (pointee_type)
+ pointee_type->Clear();
+ return false;
+}
+
+bool TypeSystemClang::IsPointerOrReferenceType(
+ lldb::opaque_compiler_type_t type, CompilerType *pointee_type) {
+ if (type) {
+ clang::QualType qual_type = RemoveWrappingTypes(GetCanonicalQualType(type));
+ const clang::Type::TypeClass type_class = qual_type->getTypeClass();
+ switch (type_class) {
+ case clang::Type::Builtin:
+ switch (llvm::cast<clang::BuiltinType>(qual_type)->getKind()) {
+ default:
+ break;
+ case clang::BuiltinType::ObjCId:
+ case clang::BuiltinType::ObjCClass:
+ return true;
+ }
+ return false;
+ case clang::Type::ObjCObjectPointer:
+ if (pointee_type)
+ pointee_type->SetCompilerType(
+ this, llvm::cast<clang::ObjCObjectPointerType>(qual_type)
+ ->getPointeeType().getAsOpaquePtr());
+ return true;
+ case clang::Type::BlockPointer:
+ if (pointee_type)
+ pointee_type->SetCompilerType(
+ this, llvm::cast<clang::BlockPointerType>(qual_type)
+ ->getPointeeType()
+ .getAsOpaquePtr());
+ return true;
+ case clang::Type::Pointer:
+ if (pointee_type)
+ pointee_type->SetCompilerType(this,
+ llvm::cast<clang::PointerType>(qual_type)
+ ->getPointeeType()
+ .getAsOpaquePtr());
+ return true;
+ case clang::Type::MemberPointer:
+ if (pointee_type)
+ pointee_type->SetCompilerType(
+ this, llvm::cast<clang::MemberPointerType>(qual_type)
+ ->getPointeeType()
+ .getAsOpaquePtr());
+ return true;
+ case clang::Type::LValueReference:
+ if (pointee_type)
+ pointee_type->SetCompilerType(
+ this, llvm::cast<clang::LValueReferenceType>(qual_type)
+ ->desugar()
+ .getAsOpaquePtr());
+ return true;
+ case clang::Type::RValueReference:
+ if (pointee_type)
+ pointee_type->SetCompilerType(
+ this, llvm::cast<clang::RValueReferenceType>(qual_type)
+ ->desugar()
+ .getAsOpaquePtr());
+ return true;
+ default:
+ break;
+ }
+ }
+ if (pointee_type)
+ pointee_type->Clear();
+ return false;
+}
+
+bool TypeSystemClang::IsReferenceType(lldb::opaque_compiler_type_t type,
+ CompilerType *pointee_type,
+ bool *is_rvalue) {
+ if (type) {
+ clang::QualType qual_type = RemoveWrappingTypes(GetCanonicalQualType(type));
+ const clang::Type::TypeClass type_class = qual_type->getTypeClass();
+
+ switch (type_class) {
+ case clang::Type::LValueReference:
+ if (pointee_type)
+ pointee_type->SetCompilerType(
+ this, llvm::cast<clang::LValueReferenceType>(qual_type)
+ ->desugar()
+ .getAsOpaquePtr());
+ if (is_rvalue)
+ *is_rvalue = false;
+ return true;
+ case clang::Type::RValueReference:
+ if (pointee_type)
+ pointee_type->SetCompilerType(
+ this, llvm::cast<clang::RValueReferenceType>(qual_type)
+ ->desugar()
+ .getAsOpaquePtr());
+ if (is_rvalue)
+ *is_rvalue = true;
+ return true;
+
+ default:
+ break;
+ }
+ }
+ if (pointee_type)
+ pointee_type->Clear();
+ return false;
+}
+
+bool TypeSystemClang::IsFloatingPointType(lldb::opaque_compiler_type_t type,
+ uint32_t &count, bool &is_complex) {
+ if (type) {
+ clang::QualType qual_type(GetCanonicalQualType(type));
+
+ if (const clang::BuiltinType *BT = llvm::dyn_cast<clang::BuiltinType>(
+ qual_type->getCanonicalTypeInternal())) {
+ clang::BuiltinType::Kind kind = BT->getKind();
+ if (kind >= clang::BuiltinType::Float &&
+ kind <= clang::BuiltinType::LongDouble) {
+ count = 1;
+ is_complex = false;
+ return true;
+ }
+ } else if (const clang::ComplexType *CT =
+ llvm::dyn_cast<clang::ComplexType>(
+ qual_type->getCanonicalTypeInternal())) {
+ if (IsFloatingPointType(CT->getElementType().getAsOpaquePtr(), count,
+ is_complex)) {
+ count = 2;
+ is_complex = true;
+ return true;
+ }
+ } else if (const clang::VectorType *VT = llvm::dyn_cast<clang::VectorType>(
+ qual_type->getCanonicalTypeInternal())) {
+ if (IsFloatingPointType(VT->getElementType().getAsOpaquePtr(), count,
+ is_complex)) {
+ count = VT->getNumElements();
+ is_complex = false;
+ return true;
+ }
+ }
+ }
+ count = 0;
+ is_complex = false;
+ return false;
+}
+
+bool TypeSystemClang::IsDefined(lldb::opaque_compiler_type_t type) {
+ if (!type)
+ return false;
+
+ clang::QualType qual_type(GetQualType(type));
+ const clang::TagType *tag_type =
+ llvm::dyn_cast<clang::TagType>(qual_type.getTypePtr());
+ if (tag_type) {
+ clang::TagDecl *tag_decl = tag_type->getDecl();
+ if (tag_decl)
+ return tag_decl->isCompleteDefinition();
+ return false;
+ } else {
+ const clang::ObjCObjectType *objc_class_type =
+ llvm::dyn_cast<clang::ObjCObjectType>(qual_type);
+ if (objc_class_type) {
+ clang::ObjCInterfaceDecl *class_interface_decl =
+ objc_class_type->getInterface();
+ if (class_interface_decl)
+ return class_interface_decl->getDefinition() != nullptr;
+ return false;
+ }
+ }
+ return true;
+}
+
+bool TypeSystemClang::IsObjCClassType(const CompilerType &type) {
+ if (ClangUtil::IsClangType(type)) {
+ clang::QualType qual_type(ClangUtil::GetCanonicalQualType(type));
+
+ const clang::ObjCObjectPointerType *obj_pointer_type =
+ llvm::dyn_cast<clang::ObjCObjectPointerType>(qual_type);
+
+ if (obj_pointer_type)
+ return obj_pointer_type->isObjCClassType();
+ }
+ return false;
+}
+
+bool TypeSystemClang::IsObjCObjectOrInterfaceType(const CompilerType &type) {
+ if (ClangUtil::IsClangType(type))
+ return ClangUtil::GetCanonicalQualType(type)->isObjCObjectOrInterfaceType();
+ return false;
+}
+
+bool TypeSystemClang::IsClassType(lldb::opaque_compiler_type_t type) {
+ if (!type)
+ return false;
+ clang::QualType qual_type(GetCanonicalQualType(type));
+ const clang::Type::TypeClass type_class = qual_type->getTypeClass();
+ return (type_class == clang::Type::Record);
+}
+
+bool TypeSystemClang::IsEnumType(lldb::opaque_compiler_type_t type) {
+ if (!type)
+ return false;
+ clang::QualType qual_type(GetCanonicalQualType(type));
+ const clang::Type::TypeClass type_class = qual_type->getTypeClass();
+ return (type_class == clang::Type::Enum);
+}
+
+bool TypeSystemClang::IsPolymorphicClass(lldb::opaque_compiler_type_t type) {
+ if (type) {
+ clang::QualType qual_type(GetCanonicalQualType(type));
+ const clang::Type::TypeClass type_class = qual_type->getTypeClass();
+ switch (type_class) {
+ case clang::Type::Record:
+ if (GetCompleteType(type)) {
+ const clang::RecordType *record_type =
+ llvm::cast<clang::RecordType>(qual_type.getTypePtr());
+ const clang::RecordDecl *record_decl = record_type->getDecl();
+ if (record_decl) {
+ const clang::CXXRecordDecl *cxx_record_decl =
+ llvm::dyn_cast<clang::CXXRecordDecl>(record_decl);
+ if (cxx_record_decl)
+ return cxx_record_decl->isPolymorphic();
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ return false;
+}
+
+bool TypeSystemClang::IsPossibleDynamicType(lldb::opaque_compiler_type_t type,
+ CompilerType *dynamic_pointee_type,
+ bool check_cplusplus,
+ bool check_objc) {
+ clang::QualType pointee_qual_type;
+ if (type) {
+ clang::QualType qual_type = RemoveWrappingTypes(GetCanonicalQualType(type));
+ bool success = false;
+ const clang::Type::TypeClass type_class = qual_type->getTypeClass();
+ switch (type_class) {
+ case clang::Type::Builtin:
+ if (check_objc &&
+ llvm::cast<clang::BuiltinType>(qual_type)->getKind() ==
+ clang::BuiltinType::ObjCId) {
+ if (dynamic_pointee_type)
+ dynamic_pointee_type->SetCompilerType(this, type);
+ return true;
+ }
+ break;
+
+ case clang::Type::ObjCObjectPointer:
+ if (check_objc) {
+ if (auto objc_pointee_type =
+ qual_type->getPointeeType().getTypePtrOrNull()) {
+ if (auto objc_object_type =
+ llvm::dyn_cast_or_null<clang::ObjCObjectType>(
+ objc_pointee_type)) {
+ if (objc_object_type->isObjCClass())
+ return false;
+ }
+ }
+ if (dynamic_pointee_type)
+ dynamic_pointee_type->SetCompilerType(
+ this, llvm::cast<clang::ObjCObjectPointerType>(qual_type)
+ ->getPointeeType()
+ .getAsOpaquePtr());
+ return true;
+ }
+ break;
+
+ case clang::Type::Pointer:
+ pointee_qual_type =
+ llvm::cast<clang::PointerType>(qual_type)->getPointeeType();
+ success = true;
+ break;
+
+ case clang::Type::LValueReference:
+ case clang::Type::RValueReference:
+ pointee_qual_type =
+ llvm::cast<clang::ReferenceType>(qual_type)->getPointeeType();
+ success = true;
+ break;
+
+ default:
+ break;
+ }
+
+ if (success) {
+ // Check to make sure what we are pointing too is a possible dynamic C++
+ // type We currently accept any "void *" (in case we have a class that
+ // has been watered down to an opaque pointer) and virtual C++ classes.
+ const clang::Type::TypeClass pointee_type_class =
+ pointee_qual_type.getCanonicalType()->getTypeClass();
+ switch (pointee_type_class) {
+ case clang::Type::Builtin:
+ switch (llvm::cast<clang::BuiltinType>(pointee_qual_type)->getKind()) {
+ case clang::BuiltinType::UnknownAny:
+ case clang::BuiltinType::Void:
+ if (dynamic_pointee_type)
+ dynamic_pointee_type->SetCompilerType(
+ this, pointee_qual_type.getAsOpaquePtr());
+ return true;
+ default:
+ break;
+ }
+ break;
+
+ case clang::Type::Record:
+ if (check_cplusplus) {
+ clang::CXXRecordDecl *cxx_record_decl =
+ pointee_qual_type->getAsCXXRecordDecl();
+ if (cxx_record_decl) {
+ bool is_complete = cxx_record_decl->isCompleteDefinition();
+
+ if (is_complete)
+ success = cxx_record_decl->isDynamicClass();
+ else {
+ ClangASTMetadata *metadata = GetMetadata(cxx_record_decl);
+ if (metadata)
+ success = metadata->GetIsDynamicCXXType();
+ else {
+ is_complete = GetType(pointee_qual_type).GetCompleteType();
+ if (is_complete)
+ success = cxx_record_decl->isDynamicClass();
+ else
+ success = false;
+ }
+ }
+
+ if (success) {
+ if (dynamic_pointee_type)
+ dynamic_pointee_type->SetCompilerType(
+ this, pointee_qual_type.getAsOpaquePtr());
+ return true;
+ }
+ }
+ }
+ break;
+
+ case clang::Type::ObjCObject:
+ case clang::Type::ObjCInterface:
+ if (check_objc) {
+ if (dynamic_pointee_type)
+ dynamic_pointee_type->SetCompilerType(
+ this, pointee_qual_type.getAsOpaquePtr());
+ return true;
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+ if (dynamic_pointee_type)
+ dynamic_pointee_type->Clear();
+ return false;
+}
+
+bool TypeSystemClang::IsScalarType(lldb::opaque_compiler_type_t type) {
+ if (!type)
+ return false;
+
+ return (GetTypeInfo(type, nullptr) & eTypeIsScalar) != 0;
+}
+
+bool TypeSystemClang::IsTypedefType(lldb::opaque_compiler_type_t type) {
+ if (!type)
+ return false;
+ return GetQualType(type)->getTypeClass() == clang::Type::Typedef;
+}
+
+bool TypeSystemClang::IsVoidType(lldb::opaque_compiler_type_t type) {
+ if (!type)
+ return false;
+ return GetCanonicalQualType(type)->isVoidType();
+}
+
+bool TypeSystemClang::CanPassInRegisters(const CompilerType &type) {
+ if (auto *record_decl =
+ TypeSystemClang::GetAsRecordDecl(type)) {
+ return record_decl->canPassInRegisters();
+ }
+ return false;
+}
+
+bool TypeSystemClang::SupportsLanguage(lldb::LanguageType language) {
+ return TypeSystemClangSupportsLanguage(language);
+}
+
+Optional<std::string>
+TypeSystemClang::GetCXXClassName(const CompilerType &type) {
+ if (!type)
+ return llvm::None;
+
+ clang::QualType qual_type(ClangUtil::GetCanonicalQualType(type));
+ if (qual_type.isNull())
+ return llvm::None;
+
+ clang::CXXRecordDecl *cxx_record_decl = qual_type->getAsCXXRecordDecl();
+ if (!cxx_record_decl)
+ return llvm::None;
+
+ return std::string(cxx_record_decl->getIdentifier()->getNameStart());
+}
+
+bool TypeSystemClang::IsCXXClassType(const CompilerType &type) {
+ if (!type)
+ return false;
+
+ clang::QualType qual_type(ClangUtil::GetCanonicalQualType(type));
+ return !qual_type.isNull() && qual_type->getAsCXXRecordDecl() != nullptr;
+}
+
+bool TypeSystemClang::IsBeingDefined(lldb::opaque_compiler_type_t type) {
+ if (!type)
+ return false;
+ clang::QualType qual_type(GetCanonicalQualType(type));
+ const clang::TagType *tag_type = llvm::dyn_cast<clang::TagType>(qual_type);
+ if (tag_type)
+ return tag_type->isBeingDefined();
+ return false;
+}
+
+bool TypeSystemClang::IsObjCObjectPointerType(const CompilerType &type,
+ CompilerType *class_type_ptr) {
+ if (!ClangUtil::IsClangType(type))
+ return false;
+
+ clang::QualType qual_type(ClangUtil::GetCanonicalQualType(type));
+
+ if (!qual_type.isNull() && qual_type->isObjCObjectPointerType()) {
+ if (class_type_ptr) {
+ if (!qual_type->isObjCClassType() && !qual_type->isObjCIdType()) {
+ const clang::ObjCObjectPointerType *obj_pointer_type =
+ llvm::dyn_cast<clang::ObjCObjectPointerType>(qual_type);
+ if (obj_pointer_type == nullptr)
+ class_type_ptr->Clear();
+ else
+ class_type_ptr->SetCompilerType(
+ type.GetTypeSystem(),
+ clang::QualType(obj_pointer_type->getInterfaceType(), 0)
+ .getAsOpaquePtr());
+ }
+ }
+ return true;
+ }
+ if (class_type_ptr)
+ class_type_ptr->Clear();
+ return false;
+}
+
+// Type Completion
+
+bool TypeSystemClang::GetCompleteType(lldb::opaque_compiler_type_t type) {
+ if (!type)
+ return false;
+ const bool allow_completion = true;
+ return GetCompleteQualType(&getASTContext(), GetQualType(type),
+ allow_completion);
+}
+
+ConstString TypeSystemClang::GetTypeName(lldb::opaque_compiler_type_t type) {
+ std::string type_name;
+ if (type) {
+ clang::PrintingPolicy printing_policy(getASTContext().getPrintingPolicy());
+ clang::QualType qual_type(GetQualType(type));
+ printing_policy.SuppressTagKeyword = true;
+ const clang::TypedefType *typedef_type =
+ qual_type->getAs<clang::TypedefType>();
+ if (typedef_type) {
+ const clang::TypedefNameDecl *typedef_decl = typedef_type->getDecl();
+ type_name = typedef_decl->getQualifiedNameAsString();
+ } else {
+ type_name = qual_type.getAsString(printing_policy);
+ }
+ }
+ return ConstString(type_name);
+}
+
+uint32_t
+TypeSystemClang::GetTypeInfo(lldb::opaque_compiler_type_t type,
+ CompilerType *pointee_or_element_clang_type) {
+ if (!type)
+ return 0;
+
+ if (pointee_or_element_clang_type)
+ pointee_or_element_clang_type->Clear();
+
+ clang::QualType qual_type =
+ RemoveWrappingTypes(GetQualType(type), {clang::Type::Typedef});
+
+ const clang::Type::TypeClass type_class = qual_type->getTypeClass();
+ switch (type_class) {
+ case clang::Type::Attributed:
+ return GetTypeInfo(
+ qual_type->getAs<clang::AttributedType>()
+ ->getModifiedType().getAsOpaquePtr(),
+ pointee_or_element_clang_type);
+ case clang::Type::Builtin: {
+ const clang::BuiltinType *builtin_type = llvm::dyn_cast<clang::BuiltinType>(
+ qual_type->getCanonicalTypeInternal());
+
+ uint32_t builtin_type_flags = eTypeIsBuiltIn | eTypeHasValue;
+ switch (builtin_type->getKind()) {
+ case clang::BuiltinType::ObjCId:
+ case clang::BuiltinType::ObjCClass:
+ if (pointee_or_element_clang_type)
+ pointee_or_element_clang_type->SetCompilerType(
+ this, getASTContext().ObjCBuiltinClassTy.getAsOpaquePtr());
+ builtin_type_flags |= eTypeIsPointer | eTypeIsObjC;
+ break;
+
+ case clang::BuiltinType::ObjCSel:
+ if (pointee_or_element_clang_type)
+ pointee_or_element_clang_type->SetCompilerType(
+ this, getASTContext().CharTy.getAsOpaquePtr());
+ builtin_type_flags |= eTypeIsPointer | eTypeIsObjC;
+ break;
+
+ case clang::BuiltinType::Bool:
+ case clang::BuiltinType::Char_U:
+ case clang::BuiltinType::UChar:
+ case clang::BuiltinType::WChar_U:
+ case clang::BuiltinType::Char16:
+ case clang::BuiltinType::Char32:
+ case clang::BuiltinType::UShort:
+ case clang::BuiltinType::UInt:
+ case clang::BuiltinType::ULong:
+ case clang::BuiltinType::ULongLong:
+ case clang::BuiltinType::UInt128:
+ case clang::BuiltinType::Char_S:
+ case clang::BuiltinType::SChar:
+ case clang::BuiltinType::WChar_S:
+ case clang::BuiltinType::Short:
+ case clang::BuiltinType::Int:
+ case clang::BuiltinType::Long:
+ case clang::BuiltinType::LongLong:
+ case clang::BuiltinType::Int128:
+ case clang::BuiltinType::Float:
+ case clang::BuiltinType::Double:
+ case clang::BuiltinType::LongDouble:
+ builtin_type_flags |= eTypeIsScalar;
+ if (builtin_type->isInteger()) {
+ builtin_type_flags |= eTypeIsInteger;
+ if (builtin_type->isSignedInteger())
+ builtin_type_flags |= eTypeIsSigned;
+ } else if (builtin_type->isFloatingPoint())
+ builtin_type_flags |= eTypeIsFloat;
+ break;
+ default:
+ break;
+ }
+ return builtin_type_flags;
+ }
+
+ case clang::Type::BlockPointer:
+ if (pointee_or_element_clang_type)
+ pointee_or_element_clang_type->SetCompilerType(
+ this, qual_type->getPointeeType().getAsOpaquePtr());
+ return eTypeIsPointer | eTypeHasChildren | eTypeIsBlock;
+
+ case clang::Type::Complex: {
+ uint32_t complex_type_flags =
+ eTypeIsBuiltIn | eTypeHasValue | eTypeIsComplex;
+ const clang::ComplexType *complex_type = llvm::dyn_cast<clang::ComplexType>(
+ qual_type->getCanonicalTypeInternal());
+ if (complex_type) {
+ clang::QualType complex_element_type(complex_type->getElementType());
+ if (complex_element_type->isIntegerType())
+ complex_type_flags |= eTypeIsFloat;
+ else if (complex_element_type->isFloatingType())
+ complex_type_flags |= eTypeIsInteger;
+ }
+ return complex_type_flags;
+ } break;
+
+ case clang::Type::ConstantArray:
+ case clang::Type::DependentSizedArray:
+ case clang::Type::IncompleteArray:
+ case clang::Type::VariableArray:
+ if (pointee_or_element_clang_type)
+ pointee_or_element_clang_type->SetCompilerType(
+ this, llvm::cast<clang::ArrayType>(qual_type.getTypePtr())
+ ->getElementType()
+ .getAsOpaquePtr());
+ return eTypeHasChildren | eTypeIsArray;
+
+ case clang::Type::DependentName:
+ return 0;
+ case clang::Type::DependentSizedExtVector:
+ return eTypeHasChildren | eTypeIsVector;
+ case clang::Type::DependentTemplateSpecialization:
+ return eTypeIsTemplate;
+
+ case clang::Type::Enum:
+ if (pointee_or_element_clang_type)
+ pointee_or_element_clang_type->SetCompilerType(
+ this, llvm::cast<clang::EnumType>(qual_type)
+ ->getDecl()
+ ->getIntegerType()
+ .getAsOpaquePtr());
+ return eTypeIsEnumeration | eTypeHasValue;
+
+ case clang::Type::FunctionProto:
+ return eTypeIsFuncPrototype | eTypeHasValue;
+ case clang::Type::FunctionNoProto:
+ return eTypeIsFuncPrototype | eTypeHasValue;
+ case clang::Type::InjectedClassName:
+ return 0;
+
+ case clang::Type::LValueReference:
+ case clang::Type::RValueReference:
+ if (pointee_or_element_clang_type)
+ pointee_or_element_clang_type->SetCompilerType(
+ this, llvm::cast<clang::ReferenceType>(qual_type.getTypePtr())
+ ->getPointeeType()
+ .getAsOpaquePtr());
+ return eTypeHasChildren | eTypeIsReference | eTypeHasValue;
+
+ case clang::Type::MemberPointer:
+ return eTypeIsPointer | eTypeIsMember | eTypeHasValue;
+
+ case clang::Type::ObjCObjectPointer:
+ if (pointee_or_element_clang_type)
+ pointee_or_element_clang_type->SetCompilerType(
+ this, qual_type->getPointeeType().getAsOpaquePtr());
+ return eTypeHasChildren | eTypeIsObjC | eTypeIsClass | eTypeIsPointer |
+ eTypeHasValue;
+
+ case clang::Type::ObjCObject:
+ return eTypeHasChildren | eTypeIsObjC | eTypeIsClass;
+ case clang::Type::ObjCInterface:
+ return eTypeHasChildren | eTypeIsObjC | eTypeIsClass;
+
+ case clang::Type::Pointer:
+ if (pointee_or_element_clang_type)
+ pointee_or_element_clang_type->SetCompilerType(
+ this, qual_type->getPointeeType().getAsOpaquePtr());
+ return eTypeHasChildren | eTypeIsPointer | eTypeHasValue;
+
+ case clang::Type::Record:
+ if (qual_type->getAsCXXRecordDecl())
+ return eTypeHasChildren | eTypeIsClass | eTypeIsCPlusPlus;
+ else
+ return eTypeHasChildren | eTypeIsStructUnion;
+ break;
+ case clang::Type::SubstTemplateTypeParm:
+ return eTypeIsTemplate;
+ case clang::Type::TemplateTypeParm:
+ return eTypeIsTemplate;
+ case clang::Type::TemplateSpecialization:
+ return eTypeIsTemplate;
+
+ case clang::Type::Typedef:
+ return eTypeIsTypedef | GetType(llvm::cast<clang::TypedefType>(qual_type)
+ ->getDecl()
+ ->getUnderlyingType())
+ .GetTypeInfo(pointee_or_element_clang_type);
+ case clang::Type::UnresolvedUsing:
+ return 0;
+
+ case clang::Type::ExtVector:
+ case clang::Type::Vector: {
+ uint32_t vector_type_flags = eTypeHasChildren | eTypeIsVector;
+ const clang::VectorType *vector_type = llvm::dyn_cast<clang::VectorType>(
+ qual_type->getCanonicalTypeInternal());
+ if (vector_type) {
+ if (vector_type->isIntegerType())
+ vector_type_flags |= eTypeIsFloat;
+ else if (vector_type->isFloatingType())
+ vector_type_flags |= eTypeIsInteger;
+ }
+ return vector_type_flags;
+ }
+ default:
+ return 0;
+ }
+ return 0;
+}
+
+lldb::LanguageType
+TypeSystemClang::GetMinimumLanguage(lldb::opaque_compiler_type_t type) {
+ if (!type)
+ return lldb::eLanguageTypeC;
+
+ // If the type is a reference, then resolve it to what it refers to first:
+ clang::QualType qual_type(GetCanonicalQualType(type).getNonReferenceType());
+ if (qual_type->isAnyPointerType()) {
+ if (qual_type->isObjCObjectPointerType())
+ return lldb::eLanguageTypeObjC;
+ if (qual_type->getPointeeCXXRecordDecl())
+ return lldb::eLanguageTypeC_plus_plus;
+
+ clang::QualType pointee_type(qual_type->getPointeeType());
+ if (pointee_type->getPointeeCXXRecordDecl())
+ return lldb::eLanguageTypeC_plus_plus;
+ if (pointee_type->isObjCObjectOrInterfaceType())
+ return lldb::eLanguageTypeObjC;
+ if (pointee_type->isObjCClassType())
+ return lldb::eLanguageTypeObjC;
+ if (pointee_type.getTypePtr() ==
+ getASTContext().ObjCBuiltinIdTy.getTypePtr())
+ return lldb::eLanguageTypeObjC;
+ } else {
+ if (qual_type->isObjCObjectOrInterfaceType())
+ return lldb::eLanguageTypeObjC;
+ if (qual_type->getAsCXXRecordDecl())
+ return lldb::eLanguageTypeC_plus_plus;
+ switch (qual_type->getTypeClass()) {
+ default:
+ break;
+ case clang::Type::Builtin:
+ switch (llvm::cast<clang::BuiltinType>(qual_type)->getKind()) {
+ default:
+ case clang::BuiltinType::Void:
+ case clang::BuiltinType::Bool:
+ case clang::BuiltinType::Char_U:
+ case clang::BuiltinType::UChar:
+ case clang::BuiltinType::WChar_U:
+ case clang::BuiltinType::Char16:
+ case clang::BuiltinType::Char32:
+ case clang::BuiltinType::UShort:
+ case clang::BuiltinType::UInt:
+ case clang::BuiltinType::ULong:
+ case clang::BuiltinType::ULongLong:
+ case clang::BuiltinType::UInt128:
+ case clang::BuiltinType::Char_S:
+ case clang::BuiltinType::SChar:
+ case clang::BuiltinType::WChar_S:
+ case clang::BuiltinType::Short:
+ case clang::BuiltinType::Int:
+ case clang::BuiltinType::Long:
+ case clang::BuiltinType::LongLong:
+ case clang::BuiltinType::Int128:
+ case clang::BuiltinType::Float:
+ case clang::BuiltinType::Double:
+ case clang::BuiltinType::LongDouble:
+ break;
+
+ case clang::BuiltinType::NullPtr:
+ return eLanguageTypeC_plus_plus;
+
+ case clang::BuiltinType::ObjCId:
+ case clang::BuiltinType::ObjCClass:
+ case clang::BuiltinType::ObjCSel:
+ return eLanguageTypeObjC;
+
+ case clang::BuiltinType::Dependent:
+ case clang::BuiltinType::Overload:
+ case clang::BuiltinType::BoundMember:
+ case clang::BuiltinType::UnknownAny:
+ break;
+ }
+ break;
+ case clang::Type::Typedef:
+ return GetType(llvm::cast<clang::TypedefType>(qual_type)
+ ->getDecl()
+ ->getUnderlyingType())
+ .GetMinimumLanguage();
+ }
+ }
+ return lldb::eLanguageTypeC;
+}
+
+lldb::TypeClass
+TypeSystemClang::GetTypeClass(lldb::opaque_compiler_type_t type) {
+ if (!type)
+ return lldb::eTypeClassInvalid;
+
+ clang::QualType qual_type =
+ RemoveWrappingTypes(GetQualType(type), {clang::Type::Typedef});
+
+ switch (qual_type->getTypeClass()) {
+ case clang::Type::Atomic:
+ case clang::Type::Auto:
+ case clang::Type::Decltype:
+ case clang::Type::Elaborated:
+ case clang::Type::Paren:
+ case clang::Type::TypeOf:
+ case clang::Type::TypeOfExpr:
+ llvm_unreachable("Handled in RemoveWrappingTypes!");
+ case clang::Type::UnaryTransform:
+ break;
+ case clang::Type::FunctionNoProto:
+ return lldb::eTypeClassFunction;
+ case clang::Type::FunctionProto:
+ return lldb::eTypeClassFunction;
+ case clang::Type::IncompleteArray:
+ return lldb::eTypeClassArray;
+ case clang::Type::VariableArray:
+ return lldb::eTypeClassArray;
+ case clang::Type::ConstantArray:
+ return lldb::eTypeClassArray;
+ case clang::Type::DependentSizedArray:
+ return lldb::eTypeClassArray;
+ case clang::Type::DependentSizedExtVector:
+ return lldb::eTypeClassVector;
+ case clang::Type::DependentVector:
+ return lldb::eTypeClassVector;
+ case clang::Type::ExtVector:
+ return lldb::eTypeClassVector;
+ case clang::Type::Vector:
+ return lldb::eTypeClassVector;
+ case clang::Type::Builtin:
+ return lldb::eTypeClassBuiltin;
+ case clang::Type::ObjCObjectPointer:
+ return lldb::eTypeClassObjCObjectPointer;
+ case clang::Type::BlockPointer:
+ return lldb::eTypeClassBlockPointer;
+ case clang::Type::Pointer:
+ return lldb::eTypeClassPointer;
+ case clang::Type::LValueReference:
+ return lldb::eTypeClassReference;
+ case clang::Type::RValueReference:
+ return lldb::eTypeClassReference;
+ case clang::Type::MemberPointer:
+ return lldb::eTypeClassMemberPointer;
+ case clang::Type::Complex:
+ if (qual_type->isComplexType())
+ return lldb::eTypeClassComplexFloat;
+ else
+ return lldb::eTypeClassComplexInteger;
+ case clang::Type::ObjCObject:
+ return lldb::eTypeClassObjCObject;
+ case clang::Type::ObjCInterface:
+ return lldb::eTypeClassObjCInterface;
+ case clang::Type::Record: {
+ const clang::RecordType *record_type =
+ llvm::cast<clang::RecordType>(qual_type.getTypePtr());
+ const clang::RecordDecl *record_decl = record_type->getDecl();
+ if (record_decl->isUnion())
+ return lldb::eTypeClassUnion;
+ else if (record_decl->isStruct())
+ return lldb::eTypeClassStruct;
+ else
+ return lldb::eTypeClassClass;
+ } break;
+ case clang::Type::Enum:
+ return lldb::eTypeClassEnumeration;
+ case clang::Type::Typedef:
+ return lldb::eTypeClassTypedef;
+ case clang::Type::UnresolvedUsing:
+ break;
+
+ case clang::Type::Attributed:
+ break;
+ case clang::Type::TemplateTypeParm:
+ break;
+ case clang::Type::SubstTemplateTypeParm:
+ break;
+ case clang::Type::SubstTemplateTypeParmPack:
+ break;
+ case clang::Type::InjectedClassName:
+ break;
+ case clang::Type::DependentName:
+ break;
+ case clang::Type::DependentTemplateSpecialization:
+ break;
+ case clang::Type::PackExpansion:
+ break;
+
+ case clang::Type::TemplateSpecialization:
+ break;
+ case clang::Type::DeducedTemplateSpecialization:
+ break;
+ case clang::Type::Pipe:
+ break;
+
+ // pointer type decayed from an array or function type.
+ case clang::Type::Decayed:
+ break;
+ case clang::Type::Adjusted:
+ break;
+ case clang::Type::ObjCTypeParam:
+ break;
+
+ case clang::Type::DependentAddressSpace:
+ break;
+ case clang::Type::MacroQualified:
+ break;
+ }
+ // We don't know hot to display this type...
+ return lldb::eTypeClassOther;
+}
+
+unsigned TypeSystemClang::GetTypeQualifiers(lldb::opaque_compiler_type_t type) {
+ if (type)
+ return GetQualType(type).getQualifiers().getCVRQualifiers();
+ return 0;
+}
+
+// Creating related types
+
+CompilerType
+TypeSystemClang::GetArrayElementType(lldb::opaque_compiler_type_t type,
+ uint64_t *stride) {
+ if (type) {
+ clang::QualType qual_type(GetQualType(type));
+
+ const clang::Type *array_eletype =
+ qual_type.getTypePtr()->getArrayElementTypeNoTypeQual();
+
+ if (!array_eletype)
+ return CompilerType();
+
+ CompilerType element_type = GetType(clang::QualType(array_eletype, 0));
+
+ // TODO: the real stride will be >= this value.. find the real one!
+ if (stride)
+ if (Optional<uint64_t> size = element_type.GetByteSize(nullptr))
+ *stride = *size;
+
+ return element_type;
+ }
+ return CompilerType();
+}
+
+CompilerType TypeSystemClang::GetArrayType(lldb::opaque_compiler_type_t type,
+ uint64_t size) {
+ if (type) {
+ clang::QualType qual_type(GetCanonicalQualType(type));
+ clang::ASTContext &ast_ctx = getASTContext();
+ if (size != 0)
+ return GetType(ast_ctx.getConstantArrayType(
+ qual_type, llvm::APInt(64, size), nullptr,
+ clang::ArrayType::ArraySizeModifier::Normal, 0));
+ else
+ return GetType(ast_ctx.getIncompleteArrayType(
+ qual_type, clang::ArrayType::ArraySizeModifier::Normal, 0));
+ }
+
+ return CompilerType();
+}
+
+CompilerType
+TypeSystemClang::GetCanonicalType(lldb::opaque_compiler_type_t type) {
+ if (type)
+ return GetType(GetCanonicalQualType(type));
+ return CompilerType();
+}
+
+static clang::QualType GetFullyUnqualifiedType_Impl(clang::ASTContext *ast,
+ clang::QualType qual_type) {
+ if (qual_type->isPointerType())
+ qual_type = ast->getPointerType(
+ GetFullyUnqualifiedType_Impl(ast, qual_type->getPointeeType()));
+ else
+ qual_type = qual_type.getUnqualifiedType();
+ qual_type.removeLocalConst();
+ qual_type.removeLocalRestrict();
+ qual_type.removeLocalVolatile();
+ return qual_type;
+}
+
+CompilerType
+TypeSystemClang::GetFullyUnqualifiedType(lldb::opaque_compiler_type_t type) {
+ if (type)
+ return GetType(
+ GetFullyUnqualifiedType_Impl(&getASTContext(), GetQualType(type)));
+ return CompilerType();
+}
+
+int TypeSystemClang::GetFunctionArgumentCount(
+ lldb::opaque_compiler_type_t type) {
+ if (type) {
+ const clang::FunctionProtoType *func =
+ llvm::dyn_cast<clang::FunctionProtoType>(GetCanonicalQualType(type));
+ if (func)
+ return func->getNumParams();
+ }
+ return -1;
+}
+
+CompilerType TypeSystemClang::GetFunctionArgumentTypeAtIndex(
+ lldb::opaque_compiler_type_t type, size_t idx) {
+ if (type) {
+ const clang::FunctionProtoType *func =
+ llvm::dyn_cast<clang::FunctionProtoType>(GetQualType(type));
+ if (func) {
+ const uint32_t num_args = func->getNumParams();
+ if (idx < num_args)
+ return GetType(func->getParamType(idx));
+ }
+ }
+ return CompilerType();
+}
+
+CompilerType
+TypeSystemClang::GetFunctionReturnType(lldb::opaque_compiler_type_t type) {
+ if (type) {
+ clang::QualType qual_type(GetQualType(type));
+ const clang::FunctionProtoType *func =
+ llvm::dyn_cast<clang::FunctionProtoType>(qual_type.getTypePtr());
+ if (func)
+ return GetType(func->getReturnType());
+ }
+ return CompilerType();
+}
+
+size_t
+TypeSystemClang::GetNumMemberFunctions(lldb::opaque_compiler_type_t type) {
+ size_t num_functions = 0;
+ if (type) {
+ clang::QualType qual_type = RemoveWrappingTypes(GetCanonicalQualType(type));
+ switch (qual_type->getTypeClass()) {
+ case clang::Type::Record:
+ if (GetCompleteQualType(&getASTContext(), qual_type)) {
+ const clang::RecordType *record_type =
+ llvm::cast<clang::RecordType>(qual_type.getTypePtr());
+ const clang::RecordDecl *record_decl = record_type->getDecl();
+ assert(record_decl);
+ const clang::CXXRecordDecl *cxx_record_decl =
+ llvm::dyn_cast<clang::CXXRecordDecl>(record_decl);
+ if (cxx_record_decl)
+ num_functions = std::distance(cxx_record_decl->method_begin(),
+ cxx_record_decl->method_end());
+ }
+ break;
+
+ case clang::Type::ObjCObjectPointer: {
+ const clang::ObjCObjectPointerType *objc_class_type =
+ qual_type->getAs<clang::ObjCObjectPointerType>();
+ const clang::ObjCInterfaceType *objc_interface_type =
+ objc_class_type->getInterfaceType();
+ if (objc_interface_type &&
+ GetCompleteType(static_cast<lldb::opaque_compiler_type_t>(
+ const_cast<clang::ObjCInterfaceType *>(objc_interface_type)))) {
+ clang::ObjCInterfaceDecl *class_interface_decl =
+ objc_interface_type->getDecl();
+ if (class_interface_decl) {
+ num_functions = std::distance(class_interface_decl->meth_begin(),
+ class_interface_decl->meth_end());
+ }
+ }
+ break;
+ }
+
+ case clang::Type::ObjCObject:
+ case clang::Type::ObjCInterface:
+ if (GetCompleteType(type)) {
+ const clang::ObjCObjectType *objc_class_type =
+ llvm::dyn_cast<clang::ObjCObjectType>(qual_type.getTypePtr());
+ if (objc_class_type) {
+ clang::ObjCInterfaceDecl *class_interface_decl =
+ objc_class_type->getInterface();
+ if (class_interface_decl)
+ num_functions = std::distance(class_interface_decl->meth_begin(),
+ class_interface_decl->meth_end());
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ return num_functions;
+}
+
+TypeMemberFunctionImpl
+TypeSystemClang::GetMemberFunctionAtIndex(lldb::opaque_compiler_type_t type,
+ size_t idx) {
+ std::string name;
+ MemberFunctionKind kind(MemberFunctionKind::eMemberFunctionKindUnknown);
+ CompilerType clang_type;
+ CompilerDecl clang_decl;
+ if (type) {
+ clang::QualType qual_type = RemoveWrappingTypes(GetCanonicalQualType(type));
+ switch (qual_type->getTypeClass()) {
+ case clang::Type::Record:
+ if (GetCompleteQualType(&getASTContext(), qual_type)) {
+ const clang::RecordType *record_type =
+ llvm::cast<clang::RecordType>(qual_type.getTypePtr());
+ const clang::RecordDecl *record_decl = record_type->getDecl();
+ assert(record_decl);
+ const clang::CXXRecordDecl *cxx_record_decl =
+ llvm::dyn_cast<clang::CXXRecordDecl>(record_decl);
+ if (cxx_record_decl) {
+ auto method_iter = cxx_record_decl->method_begin();
+ auto method_end = cxx_record_decl->method_end();
+ if (idx <
+ static_cast<size_t>(std::distance(method_iter, method_end))) {
+ std::advance(method_iter, idx);
+ clang::CXXMethodDecl *cxx_method_decl =
+ method_iter->getCanonicalDecl();
+ if (cxx_method_decl) {
+ name = cxx_method_decl->getDeclName().getAsString();
+ if (cxx_method_decl->isStatic())
+ kind = lldb::eMemberFunctionKindStaticMethod;
+ else if (llvm::isa<clang::CXXConstructorDecl>(cxx_method_decl))
+ kind = lldb::eMemberFunctionKindConstructor;
+ else if (llvm::isa<clang::CXXDestructorDecl>(cxx_method_decl))
+ kind = lldb::eMemberFunctionKindDestructor;
+ else
+ kind = lldb::eMemberFunctionKindInstanceMethod;
+ clang_type = GetType(cxx_method_decl->getType());
+ clang_decl = GetCompilerDecl(cxx_method_decl);
+ }
+ }
+ }
+ }
+ break;
+
+ case clang::Type::ObjCObjectPointer: {
+ const clang::ObjCObjectPointerType *objc_class_type =
+ qual_type->getAs<clang::ObjCObjectPointerType>();
+ const clang::ObjCInterfaceType *objc_interface_type =
+ objc_class_type->getInterfaceType();
+ if (objc_interface_type &&
+ GetCompleteType(static_cast<lldb::opaque_compiler_type_t>(
+ const_cast<clang::ObjCInterfaceType *>(objc_interface_type)))) {
+ clang::ObjCInterfaceDecl *class_interface_decl =
+ objc_interface_type->getDecl();
+ if (class_interface_decl) {
+ auto method_iter = class_interface_decl->meth_begin();
+ auto method_end = class_interface_decl->meth_end();
+ if (idx <
+ static_cast<size_t>(std::distance(method_iter, method_end))) {
+ std::advance(method_iter, idx);
+ clang::ObjCMethodDecl *objc_method_decl =
+ method_iter->getCanonicalDecl();
+ if (objc_method_decl) {
+ clang_decl = GetCompilerDecl(objc_method_decl);
+ name = objc_method_decl->getSelector().getAsString();
+ if (objc_method_decl->isClassMethod())
+ kind = lldb::eMemberFunctionKindStaticMethod;
+ else
+ kind = lldb::eMemberFunctionKindInstanceMethod;
+ }
+ }
+ }
+ }
+ break;
+ }
+
+ case clang::Type::ObjCObject:
+ case clang::Type::ObjCInterface:
+ if (GetCompleteType(type)) {
+ const clang::ObjCObjectType *objc_class_type =
+ llvm::dyn_cast<clang::ObjCObjectType>(qual_type.getTypePtr());
+ if (objc_class_type) {
+ clang::ObjCInterfaceDecl *class_interface_decl =
+ objc_class_type->getInterface();
+ if (class_interface_decl) {
+ auto method_iter = class_interface_decl->meth_begin();
+ auto method_end = class_interface_decl->meth_end();
+ if (idx <
+ static_cast<size_t>(std::distance(method_iter, method_end))) {
+ std::advance(method_iter, idx);
+ clang::ObjCMethodDecl *objc_method_decl =
+ method_iter->getCanonicalDecl();
+ if (objc_method_decl) {
+ clang_decl = GetCompilerDecl(objc_method_decl);
+ name = objc_method_decl->getSelector().getAsString();
+ if (objc_method_decl->isClassMethod())
+ kind = lldb::eMemberFunctionKindStaticMethod;
+ else
+ kind = lldb::eMemberFunctionKindInstanceMethod;
+ }
+ }
+ }
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ if (kind == eMemberFunctionKindUnknown)
+ return TypeMemberFunctionImpl();
+ else
+ return TypeMemberFunctionImpl(clang_type, clang_decl, name, kind);
+}
+
+CompilerType
+TypeSystemClang::GetNonReferenceType(lldb::opaque_compiler_type_t type) {
+ if (type)
+ return GetType(GetQualType(type).getNonReferenceType());
+ return CompilerType();
+}
+
+CompilerType TypeSystemClang::CreateTypedefType(
+ const CompilerType &type, const char *typedef_name,
+ const CompilerDeclContext &compiler_decl_ctx) {
+ if (type && typedef_name && typedef_name[0]) {
+ TypeSystemClang *ast =
+ llvm::dyn_cast<TypeSystemClang>(type.GetTypeSystem());
+ if (!ast)
+ return CompilerType();
+ clang::ASTContext &clang_ast = ast->getASTContext();
+ clang::QualType qual_type(ClangUtil::GetQualType(type));
+
+ clang::DeclContext *decl_ctx =
+ TypeSystemClang::DeclContextGetAsDeclContext(compiler_decl_ctx);
+ if (decl_ctx == nullptr)
+ decl_ctx = ast->getASTContext().getTranslationUnitDecl();
+
+ clang::TypedefDecl *decl = clang::TypedefDecl::Create(
+ clang_ast, decl_ctx, clang::SourceLocation(), clang::SourceLocation(),
+ &clang_ast.Idents.get(typedef_name),
+ clang_ast.getTrivialTypeSourceInfo(qual_type));
+
+ decl->setAccess(clang::AS_public); // TODO respect proper access specifier
+
+ decl_ctx->addDecl(decl);
+
+ // Get a uniqued clang::QualType for the typedef decl type
+ return ast->GetType(clang_ast.getTypedefType(decl));
+ }
+ return CompilerType();
+}
+
+CompilerType
+TypeSystemClang::GetPointeeType(lldb::opaque_compiler_type_t type) {
+ if (type) {
+ clang::QualType qual_type(GetQualType(type));
+ return GetType(qual_type.getTypePtr()->getPointeeType());
+ }
+ return CompilerType();
+}
+
+CompilerType
+TypeSystemClang::GetPointerType(lldb::opaque_compiler_type_t type) {
+ if (type) {
+ clang::QualType qual_type(GetQualType(type));
+
+ const clang::Type::TypeClass type_class = qual_type->getTypeClass();
+ switch (type_class) {
+ case clang::Type::ObjCObject:
+ case clang::Type::ObjCInterface:
+ return GetType(getASTContext().getObjCObjectPointerType(qual_type));
+
+ default:
+ return GetType(getASTContext().getPointerType(qual_type));
+ }
+ }
+ return CompilerType();
+}
+
+CompilerType
+TypeSystemClang::GetLValueReferenceType(lldb::opaque_compiler_type_t type) {
+ if (type)
+ return GetType(getASTContext().getLValueReferenceType(GetQualType(type)));
+ else
+ return CompilerType();
+}
+
+CompilerType
+TypeSystemClang::GetRValueReferenceType(lldb::opaque_compiler_type_t type) {
+ if (type)
+ return GetType(getASTContext().getRValueReferenceType(GetQualType(type)));
+ else
+ return CompilerType();
+}
+
+CompilerType TypeSystemClang::GetAtomicType(lldb::opaque_compiler_type_t type) {
+ if (!type)
+ return CompilerType();
+ return GetType(getASTContext().getAtomicType(GetQualType(type)));
+}
+
+CompilerType
+TypeSystemClang::AddConstModifier(lldb::opaque_compiler_type_t type) {
+ if (type) {
+ clang::QualType result(GetQualType(type));
+ result.addConst();
+ return GetType(result);
+ }
+ return CompilerType();
+}
+
+CompilerType
+TypeSystemClang::AddVolatileModifier(lldb::opaque_compiler_type_t type) {
+ if (type) {
+ clang::QualType result(GetQualType(type));
+ result.addVolatile();
+ return GetType(result);
+ }
+ return CompilerType();
+}
+
+CompilerType
+TypeSystemClang::AddRestrictModifier(lldb::opaque_compiler_type_t type) {
+ if (type) {
+ clang::QualType result(GetQualType(type));
+ result.addRestrict();
+ return GetType(result);
+ }
+ return CompilerType();
+}
+
+CompilerType
+TypeSystemClang::CreateTypedef(lldb::opaque_compiler_type_t type,
+ const char *typedef_name,
+ const CompilerDeclContext &compiler_decl_ctx) {
+ if (type) {
+ clang::ASTContext &clang_ast = getASTContext();
+ clang::QualType qual_type(GetQualType(type));
+
+ clang::DeclContext *decl_ctx =
+ TypeSystemClang::DeclContextGetAsDeclContext(compiler_decl_ctx);
+ if (decl_ctx == nullptr)
+ decl_ctx = getASTContext().getTranslationUnitDecl();
+
+ clang::TypedefDecl *decl = clang::TypedefDecl::Create(
+ clang_ast, decl_ctx, clang::SourceLocation(), clang::SourceLocation(),
+ &clang_ast.Idents.get(typedef_name),
+ clang_ast.getTrivialTypeSourceInfo(qual_type));
+
+ clang::TagDecl *tdecl = nullptr;
+ if (!qual_type.isNull()) {
+ if (const clang::RecordType *rt = qual_type->getAs<clang::RecordType>())
+ tdecl = rt->getDecl();
+ if (const clang::EnumType *et = qual_type->getAs<clang::EnumType>())
+ tdecl = et->getDecl();
+ }
+
+ // Check whether this declaration is an anonymous struct, union, or enum,
+ // hidden behind a typedef. If so, we try to check whether we have a
+ // typedef tag to attach to the original record declaration
+ if (tdecl && !tdecl->getIdentifier() && !tdecl->getTypedefNameForAnonDecl())
+ tdecl->setTypedefNameForAnonDecl(decl);
+
+ decl->setAccess(clang::AS_public); // TODO respect proper access specifier
+
+ // Get a uniqued clang::QualType for the typedef decl type
+ return GetType(clang_ast.getTypedefType(decl));
+ }
+ return CompilerType();
+}
+
+CompilerType
+TypeSystemClang::GetTypedefedType(lldb::opaque_compiler_type_t type) {
+ if (type) {
+ const clang::TypedefType *typedef_type =
+ llvm::dyn_cast<clang::TypedefType>(GetQualType(type));
+ if (typedef_type)
+ return GetType(typedef_type->getDecl()->getUnderlyingType());
+ }
+ return CompilerType();
+}
+
+// Create related types using the current type's AST
+
+CompilerType TypeSystemClang::GetBasicTypeFromAST(lldb::BasicType basic_type) {
+ return TypeSystemClang::GetBasicType(basic_type);
+}
+// Exploring the type
+
+const llvm::fltSemantics &
+TypeSystemClang::GetFloatTypeSemantics(size_t byte_size) {
+ clang::ASTContext &ast = getASTContext();
+ const size_t bit_size = byte_size * 8;
+ if (bit_size == ast.getTypeSize(ast.FloatTy))
+ return ast.getFloatTypeSemantics(ast.FloatTy);
+ else if (bit_size == ast.getTypeSize(ast.DoubleTy))
+ return ast.getFloatTypeSemantics(ast.DoubleTy);
+ else if (bit_size == ast.getTypeSize(ast.LongDoubleTy))
+ return ast.getFloatTypeSemantics(ast.LongDoubleTy);
+ else if (bit_size == ast.getTypeSize(ast.HalfTy))
+ return ast.getFloatTypeSemantics(ast.HalfTy);
+ return llvm::APFloatBase::Bogus();
+}
+
+Optional<uint64_t>
+TypeSystemClang::GetBitSize(lldb::opaque_compiler_type_t type,
+ ExecutionContextScope *exe_scope) {
+ if (GetCompleteType(type)) {
+ clang::QualType qual_type(GetCanonicalQualType(type));
+ const clang::Type::TypeClass type_class = qual_type->getTypeClass();
+ switch (type_class) {
+ case clang::Type::Record:
+ if (GetCompleteType(type))
+ return getASTContext().getTypeSize(qual_type);
+ else
+ return None;
+ break;
+
+ case clang::Type::ObjCInterface:
+ case clang::Type::ObjCObject: {
+ ExecutionContext exe_ctx(exe_scope);
+ Process *process = exe_ctx.GetProcessPtr();
+ if (process) {
+ ObjCLanguageRuntime *objc_runtime = ObjCLanguageRuntime::Get(*process);
+ if (objc_runtime) {
+ uint64_t bit_size = 0;
+ if (objc_runtime->GetTypeBitSize(GetType(qual_type), bit_size))
+ return bit_size;
+ }
+ } else {
+ static bool g_printed = false;
+ if (!g_printed) {
+ StreamString s;
+ DumpTypeDescription(type, &s);
+
+ llvm::outs() << "warning: trying to determine the size of type ";
+ llvm::outs() << s.GetString() << "\n";
+ llvm::outs() << "without a valid ExecutionContext. this is not "
+ "reliable. please file a bug against LLDB.\n";
+ llvm::outs() << "backtrace:\n";
+ llvm::sys::PrintStackTrace(llvm::outs());
+ llvm::outs() << "\n";
+ g_printed = true;
+ }
+ }
+ }
+ LLVM_FALLTHROUGH;
+ default:
+ const uint32_t bit_size = getASTContext().getTypeSize(qual_type);
+ if (bit_size == 0) {
+ if (qual_type->isIncompleteArrayType())
+ return getASTContext().getTypeSize(
+ qual_type->getArrayElementTypeNoTypeQual()
+ ->getCanonicalTypeUnqualified());
+ }
+ if (qual_type->isObjCObjectOrInterfaceType())
+ return bit_size +
+ getASTContext().getTypeSize(getASTContext().ObjCBuiltinClassTy);
+ // Function types actually have a size of 0, that's not an error.
+ if (qual_type->isFunctionProtoType())
+ return bit_size;
+ if (bit_size)
+ return bit_size;
+ }
+ }
+ return None;
+}
+
+llvm::Optional<size_t>
+TypeSystemClang::GetTypeBitAlign(lldb::opaque_compiler_type_t type,
+ ExecutionContextScope *exe_scope) {
+ if (GetCompleteType(type))
+ return getASTContext().getTypeAlign(GetQualType(type));
+ return {};
+}
+
+lldb::Encoding TypeSystemClang::GetEncoding(lldb::opaque_compiler_type_t type,
+ uint64_t &count) {
+ if (!type)
+ return lldb::eEncodingInvalid;
+
+ count = 1;
+ clang::QualType qual_type = RemoveWrappingTypes(GetCanonicalQualType(type));
+
+ switch (qual_type->getTypeClass()) {
+ case clang::Type::Atomic:
+ case clang::Type::Auto:
+ case clang::Type::Decltype:
+ case clang::Type::Elaborated:
+ case clang::Type::Paren:
+ case clang::Type::Typedef:
+ case clang::Type::TypeOf:
+ case clang::Type::TypeOfExpr:
+ llvm_unreachable("Handled in RemoveWrappingTypes!");
+
+ case clang::Type::UnaryTransform:
+ break;
+
+ case clang::Type::FunctionNoProto:
+ case clang::Type::FunctionProto:
+ break;
+
+ case clang::Type::IncompleteArray:
+ case clang::Type::VariableArray:
+ break;
+
+ case clang::Type::ConstantArray:
+ break;
+
+ case clang::Type::DependentVector:
+ case clang::Type::ExtVector:
+ case clang::Type::Vector:
+ // TODO: Set this to more than one???
+ break;
+
+ case clang::Type::Builtin:
+ switch (llvm::cast<clang::BuiltinType>(qual_type)->getKind()) {
+ case clang::BuiltinType::Void:
+ break;
+
+ case clang::BuiltinType::Bool:
+ case clang::BuiltinType::Char_S:
+ case clang::BuiltinType::SChar:
+ case clang::BuiltinType::WChar_S:
+ case clang::BuiltinType::Short:
+ case clang::BuiltinType::Int:
+ case clang::BuiltinType::Long:
+ case clang::BuiltinType::LongLong:
+ case clang::BuiltinType::Int128:
+ return lldb::eEncodingSint;
+
+ case clang::BuiltinType::Char_U:
+ case clang::BuiltinType::UChar:
+ case clang::BuiltinType::WChar_U:
+ case clang::BuiltinType::Char8:
+ case clang::BuiltinType::Char16:
+ case clang::BuiltinType::Char32:
+ case clang::BuiltinType::UShort:
+ case clang::BuiltinType::UInt:
+ case clang::BuiltinType::ULong:
+ case clang::BuiltinType::ULongLong:
+ case clang::BuiltinType::UInt128:
+ return lldb::eEncodingUint;
+
+ // Fixed point types. Note that they are currently ignored.
+ case clang::BuiltinType::ShortAccum:
+ case clang::BuiltinType::Accum:
+ case clang::BuiltinType::LongAccum:
+ case clang::BuiltinType::UShortAccum:
+ case clang::BuiltinType::UAccum:
+ case clang::BuiltinType::ULongAccum:
+ case clang::BuiltinType::ShortFract:
+ case clang::BuiltinType::Fract:
+ case clang::BuiltinType::LongFract:
+ case clang::BuiltinType::UShortFract:
+ case clang::BuiltinType::UFract:
+ case clang::BuiltinType::ULongFract:
+ case clang::BuiltinType::SatShortAccum:
+ case clang::BuiltinType::SatAccum:
+ case clang::BuiltinType::SatLongAccum:
+ case clang::BuiltinType::SatUShortAccum:
+ case clang::BuiltinType::SatUAccum:
+ case clang::BuiltinType::SatULongAccum:
+ case clang::BuiltinType::SatShortFract:
+ case clang::BuiltinType::SatFract:
+ case clang::BuiltinType::SatLongFract:
+ case clang::BuiltinType::SatUShortFract:
+ case clang::BuiltinType::SatUFract:
+ case clang::BuiltinType::SatULongFract:
+ break;
+
+ case clang::BuiltinType::Half:
+ case clang::BuiltinType::Float:
+ case clang::BuiltinType::Float16:
+ case clang::BuiltinType::Float128:
+ case clang::BuiltinType::Double:
+ case clang::BuiltinType::LongDouble:
+ return lldb::eEncodingIEEE754;
+
+ case clang::BuiltinType::ObjCClass:
+ case clang::BuiltinType::ObjCId:
+ case clang::BuiltinType::ObjCSel:
+ return lldb::eEncodingUint;
+
+ case clang::BuiltinType::NullPtr:
+ return lldb::eEncodingUint;
+
+ case clang::BuiltinType::Kind::ARCUnbridgedCast:
+ case clang::BuiltinType::Kind::BoundMember:
+ case clang::BuiltinType::Kind::BuiltinFn:
+ case clang::BuiltinType::Kind::Dependent:
+ case clang::BuiltinType::Kind::OCLClkEvent:
+ case clang::BuiltinType::Kind::OCLEvent:
+ case clang::BuiltinType::Kind::OCLImage1dRO:
+ case clang::BuiltinType::Kind::OCLImage1dWO:
+ case clang::BuiltinType::Kind::OCLImage1dRW:
+ case clang::BuiltinType::Kind::OCLImage1dArrayRO:
+ case clang::BuiltinType::Kind::OCLImage1dArrayWO:
+ case clang::BuiltinType::Kind::OCLImage1dArrayRW:
+ case clang::BuiltinType::Kind::OCLImage1dBufferRO:
+ case clang::BuiltinType::Kind::OCLImage1dBufferWO:
+ case clang::BuiltinType::Kind::OCLImage1dBufferRW:
+ case clang::BuiltinType::Kind::OCLImage2dRO:
+ case clang::BuiltinType::Kind::OCLImage2dWO:
+ case clang::BuiltinType::Kind::OCLImage2dRW:
+ case clang::BuiltinType::Kind::OCLImage2dArrayRO:
+ case clang::BuiltinType::Kind::OCLImage2dArrayWO:
+ case clang::BuiltinType::Kind::OCLImage2dArrayRW:
+ case clang::BuiltinType::Kind::OCLImage2dArrayDepthRO:
+ case clang::BuiltinType::Kind::OCLImage2dArrayDepthWO:
+ case clang::BuiltinType::Kind::OCLImage2dArrayDepthRW:
+ case clang::BuiltinType::Kind::OCLImage2dArrayMSAARO:
+ case clang::BuiltinType::Kind::OCLImage2dArrayMSAAWO:
+ case clang::BuiltinType::Kind::OCLImage2dArrayMSAARW:
+ case clang::BuiltinType::Kind::OCLImage2dArrayMSAADepthRO:
+ case clang::BuiltinType::Kind::OCLImage2dArrayMSAADepthWO:
+ case clang::BuiltinType::Kind::OCLImage2dArrayMSAADepthRW:
+ case clang::BuiltinType::Kind::OCLImage2dDepthRO:
+ case clang::BuiltinType::Kind::OCLImage2dDepthWO:
+ case clang::BuiltinType::Kind::OCLImage2dDepthRW:
+ case clang::BuiltinType::Kind::OCLImage2dMSAARO:
+ case clang::BuiltinType::Kind::OCLImage2dMSAAWO:
+ case clang::BuiltinType::Kind::OCLImage2dMSAARW:
+ case clang::BuiltinType::Kind::OCLImage2dMSAADepthRO:
+ case clang::BuiltinType::Kind::OCLImage2dMSAADepthWO:
+ case clang::BuiltinType::Kind::OCLImage2dMSAADepthRW:
+ case clang::BuiltinType::Kind::OCLImage3dRO:
+ case clang::BuiltinType::Kind::OCLImage3dWO:
+ case clang::BuiltinType::Kind::OCLImage3dRW:
+ case clang::BuiltinType::Kind::OCLQueue:
+ case clang::BuiltinType::Kind::OCLReserveID:
+ case clang::BuiltinType::Kind::OCLSampler:
+ case clang::BuiltinType::Kind::OMPArraySection:
+ case clang::BuiltinType::Kind::Overload:
+ case clang::BuiltinType::Kind::PseudoObject:
+ case clang::BuiltinType::Kind::UnknownAny:
+ break;
+
+ case clang::BuiltinType::OCLIntelSubgroupAVCMcePayload:
+ case clang::BuiltinType::OCLIntelSubgroupAVCImePayload:
+ case clang::BuiltinType::OCLIntelSubgroupAVCRefPayload:
+ case clang::BuiltinType::OCLIntelSubgroupAVCSicPayload:
+ case clang::BuiltinType::OCLIntelSubgroupAVCMceResult:
+ case clang::BuiltinType::OCLIntelSubgroupAVCImeResult:
+ case clang::BuiltinType::OCLIntelSubgroupAVCRefResult:
+ case clang::BuiltinType::OCLIntelSubgroupAVCSicResult:
+ case clang::BuiltinType::OCLIntelSubgroupAVCImeResultSingleRefStreamout:
+ case clang::BuiltinType::OCLIntelSubgroupAVCImeResultDualRefStreamout:
+ case clang::BuiltinType::OCLIntelSubgroupAVCImeSingleRefStreamin:
+ case clang::BuiltinType::OCLIntelSubgroupAVCImeDualRefStreamin:
+ break;
+
+ case clang::BuiltinType::SveBool:
+ case clang::BuiltinType::SveInt8:
+ case clang::BuiltinType::SveInt16:
+ case clang::BuiltinType::SveInt32:
+ case clang::BuiltinType::SveInt64:
+ case clang::BuiltinType::SveUint8:
+ case clang::BuiltinType::SveUint16:
+ case clang::BuiltinType::SveUint32:
+ case clang::BuiltinType::SveUint64:
+ case clang::BuiltinType::SveFloat16:
+ case clang::BuiltinType::SveFloat32:
+ case clang::BuiltinType::SveFloat64:
+ break;
+ }
+ break;
+ // All pointer types are represented as unsigned integer encodings. We may
+ // nee to add a eEncodingPointer if we ever need to know the difference
+ case clang::Type::ObjCObjectPointer:
+ case clang::Type::BlockPointer:
+ case clang::Type::Pointer:
+ case clang::Type::LValueReference:
+ case clang::Type::RValueReference:
+ case clang::Type::MemberPointer:
+ return lldb::eEncodingUint;
+ case clang::Type::Complex: {
+ lldb::Encoding encoding = lldb::eEncodingIEEE754;
+ if (qual_type->isComplexType())
+ encoding = lldb::eEncodingIEEE754;
+ else {
+ const clang::ComplexType *complex_type =
+ qual_type->getAsComplexIntegerType();
+ if (complex_type)
+ encoding = GetType(complex_type->getElementType()).GetEncoding(count);
+ else
+ encoding = lldb::eEncodingSint;
+ }
+ count = 2;
+ return encoding;
+ }
+
+ case clang::Type::ObjCInterface:
+ break;
+ case clang::Type::Record:
+ break;
+ case clang::Type::Enum:
+ return lldb::eEncodingSint;
+ case clang::Type::DependentSizedArray:
+ case clang::Type::DependentSizedExtVector:
+ case clang::Type::UnresolvedUsing:
+ case clang::Type::Attributed:
+ case clang::Type::TemplateTypeParm:
+ case clang::Type::SubstTemplateTypeParm:
+ case clang::Type::SubstTemplateTypeParmPack:
+ case clang::Type::InjectedClassName:
+ case clang::Type::DependentName:
+ case clang::Type::DependentTemplateSpecialization:
+ case clang::Type::PackExpansion:
+ case clang::Type::ObjCObject:
+
+ case clang::Type::TemplateSpecialization:
+ case clang::Type::DeducedTemplateSpecialization:
+ case clang::Type::Adjusted:
+ case clang::Type::Pipe:
+ break;
+
+ // pointer type decayed from an array or function type.
+ case clang::Type::Decayed:
+ break;
+ case clang::Type::ObjCTypeParam:
+ break;
+
+ case clang::Type::DependentAddressSpace:
+ break;
+ case clang::Type::MacroQualified:
+ break;
+ }
+ count = 0;
+ return lldb::eEncodingInvalid;
+}
+
+lldb::Format TypeSystemClang::GetFormat(lldb::opaque_compiler_type_t type) {
+ if (!type)
+ return lldb::eFormatDefault;
+
+ clang::QualType qual_type = RemoveWrappingTypes(GetCanonicalQualType(type));
+
+ switch (qual_type->getTypeClass()) {
+ case clang::Type::Atomic:
+ case clang::Type::Auto:
+ case clang::Type::Decltype:
+ case clang::Type::Elaborated:
+ case clang::Type::Paren:
+ case clang::Type::Typedef:
+ case clang::Type::TypeOf:
+ case clang::Type::TypeOfExpr:
+ llvm_unreachable("Handled in RemoveWrappingTypes!");
+ case clang::Type::UnaryTransform:
+ break;
+
+ case clang::Type::FunctionNoProto:
+ case clang::Type::FunctionProto:
+ break;
+
+ case clang::Type::IncompleteArray:
+ case clang::Type::VariableArray:
+ break;
+
+ case clang::Type::ConstantArray:
+ return lldb::eFormatVoid; // no value
+
+ case clang::Type::DependentVector:
+ case clang::Type::ExtVector:
+ case clang::Type::Vector:
+ break;
+
+ case clang::Type::Builtin:
+ switch (llvm::cast<clang::BuiltinType>(qual_type)->getKind()) {
+ // default: assert(0 && "Unknown builtin type!");
+ case clang::BuiltinType::UnknownAny:
+ case clang::BuiltinType::Void:
+ case clang::BuiltinType::BoundMember:
+ break;
+
+ case clang::BuiltinType::Bool:
+ return lldb::eFormatBoolean;
+ case clang::BuiltinType::Char_S:
+ case clang::BuiltinType::SChar:
+ case clang::BuiltinType::WChar_S:
+ case clang::BuiltinType::Char_U:
+ case clang::BuiltinType::UChar:
+ case clang::BuiltinType::WChar_U:
+ return lldb::eFormatChar;
+ case clang::BuiltinType::Char16:
+ return lldb::eFormatUnicode16;
+ case clang::BuiltinType::Char32:
+ return lldb::eFormatUnicode32;
+ case clang::BuiltinType::UShort:
+ return lldb::eFormatUnsigned;
+ case clang::BuiltinType::Short:
+ return lldb::eFormatDecimal;
+ case clang::BuiltinType::UInt:
+ return lldb::eFormatUnsigned;
+ case clang::BuiltinType::Int:
+ return lldb::eFormatDecimal;
+ case clang::BuiltinType::ULong:
+ return lldb::eFormatUnsigned;
+ case clang::BuiltinType::Long:
+ return lldb::eFormatDecimal;
+ case clang::BuiltinType::ULongLong:
+ return lldb::eFormatUnsigned;
+ case clang::BuiltinType::LongLong:
+ return lldb::eFormatDecimal;
+ case clang::BuiltinType::UInt128:
+ return lldb::eFormatUnsigned;
+ case clang::BuiltinType::Int128:
+ return lldb::eFormatDecimal;
+ case clang::BuiltinType::Half:
+ case clang::BuiltinType::Float:
+ case clang::BuiltinType::Double:
+ case clang::BuiltinType::LongDouble:
+ return lldb::eFormatFloat;
+ default:
+ return lldb::eFormatHex;
+ }
+ break;
+ case clang::Type::ObjCObjectPointer:
+ return lldb::eFormatHex;
+ case clang::Type::BlockPointer:
+ return lldb::eFormatHex;
+ case clang::Type::Pointer:
+ return lldb::eFormatHex;
+ case clang::Type::LValueReference:
+ case clang::Type::RValueReference:
+ return lldb::eFormatHex;
+ case clang::Type::MemberPointer:
+ break;
+ case clang::Type::Complex: {
+ if (qual_type->isComplexType())
+ return lldb::eFormatComplex;
+ else
+ return lldb::eFormatComplexInteger;
+ }
+ case clang::Type::ObjCInterface:
+ break;
+ case clang::Type::Record:
+ break;
+ case clang::Type::Enum:
+ return lldb::eFormatEnum;
+ case clang::Type::DependentSizedArray:
+ case clang::Type::DependentSizedExtVector:
+ case clang::Type::UnresolvedUsing:
+ case clang::Type::Attributed:
+ case clang::Type::TemplateTypeParm:
+ case clang::Type::SubstTemplateTypeParm:
+ case clang::Type::SubstTemplateTypeParmPack:
+ case clang::Type::InjectedClassName:
+ case clang::Type::DependentName:
+ case clang::Type::DependentTemplateSpecialization:
+ case clang::Type::PackExpansion:
+ case clang::Type::ObjCObject:
+
+ case clang::Type::TemplateSpecialization:
+ case clang::Type::DeducedTemplateSpecialization:
+ case clang::Type::Adjusted:
+ case clang::Type::Pipe:
+ break;
+
+ // pointer type decayed from an array or function type.
+ case clang::Type::Decayed:
+ break;
+ case clang::Type::ObjCTypeParam:
+ break;
+
+ case clang::Type::DependentAddressSpace:
+ break;
+ case clang::Type::MacroQualified:
+ break;
+ }
+ // We don't know hot to display this type...
+ return lldb::eFormatBytes;
+}
+
+static bool ObjCDeclHasIVars(clang::ObjCInterfaceDecl *class_interface_decl,
+ bool check_superclass) {
+ while (class_interface_decl) {
+ if (class_interface_decl->ivar_size() > 0)
+ return true;
+
+ if (check_superclass)
+ class_interface_decl = class_interface_decl->getSuperClass();
+ else
+ break;
+ }
+ return false;
+}
+
+static Optional<SymbolFile::ArrayInfo>
+GetDynamicArrayInfo(TypeSystemClang &ast, SymbolFile *sym_file,
+ clang::QualType qual_type,
+ const ExecutionContext *exe_ctx) {
+ if (qual_type->isIncompleteArrayType())
+ if (auto *metadata = ast.GetMetadata(qual_type.getTypePtr()))
+ return sym_file->GetDynamicArrayInfoForUID(metadata->GetUserID(),
+ exe_ctx);
+ return llvm::None;
+}
+
+uint32_t TypeSystemClang::GetNumChildren(lldb::opaque_compiler_type_t type,
+ bool omit_empty_base_classes,
+ const ExecutionContext *exe_ctx) {
+ if (!type)
+ return 0;
+
+ uint32_t num_children = 0;
+ clang::QualType qual_type(RemoveWrappingTypes(GetQualType(type)));
+ const clang::Type::TypeClass type_class = qual_type->getTypeClass();
+ switch (type_class) {
+ case clang::Type::Builtin:
+ switch (llvm::cast<clang::BuiltinType>(qual_type)->getKind()) {
+ case clang::BuiltinType::ObjCId: // child is Class
+ case clang::BuiltinType::ObjCClass: // child is Class
+ num_children = 1;
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case clang::Type::Complex:
+ return 0;
+ case clang::Type::Record:
+ if (GetCompleteQualType(&getASTContext(), qual_type)) {
+ const clang::RecordType *record_type =
+ llvm::cast<clang::RecordType>(qual_type.getTypePtr());
+ const clang::RecordDecl *record_decl = record_type->getDecl();
+ assert(record_decl);
+ const clang::CXXRecordDecl *cxx_record_decl =
+ llvm::dyn_cast<clang::CXXRecordDecl>(record_decl);
+ if (cxx_record_decl) {
+ if (omit_empty_base_classes) {
+ // Check each base classes to see if it or any of its base classes
+ // contain any fields. This can help limit the noise in variable
+ // views by not having to show base classes that contain no members.
+ clang::CXXRecordDecl::base_class_const_iterator base_class,
+ base_class_end;
+ for (base_class = cxx_record_decl->bases_begin(),
+ base_class_end = cxx_record_decl->bases_end();
+ base_class != base_class_end; ++base_class) {
+ const clang::CXXRecordDecl *base_class_decl =
+ llvm::cast<clang::CXXRecordDecl>(
+ base_class->getType()
+ ->getAs<clang::RecordType>()
+ ->getDecl());
+
+ // Skip empty base classes
+ if (!TypeSystemClang::RecordHasFields(base_class_decl))
+ continue;
+
+ num_children++;
+ }
+ } else {
+ // Include all base classes
+ num_children += cxx_record_decl->getNumBases();
+ }
+ }
+ clang::RecordDecl::field_iterator field, field_end;
+ for (field = record_decl->field_begin(),
+ field_end = record_decl->field_end();
+ field != field_end; ++field)
+ ++num_children;
+ }
+ break;
+
+ case clang::Type::ObjCObject:
+ case clang::Type::ObjCInterface:
+ if (GetCompleteQualType(&getASTContext(), qual_type)) {
+ const clang::ObjCObjectType *objc_class_type =
+ llvm::dyn_cast<clang::ObjCObjectType>(qual_type.getTypePtr());
+ assert(objc_class_type);
+ if (objc_class_type) {
+ clang::ObjCInterfaceDecl *class_interface_decl =
+ objc_class_type->getInterface();
+
+ if (class_interface_decl) {
+
+ clang::ObjCInterfaceDecl *superclass_interface_decl =
+ class_interface_decl->getSuperClass();
+ if (superclass_interface_decl) {
+ if (omit_empty_base_classes) {
+ if (ObjCDeclHasIVars(superclass_interface_decl, true))
+ ++num_children;
+ } else
+ ++num_children;
+ }
+
+ num_children += class_interface_decl->ivar_size();
+ }
+ }
+ }
+ break;
+
+ case clang::Type::ObjCObjectPointer: {
+ const clang::ObjCObjectPointerType *pointer_type =
+ llvm::cast<clang::ObjCObjectPointerType>(qual_type.getTypePtr());
+ clang::QualType pointee_type = pointer_type->getPointeeType();
+ uint32_t num_pointee_children =
+ GetType(pointee_type).GetNumChildren(omit_empty_base_classes, exe_ctx);
+ // If this type points to a simple type, then it has 1 child
+ if (num_pointee_children == 0)
+ num_children = 1;
+ else
+ num_children = num_pointee_children;
+ } break;
+
+ case clang::Type::Vector:
+ case clang::Type::ExtVector:
+ num_children =
+ llvm::cast<clang::VectorType>(qual_type.getTypePtr())->getNumElements();
+ break;
+
+ case clang::Type::ConstantArray:
+ num_children = llvm::cast<clang::ConstantArrayType>(qual_type.getTypePtr())
+ ->getSize()
+ .getLimitedValue();
+ break;
+ case clang::Type::IncompleteArray:
+ if (auto array_info =
+ GetDynamicArrayInfo(*this, GetSymbolFile(), qual_type, exe_ctx))
+ // Only 1-dimensional arrays are supported.
+ num_children = array_info->element_orders.size()
+ ? array_info->element_orders.back()
+ : 0;
+ break;
+
+ case clang::Type::Pointer: {
+ const clang::PointerType *pointer_type =
+ llvm::cast<clang::PointerType>(qual_type.getTypePtr());
+ clang::QualType pointee_type(pointer_type->getPointeeType());
+ uint32_t num_pointee_children =
+ GetType(pointee_type).GetNumChildren(omit_empty_base_classes, exe_ctx);
+ if (num_pointee_children == 0) {
+ // We have a pointer to a pointee type that claims it has no children. We
+ // will want to look at
+ num_children = GetNumPointeeChildren(pointee_type);
+ } else
+ num_children = num_pointee_children;
+ } break;
+
+ case clang::Type::LValueReference:
+ case clang::Type::RValueReference: {
+ const clang::ReferenceType *reference_type =
+ llvm::cast<clang::ReferenceType>(qual_type.getTypePtr());
+ clang::QualType pointee_type = reference_type->getPointeeType();
+ uint32_t num_pointee_children =
+ GetType(pointee_type).GetNumChildren(omit_empty_base_classes, exe_ctx);
+ // If this type points to a simple type, then it has 1 child
+ if (num_pointee_children == 0)
+ num_children = 1;
+ else
+ num_children = num_pointee_children;
+ } break;
+
+ default:
+ break;
+ }
+ return num_children;
+}
+
+CompilerType TypeSystemClang::GetBuiltinTypeByName(ConstString name) {
+ return GetBasicType(GetBasicTypeEnumeration(name));
+}
+
+lldb::BasicType
+TypeSystemClang::GetBasicTypeEnumeration(lldb::opaque_compiler_type_t type) {
+ if (type) {
+ clang::QualType qual_type(GetQualType(type));
+ const clang::Type::TypeClass type_class = qual_type->getTypeClass();
+ if (type_class == clang::Type::Builtin) {
+ switch (llvm::cast<clang::BuiltinType>(qual_type)->getKind()) {
+ case clang::BuiltinType::Void:
+ return eBasicTypeVoid;
+ case clang::BuiltinType::Bool:
+ return eBasicTypeBool;
+ case clang::BuiltinType::Char_S:
+ return eBasicTypeSignedChar;
+ case clang::BuiltinType::Char_U:
+ return eBasicTypeUnsignedChar;
+ case clang::BuiltinType::Char16:
+ return eBasicTypeChar16;
+ case clang::BuiltinType::Char32:
+ return eBasicTypeChar32;
+ case clang::BuiltinType::UChar:
+ return eBasicTypeUnsignedChar;
+ case clang::BuiltinType::SChar:
+ return eBasicTypeSignedChar;
+ case clang::BuiltinType::WChar_S:
+ return eBasicTypeSignedWChar;
+ case clang::BuiltinType::WChar_U:
+ return eBasicTypeUnsignedWChar;
+ case clang::BuiltinType::Short:
+ return eBasicTypeShort;
+ case clang::BuiltinType::UShort:
+ return eBasicTypeUnsignedShort;
+ case clang::BuiltinType::Int:
+ return eBasicTypeInt;
+ case clang::BuiltinType::UInt:
+ return eBasicTypeUnsignedInt;
+ case clang::BuiltinType::Long:
+ return eBasicTypeLong;
+ case clang::BuiltinType::ULong:
+ return eBasicTypeUnsignedLong;
+ case clang::BuiltinType::LongLong:
+ return eBasicTypeLongLong;
+ case clang::BuiltinType::ULongLong:
+ return eBasicTypeUnsignedLongLong;
+ case clang::BuiltinType::Int128:
+ return eBasicTypeInt128;
+ case clang::BuiltinType::UInt128:
+ return eBasicTypeUnsignedInt128;
+
+ case clang::BuiltinType::Half:
+ return eBasicTypeHalf;
+ case clang::BuiltinType::Float:
+ return eBasicTypeFloat;
+ case clang::BuiltinType::Double:
+ return eBasicTypeDouble;
+ case clang::BuiltinType::LongDouble:
+ return eBasicTypeLongDouble;
+
+ case clang::BuiltinType::NullPtr:
+ return eBasicTypeNullPtr;
+ case clang::BuiltinType::ObjCId:
+ return eBasicTypeObjCID;
+ case clang::BuiltinType::ObjCClass:
+ return eBasicTypeObjCClass;
+ case clang::BuiltinType::ObjCSel:
+ return eBasicTypeObjCSel;
+ default:
+ return eBasicTypeOther;
+ }
+ }
+ }
+ return eBasicTypeInvalid;
+}
+
+void TypeSystemClang::ForEachEnumerator(
+ lldb::opaque_compiler_type_t type,
+ std::function<bool(const CompilerType &integer_type,
+ ConstString name,
+ const llvm::APSInt &value)> const &callback) {
+ const clang::EnumType *enum_type =
+ llvm::dyn_cast<clang::EnumType>(GetCanonicalQualType(type));
+ if (enum_type) {
+ const clang::EnumDecl *enum_decl = enum_type->getDecl();
+ if (enum_decl) {
+ CompilerType integer_type = GetType(enum_decl->getIntegerType());
+
+ clang::EnumDecl::enumerator_iterator enum_pos, enum_end_pos;
+ for (enum_pos = enum_decl->enumerator_begin(),
+ enum_end_pos = enum_decl->enumerator_end();
+ enum_pos != enum_end_pos; ++enum_pos) {
+ ConstString name(enum_pos->getNameAsString().c_str());
+ if (!callback(integer_type, name, enum_pos->getInitVal()))
+ break;
+ }
+ }
+ }
+}
+
+#pragma mark Aggregate Types
+
+uint32_t TypeSystemClang::GetNumFields(lldb::opaque_compiler_type_t type) {
+ if (!type)
+ return 0;
+
+ uint32_t count = 0;
+ clang::QualType qual_type(RemoveWrappingTypes(GetCanonicalQualType(type)));
+ const clang::Type::TypeClass type_class = qual_type->getTypeClass();
+ switch (type_class) {
+ case clang::Type::Record:
+ if (GetCompleteType(type)) {
+ const clang::RecordType *record_type =
+ llvm::dyn_cast<clang::RecordType>(qual_type.getTypePtr());
+ if (record_type) {
+ clang::RecordDecl *record_decl = record_type->getDecl();
+ if (record_decl) {
+ uint32_t field_idx = 0;
+ clang::RecordDecl::field_iterator field, field_end;
+ for (field = record_decl->field_begin(),
+ field_end = record_decl->field_end();
+ field != field_end; ++field)
+ ++field_idx;
+ count = field_idx;
+ }
+ }
+ }
+ break;
+
+ case clang::Type::ObjCObjectPointer: {
+ const clang::ObjCObjectPointerType *objc_class_type =
+ qual_type->getAs<clang::ObjCObjectPointerType>();
+ const clang::ObjCInterfaceType *objc_interface_type =
+ objc_class_type->getInterfaceType();
+ if (objc_interface_type &&
+ GetCompleteType(static_cast<lldb::opaque_compiler_type_t>(
+ const_cast<clang::ObjCInterfaceType *>(objc_interface_type)))) {
+ clang::ObjCInterfaceDecl *class_interface_decl =
+ objc_interface_type->getDecl();
+ if (class_interface_decl) {
+ count = class_interface_decl->ivar_size();
+ }
+ }
+ break;
+ }
+
+ case clang::Type::ObjCObject:
+ case clang::Type::ObjCInterface:
+ if (GetCompleteType(type)) {
+ const clang::ObjCObjectType *objc_class_type =
+ llvm::dyn_cast<clang::ObjCObjectType>(qual_type.getTypePtr());
+ if (objc_class_type) {
+ clang::ObjCInterfaceDecl *class_interface_decl =
+ objc_class_type->getInterface();
+
+ if (class_interface_decl)
+ count = class_interface_decl->ivar_size();
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+ return count;
+}
+
+static lldb::opaque_compiler_type_t
+GetObjCFieldAtIndex(clang::ASTContext *ast,
+ clang::ObjCInterfaceDecl *class_interface_decl, size_t idx,
+ std::string &name, uint64_t *bit_offset_ptr,
+ uint32_t *bitfield_bit_size_ptr, bool *is_bitfield_ptr) {
+ if (class_interface_decl) {
+ if (idx < (class_interface_decl->ivar_size())) {
+ clang::ObjCInterfaceDecl::ivar_iterator ivar_pos,
+ ivar_end = class_interface_decl->ivar_end();
+ uint32_t ivar_idx = 0;
+
+ for (ivar_pos = class_interface_decl->ivar_begin(); ivar_pos != ivar_end;
+ ++ivar_pos, ++ivar_idx) {
+ if (ivar_idx == idx) {
+ const clang::ObjCIvarDecl *ivar_decl = *ivar_pos;
+
+ clang::QualType ivar_qual_type(ivar_decl->getType());
+
+ name.assign(ivar_decl->getNameAsString());
+
+ if (bit_offset_ptr) {
+ const clang::ASTRecordLayout &interface_layout =
+ ast->getASTObjCInterfaceLayout(class_interface_decl);
+ *bit_offset_ptr = interface_layout.getFieldOffset(ivar_idx);
+ }
+
+ const bool is_bitfield = ivar_pos->isBitField();
+
+ if (bitfield_bit_size_ptr) {
+ *bitfield_bit_size_ptr = 0;
+
+ if (is_bitfield && ast) {
+ clang::Expr *bitfield_bit_size_expr = ivar_pos->getBitWidth();
+ clang::Expr::EvalResult result;
+ if (bitfield_bit_size_expr &&
+ bitfield_bit_size_expr->EvaluateAsInt(result, *ast)) {
+ llvm::APSInt bitfield_apsint = result.Val.getInt();
+ *bitfield_bit_size_ptr = bitfield_apsint.getLimitedValue();
+ }
+ }
+ }
+ if (is_bitfield_ptr)
+ *is_bitfield_ptr = is_bitfield;
+
+ return ivar_qual_type.getAsOpaquePtr();
+ }
+ }
+ }
+ }
+ return nullptr;
+}
+
+CompilerType TypeSystemClang::GetFieldAtIndex(lldb::opaque_compiler_type_t type,
+ size_t idx, std::string &name,
+ uint64_t *bit_offset_ptr,
+ uint32_t *bitfield_bit_size_ptr,
+ bool *is_bitfield_ptr) {
+ if (!type)
+ return CompilerType();
+
+ clang::QualType qual_type(RemoveWrappingTypes(GetCanonicalQualType(type)));
+ const clang::Type::TypeClass type_class = qual_type->getTypeClass();
+ switch (type_class) {
+ case clang::Type::Record:
+ if (GetCompleteType(type)) {
+ const clang::RecordType *record_type =
+ llvm::cast<clang::RecordType>(qual_type.getTypePtr());
+ const clang::RecordDecl *record_decl = record_type->getDecl();
+ uint32_t field_idx = 0;
+ clang::RecordDecl::field_iterator field, field_end;
+ for (field = record_decl->field_begin(),
+ field_end = record_decl->field_end();
+ field != field_end; ++field, ++field_idx) {
+ if (idx == field_idx) {
+ // Print the member type if requested
+ // Print the member name and equal sign
+ name.assign(field->getNameAsString());
+
+ // Figure out the type byte size (field_type_info.first) and
+ // alignment (field_type_info.second) from the AST context.
+ if (bit_offset_ptr) {
+ const clang::ASTRecordLayout &record_layout =
+ getASTContext().getASTRecordLayout(record_decl);
+ *bit_offset_ptr = record_layout.getFieldOffset(field_idx);
+ }
+
+ const bool is_bitfield = field->isBitField();
+
+ if (bitfield_bit_size_ptr) {
+ *bitfield_bit_size_ptr = 0;
+
+ if (is_bitfield) {
+ clang::Expr *bitfield_bit_size_expr = field->getBitWidth();
+ clang::Expr::EvalResult result;
+ if (bitfield_bit_size_expr &&
+ bitfield_bit_size_expr->EvaluateAsInt(result,
+ getASTContext())) {
+ llvm::APSInt bitfield_apsint = result.Val.getInt();
+ *bitfield_bit_size_ptr = bitfield_apsint.getLimitedValue();
+ }
+ }
+ }
+ if (is_bitfield_ptr)
+ *is_bitfield_ptr = is_bitfield;
+
+ return GetType(field->getType());
+ }
+ }
+ }
+ break;
+
+ case clang::Type::ObjCObjectPointer: {
+ const clang::ObjCObjectPointerType *objc_class_type =
+ qual_type->getAs<clang::ObjCObjectPointerType>();
+ const clang::ObjCInterfaceType *objc_interface_type =
+ objc_class_type->getInterfaceType();
+ if (objc_interface_type &&
+ GetCompleteType(static_cast<lldb::opaque_compiler_type_t>(
+ const_cast<clang::ObjCInterfaceType *>(objc_interface_type)))) {
+ clang::ObjCInterfaceDecl *class_interface_decl =
+ objc_interface_type->getDecl();
+ if (class_interface_decl) {
+ return CompilerType(
+ this, GetObjCFieldAtIndex(&getASTContext(), class_interface_decl,
+ idx, name, bit_offset_ptr,
+ bitfield_bit_size_ptr, is_bitfield_ptr));
+ }
+ }
+ break;
+ }
+
+ case clang::Type::ObjCObject:
+ case clang::Type::ObjCInterface:
+ if (GetCompleteType(type)) {
+ const clang::ObjCObjectType *objc_class_type =
+ llvm::dyn_cast<clang::ObjCObjectType>(qual_type.getTypePtr());
+ assert(objc_class_type);
+ if (objc_class_type) {
+ clang::ObjCInterfaceDecl *class_interface_decl =
+ objc_class_type->getInterface();
+ return CompilerType(
+ this, GetObjCFieldAtIndex(&getASTContext(), class_interface_decl,
+ idx, name, bit_offset_ptr,
+ bitfield_bit_size_ptr, is_bitfield_ptr));
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+ return CompilerType();
+}
+
+uint32_t
+TypeSystemClang::GetNumDirectBaseClasses(lldb::opaque_compiler_type_t type) {
+ uint32_t count = 0;
+ clang::QualType qual_type = RemoveWrappingTypes(GetCanonicalQualType(type));
+ const clang::Type::TypeClass type_class = qual_type->getTypeClass();
+ switch (type_class) {
+ case clang::Type::Record:
+ if (GetCompleteType(type)) {
+ const clang::CXXRecordDecl *cxx_record_decl =
+ qual_type->getAsCXXRecordDecl();
+ if (cxx_record_decl)
+ count = cxx_record_decl->getNumBases();
+ }
+ break;
+
+ case clang::Type::ObjCObjectPointer:
+ count = GetPointeeType(type).GetNumDirectBaseClasses();
+ break;
+
+ case clang::Type::ObjCObject:
+ if (GetCompleteType(type)) {
+ const clang::ObjCObjectType *objc_class_type =
+ qual_type->getAsObjCQualifiedInterfaceType();
+ if (objc_class_type) {
+ clang::ObjCInterfaceDecl *class_interface_decl =
+ objc_class_type->getInterface();
+
+ if (class_interface_decl && class_interface_decl->getSuperClass())
+ count = 1;
+ }
+ }
+ break;
+ case clang::Type::ObjCInterface:
+ if (GetCompleteType(type)) {
+ const clang::ObjCInterfaceType *objc_interface_type =
+ qual_type->getAs<clang::ObjCInterfaceType>();
+ if (objc_interface_type) {
+ clang::ObjCInterfaceDecl *class_interface_decl =
+ objc_interface_type->getInterface();
+
+ if (class_interface_decl && class_interface_decl->getSuperClass())
+ count = 1;
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+ return count;
+}
+
+uint32_t
+TypeSystemClang::GetNumVirtualBaseClasses(lldb::opaque_compiler_type_t type) {
+ uint32_t count = 0;
+ clang::QualType qual_type = RemoveWrappingTypes(GetCanonicalQualType(type));
+ const clang::Type::TypeClass type_class = qual_type->getTypeClass();
+ switch (type_class) {
+ case clang::Type::Record:
+ if (GetCompleteType(type)) {
+ const clang::CXXRecordDecl *cxx_record_decl =
+ qual_type->getAsCXXRecordDecl();
+ if (cxx_record_decl)
+ count = cxx_record_decl->getNumVBases();
+ }
+ break;
+
+ default:
+ break;
+ }
+ return count;
+}
+
+CompilerType TypeSystemClang::GetDirectBaseClassAtIndex(
+ lldb::opaque_compiler_type_t type, size_t idx, uint32_t *bit_offset_ptr) {
+ clang::QualType qual_type = RemoveWrappingTypes(GetCanonicalQualType(type));
+ const clang::Type::TypeClass type_class = qual_type->getTypeClass();
+ switch (type_class) {
+ case clang::Type::Record:
+ if (GetCompleteType(type)) {
+ const clang::CXXRecordDecl *cxx_record_decl =
+ qual_type->getAsCXXRecordDecl();
+ if (cxx_record_decl) {
+ uint32_t curr_idx = 0;
+ clang::CXXRecordDecl::base_class_const_iterator base_class,
+ base_class_end;
+ for (base_class = cxx_record_decl->bases_begin(),
+ base_class_end = cxx_record_decl->bases_end();
+ base_class != base_class_end; ++base_class, ++curr_idx) {
+ if (curr_idx == idx) {
+ if (bit_offset_ptr) {
+ const clang::ASTRecordLayout &record_layout =
+ getASTContext().getASTRecordLayout(cxx_record_decl);
+ const clang::CXXRecordDecl *base_class_decl =
+ llvm::cast<clang::CXXRecordDecl>(
+ base_class->getType()
+ ->getAs<clang::RecordType>()
+ ->getDecl());
+ if (base_class->isVirtual())
+ *bit_offset_ptr =
+ record_layout.getVBaseClassOffset(base_class_decl)
+ .getQuantity() *
+ 8;
+ else
+ *bit_offset_ptr =
+ record_layout.getBaseClassOffset(base_class_decl)
+ .getQuantity() *
+ 8;
+ }
+ return GetType(base_class->getType());
+ }
+ }
+ }
+ }
+ break;
+
+ case clang::Type::ObjCObjectPointer:
+ return GetPointeeType(type).GetDirectBaseClassAtIndex(idx, bit_offset_ptr);
+
+ case clang::Type::ObjCObject:
+ if (idx == 0 && GetCompleteType(type)) {
+ const clang::ObjCObjectType *objc_class_type =
+ qual_type->getAsObjCQualifiedInterfaceType();
+ if (objc_class_type) {
+ clang::ObjCInterfaceDecl *class_interface_decl =
+ objc_class_type->getInterface();
+
+ if (class_interface_decl) {
+ clang::ObjCInterfaceDecl *superclass_interface_decl =
+ class_interface_decl->getSuperClass();
+ if (superclass_interface_decl) {
+ if (bit_offset_ptr)
+ *bit_offset_ptr = 0;
+ return GetType(getASTContext().getObjCInterfaceType(
+ superclass_interface_decl));
+ }
+ }
+ }
+ }
+ break;
+ case clang::Type::ObjCInterface:
+ if (idx == 0 && GetCompleteType(type)) {
+ const clang::ObjCObjectType *objc_interface_type =
+ qual_type->getAs<clang::ObjCInterfaceType>();
+ if (objc_interface_type) {
+ clang::ObjCInterfaceDecl *class_interface_decl =
+ objc_interface_type->getInterface();
+
+ if (class_interface_decl) {
+ clang::ObjCInterfaceDecl *superclass_interface_decl =
+ class_interface_decl->getSuperClass();
+ if (superclass_interface_decl) {
+ if (bit_offset_ptr)
+ *bit_offset_ptr = 0;
+ return GetType(getASTContext().getObjCInterfaceType(
+ superclass_interface_decl));
+ }
+ }
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+ return CompilerType();
+}
+
+CompilerType TypeSystemClang::GetVirtualBaseClassAtIndex(
+ lldb::opaque_compiler_type_t type, size_t idx, uint32_t *bit_offset_ptr) {
+ clang::QualType qual_type = RemoveWrappingTypes(GetCanonicalQualType(type));
+ const clang::Type::TypeClass type_class = qual_type->getTypeClass();
+ switch (type_class) {
+ case clang::Type::Record:
+ if (GetCompleteType(type)) {
+ const clang::CXXRecordDecl *cxx_record_decl =
+ qual_type->getAsCXXRecordDecl();
+ if (cxx_record_decl) {
+ uint32_t curr_idx = 0;
+ clang::CXXRecordDecl::base_class_const_iterator base_class,
+ base_class_end;
+ for (base_class = cxx_record_decl->vbases_begin(),
+ base_class_end = cxx_record_decl->vbases_end();
+ base_class != base_class_end; ++base_class, ++curr_idx) {
+ if (curr_idx == idx) {
+ if (bit_offset_ptr) {
+ const clang::ASTRecordLayout &record_layout =
+ getASTContext().getASTRecordLayout(cxx_record_decl);
+ const clang::CXXRecordDecl *base_class_decl =
+ llvm::cast<clang::CXXRecordDecl>(
+ base_class->getType()
+ ->getAs<clang::RecordType>()
+ ->getDecl());
+ *bit_offset_ptr =
+ record_layout.getVBaseClassOffset(base_class_decl)
+ .getQuantity() *
+ 8;
+ }
+ return GetType(base_class->getType());
+ }
+ }
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+ return CompilerType();
+}
+
+// If a pointer to a pointee type (the clang_type arg) says that it has no
+// children, then we either need to trust it, or override it and return a
+// different result. For example, an "int *" has one child that is an integer,
+// but a function pointer doesn't have any children. Likewise if a Record type
+// claims it has no children, then there really is nothing to show.
+uint32_t TypeSystemClang::GetNumPointeeChildren(clang::QualType type) {
+ if (type.isNull())
+ return 0;
+
+ clang::QualType qual_type = RemoveWrappingTypes(type.getCanonicalType());
+ const clang::Type::TypeClass type_class = qual_type->getTypeClass();
+ switch (type_class) {
+ case clang::Type::Builtin:
+ switch (llvm::cast<clang::BuiltinType>(qual_type)->getKind()) {
+ case clang::BuiltinType::UnknownAny:
+ case clang::BuiltinType::Void:
+ case clang::BuiltinType::NullPtr:
+ case clang::BuiltinType::OCLEvent:
+ case clang::BuiltinType::OCLImage1dRO:
+ case clang::BuiltinType::OCLImage1dWO:
+ case clang::BuiltinType::OCLImage1dRW:
+ case clang::BuiltinType::OCLImage1dArrayRO:
+ case clang::BuiltinType::OCLImage1dArrayWO:
+ case clang::BuiltinType::OCLImage1dArrayRW:
+ case clang::BuiltinType::OCLImage1dBufferRO:
+ case clang::BuiltinType::OCLImage1dBufferWO:
+ case clang::BuiltinType::OCLImage1dBufferRW:
+ case clang::BuiltinType::OCLImage2dRO:
+ case clang::BuiltinType::OCLImage2dWO:
+ case clang::BuiltinType::OCLImage2dRW:
+ case clang::BuiltinType::OCLImage2dArrayRO:
+ case clang::BuiltinType::OCLImage2dArrayWO:
+ case clang::BuiltinType::OCLImage2dArrayRW:
+ case clang::BuiltinType::OCLImage3dRO:
+ case clang::BuiltinType::OCLImage3dWO:
+ case clang::BuiltinType::OCLImage3dRW:
+ case clang::BuiltinType::OCLSampler:
+ return 0;
+ case clang::BuiltinType::Bool:
+ case clang::BuiltinType::Char_U:
+ case clang::BuiltinType::UChar:
+ case clang::BuiltinType::WChar_U:
+ case clang::BuiltinType::Char16:
+ case clang::BuiltinType::Char32:
+ case clang::BuiltinType::UShort:
+ case clang::BuiltinType::UInt:
+ case clang::BuiltinType::ULong:
+ case clang::BuiltinType::ULongLong:
+ case clang::BuiltinType::UInt128:
+ case clang::BuiltinType::Char_S:
+ case clang::BuiltinType::SChar:
+ case clang::BuiltinType::WChar_S:
+ case clang::BuiltinType::Short:
+ case clang::BuiltinType::Int:
+ case clang::BuiltinType::Long:
+ case clang::BuiltinType::LongLong:
+ case clang::BuiltinType::Int128:
+ case clang::BuiltinType::Float:
+ case clang::BuiltinType::Double:
+ case clang::BuiltinType::LongDouble:
+ case clang::BuiltinType::Dependent:
+ case clang::BuiltinType::Overload:
+ case clang::BuiltinType::ObjCId:
+ case clang::BuiltinType::ObjCClass:
+ case clang::BuiltinType::ObjCSel:
+ case clang::BuiltinType::BoundMember:
+ case clang::BuiltinType::Half:
+ case clang::BuiltinType::ARCUnbridgedCast:
+ case clang::BuiltinType::PseudoObject:
+ case clang::BuiltinType::BuiltinFn:
+ case clang::BuiltinType::OMPArraySection:
+ return 1;
+ default:
+ return 0;
+ }
+ break;
+
+ case clang::Type::Complex:
+ return 1;
+ case clang::Type::Pointer:
+ return 1;
+ case clang::Type::BlockPointer:
+ return 0; // If block pointers don't have debug info, then no children for
+ // them
+ case clang::Type::LValueReference:
+ return 1;
+ case clang::Type::RValueReference:
+ return 1;
+ case clang::Type::MemberPointer:
+ return 0;
+ case clang::Type::ConstantArray:
+ return 0;
+ case clang::Type::IncompleteArray:
+ return 0;
+ case clang::Type::VariableArray:
+ return 0;
+ case clang::Type::DependentSizedArray:
+ return 0;
+ case clang::Type::DependentSizedExtVector:
+ return 0;
+ case clang::Type::Vector:
+ return 0;
+ case clang::Type::ExtVector:
+ return 0;
+ case clang::Type::FunctionProto:
+ return 0; // When we function pointers, they have no children...
+ case clang::Type::FunctionNoProto:
+ return 0; // When we function pointers, they have no children...
+ case clang::Type::UnresolvedUsing:
+ return 0;
+ case clang::Type::Record:
+ return 0;
+ case clang::Type::Enum:
+ return 1;
+ case clang::Type::TemplateTypeParm:
+ return 1;
+ case clang::Type::SubstTemplateTypeParm:
+ return 1;
+ case clang::Type::TemplateSpecialization:
+ return 1;
+ case clang::Type::InjectedClassName:
+ return 0;
+ case clang::Type::DependentName:
+ return 1;
+ case clang::Type::DependentTemplateSpecialization:
+ return 1;
+ case clang::Type::ObjCObject:
+ return 0;
+ case clang::Type::ObjCInterface:
+ return 0;
+ case clang::Type::ObjCObjectPointer:
+ return 1;
+ default:
+ break;
+ }
+ return 0;
+}
+
+CompilerType TypeSystemClang::GetChildCompilerTypeAtIndex(
+ lldb::opaque_compiler_type_t type, ExecutionContext *exe_ctx, size_t idx,
+ bool transparent_pointers, bool omit_empty_base_classes,
+ bool ignore_array_bounds, std::string &child_name,
+ uint32_t &child_byte_size, int32_t &child_byte_offset,
+ uint32_t &child_bitfield_bit_size, uint32_t &child_bitfield_bit_offset,
+ bool &child_is_base_class, bool &child_is_deref_of_parent,
+ ValueObject *valobj, uint64_t &language_flags) {
+ if (!type)
+ return CompilerType();
+
+ auto get_exe_scope = [&exe_ctx]() {
+ return exe_ctx ? exe_ctx->GetBestExecutionContextScope() : nullptr;
+ };
+
+ clang::QualType parent_qual_type(
+ RemoveWrappingTypes(GetCanonicalQualType(type)));
+ const clang::Type::TypeClass parent_type_class =
+ parent_qual_type->getTypeClass();
+ child_bitfield_bit_size = 0;
+ child_bitfield_bit_offset = 0;
+ child_is_base_class = false;
+ language_flags = 0;
+
+ const bool idx_is_valid =
+ idx < GetNumChildren(type, omit_empty_base_classes, exe_ctx);
+ int32_t bit_offset;
+ switch (parent_type_class) {
+ case clang::Type::Builtin:
+ if (idx_is_valid) {
+ switch (llvm::cast<clang::BuiltinType>(parent_qual_type)->getKind()) {
+ case clang::BuiltinType::ObjCId:
+ case clang::BuiltinType::ObjCClass:
+ child_name = "isa";
+ child_byte_size =
+ getASTContext().getTypeSize(getASTContext().ObjCBuiltinClassTy) /
+ CHAR_BIT;
+ return GetType(getASTContext().ObjCBuiltinClassTy);
+
+ default:
+ break;
+ }
+ }
+ break;
+
+ case clang::Type::Record:
+ if (idx_is_valid && GetCompleteType(type)) {
+ const clang::RecordType *record_type =
+ llvm::cast<clang::RecordType>(parent_qual_type.getTypePtr());
+ const clang::RecordDecl *record_decl = record_type->getDecl();
+ assert(record_decl);
+ const clang::ASTRecordLayout &record_layout =
+ getASTContext().getASTRecordLayout(record_decl);
+ uint32_t child_idx = 0;
+
+ const clang::CXXRecordDecl *cxx_record_decl =
+ llvm::dyn_cast<clang::CXXRecordDecl>(record_decl);
+ if (cxx_record_decl) {
+ // We might have base classes to print out first
+ clang::CXXRecordDecl::base_class_const_iterator base_class,
+ base_class_end;
+ for (base_class = cxx_record_decl->bases_begin(),
+ base_class_end = cxx_record_decl->bases_end();
+ base_class != base_class_end; ++base_class) {
+ const clang::CXXRecordDecl *base_class_decl = nullptr;
+
+ // Skip empty base classes
+ if (omit_empty_base_classes) {
+ base_class_decl = llvm::cast<clang::CXXRecordDecl>(
+ base_class->getType()->getAs<clang::RecordType>()->getDecl());
+ if (!TypeSystemClang::RecordHasFields(base_class_decl))
+ continue;
+ }
+
+ if (idx == child_idx) {
+ if (base_class_decl == nullptr)
+ base_class_decl = llvm::cast<clang::CXXRecordDecl>(
+ base_class->getType()->getAs<clang::RecordType>()->getDecl());
+
+ if (base_class->isVirtual()) {
+ bool handled = false;
+ if (valobj) {
+ clang::VTableContextBase *vtable_ctx =
+ getASTContext().getVTableContext();
+ if (vtable_ctx)
+ handled = GetVBaseBitOffset(*vtable_ctx, *valobj,
+ record_layout, cxx_record_decl,
+ base_class_decl, bit_offset);
+ }
+ if (!handled)
+ bit_offset = record_layout.getVBaseClassOffset(base_class_decl)
+ .getQuantity() *
+ 8;
+ } else
+ bit_offset = record_layout.getBaseClassOffset(base_class_decl)
+ .getQuantity() *
+ 8;
+
+ // Base classes should be a multiple of 8 bits in size
+ child_byte_offset = bit_offset / 8;
+ CompilerType base_class_clang_type = GetType(base_class->getType());
+ child_name = base_class_clang_type.GetTypeName().AsCString("");
+ Optional<uint64_t> size =
+ base_class_clang_type.GetBitSize(get_exe_scope());
+ if (!size)
+ return {};
+ uint64_t base_class_clang_type_bit_size = *size;
+
+ // Base classes bit sizes should be a multiple of 8 bits in size
+ assert(base_class_clang_type_bit_size % 8 == 0);
+ child_byte_size = base_class_clang_type_bit_size / 8;
+ child_is_base_class = true;
+ return base_class_clang_type;
+ }
+ // We don't increment the child index in the for loop since we might
+ // be skipping empty base classes
+ ++child_idx;
+ }
+ }
+ // Make sure index is in range...
+ uint32_t field_idx = 0;
+ clang::RecordDecl::field_iterator field, field_end;
+ for (field = record_decl->field_begin(),
+ field_end = record_decl->field_end();
+ field != field_end; ++field, ++field_idx, ++child_idx) {
+ if (idx == child_idx) {
+ // Print the member type if requested
+ // Print the member name and equal sign
+ child_name.assign(field->getNameAsString());
+
+ // Figure out the type byte size (field_type_info.first) and
+ // alignment (field_type_info.second) from the AST context.
+ CompilerType field_clang_type = GetType(field->getType());
+ assert(field_idx < record_layout.getFieldCount());
+ Optional<uint64_t> size =
+ field_clang_type.GetByteSize(get_exe_scope());
+ if (!size)
+ return {};
+ child_byte_size = *size;
+ const uint32_t child_bit_size = child_byte_size * 8;
+
+ // Figure out the field offset within the current struct/union/class
+ // type
+ bit_offset = record_layout.getFieldOffset(field_idx);
+ if (FieldIsBitfield(*field, child_bitfield_bit_size)) {
+ child_bitfield_bit_offset = bit_offset % child_bit_size;
+ const uint32_t child_bit_offset =
+ bit_offset - child_bitfield_bit_offset;
+ child_byte_offset = child_bit_offset / 8;
+ } else {
+ child_byte_offset = bit_offset / 8;
+ }
+
+ return field_clang_type;
+ }
+ }
+ }
+ break;
+
+ case clang::Type::ObjCObject:
+ case clang::Type::ObjCInterface:
+ if (idx_is_valid && GetCompleteType(type)) {
+ const clang::ObjCObjectType *objc_class_type =
+ llvm::dyn_cast<clang::ObjCObjectType>(parent_qual_type.getTypePtr());
+ assert(objc_class_type);
+ if (objc_class_type) {
+ uint32_t child_idx = 0;
+ clang::ObjCInterfaceDecl *class_interface_decl =
+ objc_class_type->getInterface();
+
+ if (class_interface_decl) {
+
+ const clang::ASTRecordLayout &interface_layout =
+ getASTContext().getASTObjCInterfaceLayout(class_interface_decl);
+ clang::ObjCInterfaceDecl *superclass_interface_decl =
+ class_interface_decl->getSuperClass();
+ if (superclass_interface_decl) {
+ if (omit_empty_base_classes) {
+ CompilerType base_class_clang_type =
+ GetType(getASTContext().getObjCInterfaceType(
+ superclass_interface_decl));
+ if (base_class_clang_type.GetNumChildren(omit_empty_base_classes,
+ exe_ctx) > 0) {
+ if (idx == 0) {
+ clang::QualType ivar_qual_type(
+ getASTContext().getObjCInterfaceType(
+ superclass_interface_decl));
+
+ child_name.assign(
+ superclass_interface_decl->getNameAsString());
+
+ clang::TypeInfo ivar_type_info =
+ getASTContext().getTypeInfo(ivar_qual_type.getTypePtr());
+
+ child_byte_size = ivar_type_info.Width / 8;
+ child_byte_offset = 0;
+ child_is_base_class = true;
+
+ return GetType(ivar_qual_type);
+ }
+
+ ++child_idx;
+ }
+ } else
+ ++child_idx;
+ }
+
+ const uint32_t superclass_idx = child_idx;
+
+ if (idx < (child_idx + class_interface_decl->ivar_size())) {
+ clang::ObjCInterfaceDecl::ivar_iterator ivar_pos,
+ ivar_end = class_interface_decl->ivar_end();
+
+ for (ivar_pos = class_interface_decl->ivar_begin();
+ ivar_pos != ivar_end; ++ivar_pos) {
+ if (child_idx == idx) {
+ clang::ObjCIvarDecl *ivar_decl = *ivar_pos;
+
+ clang::QualType ivar_qual_type(ivar_decl->getType());
+
+ child_name.assign(ivar_decl->getNameAsString());
+
+ clang::TypeInfo ivar_type_info =
+ getASTContext().getTypeInfo(ivar_qual_type.getTypePtr());
+
+ child_byte_size = ivar_type_info.Width / 8;
+
+ // Figure out the field offset within the current
+ // struct/union/class type For ObjC objects, we can't trust the
+ // bit offset we get from the Clang AST, since that doesn't
+ // account for the space taken up by unbacked properties, or
+ // from the changing size of base classes that are newer than
+ // this class. So if we have a process around that we can ask
+ // about this object, do so.
+ child_byte_offset = LLDB_INVALID_IVAR_OFFSET;
+ Process *process = nullptr;
+ if (exe_ctx)
+ process = exe_ctx->GetProcessPtr();
+ if (process) {
+ ObjCLanguageRuntime *objc_runtime =
+ ObjCLanguageRuntime::Get(*process);
+ if (objc_runtime != nullptr) {
+ CompilerType parent_ast_type = GetType(parent_qual_type);
+ child_byte_offset = objc_runtime->GetByteOffsetForIvar(
+ parent_ast_type, ivar_decl->getNameAsString().c_str());
+ }
+ }
+
+ // Setting this to INT32_MAX to make sure we don't compute it
+ // twice...
+ bit_offset = INT32_MAX;
+
+ if (child_byte_offset ==
+ static_cast<int32_t>(LLDB_INVALID_IVAR_OFFSET)) {
+ bit_offset = interface_layout.getFieldOffset(child_idx -
+ superclass_idx);
+ child_byte_offset = bit_offset / 8;
+ }
+
+ // Note, the ObjC Ivar Byte offset is just that, it doesn't
+ // account for the bit offset of a bitfield within its
+ // containing object. So regardless of where we get the byte
+ // offset from, we still need to get the bit offset for
+ // bitfields from the layout.
+
+ if (FieldIsBitfield(ivar_decl, child_bitfield_bit_size)) {
+ if (bit_offset == INT32_MAX)
+ bit_offset = interface_layout.getFieldOffset(
+ child_idx - superclass_idx);
+
+ child_bitfield_bit_offset = bit_offset % 8;
+ }
+ return GetType(ivar_qual_type);
+ }
+ ++child_idx;
+ }
+ }
+ }
+ }
+ }
+ break;
+
+ case clang::Type::ObjCObjectPointer:
+ if (idx_is_valid) {
+ CompilerType pointee_clang_type(GetPointeeType(type));
+
+ if (transparent_pointers && pointee_clang_type.IsAggregateType()) {
+ child_is_deref_of_parent = false;
+ bool tmp_child_is_deref_of_parent = false;
+ return pointee_clang_type.GetChildCompilerTypeAtIndex(
+ exe_ctx, idx, transparent_pointers, omit_empty_base_classes,
+ ignore_array_bounds, child_name, child_byte_size, child_byte_offset,
+ child_bitfield_bit_size, child_bitfield_bit_offset,
+ child_is_base_class, tmp_child_is_deref_of_parent, valobj,
+ language_flags);
+ } else {
+ child_is_deref_of_parent = true;
+ const char *parent_name =
+ valobj ? valobj->GetName().GetCString() : nullptr;
+ if (parent_name) {
+ child_name.assign(1, '*');
+ child_name += parent_name;
+ }
+
+ // We have a pointer to an simple type
+ if (idx == 0 && pointee_clang_type.GetCompleteType()) {
+ if (Optional<uint64_t> size =
+ pointee_clang_type.GetByteSize(get_exe_scope())) {
+ child_byte_size = *size;
+ child_byte_offset = 0;
+ return pointee_clang_type;
+ }
+ }
+ }
+ }
+ break;
+
+ case clang::Type::Vector:
+ case clang::Type::ExtVector:
+ if (idx_is_valid) {
+ const clang::VectorType *array =
+ llvm::cast<clang::VectorType>(parent_qual_type.getTypePtr());
+ if (array) {
+ CompilerType element_type = GetType(array->getElementType());
+ if (element_type.GetCompleteType()) {
+ char element_name[64];
+ ::snprintf(element_name, sizeof(element_name), "[%" PRIu64 "]",
+ static_cast<uint64_t>(idx));
+ child_name.assign(element_name);
+ if (Optional<uint64_t> size =
+ element_type.GetByteSize(get_exe_scope())) {
+ child_byte_size = *size;
+ child_byte_offset = (int32_t)idx * (int32_t)child_byte_size;
+ return element_type;
+ }
+ }
+ }
+ }
+ break;
+
+ case clang::Type::ConstantArray:
+ case clang::Type::IncompleteArray:
+ if (ignore_array_bounds || idx_is_valid) {
+ const clang::ArrayType *array = GetQualType(type)->getAsArrayTypeUnsafe();
+ if (array) {
+ CompilerType element_type = GetType(array->getElementType());
+ if (element_type.GetCompleteType()) {
+ child_name = std::string(llvm::formatv("[{0}]", idx));
+ if (Optional<uint64_t> size =
+ element_type.GetByteSize(get_exe_scope())) {
+ child_byte_size = *size;
+ child_byte_offset = (int32_t)idx * (int32_t)child_byte_size;
+ return element_type;
+ }
+ }
+ }
+ }
+ break;
+
+ case clang::Type::Pointer: {
+ CompilerType pointee_clang_type(GetPointeeType(type));
+
+ // Don't dereference "void *" pointers
+ if (pointee_clang_type.IsVoidType())
+ return CompilerType();
+
+ if (transparent_pointers && pointee_clang_type.IsAggregateType()) {
+ child_is_deref_of_parent = false;
+ bool tmp_child_is_deref_of_parent = false;
+ return pointee_clang_type.GetChildCompilerTypeAtIndex(
+ exe_ctx, idx, transparent_pointers, omit_empty_base_classes,
+ ignore_array_bounds, child_name, child_byte_size, child_byte_offset,
+ child_bitfield_bit_size, child_bitfield_bit_offset,
+ child_is_base_class, tmp_child_is_deref_of_parent, valobj,
+ language_flags);
+ } else {
+ child_is_deref_of_parent = true;
+
+ const char *parent_name =
+ valobj ? valobj->GetName().GetCString() : nullptr;
+ if (parent_name) {
+ child_name.assign(1, '*');
+ child_name += parent_name;
+ }
+
+ // We have a pointer to an simple type
+ if (idx == 0) {
+ if (Optional<uint64_t> size =
+ pointee_clang_type.GetByteSize(get_exe_scope())) {
+ child_byte_size = *size;
+ child_byte_offset = 0;
+ return pointee_clang_type;
+ }
+ }
+ }
+ break;
+ }
+
+ case clang::Type::LValueReference:
+ case clang::Type::RValueReference:
+ if (idx_is_valid) {
+ const clang::ReferenceType *reference_type =
+ llvm::cast<clang::ReferenceType>(parent_qual_type.getTypePtr());
+ CompilerType pointee_clang_type =
+ GetType(reference_type->getPointeeType());
+ if (transparent_pointers && pointee_clang_type.IsAggregateType()) {
+ child_is_deref_of_parent = false;
+ bool tmp_child_is_deref_of_parent = false;
+ return pointee_clang_type.GetChildCompilerTypeAtIndex(
+ exe_ctx, idx, transparent_pointers, omit_empty_base_classes,
+ ignore_array_bounds, child_name, child_byte_size, child_byte_offset,
+ child_bitfield_bit_size, child_bitfield_bit_offset,
+ child_is_base_class, tmp_child_is_deref_of_parent, valobj,
+ language_flags);
+ } else {
+ const char *parent_name =
+ valobj ? valobj->GetName().GetCString() : nullptr;
+ if (parent_name) {
+ child_name.assign(1, '&');
+ child_name += parent_name;
+ }
+
+ // We have a pointer to an simple type
+ if (idx == 0) {
+ if (Optional<uint64_t> size =
+ pointee_clang_type.GetByteSize(get_exe_scope())) {
+ child_byte_size = *size;
+ child_byte_offset = 0;
+ return pointee_clang_type;
+ }
+ }
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+ return CompilerType();
+}
+
+static uint32_t GetIndexForRecordBase(const clang::RecordDecl *record_decl,
+ const clang::CXXBaseSpecifier *base_spec,
+ bool omit_empty_base_classes) {
+ uint32_t child_idx = 0;
+
+ const clang::CXXRecordDecl *cxx_record_decl =
+ llvm::dyn_cast<clang::CXXRecordDecl>(record_decl);
+
+ // const char *super_name = record_decl->getNameAsCString();
+ // const char *base_name =
+ // base_spec->getType()->getAs<clang::RecordType>()->getDecl()->getNameAsCString();
+ // printf ("GetIndexForRecordChild (%s, %s)\n", super_name, base_name);
+ //
+ if (cxx_record_decl) {
+ clang::CXXRecordDecl::base_class_const_iterator base_class, base_class_end;
+ for (base_class = cxx_record_decl->bases_begin(),
+ base_class_end = cxx_record_decl->bases_end();
+ base_class != base_class_end; ++base_class) {
+ if (omit_empty_base_classes) {
+ if (BaseSpecifierIsEmpty(base_class))
+ continue;
+ }
+
+ // printf ("GetIndexForRecordChild (%s, %s) base[%u] = %s\n",
+ // super_name, base_name,
+ // child_idx,
+ // base_class->getType()->getAs<clang::RecordType>()->getDecl()->getNameAsCString());
+ //
+ //
+ if (base_class == base_spec)
+ return child_idx;
+ ++child_idx;
+ }
+ }
+
+ return UINT32_MAX;
+}
+
+static uint32_t GetIndexForRecordChild(const clang::RecordDecl *record_decl,
+ clang::NamedDecl *canonical_decl,
+ bool omit_empty_base_classes) {
+ uint32_t child_idx = TypeSystemClang::GetNumBaseClasses(
+ llvm::dyn_cast<clang::CXXRecordDecl>(record_decl),
+ omit_empty_base_classes);
+
+ clang::RecordDecl::field_iterator field, field_end;
+ for (field = record_decl->field_begin(), field_end = record_decl->field_end();
+ field != field_end; ++field, ++child_idx) {
+ if (field->getCanonicalDecl() == canonical_decl)
+ return child_idx;
+ }
+
+ return UINT32_MAX;
+}
+
+// Look for a child member (doesn't include base classes, but it does include
+// their members) in the type hierarchy. Returns an index path into
+// "clang_type" on how to reach the appropriate member.
+//
+// class A
+// {
+// public:
+// int m_a;
+// int m_b;
+// };
+//
+// class B
+// {
+// };
+//
+// class C :
+// public B,
+// public A
+// {
+// };
+//
+// If we have a clang type that describes "class C", and we wanted to looked
+// "m_b" in it:
+//
+// With omit_empty_base_classes == false we would get an integer array back
+// with: { 1, 1 } The first index 1 is the child index for "class A" within
+// class C The second index 1 is the child index for "m_b" within class A
+//
+// With omit_empty_base_classes == true we would get an integer array back
+// with: { 0, 1 } The first index 0 is the child index for "class A" within
+// class C (since class B doesn't have any members it doesn't count) The second
+// index 1 is the child index for "m_b" within class A
+
+size_t TypeSystemClang::GetIndexOfChildMemberWithName(
+ lldb::opaque_compiler_type_t type, const char *name,
+ bool omit_empty_base_classes, std::vector<uint32_t> &child_indexes) {
+ if (type && name && name[0]) {
+ clang::QualType qual_type = RemoveWrappingTypes(GetCanonicalQualType(type));
+ const clang::Type::TypeClass type_class = qual_type->getTypeClass();
+ switch (type_class) {
+ case clang::Type::Record:
+ if (GetCompleteType(type)) {
+ const clang::RecordType *record_type =
+ llvm::cast<clang::RecordType>(qual_type.getTypePtr());
+ const clang::RecordDecl *record_decl = record_type->getDecl();
+
+ assert(record_decl);
+ uint32_t child_idx = 0;
+
+ const clang::CXXRecordDecl *cxx_record_decl =
+ llvm::dyn_cast<clang::CXXRecordDecl>(record_decl);
+
+ // Try and find a field that matches NAME
+ clang::RecordDecl::field_iterator field, field_end;
+ llvm::StringRef name_sref(name);
+ for (field = record_decl->field_begin(),
+ field_end = record_decl->field_end();
+ field != field_end; ++field, ++child_idx) {
+ llvm::StringRef field_name = field->getName();
+ if (field_name.empty()) {
+ CompilerType field_type = GetType(field->getType());
+ child_indexes.push_back(child_idx);
+ if (field_type.GetIndexOfChildMemberWithName(
+ name, omit_empty_base_classes, child_indexes))
+ return child_indexes.size();
+ child_indexes.pop_back();
+
+ } else if (field_name.equals(name_sref)) {
+ // We have to add on the number of base classes to this index!
+ child_indexes.push_back(
+ child_idx + TypeSystemClang::GetNumBaseClasses(
+ cxx_record_decl, omit_empty_base_classes));
+ return child_indexes.size();
+ }
+ }
+
+ if (cxx_record_decl) {
+ const clang::RecordDecl *parent_record_decl = cxx_record_decl;
+
+ // printf ("parent = %s\n", parent_record_decl->getNameAsCString());
+
+ // const Decl *root_cdecl = cxx_record_decl->getCanonicalDecl();
+ // Didn't find things easily, lets let clang do its thang...
+ clang::IdentifierInfo &ident_ref =
+ getASTContext().Idents.get(name_sref);
+ clang::DeclarationName decl_name(&ident_ref);
+
+ clang::CXXBasePaths paths;
+ if (cxx_record_decl->lookupInBases(
+ [decl_name](const clang::CXXBaseSpecifier *specifier,
+ clang::CXXBasePath &path) {
+ return clang::CXXRecordDecl::FindOrdinaryMember(
+ specifier, path, decl_name);
+ },
+ paths)) {
+ clang::CXXBasePaths::const_paths_iterator path,
+ path_end = paths.end();
+ for (path = paths.begin(); path != path_end; ++path) {
+ const size_t num_path_elements = path->size();
+ for (size_t e = 0; e < num_path_elements; ++e) {
+ clang::CXXBasePathElement elem = (*path)[e];
+
+ child_idx = GetIndexForRecordBase(parent_record_decl, elem.Base,
+ omit_empty_base_classes);
+ if (child_idx == UINT32_MAX) {
+ child_indexes.clear();
+ return 0;
+ } else {
+ child_indexes.push_back(child_idx);
+ parent_record_decl = llvm::cast<clang::RecordDecl>(
+ elem.Base->getType()
+ ->getAs<clang::RecordType>()
+ ->getDecl());
+ }
+ }
+ for (clang::NamedDecl *path_decl : path->Decls) {
+ child_idx = GetIndexForRecordChild(
+ parent_record_decl, path_decl, omit_empty_base_classes);
+ if (child_idx == UINT32_MAX) {
+ child_indexes.clear();
+ return 0;
+ } else {
+ child_indexes.push_back(child_idx);
+ }
+ }
+ }
+ return child_indexes.size();
+ }
+ }
+ }
+ break;
+
+ case clang::Type::ObjCObject:
+ case clang::Type::ObjCInterface:
+ if (GetCompleteType(type)) {
+ llvm::StringRef name_sref(name);
+ const clang::ObjCObjectType *objc_class_type =
+ llvm::dyn_cast<clang::ObjCObjectType>(qual_type.getTypePtr());
+ assert(objc_class_type);
+ if (objc_class_type) {
+ uint32_t child_idx = 0;
+ clang::ObjCInterfaceDecl *class_interface_decl =
+ objc_class_type->getInterface();
+
+ if (class_interface_decl) {
+ clang::ObjCInterfaceDecl::ivar_iterator ivar_pos,
+ ivar_end = class_interface_decl->ivar_end();
+ clang::ObjCInterfaceDecl *superclass_interface_decl =
+ class_interface_decl->getSuperClass();
+
+ for (ivar_pos = class_interface_decl->ivar_begin();
+ ivar_pos != ivar_end; ++ivar_pos, ++child_idx) {
+ const clang::ObjCIvarDecl *ivar_decl = *ivar_pos;
+
+ if (ivar_decl->getName().equals(name_sref)) {
+ if ((!omit_empty_base_classes && superclass_interface_decl) ||
+ (omit_empty_base_classes &&
+ ObjCDeclHasIVars(superclass_interface_decl, true)))
+ ++child_idx;
+
+ child_indexes.push_back(child_idx);
+ return child_indexes.size();
+ }
+ }
+
+ if (superclass_interface_decl) {
+ // The super class index is always zero for ObjC classes, so we
+ // push it onto the child indexes in case we find an ivar in our
+ // superclass...
+ child_indexes.push_back(0);
+
+ CompilerType superclass_clang_type =
+ GetType(getASTContext().getObjCInterfaceType(
+ superclass_interface_decl));
+ if (superclass_clang_type.GetIndexOfChildMemberWithName(
+ name, omit_empty_base_classes, child_indexes)) {
+ // We did find an ivar in a superclass so just return the
+ // results!
+ return child_indexes.size();
+ }
+
+ // We didn't find an ivar matching "name" in our superclass, pop
+ // the superclass zero index that we pushed on above.
+ child_indexes.pop_back();
+ }
+ }
+ }
+ }
+ break;
+
+ case clang::Type::ObjCObjectPointer: {
+ CompilerType objc_object_clang_type = GetType(
+ llvm::cast<clang::ObjCObjectPointerType>(qual_type.getTypePtr())
+ ->getPointeeType());
+ return objc_object_clang_type.GetIndexOfChildMemberWithName(
+ name, omit_empty_base_classes, child_indexes);
+ } break;
+
+ case clang::Type::ConstantArray: {
+ // const clang::ConstantArrayType *array =
+ // llvm::cast<clang::ConstantArrayType>(parent_qual_type.getTypePtr());
+ // const uint64_t element_count =
+ // array->getSize().getLimitedValue();
+ //
+ // if (idx < element_count)
+ // {
+ // std::pair<uint64_t, unsigned> field_type_info =
+ // ast->getTypeInfo(array->getElementType());
+ //
+ // char element_name[32];
+ // ::snprintf (element_name, sizeof (element_name),
+ // "%s[%u]", parent_name ? parent_name : "", idx);
+ //
+ // child_name.assign(element_name);
+ // assert(field_type_info.first % 8 == 0);
+ // child_byte_size = field_type_info.first / 8;
+ // child_byte_offset = idx * child_byte_size;
+ // return array->getElementType().getAsOpaquePtr();
+ // }
+ } break;
+
+ // case clang::Type::MemberPointerType:
+ // {
+ // MemberPointerType *mem_ptr_type =
+ // llvm::cast<MemberPointerType>(qual_type.getTypePtr());
+ // clang::QualType pointee_type =
+ // mem_ptr_type->getPointeeType();
+ //
+ // if (TypeSystemClang::IsAggregateType
+ // (pointee_type.getAsOpaquePtr()))
+ // {
+ // return GetIndexOfChildWithName (ast,
+ // mem_ptr_type->getPointeeType().getAsOpaquePtr(),
+ // name);
+ // }
+ // }
+ // break;
+ //
+ case clang::Type::LValueReference:
+ case clang::Type::RValueReference: {
+ const clang::ReferenceType *reference_type =
+ llvm::cast<clang::ReferenceType>(qual_type.getTypePtr());
+ clang::QualType pointee_type(reference_type->getPointeeType());
+ CompilerType pointee_clang_type = GetType(pointee_type);
+
+ if (pointee_clang_type.IsAggregateType()) {
+ return pointee_clang_type.GetIndexOfChildMemberWithName(
+ name, omit_empty_base_classes, child_indexes);
+ }
+ } break;
+
+ case clang::Type::Pointer: {
+ CompilerType pointee_clang_type(GetPointeeType(type));
+
+ if (pointee_clang_type.IsAggregateType()) {
+ return pointee_clang_type.GetIndexOfChildMemberWithName(
+ name, omit_empty_base_classes, child_indexes);
+ }
+ } break;
+
+ default:
+ break;
+ }
+ }
+ return 0;
+}
+
+// Get the index of the child of "clang_type" whose name matches. This function
+// doesn't descend into the children, but only looks one level deep and name
+// matches can include base class names.
+
+uint32_t
+TypeSystemClang::GetIndexOfChildWithName(lldb::opaque_compiler_type_t type,
+ const char *name,
+ bool omit_empty_base_classes) {
+ if (type && name && name[0]) {
+ clang::QualType qual_type = RemoveWrappingTypes(GetCanonicalQualType(type));
+
+ const clang::Type::TypeClass type_class = qual_type->getTypeClass();
+
+ switch (type_class) {
+ case clang::Type::Record:
+ if (GetCompleteType(type)) {
+ const clang::RecordType *record_type =
+ llvm::cast<clang::RecordType>(qual_type.getTypePtr());
+ const clang::RecordDecl *record_decl = record_type->getDecl();
+
+ assert(record_decl);
+ uint32_t child_idx = 0;
+
+ const clang::CXXRecordDecl *cxx_record_decl =
+ llvm::dyn_cast<clang::CXXRecordDecl>(record_decl);
+
+ if (cxx_record_decl) {
+ clang::CXXRecordDecl::base_class_const_iterator base_class,
+ base_class_end;
+ for (base_class = cxx_record_decl->bases_begin(),
+ base_class_end = cxx_record_decl->bases_end();
+ base_class != base_class_end; ++base_class) {
+ // Skip empty base classes
+ clang::CXXRecordDecl *base_class_decl =
+ llvm::cast<clang::CXXRecordDecl>(
+ base_class->getType()
+ ->getAs<clang::RecordType>()
+ ->getDecl());
+ if (omit_empty_base_classes &&
+ !TypeSystemClang::RecordHasFields(base_class_decl))
+ continue;
+
+ CompilerType base_class_clang_type = GetType(base_class->getType());
+ std::string base_class_type_name(
+ base_class_clang_type.GetTypeName().AsCString(""));
+ if (base_class_type_name == name)
+ return child_idx;
+ ++child_idx;
+ }
+ }
+
+ // Try and find a field that matches NAME
+ clang::RecordDecl::field_iterator field, field_end;
+ llvm::StringRef name_sref(name);
+ for (field = record_decl->field_begin(),
+ field_end = record_decl->field_end();
+ field != field_end; ++field, ++child_idx) {
+ if (field->getName().equals(name_sref))
+ return child_idx;
+ }
+ }
+ break;
+
+ case clang::Type::ObjCObject:
+ case clang::Type::ObjCInterface:
+ if (GetCompleteType(type)) {
+ llvm::StringRef name_sref(name);
+ const clang::ObjCObjectType *objc_class_type =
+ llvm::dyn_cast<clang::ObjCObjectType>(qual_type.getTypePtr());
+ assert(objc_class_type);
+ if (objc_class_type) {
+ uint32_t child_idx = 0;
+ clang::ObjCInterfaceDecl *class_interface_decl =
+ objc_class_type->getInterface();
+
+ if (class_interface_decl) {
+ clang::ObjCInterfaceDecl::ivar_iterator ivar_pos,
+ ivar_end = class_interface_decl->ivar_end();
+ clang::ObjCInterfaceDecl *superclass_interface_decl =
+ class_interface_decl->getSuperClass();
+
+ for (ivar_pos = class_interface_decl->ivar_begin();
+ ivar_pos != ivar_end; ++ivar_pos, ++child_idx) {
+ const clang::ObjCIvarDecl *ivar_decl = *ivar_pos;
+
+ if (ivar_decl->getName().equals(name_sref)) {
+ if ((!omit_empty_base_classes && superclass_interface_decl) ||
+ (omit_empty_base_classes &&
+ ObjCDeclHasIVars(superclass_interface_decl, true)))
+ ++child_idx;
+
+ return child_idx;
+ }
+ }
+
+ if (superclass_interface_decl) {
+ if (superclass_interface_decl->getName().equals(name_sref))
+ return 0;
+ }
+ }
+ }
+ }
+ break;
+
+ case clang::Type::ObjCObjectPointer: {
+ CompilerType pointee_clang_type = GetType(
+ llvm::cast<clang::ObjCObjectPointerType>(qual_type.getTypePtr())
+ ->getPointeeType());
+ return pointee_clang_type.GetIndexOfChildWithName(
+ name, omit_empty_base_classes);
+ } break;
+
+ case clang::Type::ConstantArray: {
+ // const clang::ConstantArrayType *array =
+ // llvm::cast<clang::ConstantArrayType>(parent_qual_type.getTypePtr());
+ // const uint64_t element_count =
+ // array->getSize().getLimitedValue();
+ //
+ // if (idx < element_count)
+ // {
+ // std::pair<uint64_t, unsigned> field_type_info =
+ // ast->getTypeInfo(array->getElementType());
+ //
+ // char element_name[32];
+ // ::snprintf (element_name, sizeof (element_name),
+ // "%s[%u]", parent_name ? parent_name : "", idx);
+ //
+ // child_name.assign(element_name);
+ // assert(field_type_info.first % 8 == 0);
+ // child_byte_size = field_type_info.first / 8;
+ // child_byte_offset = idx * child_byte_size;
+ // return array->getElementType().getAsOpaquePtr();
+ // }
+ } break;
+
+ // case clang::Type::MemberPointerType:
+ // {
+ // MemberPointerType *mem_ptr_type =
+ // llvm::cast<MemberPointerType>(qual_type.getTypePtr());
+ // clang::QualType pointee_type =
+ // mem_ptr_type->getPointeeType();
+ //
+ // if (TypeSystemClang::IsAggregateType
+ // (pointee_type.getAsOpaquePtr()))
+ // {
+ // return GetIndexOfChildWithName (ast,
+ // mem_ptr_type->getPointeeType().getAsOpaquePtr(),
+ // name);
+ // }
+ // }
+ // break;
+ //
+ case clang::Type::LValueReference:
+ case clang::Type::RValueReference: {
+ const clang::ReferenceType *reference_type =
+ llvm::cast<clang::ReferenceType>(qual_type.getTypePtr());
+ CompilerType pointee_type = GetType(reference_type->getPointeeType());
+
+ if (pointee_type.IsAggregateType()) {
+ return pointee_type.GetIndexOfChildWithName(name,
+ omit_empty_base_classes);
+ }
+ } break;
+
+ case clang::Type::Pointer: {
+ const clang::PointerType *pointer_type =
+ llvm::cast<clang::PointerType>(qual_type.getTypePtr());
+ CompilerType pointee_type = GetType(pointer_type->getPointeeType());
+
+ if (pointee_type.IsAggregateType()) {
+ return pointee_type.GetIndexOfChildWithName(name,
+ omit_empty_base_classes);
+ } else {
+ // if (parent_name)
+ // {
+ // child_name.assign(1, '*');
+ // child_name += parent_name;
+ // }
+ //
+ // // We have a pointer to an simple type
+ // if (idx == 0)
+ // {
+ // std::pair<uint64_t, unsigned> clang_type_info
+ // = ast->getTypeInfo(pointee_type);
+ // assert(clang_type_info.first % 8 == 0);
+ // child_byte_size = clang_type_info.first / 8;
+ // child_byte_offset = 0;
+ // return pointee_type.getAsOpaquePtr();
+ // }
+ }
+ } break;
+
+ default:
+ break;
+ }
+ }
+ return UINT32_MAX;
+}
+
+size_t
+TypeSystemClang::GetNumTemplateArguments(lldb::opaque_compiler_type_t type) {
+ if (!type)
+ return 0;
+
+ clang::QualType qual_type = RemoveWrappingTypes(GetCanonicalQualType(type));
+ const clang::Type::TypeClass type_class = qual_type->getTypeClass();
+ switch (type_class) {
+ case clang::Type::Record:
+ if (GetCompleteType(type)) {
+ const clang::CXXRecordDecl *cxx_record_decl =
+ qual_type->getAsCXXRecordDecl();
+ if (cxx_record_decl) {
+ const clang::ClassTemplateSpecializationDecl *template_decl =
+ llvm::dyn_cast<clang::ClassTemplateSpecializationDecl>(
+ cxx_record_decl);
+ if (template_decl)
+ return template_decl->getTemplateArgs().size();
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+const clang::ClassTemplateSpecializationDecl *
+TypeSystemClang::GetAsTemplateSpecialization(
+ lldb::opaque_compiler_type_t type) {
+ if (!type)
+ return nullptr;
+
+ clang::QualType qual_type(RemoveWrappingTypes(GetCanonicalQualType(type)));
+ const clang::Type::TypeClass type_class = qual_type->getTypeClass();
+ switch (type_class) {
+ case clang::Type::Record: {
+ if (! GetCompleteType(type))
+ return nullptr;
+ const clang::CXXRecordDecl *cxx_record_decl =
+ qual_type->getAsCXXRecordDecl();
+ if (!cxx_record_decl)
+ return nullptr;
+ return llvm::dyn_cast<clang::ClassTemplateSpecializationDecl>(
+ cxx_record_decl);
+ }
+
+ default:
+ return nullptr;
+ }
+}
+
+lldb::TemplateArgumentKind
+TypeSystemClang::GetTemplateArgumentKind(lldb::opaque_compiler_type_t type,
+ size_t arg_idx) {
+ const clang::ClassTemplateSpecializationDecl *template_decl =
+ GetAsTemplateSpecialization(type);
+ if (! template_decl || arg_idx >= template_decl->getTemplateArgs().size())
+ return eTemplateArgumentKindNull;
+
+ switch (template_decl->getTemplateArgs()[arg_idx].getKind()) {
+ case clang::TemplateArgument::Null:
+ return eTemplateArgumentKindNull;
+
+ case clang::TemplateArgument::NullPtr:
+ return eTemplateArgumentKindNullPtr;
+
+ case clang::TemplateArgument::Type:
+ return eTemplateArgumentKindType;
+
+ case clang::TemplateArgument::Declaration:
+ return eTemplateArgumentKindDeclaration;
+
+ case clang::TemplateArgument::Integral:
+ return eTemplateArgumentKindIntegral;
+
+ case clang::TemplateArgument::Template:
+ return eTemplateArgumentKindTemplate;
+
+ case clang::TemplateArgument::TemplateExpansion:
+ return eTemplateArgumentKindTemplateExpansion;
+
+ case clang::TemplateArgument::Expression:
+ return eTemplateArgumentKindExpression;
+
+ case clang::TemplateArgument::Pack:
+ return eTemplateArgumentKindPack;
+ }
+ llvm_unreachable("Unhandled clang::TemplateArgument::ArgKind");
+}
+
+CompilerType
+TypeSystemClang::GetTypeTemplateArgument(lldb::opaque_compiler_type_t type,
+ size_t idx) {
+ const clang::ClassTemplateSpecializationDecl *template_decl =
+ GetAsTemplateSpecialization(type);
+ if (!template_decl || idx >= template_decl->getTemplateArgs().size())
+ return CompilerType();
+
+ const clang::TemplateArgument &template_arg =
+ template_decl->getTemplateArgs()[idx];
+ if (template_arg.getKind() != clang::TemplateArgument::Type)
+ return CompilerType();
+
+ return GetType(template_arg.getAsType());
+}
+
+Optional<CompilerType::IntegralTemplateArgument>
+TypeSystemClang::GetIntegralTemplateArgument(lldb::opaque_compiler_type_t type,
+ size_t idx) {
+ const clang::ClassTemplateSpecializationDecl *template_decl =
+ GetAsTemplateSpecialization(type);
+ if (! template_decl || idx >= template_decl->getTemplateArgs().size())
+ return llvm::None;
+
+ const clang::TemplateArgument &template_arg =
+ template_decl->getTemplateArgs()[idx];
+ if (template_arg.getKind() != clang::TemplateArgument::Integral)
+ return llvm::None;
+
+ return {
+ {template_arg.getAsIntegral(), GetType(template_arg.getIntegralType())}};
+}
+
+CompilerType TypeSystemClang::GetTypeForFormatters(void *type) {
+ if (type)
+ return ClangUtil::RemoveFastQualifiers(CompilerType(this, type));
+ return CompilerType();
+}
+
+clang::EnumDecl *TypeSystemClang::GetAsEnumDecl(const CompilerType &type) {
+ const clang::EnumType *enutype =
+ llvm::dyn_cast<clang::EnumType>(ClangUtil::GetCanonicalQualType(type));
+ if (enutype)
+ return enutype->getDecl();
+ return nullptr;
+}
+
+clang::RecordDecl *TypeSystemClang::GetAsRecordDecl(const CompilerType &type) {
+ const clang::RecordType *record_type =
+ llvm::dyn_cast<clang::RecordType>(ClangUtil::GetCanonicalQualType(type));
+ if (record_type)
+ return record_type->getDecl();
+ return nullptr;
+}
+
+clang::TagDecl *TypeSystemClang::GetAsTagDecl(const CompilerType &type) {
+ return ClangUtil::GetAsTagDecl(type);
+}
+
+clang::TypedefNameDecl *
+TypeSystemClang::GetAsTypedefDecl(const CompilerType &type) {
+ const clang::TypedefType *typedef_type =
+ llvm::dyn_cast<clang::TypedefType>(ClangUtil::GetQualType(type));
+ if (typedef_type)
+ return typedef_type->getDecl();
+ return nullptr;
+}
+
+clang::CXXRecordDecl *
+TypeSystemClang::GetAsCXXRecordDecl(lldb::opaque_compiler_type_t type) {
+ return GetCanonicalQualType(type)->getAsCXXRecordDecl();
+}
+
+clang::ObjCInterfaceDecl *
+TypeSystemClang::GetAsObjCInterfaceDecl(const CompilerType &type) {
+ const clang::ObjCObjectType *objc_class_type =
+ llvm::dyn_cast<clang::ObjCObjectType>(
+ ClangUtil::GetCanonicalQualType(type));
+ if (objc_class_type)
+ return objc_class_type->getInterface();
+ return nullptr;
+}
+
+clang::FieldDecl *TypeSystemClang::AddFieldToRecordType(
+ const CompilerType &type, llvm::StringRef name,
+ const CompilerType &field_clang_type, AccessType access,
+ uint32_t bitfield_bit_size) {
+ if (!type.IsValid() || !field_clang_type.IsValid())
+ return nullptr;
+ TypeSystemClang *ast =
+ llvm::dyn_cast_or_null<TypeSystemClang>(type.GetTypeSystem());
+ if (!ast)
+ return nullptr;
+ clang::ASTContext &clang_ast = ast->getASTContext();
+ clang::IdentifierInfo *ident = nullptr;
+ if (!name.empty())
+ ident = &clang_ast.Idents.get(name);
+
+ clang::FieldDecl *field = nullptr;
+
+ clang::Expr *bit_width = nullptr;
+ if (bitfield_bit_size != 0) {
+ llvm::APInt bitfield_bit_size_apint(clang_ast.getTypeSize(clang_ast.IntTy),
+ bitfield_bit_size);
+ bit_width = new (clang_ast)
+ clang::IntegerLiteral(clang_ast, bitfield_bit_size_apint,
+ clang_ast.IntTy, clang::SourceLocation());
+ }
+
+ clang::RecordDecl *record_decl = ast->GetAsRecordDecl(type);
+ if (record_decl) {
+ field = clang::FieldDecl::Create(
+ clang_ast, record_decl, clang::SourceLocation(),
+ clang::SourceLocation(),
+ ident, // Identifier
+ ClangUtil::GetQualType(field_clang_type), // Field type
+ nullptr, // TInfo *
+ bit_width, // BitWidth
+ false, // Mutable
+ clang::ICIS_NoInit); // HasInit
+
+ if (name.empty()) {
+ // Determine whether this field corresponds to an anonymous struct or
+ // union.
+ if (const clang::TagType *TagT =
+ field->getType()->getAs<clang::TagType>()) {
+ if (clang::RecordDecl *Rec =
+ llvm::dyn_cast<clang::RecordDecl>(TagT->getDecl()))
+ if (!Rec->getDeclName()) {
+ Rec->setAnonymousStructOrUnion(true);
+ field->setImplicit();
+ }
+ }
+ }
+
+ if (field) {
+ field->setAccess(
+ TypeSystemClang::ConvertAccessTypeToAccessSpecifier(access));
+
+ record_decl->addDecl(field);
+
+#ifdef LLDB_CONFIGURATION_DEBUG
+ VerifyDecl(field);
+#endif
+ }
+ } else {
+ clang::ObjCInterfaceDecl *class_interface_decl =
+ ast->GetAsObjCInterfaceDecl(type);
+
+ if (class_interface_decl) {
+ const bool is_synthesized = false;
+
+ field_clang_type.GetCompleteType();
+
+ field = clang::ObjCIvarDecl::Create(
+ clang_ast, class_interface_decl, clang::SourceLocation(),
+ clang::SourceLocation(),
+ ident, // Identifier
+ ClangUtil::GetQualType(field_clang_type), // Field type
+ nullptr, // TypeSourceInfo *
+ ConvertAccessTypeToObjCIvarAccessControl(access), bit_width,
+ is_synthesized);
+
+ if (field) {
+ class_interface_decl->addDecl(field);
+
+#ifdef LLDB_CONFIGURATION_DEBUG
+ VerifyDecl(field);
+#endif
+ }
+ }
+ }
+ return field;
+}
+
+void TypeSystemClang::BuildIndirectFields(const CompilerType &type) {
+ if (!type)
+ return;
+
+ TypeSystemClang *ast = llvm::dyn_cast<TypeSystemClang>(type.GetTypeSystem());
+ if (!ast)
+ return;
+
+ clang::RecordDecl *record_decl = ast->GetAsRecordDecl(type);
+
+ if (!record_decl)
+ return;
+
+ typedef llvm::SmallVector<clang::IndirectFieldDecl *, 1> IndirectFieldVector;
+
+ IndirectFieldVector indirect_fields;
+ clang::RecordDecl::field_iterator field_pos;
+ clang::RecordDecl::field_iterator field_end_pos = record_decl->field_end();
+ clang::RecordDecl::field_iterator last_field_pos = field_end_pos;
+ for (field_pos = record_decl->field_begin(); field_pos != field_end_pos;
+ last_field_pos = field_pos++) {
+ if (field_pos->isAnonymousStructOrUnion()) {
+ clang::QualType field_qual_type = field_pos->getType();
+
+ const clang::RecordType *field_record_type =
+ field_qual_type->getAs<clang::RecordType>();
+
+ if (!field_record_type)
+ continue;
+
+ clang::RecordDecl *field_record_decl = field_record_type->getDecl();
+
+ if (!field_record_decl)
+ continue;
+
+ for (clang::RecordDecl::decl_iterator
+ di = field_record_decl->decls_begin(),
+ de = field_record_decl->decls_end();
+ di != de; ++di) {
+ if (clang::FieldDecl *nested_field_decl =
+ llvm::dyn_cast<clang::FieldDecl>(*di)) {
+ clang::NamedDecl **chain =
+ new (ast->getASTContext()) clang::NamedDecl *[2];
+ chain[0] = *field_pos;
+ chain[1] = nested_field_decl;
+ clang::IndirectFieldDecl *indirect_field =
+ clang::IndirectFieldDecl::Create(
+ ast->getASTContext(), record_decl, clang::SourceLocation(),
+ nested_field_decl->getIdentifier(),
+ nested_field_decl->getType(), {chain, 2});
+
+ indirect_field->setImplicit();
+
+ indirect_field->setAccess(TypeSystemClang::UnifyAccessSpecifiers(
+ field_pos->getAccess(), nested_field_decl->getAccess()));
+
+ indirect_fields.push_back(indirect_field);
+ } else if (clang::IndirectFieldDecl *nested_indirect_field_decl =
+ llvm::dyn_cast<clang::IndirectFieldDecl>(*di)) {
+ size_t nested_chain_size =
+ nested_indirect_field_decl->getChainingSize();
+ clang::NamedDecl **chain = new (ast->getASTContext())
+ clang::NamedDecl *[nested_chain_size + 1];
+ chain[0] = *field_pos;
+
+ int chain_index = 1;
+ for (clang::IndirectFieldDecl::chain_iterator
+ nci = nested_indirect_field_decl->chain_begin(),
+ nce = nested_indirect_field_decl->chain_end();
+ nci < nce; ++nci) {
+ chain[chain_index] = *nci;
+ chain_index++;
+ }
+
+ clang::IndirectFieldDecl *indirect_field =
+ clang::IndirectFieldDecl::Create(
+ ast->getASTContext(), record_decl, clang::SourceLocation(),
+ nested_indirect_field_decl->getIdentifier(),
+ nested_indirect_field_decl->getType(),
+ {chain, nested_chain_size + 1});
+
+ indirect_field->setImplicit();
+
+ indirect_field->setAccess(TypeSystemClang::UnifyAccessSpecifiers(
+ field_pos->getAccess(), nested_indirect_field_decl->getAccess()));
+
+ indirect_fields.push_back(indirect_field);
+ }
+ }
+ }
+ }
+
+ // Check the last field to see if it has an incomplete array type as its last
+ // member and if it does, the tell the record decl about it
+ if (last_field_pos != field_end_pos) {
+ if (last_field_pos->getType()->isIncompleteArrayType())
+ record_decl->hasFlexibleArrayMember();
+ }
+
+ for (IndirectFieldVector::iterator ifi = indirect_fields.begin(),
+ ife = indirect_fields.end();
+ ifi < ife; ++ifi) {
+ record_decl->addDecl(*ifi);
+ }
+}
+
+void TypeSystemClang::SetIsPacked(const CompilerType &type) {
+ if (type) {
+ TypeSystemClang *ast =
+ llvm::dyn_cast<TypeSystemClang>(type.GetTypeSystem());
+ if (ast) {
+ clang::RecordDecl *record_decl = GetAsRecordDecl(type);
+
+ if (!record_decl)
+ return;
+
+ record_decl->addAttr(
+ clang::PackedAttr::CreateImplicit(ast->getASTContext()));
+ }
+ }
+}
+
+clang::VarDecl *TypeSystemClang::AddVariableToRecordType(
+ const CompilerType &type, llvm::StringRef name,
+ const CompilerType &var_type, AccessType access) {
+ if (!type.IsValid() || !var_type.IsValid())
+ return nullptr;
+
+ TypeSystemClang *ast = llvm::dyn_cast<TypeSystemClang>(type.GetTypeSystem());
+ if (!ast)
+ return nullptr;
+
+ clang::RecordDecl *record_decl = ast->GetAsRecordDecl(type);
+ if (!record_decl)
+ return nullptr;
+
+ clang::VarDecl *var_decl = nullptr;
+ clang::IdentifierInfo *ident = nullptr;
+ if (!name.empty())
+ ident = &ast->getASTContext().Idents.get(name);
+
+ var_decl = clang::VarDecl::Create(
+ ast->getASTContext(), // ASTContext &
+ record_decl, // DeclContext *
+ clang::SourceLocation(), // clang::SourceLocation StartLoc
+ clang::SourceLocation(), // clang::SourceLocation IdLoc
+ ident, // clang::IdentifierInfo *
+ ClangUtil::GetQualType(var_type), // Variable clang::QualType
+ nullptr, // TypeSourceInfo *
+ clang::SC_Static); // StorageClass
+ if (!var_decl)
+ return nullptr;
+
+ var_decl->setAccess(
+ TypeSystemClang::ConvertAccessTypeToAccessSpecifier(access));
+ record_decl->addDecl(var_decl);
+
+#ifdef LLDB_CONFIGURATION_DEBUG
+ VerifyDecl(var_decl);
+#endif
+
+ return var_decl;
+}
+
+clang::CXXMethodDecl *TypeSystemClang::AddMethodToCXXRecordType(
+ lldb::opaque_compiler_type_t type, llvm::StringRef name,
+ const char *mangled_name, const CompilerType &method_clang_type,
+ lldb::AccessType access, bool is_virtual, bool is_static, bool is_inline,
+ bool is_explicit, bool is_attr_used, bool is_artificial) {
+ if (!type || !method_clang_type.IsValid() || name.empty())
+ return nullptr;
+
+ clang::QualType record_qual_type(GetCanonicalQualType(type));
+
+ clang::CXXRecordDecl *cxx_record_decl =
+ record_qual_type->getAsCXXRecordDecl();
+
+ if (cxx_record_decl == nullptr)
+ return nullptr;
+
+ clang::QualType method_qual_type(ClangUtil::GetQualType(method_clang_type));
+
+ clang::CXXMethodDecl *cxx_method_decl = nullptr;
+
+ clang::DeclarationName decl_name(&getASTContext().Idents.get(name));
+
+ const clang::FunctionType *function_type =
+ llvm::dyn_cast<clang::FunctionType>(method_qual_type.getTypePtr());
+
+ if (function_type == nullptr)
+ return nullptr;
+
+ const clang::FunctionProtoType *method_function_prototype(
+ llvm::dyn_cast<clang::FunctionProtoType>(function_type));
+
+ if (!method_function_prototype)
+ return nullptr;
+
+ unsigned int num_params = method_function_prototype->getNumParams();
+
+ clang::CXXDestructorDecl *cxx_dtor_decl(nullptr);
+ clang::CXXConstructorDecl *cxx_ctor_decl(nullptr);
+
+ if (is_artificial)
+ return nullptr; // skip everything artificial
+
+ const clang::ExplicitSpecifier explicit_spec(
+ nullptr /*expr*/, is_explicit
+ ? clang::ExplicitSpecKind::ResolvedTrue
+ : clang::ExplicitSpecKind::ResolvedFalse);
+ if (name.startswith("~")) {
+ cxx_dtor_decl = clang::CXXDestructorDecl::Create(
+ getASTContext(), cxx_record_decl, clang::SourceLocation(),
+ clang::DeclarationNameInfo(
+ getASTContext().DeclarationNames.getCXXDestructorName(
+ getASTContext().getCanonicalType(record_qual_type)),
+ clang::SourceLocation()),
+ method_qual_type, nullptr, is_inline, is_artificial,
+ ConstexprSpecKind::CSK_unspecified);
+ cxx_method_decl = cxx_dtor_decl;
+ } else if (decl_name == cxx_record_decl->getDeclName()) {
+ cxx_ctor_decl = clang::CXXConstructorDecl::Create(
+ getASTContext(), cxx_record_decl, clang::SourceLocation(),
+ clang::DeclarationNameInfo(
+ getASTContext().DeclarationNames.getCXXConstructorName(
+ getASTContext().getCanonicalType(record_qual_type)),
+ clang::SourceLocation()),
+ method_qual_type,
+ nullptr, // TypeSourceInfo *
+ explicit_spec, is_inline, is_artificial, CSK_unspecified);
+ cxx_method_decl = cxx_ctor_decl;
+ } else {
+ clang::StorageClass SC = is_static ? clang::SC_Static : clang::SC_None;
+ clang::OverloadedOperatorKind op_kind = clang::NUM_OVERLOADED_OPERATORS;
+
+ if (IsOperator(name, op_kind)) {
+ if (op_kind != clang::NUM_OVERLOADED_OPERATORS) {
+ // Check the number of operator parameters. Sometimes we have seen bad
+ // DWARF that doesn't correctly describe operators and if we try to
+ // create a method and add it to the class, clang will assert and
+ // crash, so we need to make sure things are acceptable.
+ const bool is_method = true;
+ if (!TypeSystemClang::CheckOverloadedOperatorKindParameterCount(
+ is_method, op_kind, num_params))
+ return nullptr;
+ cxx_method_decl = clang::CXXMethodDecl::Create(
+ getASTContext(), cxx_record_decl, clang::SourceLocation(),
+ clang::DeclarationNameInfo(
+ getASTContext().DeclarationNames.getCXXOperatorName(op_kind),
+ clang::SourceLocation()),
+ method_qual_type,
+ nullptr, // TypeSourceInfo *
+ SC, is_inline, CSK_unspecified, clang::SourceLocation());
+ } else if (num_params == 0) {
+ // Conversion operators don't take params...
+ cxx_method_decl = clang::CXXConversionDecl::Create(
+ getASTContext(), cxx_record_decl, clang::SourceLocation(),
+ clang::DeclarationNameInfo(
+ getASTContext().DeclarationNames.getCXXConversionFunctionName(
+ getASTContext().getCanonicalType(
+ function_type->getReturnType())),
+ clang::SourceLocation()),
+ method_qual_type,
+ nullptr, // TypeSourceInfo *
+ is_inline, explicit_spec, CSK_unspecified, clang::SourceLocation());
+ }
+ }
+
+ if (cxx_method_decl == nullptr) {
+ cxx_method_decl = clang::CXXMethodDecl::Create(
+ getASTContext(), cxx_record_decl, clang::SourceLocation(),
+ clang::DeclarationNameInfo(decl_name, clang::SourceLocation()),
+ method_qual_type,
+ nullptr, // TypeSourceInfo *
+ SC, is_inline, CSK_unspecified, clang::SourceLocation());
+ }
+ }
+
+ clang::AccessSpecifier access_specifier =
+ TypeSystemClang::ConvertAccessTypeToAccessSpecifier(access);
+
+ cxx_method_decl->setAccess(access_specifier);
+ cxx_method_decl->setVirtualAsWritten(is_virtual);
+
+ if (is_attr_used)
+ cxx_method_decl->addAttr(clang::UsedAttr::CreateImplicit(getASTContext()));
+
+ if (mangled_name != nullptr) {
+ cxx_method_decl->addAttr(clang::AsmLabelAttr::CreateImplicit(
+ getASTContext(), mangled_name, /*literal=*/false));
+ }
+
+ // Populate the method decl with parameter decls
+
+ llvm::SmallVector<clang::ParmVarDecl *, 12> params;
+
+ for (unsigned param_index = 0; param_index < num_params; ++param_index) {
+ params.push_back(clang::ParmVarDecl::Create(
+ getASTContext(), cxx_method_decl, clang::SourceLocation(),
+ clang::SourceLocation(),
+ nullptr, // anonymous
+ method_function_prototype->getParamType(param_index), nullptr,
+ clang::SC_None, nullptr));
+ }
+
+ cxx_method_decl->setParams(llvm::ArrayRef<clang::ParmVarDecl *>(params));
+
+ cxx_record_decl->addDecl(cxx_method_decl);
+
+ // Sometimes the debug info will mention a constructor (default/copy/move),
+ // destructor, or assignment operator (copy/move) but there won't be any
+ // version of this in the code. So we check if the function was artificially
+ // generated and if it is trivial and this lets the compiler/backend know
+ // that it can inline the IR for these when it needs to and we can avoid a
+ // "missing function" error when running expressions.
+
+ if (is_artificial) {
+ if (cxx_ctor_decl && ((cxx_ctor_decl->isDefaultConstructor() &&
+ cxx_record_decl->hasTrivialDefaultConstructor()) ||
+ (cxx_ctor_decl->isCopyConstructor() &&
+ cxx_record_decl->hasTrivialCopyConstructor()) ||
+ (cxx_ctor_decl->isMoveConstructor() &&
+ cxx_record_decl->hasTrivialMoveConstructor()))) {
+ cxx_ctor_decl->setDefaulted();
+ cxx_ctor_decl->setTrivial(true);
+ } else if (cxx_dtor_decl) {
+ if (cxx_record_decl->hasTrivialDestructor()) {
+ cxx_dtor_decl->setDefaulted();
+ cxx_dtor_decl->setTrivial(true);
+ }
+ } else if ((cxx_method_decl->isCopyAssignmentOperator() &&
+ cxx_record_decl->hasTrivialCopyAssignment()) ||
+ (cxx_method_decl->isMoveAssignmentOperator() &&
+ cxx_record_decl->hasTrivialMoveAssignment())) {
+ cxx_method_decl->setDefaulted();
+ cxx_method_decl->setTrivial(true);
+ }
+ }
+
+#ifdef LLDB_CONFIGURATION_DEBUG
+ VerifyDecl(cxx_method_decl);
+#endif
+
+ return cxx_method_decl;
+}
+
+void TypeSystemClang::AddMethodOverridesForCXXRecordType(
+ lldb::opaque_compiler_type_t type) {
+ if (auto *record = GetAsCXXRecordDecl(type))
+ for (auto *method : record->methods())
+ addOverridesForMethod(method);
+}
+
+#pragma mark C++ Base Classes
+
+std::unique_ptr<clang::CXXBaseSpecifier>
+TypeSystemClang::CreateBaseClassSpecifier(lldb::opaque_compiler_type_t type,
+ AccessType access, bool is_virtual,
+ bool base_of_class) {
+ if (!type)
+ return nullptr;
+
+ return std::make_unique<clang::CXXBaseSpecifier>(
+ clang::SourceRange(), is_virtual, base_of_class,
+ TypeSystemClang::ConvertAccessTypeToAccessSpecifier(access),
+ getASTContext().getTrivialTypeSourceInfo(GetQualType(type)),
+ clang::SourceLocation());
+}
+
+bool TypeSystemClang::TransferBaseClasses(
+ lldb::opaque_compiler_type_t type,
+ std::vector<std::unique_ptr<clang::CXXBaseSpecifier>> bases) {
+ if (!type)
+ return false;
+ clang::CXXRecordDecl *cxx_record_decl = GetAsCXXRecordDecl(type);
+ if (!cxx_record_decl)
+ return false;
+ std::vector<clang::CXXBaseSpecifier *> raw_bases;
+ raw_bases.reserve(bases.size());
+
+ // Clang will make a copy of them, so it's ok that we pass pointers that we're
+ // about to destroy.
+ for (auto &b : bases)
+ raw_bases.push_back(b.get());
+ cxx_record_decl->setBases(raw_bases.data(), raw_bases.size());
+ return true;
+}
+
+bool TypeSystemClang::SetObjCSuperClass(
+ const CompilerType &type, const CompilerType &superclass_clang_type) {
+ TypeSystemClang *ast =
+ llvm::dyn_cast_or_null<TypeSystemClang>(type.GetTypeSystem());
+ if (!ast)
+ return false;
+ clang::ASTContext &clang_ast = ast->getASTContext();
+
+ if (type && superclass_clang_type.IsValid() &&
+ superclass_clang_type.GetTypeSystem() == type.GetTypeSystem()) {
+ clang::ObjCInterfaceDecl *class_interface_decl =
+ GetAsObjCInterfaceDecl(type);
+ clang::ObjCInterfaceDecl *super_interface_decl =
+ GetAsObjCInterfaceDecl(superclass_clang_type);
+ if (class_interface_decl && super_interface_decl) {
+ class_interface_decl->setSuperClass(clang_ast.getTrivialTypeSourceInfo(
+ clang_ast.getObjCInterfaceType(super_interface_decl)));
+ return true;
+ }
+ }
+ return false;
+}
+
+bool TypeSystemClang::AddObjCClassProperty(
+ const CompilerType &type, const char *property_name,
+ const CompilerType &property_clang_type, clang::ObjCIvarDecl *ivar_decl,
+ const char *property_setter_name, const char *property_getter_name,
+ uint32_t property_attributes, ClangASTMetadata *metadata) {
+ if (!type || !property_clang_type.IsValid() || property_name == nullptr ||
+ property_name[0] == '\0')
+ return false;
+ TypeSystemClang *ast = llvm::dyn_cast<TypeSystemClang>(type.GetTypeSystem());
+ if (!ast)
+ return false;
+ clang::ASTContext &clang_ast = ast->getASTContext();
+
+ clang::ObjCInterfaceDecl *class_interface_decl = GetAsObjCInterfaceDecl(type);
+ if (!class_interface_decl)
+ return false;
+
+ CompilerType property_clang_type_to_access;
+
+ if (property_clang_type.IsValid())
+ property_clang_type_to_access = property_clang_type;
+ else if (ivar_decl)
+ property_clang_type_to_access = ast->GetType(ivar_decl->getType());
+
+ if (!class_interface_decl || !property_clang_type_to_access.IsValid())
+ return false;
+
+ clang::TypeSourceInfo *prop_type_source;
+ if (ivar_decl)
+ prop_type_source = clang_ast.getTrivialTypeSourceInfo(ivar_decl->getType());
+ else
+ prop_type_source = clang_ast.getTrivialTypeSourceInfo(
+ ClangUtil::GetQualType(property_clang_type));
+
+ clang::ObjCPropertyDecl *property_decl = clang::ObjCPropertyDecl::Create(
+ clang_ast, class_interface_decl,
+ clang::SourceLocation(), // Source Location
+ &clang_ast.Idents.get(property_name),
+ clang::SourceLocation(), // Source Location for AT
+ clang::SourceLocation(), // Source location for (
+ ivar_decl ? ivar_decl->getType()
+ : ClangUtil::GetQualType(property_clang_type),
+ prop_type_source);
+
+ if (!property_decl)
+ return false;
+
+ if (metadata)
+ ast->SetMetadata(property_decl, *metadata);
+
+ class_interface_decl->addDecl(property_decl);
+
+ clang::Selector setter_sel, getter_sel;
+
+ if (property_setter_name) {
+ std::string property_setter_no_colon(property_setter_name,
+ strlen(property_setter_name) - 1);
+ clang::IdentifierInfo *setter_ident =
+ &clang_ast.Idents.get(property_setter_no_colon);
+ setter_sel = clang_ast.Selectors.getSelector(1, &setter_ident);
+ } else if (!(property_attributes & DW_APPLE_PROPERTY_readonly)) {
+ std::string setter_sel_string("set");
+ setter_sel_string.push_back(::toupper(property_name[0]));
+ setter_sel_string.append(&property_name[1]);
+ clang::IdentifierInfo *setter_ident =
+ &clang_ast.Idents.get(setter_sel_string);
+ setter_sel = clang_ast.Selectors.getSelector(1, &setter_ident);
+ }
+ property_decl->setSetterName(setter_sel);
+ property_decl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_setter);
+
+ if (property_getter_name != nullptr) {
+ clang::IdentifierInfo *getter_ident =
+ &clang_ast.Idents.get(property_getter_name);
+ getter_sel = clang_ast.Selectors.getSelector(0, &getter_ident);
+ } else {
+ clang::IdentifierInfo *getter_ident = &clang_ast.Idents.get(property_name);
+ getter_sel = clang_ast.Selectors.getSelector(0, &getter_ident);
+ }
+ property_decl->setGetterName(getter_sel);
+ property_decl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_getter);
+
+ if (ivar_decl)
+ property_decl->setPropertyIvarDecl(ivar_decl);
+
+ if (property_attributes & DW_APPLE_PROPERTY_readonly)
+ property_decl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_readonly);
+ if (property_attributes & DW_APPLE_PROPERTY_readwrite)
+ property_decl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_readwrite);
+ if (property_attributes & DW_APPLE_PROPERTY_assign)
+ property_decl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_assign);
+ if (property_attributes & DW_APPLE_PROPERTY_retain)
+ property_decl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_retain);
+ if (property_attributes & DW_APPLE_PROPERTY_copy)
+ property_decl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_copy);
+ if (property_attributes & DW_APPLE_PROPERTY_nonatomic)
+ property_decl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_nonatomic);
+ if (property_attributes & ObjCPropertyDecl::OBJC_PR_nullability)
+ property_decl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_nullability);
+ if (property_attributes & ObjCPropertyDecl::OBJC_PR_null_resettable)
+ property_decl->setPropertyAttributes(
+ ObjCPropertyDecl::OBJC_PR_null_resettable);
+ if (property_attributes & ObjCPropertyDecl::OBJC_PR_class)
+ property_decl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_class);
+
+ const bool isInstance =
+ (property_attributes & ObjCPropertyDecl::OBJC_PR_class) == 0;
+
+ clang::ObjCMethodDecl *getter = nullptr;
+ if (!getter_sel.isNull())
+ getter = isInstance ? class_interface_decl->lookupInstanceMethod(getter_sel)
+ : class_interface_decl->lookupClassMethod(getter_sel);
+ if (!getter_sel.isNull() && !getter) {
+ const bool isVariadic = false;
+ const bool isPropertyAccessor = false;
+ const bool isSynthesizedAccessorStub = false;
+ const bool isImplicitlyDeclared = true;
+ const bool isDefined = false;
+ const clang::ObjCMethodDecl::ImplementationControl impControl =
+ clang::ObjCMethodDecl::None;
+ const bool HasRelatedResultType = false;
+
+ getter = clang::ObjCMethodDecl::Create(
+ clang_ast, clang::SourceLocation(), clang::SourceLocation(), getter_sel,
+ ClangUtil::GetQualType(property_clang_type_to_access), nullptr,
+ class_interface_decl, isInstance, isVariadic, isPropertyAccessor,
+ isSynthesizedAccessorStub, isImplicitlyDeclared, isDefined, impControl,
+ HasRelatedResultType);
+
+ if (getter) {
+ if (metadata)
+ ast->SetMetadata(getter, *metadata);
+
+ getter->setMethodParams(clang_ast, llvm::ArrayRef<clang::ParmVarDecl *>(),
+ llvm::ArrayRef<clang::SourceLocation>());
+ class_interface_decl->addDecl(getter);
+ }
+ }
+ if (getter) {
+ getter->setPropertyAccessor(true);
+ property_decl->setGetterMethodDecl(getter);
+ }
+
+ clang::ObjCMethodDecl *setter = nullptr;
+ setter = isInstance ? class_interface_decl->lookupInstanceMethod(setter_sel)
+ : class_interface_decl->lookupClassMethod(setter_sel);
+ if (!setter_sel.isNull() && !setter) {
+ clang::QualType result_type = clang_ast.VoidTy;
+ const bool isVariadic = false;
+ const bool isPropertyAccessor = true;
+ const bool isSynthesizedAccessorStub = false;
+ const bool isImplicitlyDeclared = true;
+ const bool isDefined = false;
+ const clang::ObjCMethodDecl::ImplementationControl impControl =
+ clang::ObjCMethodDecl::None;
+ const bool HasRelatedResultType = false;
+
+ setter = clang::ObjCMethodDecl::Create(
+ clang_ast, clang::SourceLocation(), clang::SourceLocation(), setter_sel,
+ result_type, nullptr, class_interface_decl, isInstance, isVariadic,
+ isPropertyAccessor, isSynthesizedAccessorStub, isImplicitlyDeclared,
+ isDefined, impControl, HasRelatedResultType);
+
+ if (setter) {
+ if (metadata)
+ ast->SetMetadata(setter, *metadata);
+
+ llvm::SmallVector<clang::ParmVarDecl *, 1> params;
+ params.push_back(clang::ParmVarDecl::Create(
+ clang_ast, setter, clang::SourceLocation(), clang::SourceLocation(),
+ nullptr, // anonymous
+ ClangUtil::GetQualType(property_clang_type_to_access), nullptr,
+ clang::SC_Auto, nullptr));
+
+ setter->setMethodParams(clang_ast,
+ llvm::ArrayRef<clang::ParmVarDecl *>(params),
+ llvm::ArrayRef<clang::SourceLocation>());
+
+ class_interface_decl->addDecl(setter);
+ }
+ }
+ if (setter) {
+ setter->setPropertyAccessor(true);
+ property_decl->setSetterMethodDecl(setter);
+ }
+
+ return true;
+}
+
+bool TypeSystemClang::IsObjCClassTypeAndHasIVars(const CompilerType &type,
+ bool check_superclass) {
+ clang::ObjCInterfaceDecl *class_interface_decl = GetAsObjCInterfaceDecl(type);
+ if (class_interface_decl)
+ return ObjCDeclHasIVars(class_interface_decl, check_superclass);
+ return false;
+}
+
+clang::ObjCMethodDecl *TypeSystemClang::AddMethodToObjCObjectType(
+ const CompilerType &type,
+ const char *name, // the full symbol name as seen in the symbol table
+ // (lldb::opaque_compiler_type_t type, "-[NString
+ // stringWithCString:]")
+ const CompilerType &method_clang_type, lldb::AccessType access,
+ bool is_artificial, bool is_variadic, bool is_objc_direct_call) {
+ if (!type || !method_clang_type.IsValid())
+ return nullptr;
+
+ clang::ObjCInterfaceDecl *class_interface_decl = GetAsObjCInterfaceDecl(type);
+
+ if (class_interface_decl == nullptr)
+ return nullptr;
+ TypeSystemClang *lldb_ast =
+ llvm::dyn_cast<TypeSystemClang>(type.GetTypeSystem());
+ if (lldb_ast == nullptr)
+ return nullptr;
+ clang::ASTContext &ast = lldb_ast->getASTContext();
+
+ const char *selector_start = ::strchr(name, ' ');
+ if (selector_start == nullptr)
+ return nullptr;
+
+ selector_start++;
+ llvm::SmallVector<clang::IdentifierInfo *, 12> selector_idents;
+
+ size_t len = 0;
+ const char *start;
+ // printf ("name = '%s'\n", name);
+
+ unsigned num_selectors_with_args = 0;
+ for (start = selector_start; start && *start != '\0' && *start != ']';
+ start += len) {
+ len = ::strcspn(start, ":]");
+ bool has_arg = (start[len] == ':');
+ if (has_arg)
+ ++num_selectors_with_args;
+ selector_idents.push_back(&ast.Idents.get(llvm::StringRef(start, len)));
+ if (has_arg)
+ len += 1;
+ }
+
+ if (selector_idents.size() == 0)
+ return nullptr;
+
+ clang::Selector method_selector = ast.Selectors.getSelector(
+ num_selectors_with_args ? selector_idents.size() : 0,
+ selector_idents.data());
+
+ clang::QualType method_qual_type(ClangUtil::GetQualType(method_clang_type));
+
+ // Populate the method decl with parameter decls
+ const clang::Type *method_type(method_qual_type.getTypePtr());
+
+ if (method_type == nullptr)
+ return nullptr;
+
+ const clang::FunctionProtoType *method_function_prototype(
+ llvm::dyn_cast<clang::FunctionProtoType>(method_type));
+
+ if (!method_function_prototype)
+ return nullptr;
+
+ const bool isInstance = (name[0] == '-');
+ const bool isVariadic = is_variadic;
+ const bool isPropertyAccessor = false;
+ const bool isSynthesizedAccessorStub = false;
+ /// Force this to true because we don't have source locations.
+ const bool isImplicitlyDeclared = true;
+ const bool isDefined = false;
+ const clang::ObjCMethodDecl::ImplementationControl impControl =
+ clang::ObjCMethodDecl::None;
+ const bool HasRelatedResultType = false;
+
+ const unsigned num_args = method_function_prototype->getNumParams();
+
+ if (num_args != num_selectors_with_args)
+ return nullptr; // some debug information is corrupt. We are not going to
+ // deal with it.
+
+ clang::ObjCMethodDecl *objc_method_decl = clang::ObjCMethodDecl::Create(
+ ast,
+ clang::SourceLocation(), // beginLoc,
+ clang::SourceLocation(), // endLoc,
+ method_selector, method_function_prototype->getReturnType(),
+ nullptr, // TypeSourceInfo *ResultTInfo,
+ lldb_ast->GetDeclContextForType(ClangUtil::GetQualType(type)), isInstance,
+ isVariadic, isPropertyAccessor, isSynthesizedAccessorStub,
+ isImplicitlyDeclared, isDefined, impControl, HasRelatedResultType);
+
+ if (objc_method_decl == nullptr)
+ return nullptr;
+
+ if (num_args > 0) {
+ llvm::SmallVector<clang::ParmVarDecl *, 12> params;
+
+ for (unsigned param_index = 0; param_index < num_args; ++param_index) {
+ params.push_back(clang::ParmVarDecl::Create(
+ ast, objc_method_decl, clang::SourceLocation(),
+ clang::SourceLocation(),
+ nullptr, // anonymous
+ method_function_prototype->getParamType(param_index), nullptr,
+ clang::SC_Auto, nullptr));
+ }
+
+ objc_method_decl->setMethodParams(
+ ast, llvm::ArrayRef<clang::ParmVarDecl *>(params),
+ llvm::ArrayRef<clang::SourceLocation>());
+ }
+
+ if (is_objc_direct_call) {
+ // Add a the objc_direct attribute to the declaration we generate that
+ // we generate a direct method call for this ObjCMethodDecl.
+ objc_method_decl->addAttr(
+ clang::ObjCDirectAttr::CreateImplicit(ast, SourceLocation()));
+ // Usually Sema is creating implicit parameters (e.g., self) when it
+ // parses the method. We don't have a parsing Sema when we build our own
+ // AST here so we manually need to create these implicit parameters to
+ // make the direct call code generation happy.
+ objc_method_decl->createImplicitParams(ast, class_interface_decl);
+ }
+
+ class_interface_decl->addDecl(objc_method_decl);
+
+#ifdef LLDB_CONFIGURATION_DEBUG
+ VerifyDecl(objc_method_decl);
+#endif
+
+ return objc_method_decl;
+}
+
+bool TypeSystemClang::SetHasExternalStorage(lldb::opaque_compiler_type_t type,
+ bool has_extern) {
+ if (!type)
+ return false;
+
+ clang::QualType qual_type(RemoveWrappingTypes(GetCanonicalQualType(type)));
+
+ const clang::Type::TypeClass type_class = qual_type->getTypeClass();
+ switch (type_class) {
+ case clang::Type::Record: {
+ clang::CXXRecordDecl *cxx_record_decl = qual_type->getAsCXXRecordDecl();
+ if (cxx_record_decl) {
+ cxx_record_decl->setHasExternalLexicalStorage(has_extern);
+ cxx_record_decl->setHasExternalVisibleStorage(has_extern);
+ return true;
+ }
+ } break;
+
+ case clang::Type::Enum: {
+ clang::EnumDecl *enum_decl =
+ llvm::cast<clang::EnumType>(qual_type)->getDecl();
+ if (enum_decl) {
+ enum_decl->setHasExternalLexicalStorage(has_extern);
+ enum_decl->setHasExternalVisibleStorage(has_extern);
+ return true;
+ }
+ } break;
+
+ case clang::Type::ObjCObject:
+ case clang::Type::ObjCInterface: {
+ const clang::ObjCObjectType *objc_class_type =
+ llvm::dyn_cast<clang::ObjCObjectType>(qual_type.getTypePtr());
+ assert(objc_class_type);
+ if (objc_class_type) {
+ clang::ObjCInterfaceDecl *class_interface_decl =
+ objc_class_type->getInterface();
+
+ if (class_interface_decl) {
+ class_interface_decl->setHasExternalLexicalStorage(has_extern);
+ class_interface_decl->setHasExternalVisibleStorage(has_extern);
+ return true;
+ }
+ }
+ } break;
+
+ default:
+ break;
+ }
+ return false;
+}
+
+#pragma mark TagDecl
+
+bool TypeSystemClang::StartTagDeclarationDefinition(const CompilerType &type) {
+ clang::QualType qual_type(ClangUtil::GetQualType(type));
+ if (!qual_type.isNull()) {
+ const clang::TagType *tag_type = qual_type->getAs<clang::TagType>();
+ if (tag_type) {
+ clang::TagDecl *tag_decl = tag_type->getDecl();
+ if (tag_decl) {
+ tag_decl->startDefinition();
+ return true;
+ }
+ }
+
+ const clang::ObjCObjectType *object_type =
+ qual_type->getAs<clang::ObjCObjectType>();
+ if (object_type) {
+ clang::ObjCInterfaceDecl *interface_decl = object_type->getInterface();
+ if (interface_decl) {
+ interface_decl->startDefinition();
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+bool TypeSystemClang::CompleteTagDeclarationDefinition(
+ const CompilerType &type) {
+ clang::QualType qual_type(ClangUtil::GetQualType(type));
+ if (qual_type.isNull())
+ return false;
+
+ // Make sure we use the same methodology as
+ // TypeSystemClang::StartTagDeclarationDefinition() as to how we start/end
+ // the definition.
+ const clang::TagType *tag_type = qual_type->getAs<clang::TagType>();
+ if (tag_type) {
+ clang::TagDecl *tag_decl = tag_type->getDecl();
+
+ if (auto *cxx_record_decl = llvm::dyn_cast<CXXRecordDecl>(tag_decl)) {
+ // If we have a move constructor declared but no copy constructor we
+ // need to explicitly mark it as deleted. Usually Sema would do this for
+ // us in Sema::DeclareImplicitCopyConstructor but we don't have a Sema
+ // when building an AST from debug information.
+ // See also:
+ // C++11 [class.copy]p7, p18:
+ // If the class definition declares a move constructor or move assignment
+ // operator, an implicitly declared copy constructor or copy assignment
+ // operator is defined as deleted.
+ if (cxx_record_decl->hasUserDeclaredMoveConstructor() &&
+ cxx_record_decl->needsImplicitCopyConstructor())
+ cxx_record_decl->setImplicitCopyConstructorIsDeleted();
+
+ if (!cxx_record_decl->isCompleteDefinition())
+ cxx_record_decl->completeDefinition();
+ cxx_record_decl->setHasLoadedFieldsFromExternalStorage(true);
+ cxx_record_decl->setHasExternalLexicalStorage(false);
+ cxx_record_decl->setHasExternalVisibleStorage(false);
+ return true;
+ }
+ }
+
+ const clang::EnumType *enutype = qual_type->getAs<clang::EnumType>();
+
+ if (!enutype)
+ return false;
+ clang::EnumDecl *enum_decl = enutype->getDecl();
+
+ if (enum_decl->isCompleteDefinition())
+ return true;
+
+ TypeSystemClang *lldb_ast =
+ llvm::dyn_cast<TypeSystemClang>(type.GetTypeSystem());
+ if (lldb_ast == nullptr)
+ return false;
+ clang::ASTContext &ast = lldb_ast->getASTContext();
+
+ /// TODO This really needs to be fixed.
+
+ QualType integer_type(enum_decl->getIntegerType());
+ if (!integer_type.isNull()) {
+ unsigned NumPositiveBits = 1;
+ unsigned NumNegativeBits = 0;
+
+ clang::QualType promotion_qual_type;
+ // If the enum integer type is less than an integer in bit width,
+ // then we must promote it to an integer size.
+ if (ast.getTypeSize(enum_decl->getIntegerType()) <
+ ast.getTypeSize(ast.IntTy)) {
+ if (enum_decl->getIntegerType()->isSignedIntegerType())
+ promotion_qual_type = ast.IntTy;
+ else
+ promotion_qual_type = ast.UnsignedIntTy;
+ } else
+ promotion_qual_type = enum_decl->getIntegerType();
+
+ enum_decl->completeDefinition(enum_decl->getIntegerType(),
+ promotion_qual_type, NumPositiveBits,
+ NumNegativeBits);
+ }
+ return true;
+}
+
+clang::EnumConstantDecl *TypeSystemClang::AddEnumerationValueToEnumerationType(
+ const CompilerType &enum_type, const Declaration &decl, const char *name,
+ const llvm::APSInt &value) {
+
+ if (!enum_type || ConstString(name).IsEmpty())
+ return nullptr;
+
+ lldbassert(enum_type.GetTypeSystem() == static_cast<TypeSystem *>(this));
+
+ lldb::opaque_compiler_type_t enum_opaque_compiler_type =
+ enum_type.GetOpaqueQualType();
+
+ if (!enum_opaque_compiler_type)
+ return nullptr;
+
+ clang::QualType enum_qual_type(
+ GetCanonicalQualType(enum_opaque_compiler_type));
+
+ const clang::Type *clang_type = enum_qual_type.getTypePtr();
+
+ if (!clang_type)
+ return nullptr;
+
+ const clang::EnumType *enutype = llvm::dyn_cast<clang::EnumType>(clang_type);
+
+ if (!enutype)
+ return nullptr;
+
+ clang::EnumConstantDecl *enumerator_decl = clang::EnumConstantDecl::Create(
+ getASTContext(), enutype->getDecl(), clang::SourceLocation(),
+ name ? &getASTContext().Idents.get(name) : nullptr, // Identifier
+ clang::QualType(enutype, 0), nullptr, value);
+
+ if (!enumerator_decl)
+ return nullptr;
+
+ enutype->getDecl()->addDecl(enumerator_decl);
+
+#ifdef LLDB_CONFIGURATION_DEBUG
+ VerifyDecl(enumerator_decl);
+#endif
+
+ return enumerator_decl;
+}
+
+clang::EnumConstantDecl *TypeSystemClang::AddEnumerationValueToEnumerationType(
+ const CompilerType &enum_type, const Declaration &decl, const char *name,
+ int64_t enum_value, uint32_t enum_value_bit_size) {
+ CompilerType underlying_type =
+ GetEnumerationIntegerType(enum_type.GetOpaqueQualType());
+ bool is_signed = false;
+ underlying_type.IsIntegerType(is_signed);
+
+ llvm::APSInt value(enum_value_bit_size, is_signed);
+ value = enum_value;
+
+ return AddEnumerationValueToEnumerationType(enum_type, decl, name, value);
+}
+
+CompilerType
+TypeSystemClang::GetEnumerationIntegerType(lldb::opaque_compiler_type_t type) {
+ clang::QualType enum_qual_type(GetCanonicalQualType(type));
+ const clang::Type *clang_type = enum_qual_type.getTypePtr();
+ if (clang_type) {
+ const clang::EnumType *enutype =
+ llvm::dyn_cast<clang::EnumType>(clang_type);
+ if (enutype) {
+ clang::EnumDecl *enum_decl = enutype->getDecl();
+ if (enum_decl)
+ return GetType(enum_decl->getIntegerType());
+ }
+ }
+ return CompilerType();
+}
+
+CompilerType
+TypeSystemClang::CreateMemberPointerType(const CompilerType &type,
+ const CompilerType &pointee_type) {
+ if (type && pointee_type.IsValid() &&
+ type.GetTypeSystem() == pointee_type.GetTypeSystem()) {
+ TypeSystemClang *ast =
+ llvm::dyn_cast<TypeSystemClang>(type.GetTypeSystem());
+ if (!ast)
+ return CompilerType();
+ return ast->GetType(ast->getASTContext().getMemberPointerType(
+ ClangUtil::GetQualType(pointee_type),
+ ClangUtil::GetQualType(type).getTypePtr()));
+ }
+ return CompilerType();
+}
+
+// Dumping types
+#define DEPTH_INCREMENT 2
+
+#ifndef NDEBUG
+LLVM_DUMP_METHOD void
+TypeSystemClang::dump(lldb::opaque_compiler_type_t type) const {
+ if (!type)
+ return;
+ clang::QualType qual_type(GetQualType(type));
+ qual_type.dump();
+}
+#endif
+
+void TypeSystemClang::Dump(Stream &s) {
+ Decl *tu = Decl::castFromDeclContext(GetTranslationUnitDecl());
+ tu->dump(s.AsRawOstream());
+}
+
+void TypeSystemClang::DumpFromSymbolFile(Stream &s,
+ llvm::StringRef symbol_name) {
+ SymbolFile *symfile = GetSymbolFile();
+
+ if (!symfile)
+ return;
+
+ lldb_private::TypeList type_list;
+ symfile->GetTypes(nullptr, eTypeClassAny, type_list);
+ size_t ntypes = type_list.GetSize();
+
+ for (size_t i = 0; i < ntypes; ++i) {
+ TypeSP type = type_list.GetTypeAtIndex(i);
+
+ if (!symbol_name.empty())
+ if (symbol_name != type->GetName().GetStringRef())
+ continue;
+
+ s << type->GetName().AsCString() << "\n";
+
+ CompilerType full_type = type->GetFullCompilerType();
+ if (clang::TagDecl *tag_decl = GetAsTagDecl(full_type)) {
+ tag_decl->dump(s.AsRawOstream());
+ continue;
+ }
+ if (clang::TypedefNameDecl *typedef_decl = GetAsTypedefDecl(full_type)) {
+ typedef_decl->dump(s.AsRawOstream());
+ continue;
+ }
+ if (auto *objc_obj = llvm::dyn_cast<clang::ObjCObjectType>(
+ ClangUtil::GetQualType(full_type).getTypePtr())) {
+ if (clang::ObjCInterfaceDecl *interface_decl = objc_obj->getInterface()) {
+ interface_decl->dump(s.AsRawOstream());
+ continue;
+ }
+ }
+ GetCanonicalQualType(full_type.GetOpaqueQualType()).dump(s.AsRawOstream());
+ }
+}
+
+void TypeSystemClang::DumpValue(
+ lldb::opaque_compiler_type_t type, ExecutionContext *exe_ctx, Stream *s,
+ lldb::Format format, const lldb_private::DataExtractor &data,
+ lldb::offset_t data_byte_offset, size_t data_byte_size,
+ uint32_t bitfield_bit_size, uint32_t bitfield_bit_offset, bool show_types,
+ bool show_summary, bool verbose, uint32_t depth) {
+ if (!type)
+ return;
+
+ clang::QualType qual_type(GetQualType(type));
+ switch (qual_type->getTypeClass()) {
+ case clang::Type::Record:
+ if (GetCompleteType(type)) {
+ const clang::RecordType *record_type =
+ llvm::cast<clang::RecordType>(qual_type.getTypePtr());
+ const clang::RecordDecl *record_decl = record_type->getDecl();
+ assert(record_decl);
+ uint32_t field_bit_offset = 0;
+ uint32_t field_byte_offset = 0;
+ const clang::ASTRecordLayout &record_layout =
+ getASTContext().getASTRecordLayout(record_decl);
+ uint32_t child_idx = 0;
+
+ const clang::CXXRecordDecl *cxx_record_decl =
+ llvm::dyn_cast<clang::CXXRecordDecl>(record_decl);
+ if (cxx_record_decl) {
+ // We might have base classes to print out first
+ clang::CXXRecordDecl::base_class_const_iterator base_class,
+ base_class_end;
+ for (base_class = cxx_record_decl->bases_begin(),
+ base_class_end = cxx_record_decl->bases_end();
+ base_class != base_class_end; ++base_class) {
+ const clang::CXXRecordDecl *base_class_decl =
+ llvm::cast<clang::CXXRecordDecl>(
+ base_class->getType()->getAs<clang::RecordType>()->getDecl());
+
+ // Skip empty base classes
+ if (!verbose && !TypeSystemClang::RecordHasFields(base_class_decl))
+ continue;
+
+ if (base_class->isVirtual())
+ field_bit_offset =
+ record_layout.getVBaseClassOffset(base_class_decl)
+ .getQuantity() *
+ 8;
+ else
+ field_bit_offset = record_layout.getBaseClassOffset(base_class_decl)
+ .getQuantity() *
+ 8;
+ field_byte_offset = field_bit_offset / 8;
+ assert(field_bit_offset % 8 == 0);
+ if (child_idx == 0)
+ s->PutChar('{');
+ else
+ s->PutChar(',');
+
+ clang::QualType base_class_qual_type = base_class->getType();
+ std::string base_class_type_name(base_class_qual_type.getAsString());
+
+ // Indent and print the base class type name
+ s->Format("\n{0}{1}", llvm::fmt_repeat(" ", depth + DEPTH_INCREMENT),
+ base_class_type_name);
+
+ clang::TypeInfo base_class_type_info =
+ getASTContext().getTypeInfo(base_class_qual_type);
+
+ // Dump the value of the member
+ CompilerType base_clang_type = GetType(base_class_qual_type);
+ base_clang_type.DumpValue(
+ exe_ctx,
+ s, // Stream to dump to
+ base_clang_type
+ .GetFormat(), // The format with which to display the member
+ data, // Data buffer containing all bytes for this type
+ data_byte_offset + field_byte_offset, // Offset into "data" where
+ // to grab value from
+ base_class_type_info.Width / 8, // Size of this type in bytes
+ 0, // Bitfield bit size
+ 0, // Bitfield bit offset
+ show_types, // Boolean indicating if we should show the variable
+ // types
+ show_summary, // Boolean indicating if we should show a summary
+ // for the current type
+ verbose, // Verbose output?
+ depth + DEPTH_INCREMENT); // Scope depth for any types that have
+ // children
+
+ ++child_idx;
+ }
+ }
+ uint32_t field_idx = 0;
+ clang::RecordDecl::field_iterator field, field_end;
+ for (field = record_decl->field_begin(),
+ field_end = record_decl->field_end();
+ field != field_end; ++field, ++field_idx, ++child_idx) {
+ // Print the starting squiggly bracket (if this is the first member) or
+ // comma (for member 2 and beyond) for the struct/union/class member.
+ if (child_idx == 0)
+ s->PutChar('{');
+ else
+ s->PutChar(',');
+
+ // Indent
+ s->Printf("\n%*s", depth + DEPTH_INCREMENT, "");
+
+ clang::QualType field_type = field->getType();
+ // Print the member type if requested
+ // Figure out the type byte size (field_type_info.first) and alignment
+ // (field_type_info.second) from the AST context.
+ clang::TypeInfo field_type_info =
+ getASTContext().getTypeInfo(field_type);
+ assert(field_idx < record_layout.getFieldCount());
+ // Figure out the field offset within the current struct/union/class
+ // type
+ field_bit_offset = record_layout.getFieldOffset(field_idx);
+ field_byte_offset = field_bit_offset / 8;
+ uint32_t field_bitfield_bit_size = 0;
+ uint32_t field_bitfield_bit_offset = 0;
+ if (FieldIsBitfield(*field, field_bitfield_bit_size))
+ field_bitfield_bit_offset = field_bit_offset % 8;
+
+ if (show_types) {
+ std::string field_type_name(field_type.getAsString());
+ if (field_bitfield_bit_size > 0)
+ s->Printf("(%s:%u) ", field_type_name.c_str(),
+ field_bitfield_bit_size);
+ else
+ s->Printf("(%s) ", field_type_name.c_str());
+ }
+ // Print the member name and equal sign
+ s->Printf("%s = ", field->getNameAsString().c_str());
+
+ // Dump the value of the member
+ CompilerType field_clang_type = GetType(field_type);
+ field_clang_type.DumpValue(
+ exe_ctx,
+ s, // Stream to dump to
+ field_clang_type
+ .GetFormat(), // The format with which to display the member
+ data, // Data buffer containing all bytes for this type
+ data_byte_offset + field_byte_offset, // Offset into "data" where to
+ // grab value from
+ field_type_info.Width / 8, // Size of this type in bytes
+ field_bitfield_bit_size, // Bitfield bit size
+ field_bitfield_bit_offset, // Bitfield bit offset
+ show_types, // Boolean indicating if we should show the variable
+ // types
+ show_summary, // Boolean indicating if we should show a summary for
+ // the current type
+ verbose, // Verbose output?
+ depth + DEPTH_INCREMENT); // Scope depth for any types that have
+ // children
+ }
+
+ // Indent the trailing squiggly bracket
+ if (child_idx > 0)
+ s->Printf("\n%*s}", depth, "");
+ }
+ return;
+
+ case clang::Type::Enum:
+ if (GetCompleteType(type)) {
+ const clang::EnumType *enutype =
+ llvm::cast<clang::EnumType>(qual_type.getTypePtr());
+ const clang::EnumDecl *enum_decl = enutype->getDecl();
+ assert(enum_decl);
+ clang::EnumDecl::enumerator_iterator enum_pos, enum_end_pos;
+ lldb::offset_t offset = data_byte_offset;
+ const int64_t enum_value = data.GetMaxU64Bitfield(
+ &offset, data_byte_size, bitfield_bit_size, bitfield_bit_offset);
+ for (enum_pos = enum_decl->enumerator_begin(),
+ enum_end_pos = enum_decl->enumerator_end();
+ enum_pos != enum_end_pos; ++enum_pos) {
+ if (enum_pos->getInitVal() == enum_value) {
+ s->Printf("%s", enum_pos->getNameAsString().c_str());
+ return;
+ }
+ }
+ // If we have gotten here we didn't get find the enumerator in the enum
+ // decl, so just print the integer.
+ s->Printf("%" PRIi64, enum_value);
+ }
+ return;
+
+ case clang::Type::ConstantArray: {
+ const clang::ConstantArrayType *array =
+ llvm::cast<clang::ConstantArrayType>(qual_type.getTypePtr());
+ bool is_array_of_characters = false;
+ clang::QualType element_qual_type = array->getElementType();
+
+ const clang::Type *canonical_type =
+ element_qual_type->getCanonicalTypeInternal().getTypePtr();
+ if (canonical_type)
+ is_array_of_characters = canonical_type->isCharType();
+
+ const uint64_t element_count = array->getSize().getLimitedValue();
+
+ clang::TypeInfo field_type_info =
+ getASTContext().getTypeInfo(element_qual_type);
+
+ uint32_t element_idx = 0;
+ uint32_t element_offset = 0;
+ uint64_t element_byte_size = field_type_info.Width / 8;
+ uint32_t element_stride = element_byte_size;
+
+ if (is_array_of_characters) {
+ s->PutChar('"');
+ DumpDataExtractor(data, s, data_byte_offset, lldb::eFormatChar,
+ element_byte_size, element_count, UINT32_MAX,
+ LLDB_INVALID_ADDRESS, 0, 0);
+ s->PutChar('"');
+ return;
+ } else {
+ CompilerType element_clang_type = GetType(element_qual_type);
+ lldb::Format element_format = element_clang_type.GetFormat();
+
+ for (element_idx = 0; element_idx < element_count; ++element_idx) {
+ // Print the starting squiggly bracket (if this is the first member) or
+ // comman (for member 2 and beyong) for the struct/union/class member.
+ if (element_idx == 0)
+ s->PutChar('{');
+ else
+ s->PutChar(',');
+
+ // Indent and print the index
+ s->Printf("\n%*s[%u] ", depth + DEPTH_INCREMENT, "", element_idx);
+
+ // Figure out the field offset within the current struct/union/class
+ // type
+ element_offset = element_idx * element_stride;
+
+ // Dump the value of the member
+ element_clang_type.DumpValue(
+ exe_ctx,
+ s, // Stream to dump to
+ element_format, // The format with which to display the element
+ data, // Data buffer containing all bytes for this type
+ data_byte_offset +
+ element_offset, // Offset into "data" where to grab value from
+ element_byte_size, // Size of this type in bytes
+ 0, // Bitfield bit size
+ 0, // Bitfield bit offset
+ show_types, // Boolean indicating if we should show the variable
+ // types
+ show_summary, // Boolean indicating if we should show a summary for
+ // the current type
+ verbose, // Verbose output?
+ depth + DEPTH_INCREMENT); // Scope depth for any types that have
+ // children
+ }
+
+ // Indent the trailing squiggly bracket
+ if (element_idx > 0)
+ s->Printf("\n%*s}", depth, "");
+ }
+ }
+ return;
+
+ case clang::Type::Typedef: {
+ clang::QualType typedef_qual_type =
+ llvm::cast<clang::TypedefType>(qual_type)
+ ->getDecl()
+ ->getUnderlyingType();
+
+ CompilerType typedef_clang_type = GetType(typedef_qual_type);
+ lldb::Format typedef_format = typedef_clang_type.GetFormat();
+ clang::TypeInfo typedef_type_info =
+ getASTContext().getTypeInfo(typedef_qual_type);
+ uint64_t typedef_byte_size = typedef_type_info.Width / 8;
+
+ return typedef_clang_type.DumpValue(
+ exe_ctx,
+ s, // Stream to dump to
+ typedef_format, // The format with which to display the element
+ data, // Data buffer containing all bytes for this type
+ data_byte_offset, // Offset into "data" where to grab value from
+ typedef_byte_size, // Size of this type in bytes
+ bitfield_bit_size, // Bitfield bit size
+ bitfield_bit_offset, // Bitfield bit offset
+ show_types, // Boolean indicating if we should show the variable types
+ show_summary, // Boolean indicating if we should show a summary for the
+ // current type
+ verbose, // Verbose output?
+ depth); // Scope depth for any types that have children
+ } break;
+
+ case clang::Type::Auto: {
+ clang::QualType elaborated_qual_type =
+ llvm::cast<clang::AutoType>(qual_type)->getDeducedType();
+ CompilerType elaborated_clang_type = GetType(elaborated_qual_type);
+ lldb::Format elaborated_format = elaborated_clang_type.GetFormat();
+ clang::TypeInfo elaborated_type_info =
+ getASTContext().getTypeInfo(elaborated_qual_type);
+ uint64_t elaborated_byte_size = elaborated_type_info.Width / 8;
+
+ return elaborated_clang_type.DumpValue(
+ exe_ctx,
+ s, // Stream to dump to
+ elaborated_format, // The format with which to display the element
+ data, // Data buffer containing all bytes for this type
+ data_byte_offset, // Offset into "data" where to grab value from
+ elaborated_byte_size, // Size of this type in bytes
+ bitfield_bit_size, // Bitfield bit size
+ bitfield_bit_offset, // Bitfield bit offset
+ show_types, // Boolean indicating if we should show the variable types
+ show_summary, // Boolean indicating if we should show a summary for the
+ // current type
+ verbose, // Verbose output?
+ depth); // Scope depth for any types that have children
+ } break;
+
+ case clang::Type::Elaborated: {
+ clang::QualType elaborated_qual_type =
+ llvm::cast<clang::ElaboratedType>(qual_type)->getNamedType();
+ CompilerType elaborated_clang_type = GetType(elaborated_qual_type);
+ lldb::Format elaborated_format = elaborated_clang_type.GetFormat();
+ clang::TypeInfo elaborated_type_info =
+ getASTContext().getTypeInfo(elaborated_qual_type);
+ uint64_t elaborated_byte_size = elaborated_type_info.Width / 8;
+
+ return elaborated_clang_type.DumpValue(
+ exe_ctx,
+ s, // Stream to dump to
+ elaborated_format, // The format with which to display the element
+ data, // Data buffer containing all bytes for this type
+ data_byte_offset, // Offset into "data" where to grab value from
+ elaborated_byte_size, // Size of this type in bytes
+ bitfield_bit_size, // Bitfield bit size
+ bitfield_bit_offset, // Bitfield bit offset
+ show_types, // Boolean indicating if we should show the variable types
+ show_summary, // Boolean indicating if we should show a summary for the
+ // current type
+ verbose, // Verbose output?
+ depth); // Scope depth for any types that have children
+ } break;
+
+ case clang::Type::Paren: {
+ clang::QualType desugar_qual_type =
+ llvm::cast<clang::ParenType>(qual_type)->desugar();
+ CompilerType desugar_clang_type = GetType(desugar_qual_type);
+
+ lldb::Format desugar_format = desugar_clang_type.GetFormat();
+ clang::TypeInfo desugar_type_info =
+ getASTContext().getTypeInfo(desugar_qual_type);
+ uint64_t desugar_byte_size = desugar_type_info.Width / 8;
+
+ return desugar_clang_type.DumpValue(
+ exe_ctx,
+ s, // Stream to dump to
+ desugar_format, // The format with which to display the element
+ data, // Data buffer containing all bytes for this type
+ data_byte_offset, // Offset into "data" where to grab value from
+ desugar_byte_size, // Size of this type in bytes
+ bitfield_bit_size, // Bitfield bit size
+ bitfield_bit_offset, // Bitfield bit offset
+ show_types, // Boolean indicating if we should show the variable types
+ show_summary, // Boolean indicating if we should show a summary for the
+ // current type
+ verbose, // Verbose output?
+ depth); // Scope depth for any types that have children
+ } break;
+
+ default:
+ // We are down to a scalar type that we just need to display.
+ DumpDataExtractor(data, s, data_byte_offset, format, data_byte_size, 1,
+ UINT32_MAX, LLDB_INVALID_ADDRESS, bitfield_bit_size,
+ bitfield_bit_offset);
+
+ if (show_summary)
+ DumpSummary(type, exe_ctx, s, data, data_byte_offset, data_byte_size);
+ break;
+ }
+}
+
+static bool DumpEnumValue(const clang::QualType &qual_type, Stream *s,
+ const DataExtractor &data, lldb::offset_t byte_offset,
+ size_t byte_size, uint32_t bitfield_bit_offset,
+ uint32_t bitfield_bit_size) {
+ const clang::EnumType *enutype =
+ llvm::cast<clang::EnumType>(qual_type.getTypePtr());
+ const clang::EnumDecl *enum_decl = enutype->getDecl();
+ assert(enum_decl);
+ lldb::offset_t offset = byte_offset;
+ const uint64_t enum_svalue = data.GetMaxS64Bitfield(
+ &offset, byte_size, bitfield_bit_size, bitfield_bit_offset);
+ bool can_be_bitfield = true;
+ uint64_t covered_bits = 0;
+ int num_enumerators = 0;
+
+ // Try to find an exact match for the value.
+ // At the same time, we're applying a heuristic to determine whether we want
+ // to print this enum as a bitfield. We're likely dealing with a bitfield if
+ // every enumrator is either a one bit value or a superset of the previous
+ // enumerators. Also 0 doesn't make sense when the enumerators are used as
+ // flags.
+ for (auto enumerator : enum_decl->enumerators()) {
+ uint64_t val = enumerator->getInitVal().getSExtValue();
+ val = llvm::SignExtend64(val, 8*byte_size);
+ if (llvm::countPopulation(val) != 1 && (val & ~covered_bits) != 0)
+ can_be_bitfield = false;
+ covered_bits |= val;
+ ++num_enumerators;
+ if (val == enum_svalue) {
+ // Found an exact match, that's all we need to do.
+ s->PutCString(enumerator->getNameAsString());
+ return true;
+ }
+ }
+
+ // Unsigned values make more sense for flags.
+ offset = byte_offset;
+ const uint64_t enum_uvalue = data.GetMaxU64Bitfield(
+ &offset, byte_size, bitfield_bit_size, bitfield_bit_offset);
+
+ // No exact match, but we don't think this is a bitfield. Print the value as
+ // decimal.
+ if (!can_be_bitfield) {
+ if (qual_type->isSignedIntegerOrEnumerationType())
+ s->Printf("%" PRIi64, enum_svalue);
+ else
+ s->Printf("%" PRIu64, enum_uvalue);
+ return true;
+ }
+
+ uint64_t remaining_value = enum_uvalue;
+ std::vector<std::pair<uint64_t, llvm::StringRef>> values;
+ values.reserve(num_enumerators);
+ for (auto enumerator : enum_decl->enumerators())
+ if (auto val = enumerator->getInitVal().getZExtValue())
+ values.emplace_back(val, enumerator->getName());
+
+ // Sort in reverse order of the number of the population count, so that in
+ // `enum {A, B, ALL = A|B }` we visit ALL first. Use a stable sort so that
+ // A | C where A is declared before C is displayed in this order.
+ std::stable_sort(values.begin(), values.end(), [](const auto &a, const auto &b) {
+ return llvm::countPopulation(a.first) > llvm::countPopulation(b.first);
+ });
+
+ for (const auto &val : values) {
+ if ((remaining_value & val.first) != val.first)
+ continue;
+ remaining_value &= ~val.first;
+ s->PutCString(val.second);
+ if (remaining_value)
+ s->PutCString(" | ");
+ }
+
+ // If there is a remainder that is not covered by the value, print it as hex.
+ if (remaining_value)
+ s->Printf("0x%" PRIx64, remaining_value);
+
+ return true;
+}
+
+bool TypeSystemClang::DumpTypeValue(
+ lldb::opaque_compiler_type_t type, Stream *s, lldb::Format format,
+ const lldb_private::DataExtractor &data, lldb::offset_t byte_offset,
+ size_t byte_size, uint32_t bitfield_bit_size, uint32_t bitfield_bit_offset,
+ ExecutionContextScope *exe_scope) {
+ if (!type)
+ return false;
+ if (IsAggregateType(type)) {
+ return false;
+ } else {
+ clang::QualType qual_type(GetQualType(type));
+
+ const clang::Type::TypeClass type_class = qual_type->getTypeClass();
+
+ if (type_class == clang::Type::Elaborated) {
+ qual_type = llvm::cast<clang::ElaboratedType>(qual_type)->getNamedType();
+ return DumpTypeValue(qual_type.getAsOpaquePtr(), s, format, data, byte_offset, byte_size,
+ bitfield_bit_size, bitfield_bit_offset, exe_scope);
+ }
+
+ switch (type_class) {
+ case clang::Type::Typedef: {
+ clang::QualType typedef_qual_type =
+ llvm::cast<clang::TypedefType>(qual_type)
+ ->getDecl()
+ ->getUnderlyingType();
+ CompilerType typedef_clang_type = GetType(typedef_qual_type);
+ if (format == eFormatDefault)
+ format = typedef_clang_type.GetFormat();
+ clang::TypeInfo typedef_type_info =
+ getASTContext().getTypeInfo(typedef_qual_type);
+ uint64_t typedef_byte_size = typedef_type_info.Width / 8;
+
+ return typedef_clang_type.DumpTypeValue(
+ s,
+ format, // The format with which to display the element
+ data, // Data buffer containing all bytes for this type
+ byte_offset, // Offset into "data" where to grab value from
+ typedef_byte_size, // Size of this type in bytes
+ bitfield_bit_size, // Size in bits of a bitfield value, if zero don't
+ // treat as a bitfield
+ bitfield_bit_offset, // Offset in bits of a bitfield value if
+ // bitfield_bit_size != 0
+ exe_scope);
+ } break;
+
+ case clang::Type::Enum:
+ // If our format is enum or default, show the enumeration value as its
+ // enumeration string value, else just display it as requested.
+ if ((format == eFormatEnum || format == eFormatDefault) &&
+ GetCompleteType(type))
+ return DumpEnumValue(qual_type, s, data, byte_offset, byte_size,
+ bitfield_bit_offset, bitfield_bit_size);
+ // format was not enum, just fall through and dump the value as
+ // requested....
+ LLVM_FALLTHROUGH;
+
+ default:
+ // We are down to a scalar type that we just need to display.
+ {
+ uint32_t item_count = 1;
+ // A few formats, we might need to modify our size and count for
+ // depending
+ // on how we are trying to display the value...
+ switch (format) {
+ default:
+ case eFormatBoolean:
+ case eFormatBinary:
+ case eFormatComplex:
+ case eFormatCString: // NULL terminated C strings
+ case eFormatDecimal:
+ case eFormatEnum:
+ case eFormatHex:
+ case eFormatHexUppercase:
+ case eFormatFloat:
+ case eFormatOctal:
+ case eFormatOSType:
+ case eFormatUnsigned:
+ case eFormatPointer:
+ case eFormatVectorOfChar:
+ case eFormatVectorOfSInt8:
+ case eFormatVectorOfUInt8:
+ case eFormatVectorOfSInt16:
+ case eFormatVectorOfUInt16:
+ case eFormatVectorOfSInt32:
+ case eFormatVectorOfUInt32:
+ case eFormatVectorOfSInt64:
+ case eFormatVectorOfUInt64:
+ case eFormatVectorOfFloat32:
+ case eFormatVectorOfFloat64:
+ case eFormatVectorOfUInt128:
+ break;
+
+ case eFormatChar:
+ case eFormatCharPrintable:
+ case eFormatCharArray:
+ case eFormatBytes:
+ case eFormatBytesWithASCII:
+ item_count = byte_size;
+ byte_size = 1;
+ break;
+
+ case eFormatUnicode16:
+ item_count = byte_size / 2;
+ byte_size = 2;
+ break;
+
+ case eFormatUnicode32:
+ item_count = byte_size / 4;
+ byte_size = 4;
+ break;
+ }
+ return DumpDataExtractor(data, s, byte_offset, format, byte_size,
+ item_count, UINT32_MAX, LLDB_INVALID_ADDRESS,
+ bitfield_bit_size, bitfield_bit_offset,
+ exe_scope);
+ }
+ break;
+ }
+ }
+ return false;
+}
+
+void TypeSystemClang::DumpSummary(lldb::opaque_compiler_type_t type,
+ ExecutionContext *exe_ctx, Stream *s,
+ const lldb_private::DataExtractor &data,
+ lldb::offset_t data_byte_offset,
+ size_t data_byte_size) {
+ uint32_t length = 0;
+ if (IsCStringType(type, length)) {
+ if (exe_ctx) {
+ Process *process = exe_ctx->GetProcessPtr();
+ if (process) {
+ lldb::offset_t offset = data_byte_offset;
+ lldb::addr_t pointer_address = data.GetMaxU64(&offset, data_byte_size);
+ std::vector<uint8_t> buf;
+ if (length > 0)
+ buf.resize(length);
+ else
+ buf.resize(256);
+
+ DataExtractor cstr_data(&buf.front(), buf.size(),
+ process->GetByteOrder(), 4);
+ buf.back() = '\0';
+ size_t bytes_read;
+ size_t total_cstr_len = 0;
+ Status error;
+ while ((bytes_read = process->ReadMemory(pointer_address, &buf.front(),
+ buf.size(), error)) > 0) {
+ const size_t len = strlen((const char *)&buf.front());
+ if (len == 0)
+ break;
+ if (total_cstr_len == 0)
+ s->PutCString(" \"");
+ DumpDataExtractor(cstr_data, s, 0, lldb::eFormatChar, 1, len,
+ UINT32_MAX, LLDB_INVALID_ADDRESS, 0, 0);
+ total_cstr_len += len;
+ if (len < buf.size())
+ break;
+ pointer_address += total_cstr_len;
+ }
+ if (total_cstr_len > 0)
+ s->PutChar('"');
+ }
+ }
+ }
+}
+
+void TypeSystemClang::DumpTypeDescription(lldb::opaque_compiler_type_t type) {
+ StreamFile s(stdout, false);
+ DumpTypeDescription(type, &s);
+
+ CompilerType ct(this, type);
+ const clang::Type *clang_type = ClangUtil::GetQualType(ct).getTypePtr();
+ ClangASTMetadata *metadata = GetMetadata(clang_type);
+ if (metadata) {
+ metadata->Dump(&s);
+ }
+}
+
+void TypeSystemClang::DumpTypeDescription(lldb::opaque_compiler_type_t type,
+ Stream *s) {
+ if (type) {
+ clang::QualType qual_type =
+ RemoveWrappingTypes(GetQualType(type), {clang::Type::Typedef});
+
+ llvm::SmallVector<char, 1024> buf;
+ llvm::raw_svector_ostream llvm_ostrm(buf);
+
+ const clang::Type::TypeClass type_class = qual_type->getTypeClass();
+ switch (type_class) {
+ case clang::Type::ObjCObject:
+ case clang::Type::ObjCInterface: {
+ GetCompleteType(type);
+
+ const clang::ObjCObjectType *objc_class_type =
+ llvm::dyn_cast<clang::ObjCObjectType>(qual_type.getTypePtr());
+ assert(objc_class_type);
+ if (objc_class_type) {
+ clang::ObjCInterfaceDecl *class_interface_decl =
+ objc_class_type->getInterface();
+ if (class_interface_decl) {
+ clang::PrintingPolicy policy = getASTContext().getPrintingPolicy();
+ class_interface_decl->print(llvm_ostrm, policy, s->GetIndentLevel());
+ }
+ }
+ } break;
+
+ case clang::Type::Typedef: {
+ const clang::TypedefType *typedef_type =
+ qual_type->getAs<clang::TypedefType>();
+ if (typedef_type) {
+ const clang::TypedefNameDecl *typedef_decl = typedef_type->getDecl();
+ std::string clang_typedef_name(
+ typedef_decl->getQualifiedNameAsString());
+ if (!clang_typedef_name.empty()) {
+ s->PutCString("typedef ");
+ s->PutCString(clang_typedef_name);
+ }
+ }
+ } break;
+
+ case clang::Type::Record: {
+ GetCompleteType(type);
+
+ const clang::RecordType *record_type =
+ llvm::cast<clang::RecordType>(qual_type.getTypePtr());
+ const clang::RecordDecl *record_decl = record_type->getDecl();
+ const clang::CXXRecordDecl *cxx_record_decl =
+ llvm::dyn_cast<clang::CXXRecordDecl>(record_decl);
+
+ if (cxx_record_decl)
+ cxx_record_decl->print(llvm_ostrm, getASTContext().getPrintingPolicy(),
+ s->GetIndentLevel());
+ else
+ record_decl->print(llvm_ostrm, getASTContext().getPrintingPolicy(),
+ s->GetIndentLevel());
+ } break;
+
+ default: {
+ const clang::TagType *tag_type =
+ llvm::dyn_cast<clang::TagType>(qual_type.getTypePtr());
+ if (tag_type) {
+ clang::TagDecl *tag_decl = tag_type->getDecl();
+ if (tag_decl)
+ tag_decl->print(llvm_ostrm, 0);
+ } else {
+ std::string clang_type_name(qual_type.getAsString());
+ if (!clang_type_name.empty())
+ s->PutCString(clang_type_name);
+ }
+ }
+ }
+
+ if (buf.size() > 0) {
+ s->Write(buf.data(), buf.size());
+ }
+ }
+}
+
+void TypeSystemClang::DumpTypeName(const CompilerType &type) {
+ if (ClangUtil::IsClangType(type)) {
+ clang::QualType qual_type(
+ ClangUtil::GetCanonicalQualType(ClangUtil::RemoveFastQualifiers(type)));
+
+ const clang::Type::TypeClass type_class = qual_type->getTypeClass();
+ switch (type_class) {
+ case clang::Type::Record: {
+ const clang::CXXRecordDecl *cxx_record_decl =
+ qual_type->getAsCXXRecordDecl();
+ if (cxx_record_decl)
+ printf("class %s", cxx_record_decl->getName().str().c_str());
+ } break;
+
+ case clang::Type::Enum: {
+ clang::EnumDecl *enum_decl =
+ llvm::cast<clang::EnumType>(qual_type)->getDecl();
+ if (enum_decl) {
+ printf("enum %s", enum_decl->getName().str().c_str());
+ }
+ } break;
+
+ case clang::Type::ObjCObject:
+ case clang::Type::ObjCInterface: {
+ const clang::ObjCObjectType *objc_class_type =
+ llvm::dyn_cast<clang::ObjCObjectType>(qual_type);
+ if (objc_class_type) {
+ clang::ObjCInterfaceDecl *class_interface_decl =
+ objc_class_type->getInterface();
+ // We currently can't complete objective C types through the newly
+ // added ASTContext because it only supports TagDecl objects right
+ // now...
+ if (class_interface_decl)
+ printf("@class %s", class_interface_decl->getName().str().c_str());
+ }
+ } break;
+
+ case clang::Type::Typedef:
+ printf("typedef %s", llvm::cast<clang::TypedefType>(qual_type)
+ ->getDecl()
+ ->getName()
+ .str()
+ .c_str());
+ break;
+
+ case clang::Type::Auto:
+ printf("auto ");
+ return DumpTypeName(CompilerType(type.GetTypeSystem(),
+ llvm::cast<clang::AutoType>(qual_type)
+ ->getDeducedType()
+ .getAsOpaquePtr()));
+
+ case clang::Type::Elaborated:
+ printf("elaborated ");
+ return DumpTypeName(CompilerType(
+ type.GetTypeSystem(), llvm::cast<clang::ElaboratedType>(qual_type)
+ ->getNamedType()
+ .getAsOpaquePtr()));
+
+ case clang::Type::Paren:
+ printf("paren ");
+ return DumpTypeName(CompilerType(
+ type.GetTypeSystem(),
+ llvm::cast<clang::ParenType>(qual_type)->desugar().getAsOpaquePtr()));
+
+ default:
+ printf("TypeSystemClang::DumpTypeName() type_class = %u", type_class);
+ break;
+ }
+ }
+}
+
+clang::ClassTemplateDecl *TypeSystemClang::ParseClassTemplateDecl(
+ clang::DeclContext *decl_ctx, lldb::AccessType access_type,
+ const char *parent_name, int tag_decl_kind,
+ const TypeSystemClang::TemplateParameterInfos &template_param_infos) {
+ if (template_param_infos.IsValid()) {
+ std::string template_basename(parent_name);
+ template_basename.erase(template_basename.find('<'));
+
+ return CreateClassTemplateDecl(decl_ctx, access_type,
+ template_basename.c_str(), tag_decl_kind,
+ template_param_infos);
+ }
+ return nullptr;
+}
+
+void TypeSystemClang::CompleteTagDecl(clang::TagDecl *decl) {
+ SymbolFile *sym_file = GetSymbolFile();
+ if (sym_file) {
+ CompilerType clang_type = GetTypeForDecl(decl);
+ if (clang_type)
+ sym_file->CompleteType(clang_type);
+ }
+}
+
+void TypeSystemClang::CompleteObjCInterfaceDecl(
+ clang::ObjCInterfaceDecl *decl) {
+ SymbolFile *sym_file = GetSymbolFile();
+ if (sym_file) {
+ CompilerType clang_type = GetTypeForDecl(decl);
+ if (clang_type)
+ sym_file->CompleteType(clang_type);
+ }
+}
+
+DWARFASTParser *TypeSystemClang::GetDWARFParser() {
+ if (!m_dwarf_ast_parser_up)
+ m_dwarf_ast_parser_up.reset(new DWARFASTParserClang(*this));
+ return m_dwarf_ast_parser_up.get();
+}
+
+PDBASTParser *TypeSystemClang::GetPDBParser() {
+ if (!m_pdb_ast_parser_up)
+ m_pdb_ast_parser_up.reset(new PDBASTParser(*this));
+ return m_pdb_ast_parser_up.get();
+}
+
+bool TypeSystemClang::LayoutRecordType(
+ const clang::RecordDecl *record_decl, uint64_t &bit_size,
+ uint64_t &alignment,
+ llvm::DenseMap<const clang::FieldDecl *, uint64_t> &field_offsets,
+ llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits>
+ &base_offsets,
+ llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits>
+ &vbase_offsets) {
+ lldb_private::ClangASTImporter *importer = nullptr;
+ if (m_dwarf_ast_parser_up)
+ importer = &m_dwarf_ast_parser_up->GetClangASTImporter();
+ if (!importer && m_pdb_ast_parser_up)
+ importer = &m_pdb_ast_parser_up->GetClangASTImporter();
+ if (!importer)
+ return false;
+
+ return importer->LayoutRecordType(record_decl, bit_size, alignment,
+ field_offsets, base_offsets, vbase_offsets);
+}
+
+// CompilerDecl override functions
+
+ConstString TypeSystemClang::DeclGetName(void *opaque_decl) {
+ if (opaque_decl) {
+ clang::NamedDecl *nd =
+ llvm::dyn_cast<NamedDecl>((clang::Decl *)opaque_decl);
+ if (nd != nullptr)
+ return ConstString(nd->getDeclName().getAsString());
+ }
+ return ConstString();
+}
+
+ConstString TypeSystemClang::DeclGetMangledName(void *opaque_decl) {
+ if (opaque_decl) {
+ clang::NamedDecl *nd =
+ llvm::dyn_cast<clang::NamedDecl>((clang::Decl *)opaque_decl);
+ if (nd != nullptr && !llvm::isa<clang::ObjCMethodDecl>(nd)) {
+ clang::MangleContext *mc = getMangleContext();
+ if (mc && mc->shouldMangleCXXName(nd)) {
+ llvm::SmallVector<char, 1024> buf;
+ llvm::raw_svector_ostream llvm_ostrm(buf);
+ if (llvm::isa<clang::CXXConstructorDecl>(nd)) {
+ mc->mangleCXXCtor(llvm::dyn_cast<clang::CXXConstructorDecl>(nd),
+ Ctor_Complete, llvm_ostrm);
+ } else if (llvm::isa<clang::CXXDestructorDecl>(nd)) {
+ mc->mangleCXXDtor(llvm::dyn_cast<clang::CXXDestructorDecl>(nd),
+ Dtor_Complete, llvm_ostrm);
+ } else {
+ mc->mangleName(nd, llvm_ostrm);
+ }
+ if (buf.size() > 0)
+ return ConstString(buf.data(), buf.size());
+ }
+ }
+ }
+ return ConstString();
+}
+
+CompilerDeclContext TypeSystemClang::DeclGetDeclContext(void *opaque_decl) {
+ if (opaque_decl)
+ return CreateDeclContext(((clang::Decl *)opaque_decl)->getDeclContext());
+ return CompilerDeclContext();
+}
+
+CompilerType TypeSystemClang::DeclGetFunctionReturnType(void *opaque_decl) {
+ if (clang::FunctionDecl *func_decl =
+ llvm::dyn_cast<clang::FunctionDecl>((clang::Decl *)opaque_decl))
+ return GetType(func_decl->getReturnType());
+ if (clang::ObjCMethodDecl *objc_method =
+ llvm::dyn_cast<clang::ObjCMethodDecl>((clang::Decl *)opaque_decl))
+ return GetType(objc_method->getReturnType());
+ else
+ return CompilerType();
+}
+
+size_t TypeSystemClang::DeclGetFunctionNumArguments(void *opaque_decl) {
+ if (clang::FunctionDecl *func_decl =
+ llvm::dyn_cast<clang::FunctionDecl>((clang::Decl *)opaque_decl))
+ return func_decl->param_size();
+ if (clang::ObjCMethodDecl *objc_method =
+ llvm::dyn_cast<clang::ObjCMethodDecl>((clang::Decl *)opaque_decl))
+ return objc_method->param_size();
+ else
+ return 0;
+}
+
+CompilerType TypeSystemClang::DeclGetFunctionArgumentType(void *opaque_decl,
+ size_t idx) {
+ if (clang::FunctionDecl *func_decl =
+ llvm::dyn_cast<clang::FunctionDecl>((clang::Decl *)opaque_decl)) {
+ if (idx < func_decl->param_size()) {
+ ParmVarDecl *var_decl = func_decl->getParamDecl(idx);
+ if (var_decl)
+ return GetType(var_decl->getOriginalType());
+ }
+ } else if (clang::ObjCMethodDecl *objc_method =
+ llvm::dyn_cast<clang::ObjCMethodDecl>(
+ (clang::Decl *)opaque_decl)) {
+ if (idx < objc_method->param_size())
+ return GetType(objc_method->parameters()[idx]->getOriginalType());
+ }
+ return CompilerType();
+}
+
+// CompilerDeclContext functions
+
+std::vector<CompilerDecl> TypeSystemClang::DeclContextFindDeclByName(
+ void *opaque_decl_ctx, ConstString name, const bool ignore_using_decls) {
+ std::vector<CompilerDecl> found_decls;
+ if (opaque_decl_ctx) {
+ DeclContext *root_decl_ctx = (DeclContext *)opaque_decl_ctx;
+ std::set<DeclContext *> searched;
+ std::multimap<DeclContext *, DeclContext *> search_queue;
+ SymbolFile *symbol_file = GetSymbolFile();
+
+ for (clang::DeclContext *decl_context = root_decl_ctx;
+ decl_context != nullptr && found_decls.empty();
+ decl_context = decl_context->getParent()) {
+ search_queue.insert(std::make_pair(decl_context, decl_context));
+
+ for (auto it = search_queue.find(decl_context); it != search_queue.end();
+ it++) {
+ if (!searched.insert(it->second).second)
+ continue;
+ symbol_file->ParseDeclsForContext(
+ CreateDeclContext(it->second));
+
+ for (clang::Decl *child : it->second->decls()) {
+ if (clang::UsingDirectiveDecl *ud =
+ llvm::dyn_cast<clang::UsingDirectiveDecl>(child)) {
+ if (ignore_using_decls)
+ continue;
+ clang::DeclContext *from = ud->getCommonAncestor();
+ if (searched.find(ud->getNominatedNamespace()) == searched.end())
+ search_queue.insert(
+ std::make_pair(from, ud->getNominatedNamespace()));
+ } else if (clang::UsingDecl *ud =
+ llvm::dyn_cast<clang::UsingDecl>(child)) {
+ if (ignore_using_decls)
+ continue;
+ for (clang::UsingShadowDecl *usd : ud->shadows()) {
+ clang::Decl *target = usd->getTargetDecl();
+ if (clang::NamedDecl *nd =
+ llvm::dyn_cast<clang::NamedDecl>(target)) {
+ IdentifierInfo *ii = nd->getIdentifier();
+ if (ii != nullptr &&
+ ii->getName().equals(name.AsCString(nullptr)))
+ found_decls.push_back(GetCompilerDecl(nd));
+ }
+ }
+ } else if (clang::NamedDecl *nd =
+ llvm::dyn_cast<clang::NamedDecl>(child)) {
+ IdentifierInfo *ii = nd->getIdentifier();
+ if (ii != nullptr && ii->getName().equals(name.AsCString(nullptr)))
+ found_decls.push_back(GetCompilerDecl(nd));
+ }
+ }
+ }
+ }
+ }
+ return found_decls;
+}
+
+// Look for child_decl_ctx's lookup scope in frame_decl_ctx and its parents,
+// and return the number of levels it took to find it, or
+// LLDB_INVALID_DECL_LEVEL if not found. If the decl was imported via a using
+// declaration, its name and/or type, if set, will be used to check that the
+// decl found in the scope is a match.
+//
+// The optional name is required by languages (like C++) to handle using
+// declarations like:
+//
+// void poo();
+// namespace ns {
+// void foo();
+// void goo();
+// }
+// void bar() {
+// using ns::foo;
+// // CountDeclLevels returns 0 for 'foo', 1 for 'poo', and
+// // LLDB_INVALID_DECL_LEVEL for 'goo'.
+// }
+//
+// The optional type is useful in the case that there's a specific overload
+// that we're looking for that might otherwise be shadowed, like:
+//
+// void foo(int);
+// namespace ns {
+// void foo();
+// }
+// void bar() {
+// using ns::foo;
+// // CountDeclLevels returns 0 for { 'foo', void() },
+// // 1 for { 'foo', void(int) }, and
+// // LLDB_INVALID_DECL_LEVEL for { 'foo', void(int, int) }.
+// }
+//
+// NOTE: Because file statics are at the TranslationUnit along with globals, a
+// function at file scope will return the same level as a function at global
+// scope. Ideally we'd like to treat the file scope as an additional scope just
+// below the global scope. More work needs to be done to recognise that, if
+// the decl we're trying to look up is static, we should compare its source
+// file with that of the current scope and return a lower number for it.
+uint32_t TypeSystemClang::CountDeclLevels(clang::DeclContext *frame_decl_ctx,
+ clang::DeclContext *child_decl_ctx,
+ ConstString *child_name,
+ CompilerType *child_type) {
+ if (frame_decl_ctx) {
+ std::set<DeclContext *> searched;
+ std::multimap<DeclContext *, DeclContext *> search_queue;
+ SymbolFile *symbol_file = GetSymbolFile();
+
+ // Get the lookup scope for the decl we're trying to find.
+ clang::DeclContext *parent_decl_ctx = child_decl_ctx->getParent();
+
+ // Look for it in our scope's decl context and its parents.
+ uint32_t level = 0;
+ for (clang::DeclContext *decl_ctx = frame_decl_ctx; decl_ctx != nullptr;
+ decl_ctx = decl_ctx->getParent()) {
+ if (!decl_ctx->isLookupContext())
+ continue;
+ if (decl_ctx == parent_decl_ctx)
+ // Found it!
+ return level;
+ search_queue.insert(std::make_pair(decl_ctx, decl_ctx));
+ for (auto it = search_queue.find(decl_ctx); it != search_queue.end();
+ it++) {
+ if (searched.find(it->second) != searched.end())
+ continue;
+
+ // Currently DWARF has one shared translation unit for all Decls at top
+ // level, so this would erroneously find using statements anywhere. So
+ // don't look at the top-level translation unit.
+ // TODO fix this and add a testcase that depends on it.
+
+ if (llvm::isa<clang::TranslationUnitDecl>(it->second))
+ continue;
+
+ searched.insert(it->second);
+ symbol_file->ParseDeclsForContext(
+ CreateDeclContext(it->second));
+
+ for (clang::Decl *child : it->second->decls()) {
+ if (clang::UsingDirectiveDecl *ud =
+ llvm::dyn_cast<clang::UsingDirectiveDecl>(child)) {
+ clang::DeclContext *ns = ud->getNominatedNamespace();
+ if (ns == parent_decl_ctx)
+ // Found it!
+ return level;
+ clang::DeclContext *from = ud->getCommonAncestor();
+ if (searched.find(ns) == searched.end())
+ search_queue.insert(std::make_pair(from, ns));
+ } else if (child_name) {
+ if (clang::UsingDecl *ud =
+ llvm::dyn_cast<clang::UsingDecl>(child)) {
+ for (clang::UsingShadowDecl *usd : ud->shadows()) {
+ clang::Decl *target = usd->getTargetDecl();
+ clang::NamedDecl *nd = llvm::dyn_cast<clang::NamedDecl>(target);
+ if (!nd)
+ continue;
+ // Check names.
+ IdentifierInfo *ii = nd->getIdentifier();
+ if (ii == nullptr ||
+ !ii->getName().equals(child_name->AsCString(nullptr)))
+ continue;
+ // Check types, if one was provided.
+ if (child_type) {
+ CompilerType clang_type = GetTypeForDecl(nd);
+ if (!AreTypesSame(clang_type, *child_type,
+ /*ignore_qualifiers=*/true))
+ continue;
+ }
+ // Found it!
+ return level;
+ }
+ }
+ }
+ }
+ }
+ ++level;
+ }
+ }
+ return LLDB_INVALID_DECL_LEVEL;
+}
+
+ConstString TypeSystemClang::DeclContextGetName(void *opaque_decl_ctx) {
+ if (opaque_decl_ctx) {
+ clang::NamedDecl *named_decl =
+ llvm::dyn_cast<clang::NamedDecl>((clang::DeclContext *)opaque_decl_ctx);
+ if (named_decl)
+ return ConstString(named_decl->getName());
+ }
+ return ConstString();
+}
+
+ConstString
+TypeSystemClang::DeclContextGetScopeQualifiedName(void *opaque_decl_ctx) {
+ if (opaque_decl_ctx) {
+ clang::NamedDecl *named_decl =
+ llvm::dyn_cast<clang::NamedDecl>((clang::DeclContext *)opaque_decl_ctx);
+ if (named_decl)
+ return ConstString(
+ llvm::StringRef(named_decl->getQualifiedNameAsString()));
+ }
+ return ConstString();
+}
+
+bool TypeSystemClang::DeclContextIsClassMethod(
+ void *opaque_decl_ctx, lldb::LanguageType *language_ptr,
+ bool *is_instance_method_ptr, ConstString *language_object_name_ptr) {
+ if (opaque_decl_ctx) {
+ clang::DeclContext *decl_ctx = (clang::DeclContext *)opaque_decl_ctx;
+ if (ObjCMethodDecl *objc_method =
+ llvm::dyn_cast<clang::ObjCMethodDecl>(decl_ctx)) {
+ if (is_instance_method_ptr)
+ *is_instance_method_ptr = objc_method->isInstanceMethod();
+ if (language_ptr)
+ *language_ptr = eLanguageTypeObjC;
+ if (language_object_name_ptr)
+ language_object_name_ptr->SetCString("self");
+ return true;
+ } else if (CXXMethodDecl *cxx_method =
+ llvm::dyn_cast<clang::CXXMethodDecl>(decl_ctx)) {
+ if (is_instance_method_ptr)
+ *is_instance_method_ptr = cxx_method->isInstance();
+ if (language_ptr)
+ *language_ptr = eLanguageTypeC_plus_plus;
+ if (language_object_name_ptr)
+ language_object_name_ptr->SetCString("this");
+ return true;
+ } else if (clang::FunctionDecl *function_decl =
+ llvm::dyn_cast<clang::FunctionDecl>(decl_ctx)) {
+ ClangASTMetadata *metadata = GetMetadata(function_decl);
+ if (metadata && metadata->HasObjectPtr()) {
+ if (is_instance_method_ptr)
+ *is_instance_method_ptr = true;
+ if (language_ptr)
+ *language_ptr = eLanguageTypeObjC;
+ if (language_object_name_ptr)
+ language_object_name_ptr->SetCString(metadata->GetObjectPtrName());
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+bool TypeSystemClang::DeclContextIsContainedInLookup(
+ void *opaque_decl_ctx, void *other_opaque_decl_ctx) {
+ auto *decl_ctx = (clang::DeclContext *)opaque_decl_ctx;
+ auto *other = (clang::DeclContext *)other_opaque_decl_ctx;
+
+ do {
+ // A decl context always includes its own contents in its lookup.
+ if (decl_ctx == other)
+ return true;
+
+ // If we have an inline namespace, then the lookup of the parent context
+ // also includes the inline namespace contents.
+ } while (other->isInlineNamespace() && (other = other->getParent()));
+
+ return false;
+}
+
+static bool IsClangDeclContext(const CompilerDeclContext &dc) {
+ return dc.IsValid() && isa<TypeSystemClang>(dc.GetTypeSystem());
+}
+
+clang::DeclContext *
+TypeSystemClang::DeclContextGetAsDeclContext(const CompilerDeclContext &dc) {
+ if (IsClangDeclContext(dc))
+ return (clang::DeclContext *)dc.GetOpaqueDeclContext();
+ return nullptr;
+}
+
+ObjCMethodDecl *
+TypeSystemClang::DeclContextGetAsObjCMethodDecl(const CompilerDeclContext &dc) {
+ if (IsClangDeclContext(dc))
+ return llvm::dyn_cast<clang::ObjCMethodDecl>(
+ (clang::DeclContext *)dc.GetOpaqueDeclContext());
+ return nullptr;
+}
+
+CXXMethodDecl *
+TypeSystemClang::DeclContextGetAsCXXMethodDecl(const CompilerDeclContext &dc) {
+ if (IsClangDeclContext(dc))
+ return llvm::dyn_cast<clang::CXXMethodDecl>(
+ (clang::DeclContext *)dc.GetOpaqueDeclContext());
+ return nullptr;
+}
+
+clang::FunctionDecl *
+TypeSystemClang::DeclContextGetAsFunctionDecl(const CompilerDeclContext &dc) {
+ if (IsClangDeclContext(dc))
+ return llvm::dyn_cast<clang::FunctionDecl>(
+ (clang::DeclContext *)dc.GetOpaqueDeclContext());
+ return nullptr;
+}
+
+clang::NamespaceDecl *
+TypeSystemClang::DeclContextGetAsNamespaceDecl(const CompilerDeclContext &dc) {
+ if (IsClangDeclContext(dc))
+ return llvm::dyn_cast<clang::NamespaceDecl>(
+ (clang::DeclContext *)dc.GetOpaqueDeclContext());
+ return nullptr;
+}
+
+ClangASTMetadata *
+TypeSystemClang::DeclContextGetMetaData(const CompilerDeclContext &dc,
+ const Decl *object) {
+ TypeSystemClang *ast = llvm::cast<TypeSystemClang>(dc.GetTypeSystem());
+ return ast->GetMetadata(object);
+}
+
+clang::ASTContext *
+TypeSystemClang::DeclContextGetTypeSystemClang(const CompilerDeclContext &dc) {
+ TypeSystemClang *ast =
+ llvm::dyn_cast_or_null<TypeSystemClang>(dc.GetTypeSystem());
+ if (ast)
+ return &ast->getASTContext();
+ return nullptr;
+}
+
+TypeSystemClangForExpressions::TypeSystemClangForExpressions(
+ Target &target, llvm::Triple triple)
+ : TypeSystemClang("scratch ASTContext", triple),
+ m_target_wp(target.shared_from_this()),
+ m_persistent_variables(new ClangPersistentVariables) {
+ m_scratch_ast_source_up.reset(new ClangASTSource(
+ target.shared_from_this(), m_persistent_variables->GetClangASTImporter()));
+ m_scratch_ast_source_up->InstallASTContext(*this);
+ llvm::IntrusiveRefCntPtr<clang::ExternalASTSource> proxy_ast_source(
+ m_scratch_ast_source_up->CreateProxy());
+ SetExternalSource(proxy_ast_source);
+}
+
+void TypeSystemClangForExpressions::Finalize() {
+ TypeSystemClang::Finalize();
+ m_scratch_ast_source_up.reset();
+}
+
+UserExpression *TypeSystemClangForExpressions::GetUserExpression(
+ llvm::StringRef expr, llvm::StringRef prefix, lldb::LanguageType language,
+ Expression::ResultType desired_type,
+ const EvaluateExpressionOptions &options,
+ ValueObject *ctx_obj) {
+ TargetSP target_sp = m_target_wp.lock();
+ if (!target_sp)
+ return nullptr;
+
+ return new ClangUserExpression(*target_sp.get(), expr, prefix, language,
+ desired_type, options, ctx_obj);
+}
+
+FunctionCaller *TypeSystemClangForExpressions::GetFunctionCaller(
+ const CompilerType &return_type, const Address &function_address,
+ const ValueList &arg_value_list, const char *name) {
+ TargetSP target_sp = m_target_wp.lock();
+ if (!target_sp)
+ return nullptr;
+
+ Process *process = target_sp->GetProcessSP().get();
+ if (!process)
+ return nullptr;
+
+ return new ClangFunctionCaller(*process, return_type, function_address,
+ arg_value_list, name);
+}
+
+UtilityFunction *
+TypeSystemClangForExpressions::GetUtilityFunction(const char *text,
+ const char *name) {
+ TargetSP target_sp = m_target_wp.lock();
+ if (!target_sp)
+ return nullptr;
+
+ return new ClangUtilityFunction(*target_sp.get(), text, name);
+}
+
+PersistentExpressionState *
+TypeSystemClangForExpressions::GetPersistentExpressionState() {
+ return m_persistent_variables.get();
+}
--- /dev/null
+//===-- TypeSystemClang.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 liblldb_TypeSystemClang_h_
+#define liblldb_TypeSystemClang_h_
+
+#include <stdint.h>
+
+#include <functional>
+#include <initializer_list>
+#include <map>
+#include <memory>
+#include <set>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTFwd.h"
+#include "clang/AST/TemplateBase.h"
+#include "llvm/ADT/APSInt.h"
+#include "llvm/ADT/SmallVector.h"
+
+#include "Plugins/ExpressionParser/Clang/ClangPersistentVariables.h"
+#include "lldb/Core/ClangForward.h"
+#include "lldb/Expression/ExpressionVariable.h"
+#include "lldb/Symbol/CompilerType.h"
+#include "lldb/Symbol/TypeSystem.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Utility/ConstString.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/Logging.h"
+#include "lldb/lldb-enumerations.h"
+
+class DWARFASTParserClang;
+class PDBASTParser;
+
+namespace lldb_private {
+
+class Declaration;
+
+class TypeSystemClang : public TypeSystem {
+ // LLVM RTTI support
+ static char ID;
+
+public:
+ typedef void (*CompleteTagDeclCallback)(void *baton, clang::TagDecl *);
+ typedef void (*CompleteObjCInterfaceDeclCallback)(void *baton,
+ clang::ObjCInterfaceDecl *);
+
+ // llvm casting support
+ bool isA(const void *ClassID) const override { return ClassID == &ID; }
+ static bool classof(const TypeSystem *ts) { return ts->isA(&ID); }
+
+ /// Constructs a TypeSystemClang with an ASTContext using the given triple.
+ ///
+ /// \param name The name for the TypeSystemClang (for logging purposes)
+ /// \param triple The llvm::Triple used for the ASTContext. The triple defines
+ /// certain characteristics of the ASTContext and its types
+ /// (e.g., whether certain primitive types exist or what their
+ /// signedness is).
+ explicit TypeSystemClang(llvm::StringRef name, llvm::Triple triple);
+
+ /// Constructs a TypeSystemClang that uses an existing ASTContext internally.
+ /// Useful when having an existing ASTContext created by Clang.
+ ///
+ /// \param name The name for the TypeSystemClang (for logging purposes)
+ /// \param existing_ctxt An existing ASTContext.
+ explicit TypeSystemClang(llvm::StringRef name,
+ clang::ASTContext &existing_ctxt);
+
+ ~TypeSystemClang() override;
+
+ void Finalize() override;
+
+ // PluginInterface functions
+ ConstString GetPluginName() override;
+
+ uint32_t GetPluginVersion() override;
+
+ static ConstString GetPluginNameStatic();
+
+ static lldb::TypeSystemSP CreateInstance(lldb::LanguageType language,
+ Module *module, Target *target);
+
+ static LanguageSet GetSupportedLanguagesForTypes();
+ static LanguageSet GetSupportedLanguagesForExpressions();
+
+ static void Initialize();
+
+ static void Terminate();
+
+ static TypeSystemClang *GetASTContext(clang::ASTContext *ast_ctx);
+
+ static TypeSystemClang *GetScratch(Target &target,
+ bool create_on_demand = true) {
+ auto type_system_or_err = target.GetScratchTypeSystemForLanguage(
+ lldb::eLanguageTypeC, create_on_demand);
+ if (auto err = type_system_or_err.takeError()) {
+ LLDB_LOG_ERROR(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_TARGET),
+ std::move(err), "Couldn't get scratch TypeSystemClang");
+ return nullptr;
+ }
+ return llvm::dyn_cast<TypeSystemClang>(&type_system_or_err.get());
+ }
+
+ /// Returns the display name of this TypeSystemClang that indicates what
+ /// purpose it serves in LLDB. Used for example in logs.
+ llvm::StringRef getDisplayName() const { return m_display_name; }
+
+ clang::ASTContext &getASTContext();
+
+ clang::MangleContext *getMangleContext();
+
+ std::shared_ptr<clang::TargetOptions> &getTargetOptions();
+
+ clang::TargetInfo *getTargetInfo();
+
+ void setSema(clang::Sema *s);
+ clang::Sema *getSema() { return m_sema; }
+
+ const char *GetTargetTriple();
+
+ void SetExternalSource(
+ llvm::IntrusiveRefCntPtr<clang::ExternalASTSource> &ast_source_up);
+
+ bool GetCompleteDecl(clang::Decl *decl) {
+ return TypeSystemClang::GetCompleteDecl(&getASTContext(), decl);
+ }
+
+ static void DumpDeclHiearchy(clang::Decl *decl);
+
+ static void DumpDeclContextHiearchy(clang::DeclContext *decl_ctx);
+
+ static bool DeclsAreEquivalent(clang::Decl *lhs_decl, clang::Decl *rhs_decl);
+
+ static bool GetCompleteDecl(clang::ASTContext *ast, clang::Decl *decl);
+
+ void SetMetadataAsUserID(const clang::Decl *decl, lldb::user_id_t user_id);
+ void SetMetadataAsUserID(const clang::Type *type, lldb::user_id_t user_id);
+
+ void SetMetadata(const clang::Decl *object, ClangASTMetadata &meta_data);
+
+ void SetMetadata(const clang::Type *object, ClangASTMetadata &meta_data);
+ ClangASTMetadata *GetMetadata(const clang::Decl *object);
+ ClangASTMetadata *GetMetadata(const clang::Type *object);
+
+ // Basic Types
+ CompilerType GetBuiltinTypeForEncodingAndBitSize(lldb::Encoding encoding,
+ size_t bit_size) override;
+
+ CompilerType GetBasicType(lldb::BasicType type);
+
+ static lldb::BasicType GetBasicTypeEnumeration(ConstString name);
+
+ CompilerType
+ GetBuiltinTypeForDWARFEncodingAndBitSize(llvm::StringRef type_name,
+ uint32_t dw_ate, uint32_t bit_size);
+
+ CompilerType GetCStringType(bool is_const);
+
+ static clang::DeclContext *GetDeclContextForType(clang::QualType type);
+
+ static clang::DeclContext *GetDeclContextForType(const CompilerType &type);
+
+ uint32_t GetPointerByteSize() override;
+
+ clang::TranslationUnitDecl *GetTranslationUnitDecl() {
+ return getASTContext().getTranslationUnitDecl();
+ }
+
+ static bool AreTypesSame(CompilerType type1, CompilerType type2,
+ bool ignore_qualifiers = false);
+
+ /// Creates a CompilerType form the given QualType with the current
+ /// TypeSystemClang instance as the CompilerType's typesystem.
+ /// \param qt The QualType for a type that belongs to the ASTContext of this
+ /// TypeSystemClang.
+ /// \return The CompilerType representing the given QualType. If the
+ /// QualType's type pointer is a nullptr then the function returns an
+ /// invalid CompilerType.
+ CompilerType GetType(clang::QualType qt) {
+ if (qt.getTypePtrOrNull() == nullptr)
+ return CompilerType();
+ // Check that the type actually belongs to this TypeSystemClang.
+ assert(qt->getAsTagDecl() == nullptr ||
+ &qt->getAsTagDecl()->getASTContext() == &getASTContext());
+ return CompilerType(this, qt.getAsOpaquePtr());
+ }
+
+ CompilerType GetTypeForDecl(clang::NamedDecl *decl);
+
+ CompilerType GetTypeForDecl(clang::TagDecl *decl);
+
+ CompilerType GetTypeForDecl(clang::ObjCInterfaceDecl *objc_decl);
+
+ template <typename RecordDeclType>
+ CompilerType
+ GetTypeForIdentifier(ConstString type_name,
+ clang::DeclContext *decl_context = nullptr) {
+ CompilerType compiler_type;
+
+ if (type_name.GetLength()) {
+ clang::ASTContext &ast = getASTContext();
+ if (!decl_context)
+ decl_context = ast.getTranslationUnitDecl();
+
+ clang::IdentifierInfo &myIdent = ast.Idents.get(type_name.GetCString());
+ clang::DeclarationName myName =
+ ast.DeclarationNames.getIdentifier(&myIdent);
+
+ clang::DeclContext::lookup_result result = decl_context->lookup(myName);
+
+ if (!result.empty()) {
+ clang::NamedDecl *named_decl = result[0];
+ if (const RecordDeclType *record_decl =
+ llvm::dyn_cast<RecordDeclType>(named_decl))
+ compiler_type.SetCompilerType(
+ this, clang::QualType(record_decl->getTypeForDecl(), 0)
+ .getAsOpaquePtr());
+ }
+ }
+
+ return compiler_type;
+ }
+
+ CompilerType CreateStructForIdentifier(
+ ConstString type_name,
+ const std::initializer_list<std::pair<const char *, CompilerType>>
+ &type_fields,
+ bool packed = false);
+
+ CompilerType GetOrCreateStructForIdentifier(
+ ConstString type_name,
+ const std::initializer_list<std::pair<const char *, CompilerType>>
+ &type_fields,
+ bool packed = false);
+
+ static bool IsOperator(llvm::StringRef name,
+ clang::OverloadedOperatorKind &op_kind);
+
+ // Structure, Unions, Classes
+
+ static clang::AccessSpecifier
+ ConvertAccessTypeToAccessSpecifier(lldb::AccessType access);
+
+ static clang::AccessSpecifier
+ UnifyAccessSpecifiers(clang::AccessSpecifier lhs, clang::AccessSpecifier rhs);
+
+ static uint32_t GetNumBaseClasses(const clang::CXXRecordDecl *cxx_record_decl,
+ bool omit_empty_base_classes);
+
+ CompilerType CreateRecordType(clang::DeclContext *decl_ctx,
+ lldb::AccessType access_type,
+ llvm::StringRef name, int kind,
+ lldb::LanguageType language,
+ ClangASTMetadata *metadata = nullptr,
+ bool exports_symbols = false);
+
+ class TemplateParameterInfos {
+ public:
+ bool IsValid() const {
+ if (args.empty())
+ return false;
+ return args.size() == names.size() &&
+ ((bool)pack_name == (bool)packed_args) &&
+ (!packed_args || !packed_args->packed_args);
+ }
+
+ llvm::SmallVector<const char *, 2> names;
+ llvm::SmallVector<clang::TemplateArgument, 2> args;
+
+ const char * pack_name = nullptr;
+ std::unique_ptr<TemplateParameterInfos> packed_args;
+ };
+
+ clang::FunctionTemplateDecl *
+ CreateFunctionTemplateDecl(clang::DeclContext *decl_ctx,
+ clang::FunctionDecl *func_decl, const char *name,
+ const TemplateParameterInfos &infos);
+
+ void CreateFunctionTemplateSpecializationInfo(
+ clang::FunctionDecl *func_decl, clang::FunctionTemplateDecl *Template,
+ const TemplateParameterInfos &infos);
+
+ clang::ClassTemplateDecl *
+ CreateClassTemplateDecl(clang::DeclContext *decl_ctx,
+ lldb::AccessType access_type, const char *class_name,
+ int kind, const TemplateParameterInfos &infos);
+
+ clang::TemplateTemplateParmDecl *
+ CreateTemplateTemplateParmDecl(const char *template_name);
+
+ clang::ClassTemplateSpecializationDecl *CreateClassTemplateSpecializationDecl(
+ clang::DeclContext *decl_ctx,
+ clang::ClassTemplateDecl *class_template_decl, int kind,
+ const TemplateParameterInfos &infos);
+
+ CompilerType
+ CreateClassTemplateSpecializationType(clang::ClassTemplateSpecializationDecl *
+ class_template_specialization_decl);
+
+ static clang::DeclContext *
+ GetAsDeclContext(clang::FunctionDecl *function_decl);
+
+ static bool CheckOverloadedOperatorKindParameterCount(
+ bool is_method, clang::OverloadedOperatorKind op_kind,
+ uint32_t num_params);
+
+ bool FieldIsBitfield(clang::FieldDecl *field, uint32_t &bitfield_bit_size);
+
+ static bool RecordHasFields(const clang::RecordDecl *record_decl);
+
+ CompilerType CreateObjCClass(llvm::StringRef name,
+ clang::DeclContext *decl_ctx, bool isForwardDecl,
+ bool isInternal,
+ ClangASTMetadata *metadata = nullptr);
+
+ bool SetTagTypeKind(clang::QualType type, int kind) const;
+
+ bool SetDefaultAccessForRecordFields(clang::RecordDecl *record_decl,
+ int default_accessibility,
+ int *assigned_accessibilities,
+ size_t num_assigned_accessibilities);
+
+ // Returns a mask containing bits from the TypeSystemClang::eTypeXXX
+ // enumerations
+
+ // Namespace Declarations
+
+ clang::NamespaceDecl *
+ GetUniqueNamespaceDeclaration(const char *name, clang::DeclContext *decl_ctx,
+ bool is_inline = false);
+
+ // Function Types
+
+ clang::FunctionDecl *
+ CreateFunctionDeclaration(clang::DeclContext *decl_ctx, const char *name,
+ const CompilerType &function_Type, int storage,
+ bool is_inline);
+
+ CompilerType CreateFunctionType(const CompilerType &result_type,
+ const CompilerType *args, unsigned num_args,
+ bool is_variadic, unsigned type_quals,
+ clang::CallingConv cc);
+
+ CompilerType CreateFunctionType(const CompilerType &result_type,
+ const CompilerType *args, unsigned num_args,
+ bool is_variadic, unsigned type_quals) {
+ return CreateFunctionType(result_type, args, num_args, is_variadic,
+ type_quals, clang::CC_C);
+ }
+
+ clang::ParmVarDecl *CreateParameterDeclaration(clang::DeclContext *decl_ctx,
+ const char *name,
+ const CompilerType ¶m_type,
+ int storage,
+ bool add_decl=false);
+
+ void SetFunctionParameters(clang::FunctionDecl *function_decl,
+ clang::ParmVarDecl **params, unsigned num_params);
+
+ CompilerType CreateBlockPointerType(const CompilerType &function_type);
+
+ // Array Types
+
+ CompilerType CreateArrayType(const CompilerType &element_type,
+ size_t element_count, bool is_vector);
+
+ // Enumeration Types
+ CompilerType CreateEnumerationType(const char *name,
+ clang::DeclContext *decl_ctx,
+ const Declaration &decl,
+ const CompilerType &integer_qual_type,
+ bool is_scoped);
+
+ // Integer type functions
+
+ CompilerType GetIntTypeFromBitSize(size_t bit_size, bool is_signed);
+
+ CompilerType GetPointerSizedIntType(bool is_signed);
+
+ // Floating point functions
+
+ static CompilerType GetFloatTypeFromBitSize(clang::ASTContext *ast,
+ size_t bit_size);
+
+ // TypeSystem methods
+ DWARFASTParser *GetDWARFParser() override;
+ PDBASTParser *GetPDBParser() override;
+
+ // TypeSystemClang callbacks for external source lookups.
+ void CompleteTagDecl(clang::TagDecl *);
+
+ void CompleteObjCInterfaceDecl(clang::ObjCInterfaceDecl *);
+
+ bool LayoutRecordType(
+ const clang::RecordDecl *record_decl, uint64_t &size, uint64_t &alignment,
+ llvm::DenseMap<const clang::FieldDecl *, uint64_t> &field_offsets,
+ llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits>
+ &base_offsets,
+ llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits>
+ &vbase_offsets);
+
+ /// Creates a CompilerDecl from the given Decl with the current
+ /// TypeSystemClang instance as its typesystem.
+ /// The Decl has to come from the ASTContext of this
+ /// TypeSystemClang.
+ CompilerDecl GetCompilerDecl(clang::Decl *decl) {
+ assert(&decl->getASTContext() == &getASTContext() &&
+ "CreateCompilerDecl for Decl from wrong ASTContext?");
+ return CompilerDecl(this, decl);
+ }
+
+ // CompilerDecl override functions
+ ConstString DeclGetName(void *opaque_decl) override;
+
+ ConstString DeclGetMangledName(void *opaque_decl) override;
+
+ CompilerDeclContext DeclGetDeclContext(void *opaque_decl) override;
+
+ CompilerType DeclGetFunctionReturnType(void *opaque_decl) override;
+
+ size_t DeclGetFunctionNumArguments(void *opaque_decl) override;
+
+ CompilerType DeclGetFunctionArgumentType(void *opaque_decl,
+ size_t arg_idx) override;
+
+ CompilerType GetTypeForDecl(void *opaque_decl) override;
+
+ // CompilerDeclContext override functions
+
+ /// Creates a CompilerDeclContext from the given DeclContext
+ /// with the current TypeSystemClang instance as its typesystem.
+ /// The DeclContext has to come from the ASTContext of this
+ /// TypeSystemClang.
+ CompilerDeclContext CreateDeclContext(clang::DeclContext *ctx);
+
+ std::vector<CompilerDecl>
+ DeclContextFindDeclByName(void *opaque_decl_ctx, ConstString name,
+ const bool ignore_using_decls) override;
+
+ ConstString DeclContextGetName(void *opaque_decl_ctx) override;
+
+ ConstString DeclContextGetScopeQualifiedName(void *opaque_decl_ctx) override;
+
+ bool DeclContextIsClassMethod(void *opaque_decl_ctx,
+ lldb::LanguageType *language_ptr,
+ bool *is_instance_method_ptr,
+ ConstString *language_object_name_ptr) override;
+
+ bool DeclContextIsContainedInLookup(void *opaque_decl_ctx,
+ void *other_opaque_decl_ctx) override;
+
+ // Clang specific clang::DeclContext functions
+
+ static clang::DeclContext *
+ DeclContextGetAsDeclContext(const CompilerDeclContext &dc);
+
+ static clang::ObjCMethodDecl *
+ DeclContextGetAsObjCMethodDecl(const CompilerDeclContext &dc);
+
+ static clang::CXXMethodDecl *
+ DeclContextGetAsCXXMethodDecl(const CompilerDeclContext &dc);
+
+ static clang::FunctionDecl *
+ DeclContextGetAsFunctionDecl(const CompilerDeclContext &dc);
+
+ static clang::NamespaceDecl *
+ DeclContextGetAsNamespaceDecl(const CompilerDeclContext &dc);
+
+ static ClangASTMetadata *DeclContextGetMetaData(const CompilerDeclContext &dc,
+ const clang::Decl *object);
+
+ static clang::ASTContext *
+ DeclContextGetTypeSystemClang(const CompilerDeclContext &dc);
+
+ // Tests
+
+ bool IsArrayType(lldb::opaque_compiler_type_t type,
+ CompilerType *element_type, uint64_t *size,
+ bool *is_incomplete) override;
+
+ bool IsVectorType(lldb::opaque_compiler_type_t type,
+ CompilerType *element_type, uint64_t *size) override;
+
+ bool IsAggregateType(lldb::opaque_compiler_type_t type) override;
+
+ bool IsAnonymousType(lldb::opaque_compiler_type_t type) override;
+
+ bool IsBeingDefined(lldb::opaque_compiler_type_t type) override;
+
+ bool IsCharType(lldb::opaque_compiler_type_t type) override;
+
+ bool IsCompleteType(lldb::opaque_compiler_type_t type) override;
+
+ bool IsConst(lldb::opaque_compiler_type_t type) override;
+
+ bool IsCStringType(lldb::opaque_compiler_type_t type,
+ uint32_t &length) override;
+
+ static bool IsCXXClassType(const CompilerType &type);
+
+ bool IsDefined(lldb::opaque_compiler_type_t type) override;
+
+ bool IsFloatingPointType(lldb::opaque_compiler_type_t type, uint32_t &count,
+ bool &is_complex) override;
+
+ bool IsFunctionType(lldb::opaque_compiler_type_t type,
+ bool *is_variadic_ptr) override;
+
+ uint32_t IsHomogeneousAggregate(lldb::opaque_compiler_type_t type,
+ CompilerType *base_type_ptr) override;
+
+ size_t
+ GetNumberOfFunctionArguments(lldb::opaque_compiler_type_t type) override;
+
+ CompilerType GetFunctionArgumentAtIndex(lldb::opaque_compiler_type_t type,
+ const size_t index) override;
+
+ bool IsFunctionPointerType(lldb::opaque_compiler_type_t type) override;
+
+ bool IsBlockPointerType(lldb::opaque_compiler_type_t type,
+ CompilerType *function_pointer_type_ptr) override;
+
+ bool IsIntegerType(lldb::opaque_compiler_type_t type,
+ bool &is_signed) override;
+
+ bool IsEnumerationType(lldb::opaque_compiler_type_t type,
+ bool &is_signed) override;
+
+ static bool IsObjCClassType(const CompilerType &type);
+
+ static bool IsObjCClassTypeAndHasIVars(const CompilerType &type,
+ bool check_superclass);
+
+ static bool IsObjCObjectOrInterfaceType(const CompilerType &type);
+
+ static bool IsObjCObjectPointerType(const CompilerType &type,
+ CompilerType *target_type = nullptr);
+
+ bool IsPolymorphicClass(lldb::opaque_compiler_type_t type) override;
+
+ static bool IsClassType(lldb::opaque_compiler_type_t type);
+
+ static bool IsEnumType(lldb::opaque_compiler_type_t type);
+
+ bool IsPossibleDynamicType(lldb::opaque_compiler_type_t type,
+ CompilerType *target_type, // Can pass nullptr
+ bool check_cplusplus, bool check_objc) override;
+
+ bool IsRuntimeGeneratedType(lldb::opaque_compiler_type_t type) override;
+
+ bool IsPointerType(lldb::opaque_compiler_type_t type,
+ CompilerType *pointee_type) override;
+
+ bool IsPointerOrReferenceType(lldb::opaque_compiler_type_t type,
+ CompilerType *pointee_type) override;
+
+ bool IsReferenceType(lldb::opaque_compiler_type_t type,
+ CompilerType *pointee_type, bool *is_rvalue) override;
+
+ bool IsScalarType(lldb::opaque_compiler_type_t type) override;
+
+ bool IsTypedefType(lldb::opaque_compiler_type_t type) override;
+
+ bool IsVoidType(lldb::opaque_compiler_type_t type) override;
+
+ bool CanPassInRegisters(const CompilerType &type) override;
+
+ bool SupportsLanguage(lldb::LanguageType language) override;
+
+ static llvm::Optional<std::string> GetCXXClassName(const CompilerType &type);
+
+ // Type Completion
+
+ bool GetCompleteType(lldb::opaque_compiler_type_t type) override;
+
+ // Accessors
+
+ ConstString GetTypeName(lldb::opaque_compiler_type_t type) override;
+
+ uint32_t GetTypeInfo(lldb::opaque_compiler_type_t type,
+ CompilerType *pointee_or_element_compiler_type) override;
+
+ lldb::LanguageType
+ GetMinimumLanguage(lldb::opaque_compiler_type_t type) override;
+
+ lldb::TypeClass GetTypeClass(lldb::opaque_compiler_type_t type) override;
+
+ unsigned GetTypeQualifiers(lldb::opaque_compiler_type_t type) override;
+
+ // Creating related types
+
+ // Using the current type, create a new typedef to that type using
+ // "typedef_name" as the name and "decl_ctx" as the decl context.
+ static CompilerType
+ CreateTypedefType(const CompilerType &type, const char *typedef_name,
+ const CompilerDeclContext &compiler_decl_ctx);
+
+ CompilerType GetArrayElementType(lldb::opaque_compiler_type_t type,
+ uint64_t *stride) override;
+
+ CompilerType GetArrayType(lldb::opaque_compiler_type_t type,
+ uint64_t size) override;
+
+ CompilerType GetCanonicalType(lldb::opaque_compiler_type_t type) override;
+
+ CompilerType
+ GetFullyUnqualifiedType(lldb::opaque_compiler_type_t type) override;
+
+ // Returns -1 if this isn't a function of if the function doesn't have a
+ // prototype Returns a value >= 0 if there is a prototype.
+ int GetFunctionArgumentCount(lldb::opaque_compiler_type_t type) override;
+
+ CompilerType GetFunctionArgumentTypeAtIndex(lldb::opaque_compiler_type_t type,
+ size_t idx) override;
+
+ CompilerType
+ GetFunctionReturnType(lldb::opaque_compiler_type_t type) override;
+
+ size_t GetNumMemberFunctions(lldb::opaque_compiler_type_t type) override;
+
+ TypeMemberFunctionImpl
+ GetMemberFunctionAtIndex(lldb::opaque_compiler_type_t type,
+ size_t idx) override;
+
+ CompilerType GetNonReferenceType(lldb::opaque_compiler_type_t type) override;
+
+ CompilerType GetPointeeType(lldb::opaque_compiler_type_t type) override;
+
+ CompilerType GetPointerType(lldb::opaque_compiler_type_t type) override;
+
+ CompilerType
+ GetLValueReferenceType(lldb::opaque_compiler_type_t type) override;
+
+ CompilerType
+ GetRValueReferenceType(lldb::opaque_compiler_type_t type) override;
+
+ CompilerType GetAtomicType(lldb::opaque_compiler_type_t type) override;
+
+ CompilerType AddConstModifier(lldb::opaque_compiler_type_t type) override;
+
+ CompilerType AddVolatileModifier(lldb::opaque_compiler_type_t type) override;
+
+ CompilerType AddRestrictModifier(lldb::opaque_compiler_type_t type) override;
+
+ CompilerType CreateTypedef(lldb::opaque_compiler_type_t type,
+ const char *name,
+ const CompilerDeclContext &decl_ctx) override;
+
+ // If the current object represents a typedef type, get the underlying type
+ CompilerType GetTypedefedType(lldb::opaque_compiler_type_t type) override;
+
+ // Create related types using the current type's AST
+ CompilerType GetBasicTypeFromAST(lldb::BasicType basic_type) override;
+
+ // Exploring the type
+
+ const llvm::fltSemantics &GetFloatTypeSemantics(size_t byte_size) override;
+
+ llvm::Optional<uint64_t> GetByteSize(lldb::opaque_compiler_type_t type,
+ ExecutionContextScope *exe_scope) {
+ if (llvm::Optional<uint64_t> bit_size = GetBitSize(type, exe_scope))
+ return (*bit_size + 7) / 8;
+ return llvm::None;
+ }
+
+ llvm::Optional<uint64_t>
+ GetBitSize(lldb::opaque_compiler_type_t type,
+ ExecutionContextScope *exe_scope) override;
+
+ lldb::Encoding GetEncoding(lldb::opaque_compiler_type_t type,
+ uint64_t &count) override;
+
+ lldb::Format GetFormat(lldb::opaque_compiler_type_t type) override;
+
+ llvm::Optional<size_t>
+ GetTypeBitAlign(lldb::opaque_compiler_type_t type,
+ ExecutionContextScope *exe_scope) override;
+
+ uint32_t GetNumChildren(lldb::opaque_compiler_type_t type,
+ bool omit_empty_base_classes,
+ const ExecutionContext *exe_ctx) override;
+
+ CompilerType GetBuiltinTypeByName(ConstString name) override;
+
+ lldb::BasicType
+ GetBasicTypeEnumeration(lldb::opaque_compiler_type_t type) override;
+
+ static lldb::BasicType
+ GetBasicTypeEnumeration(lldb::opaque_compiler_type_t type,
+ ConstString name);
+
+ void ForEachEnumerator(
+ lldb::opaque_compiler_type_t type,
+ std::function<bool(const CompilerType &integer_type,
+ ConstString name,
+ const llvm::APSInt &value)> const &callback) override;
+
+ uint32_t GetNumFields(lldb::opaque_compiler_type_t type) override;
+
+ CompilerType GetFieldAtIndex(lldb::opaque_compiler_type_t type, size_t idx,
+ std::string &name, uint64_t *bit_offset_ptr,
+ uint32_t *bitfield_bit_size_ptr,
+ bool *is_bitfield_ptr) override;
+
+ uint32_t GetNumDirectBaseClasses(lldb::opaque_compiler_type_t type) override;
+
+ uint32_t GetNumVirtualBaseClasses(lldb::opaque_compiler_type_t type) override;
+
+ CompilerType GetDirectBaseClassAtIndex(lldb::opaque_compiler_type_t type,
+ size_t idx,
+ uint32_t *bit_offset_ptr) override;
+
+ CompilerType GetVirtualBaseClassAtIndex(lldb::opaque_compiler_type_t type,
+ size_t idx,
+ uint32_t *bit_offset_ptr) override;
+
+ static uint32_t GetNumPointeeChildren(clang::QualType type);
+
+ CompilerType GetChildCompilerTypeAtIndex(
+ lldb::opaque_compiler_type_t type, ExecutionContext *exe_ctx, size_t idx,
+ bool transparent_pointers, bool omit_empty_base_classes,
+ bool ignore_array_bounds, std::string &child_name,
+ uint32_t &child_byte_size, int32_t &child_byte_offset,
+ uint32_t &child_bitfield_bit_size, uint32_t &child_bitfield_bit_offset,
+ bool &child_is_base_class, bool &child_is_deref_of_parent,
+ ValueObject *valobj, uint64_t &language_flags) override;
+
+ // Lookup a child given a name. This function will match base class names and
+ // member member names in "clang_type" only, not descendants.
+ uint32_t GetIndexOfChildWithName(lldb::opaque_compiler_type_t type,
+ const char *name,
+ bool omit_empty_base_classes) override;
+
+ // Lookup a child member given a name. This function will match member names
+ // only and will descend into "clang_type" children in search for the first
+ // member in this class, or any base class that matches "name".
+ // TODO: Return all matches for a given name by returning a
+ // vector<vector<uint32_t>>
+ // so we catch all names that match a given child name, not just the first.
+ size_t
+ GetIndexOfChildMemberWithName(lldb::opaque_compiler_type_t type,
+ const char *name, bool omit_empty_base_classes,
+ std::vector<uint32_t> &child_indexes) override;
+
+ size_t GetNumTemplateArguments(lldb::opaque_compiler_type_t type) override;
+
+ lldb::TemplateArgumentKind
+ GetTemplateArgumentKind(lldb::opaque_compiler_type_t type,
+ size_t idx) override;
+ CompilerType GetTypeTemplateArgument(lldb::opaque_compiler_type_t type,
+ size_t idx) override;
+ llvm::Optional<CompilerType::IntegralTemplateArgument>
+ GetIntegralTemplateArgument(lldb::opaque_compiler_type_t type,
+ size_t idx) override;
+
+ CompilerType GetTypeForFormatters(void *type) override;
+
+#define LLDB_INVALID_DECL_LEVEL UINT32_MAX
+ // LLDB_INVALID_DECL_LEVEL is returned by CountDeclLevels if child_decl_ctx
+ // could not be found in decl_ctx.
+ uint32_t CountDeclLevels(clang::DeclContext *frame_decl_ctx,
+ clang::DeclContext *child_decl_ctx,
+ ConstString *child_name = nullptr,
+ CompilerType *child_type = nullptr);
+
+ // Modifying RecordType
+ static clang::FieldDecl *AddFieldToRecordType(const CompilerType &type,
+ llvm::StringRef name,
+ const CompilerType &field_type,
+ lldb::AccessType access,
+ uint32_t bitfield_bit_size);
+
+ static void BuildIndirectFields(const CompilerType &type);
+
+ static void SetIsPacked(const CompilerType &type);
+
+ static clang::VarDecl *AddVariableToRecordType(const CompilerType &type,
+ llvm::StringRef name,
+ const CompilerType &var_type,
+ lldb::AccessType access);
+
+ clang::CXXMethodDecl *AddMethodToCXXRecordType(
+ lldb::opaque_compiler_type_t type, llvm::StringRef name,
+ const char *mangled_name, const CompilerType &method_type,
+ lldb::AccessType access, bool is_virtual, bool is_static, bool is_inline,
+ bool is_explicit, bool is_attr_used, bool is_artificial);
+
+ void AddMethodOverridesForCXXRecordType(lldb::opaque_compiler_type_t type);
+
+ // C++ Base Classes
+ std::unique_ptr<clang::CXXBaseSpecifier>
+ CreateBaseClassSpecifier(lldb::opaque_compiler_type_t type,
+ lldb::AccessType access, bool is_virtual,
+ bool base_of_class);
+
+ bool TransferBaseClasses(
+ lldb::opaque_compiler_type_t type,
+ std::vector<std::unique_ptr<clang::CXXBaseSpecifier>> bases);
+
+ static bool SetObjCSuperClass(const CompilerType &type,
+ const CompilerType &superclass_compiler_type);
+
+ static bool AddObjCClassProperty(const CompilerType &type,
+ const char *property_name,
+ const CompilerType &property_compiler_type,
+ clang::ObjCIvarDecl *ivar_decl,
+ const char *property_setter_name,
+ const char *property_getter_name,
+ uint32_t property_attributes,
+ ClangASTMetadata *metadata);
+
+ static clang::ObjCMethodDecl *AddMethodToObjCObjectType(
+ const CompilerType &type,
+ const char *name, // the full symbol name as seen in the symbol table
+ // (lldb::opaque_compiler_type_t type, "-[NString
+ // stringWithCString:]")
+ const CompilerType &method_compiler_type, lldb::AccessType access,
+ bool is_artificial, bool is_variadic, bool is_objc_direct_call);
+
+ static bool SetHasExternalStorage(lldb::opaque_compiler_type_t type,
+ bool has_extern);
+
+ // Tag Declarations
+ static bool StartTagDeclarationDefinition(const CompilerType &type);
+
+ static bool CompleteTagDeclarationDefinition(const CompilerType &type);
+
+ // Modifying Enumeration types
+ clang::EnumConstantDecl *AddEnumerationValueToEnumerationType(
+ const CompilerType &enum_type, const Declaration &decl, const char *name,
+ int64_t enum_value, uint32_t enum_value_bit_size);
+ clang::EnumConstantDecl *AddEnumerationValueToEnumerationType(
+ const CompilerType &enum_type, const Declaration &decl, const char *name,
+ const llvm::APSInt &value);
+
+ CompilerType GetEnumerationIntegerType(lldb::opaque_compiler_type_t type);
+
+ // Pointers & References
+
+ // Call this function using the class type when you want to make a member
+ // pointer type to pointee_type.
+ static CompilerType CreateMemberPointerType(const CompilerType &type,
+ const CompilerType &pointee_type);
+
+ // Dumping types
+#ifndef NDEBUG
+ /// Convenience LLVM-style dump method for use in the debugger only.
+ /// In contrast to the other \p Dump() methods this directly invokes
+ /// \p clang::QualType::dump().
+ LLVM_DUMP_METHOD void dump(lldb::opaque_compiler_type_t type) const override;
+#endif
+
+ void Dump(Stream &s);
+
+ /// Dump clang AST types from the symbol file.
+ ///
+ /// \param[in] s
+ /// A stream to send the dumped AST node(s) to
+ /// \param[in] symbol_name
+ /// The name of the symbol to dump, if it is empty dump all the symbols
+ void DumpFromSymbolFile(Stream &s, llvm::StringRef symbol_name);
+
+ void DumpValue(lldb::opaque_compiler_type_t type, ExecutionContext *exe_ctx,
+ Stream *s, lldb::Format format, const DataExtractor &data,
+ lldb::offset_t data_offset, size_t data_byte_size,
+ uint32_t bitfield_bit_size, uint32_t bitfield_bit_offset,
+ bool show_types, bool show_summary, bool verbose,
+ uint32_t depth) override;
+
+ bool DumpTypeValue(lldb::opaque_compiler_type_t type, Stream *s,
+ lldb::Format format, const DataExtractor &data,
+ lldb::offset_t data_offset, size_t data_byte_size,
+ uint32_t bitfield_bit_size, uint32_t bitfield_bit_offset,
+ ExecutionContextScope *exe_scope) override;
+
+ void DumpSummary(lldb::opaque_compiler_type_t type, ExecutionContext *exe_ctx,
+ Stream *s, const DataExtractor &data,
+ lldb::offset_t data_offset, size_t data_byte_size) override;
+
+ void DumpTypeDescription(
+ lldb::opaque_compiler_type_t type) override; // Dump to stdout
+
+ void DumpTypeDescription(lldb::opaque_compiler_type_t type,
+ Stream *s) override;
+
+ static void DumpTypeName(const CompilerType &type);
+
+ static clang::EnumDecl *GetAsEnumDecl(const CompilerType &type);
+
+ static clang::RecordDecl *GetAsRecordDecl(const CompilerType &type);
+
+ static clang::TagDecl *GetAsTagDecl(const CompilerType &type);
+
+ static clang::TypedefNameDecl *GetAsTypedefDecl(const CompilerType &type);
+
+ static clang::CXXRecordDecl *
+ GetAsCXXRecordDecl(lldb::opaque_compiler_type_t type);
+
+ static clang::ObjCInterfaceDecl *
+ GetAsObjCInterfaceDecl(const CompilerType &type);
+
+ clang::ClassTemplateDecl *ParseClassTemplateDecl(
+ clang::DeclContext *decl_ctx, lldb::AccessType access_type,
+ const char *parent_name, int tag_decl_kind,
+ const TypeSystemClang::TemplateParameterInfos &template_param_infos);
+
+ clang::BlockDecl *CreateBlockDeclaration(clang::DeclContext *ctx);
+
+ clang::UsingDirectiveDecl *
+ CreateUsingDirectiveDeclaration(clang::DeclContext *decl_ctx,
+ clang::NamespaceDecl *ns_decl);
+
+ clang::UsingDecl *CreateUsingDeclaration(clang::DeclContext *current_decl_ctx,
+ clang::NamedDecl *target);
+
+ clang::VarDecl *CreateVariableDeclaration(clang::DeclContext *decl_context,
+ const char *name,
+ clang::QualType type);
+
+ static lldb::opaque_compiler_type_t
+ GetOpaqueCompilerType(clang::ASTContext *ast, lldb::BasicType basic_type);
+
+ static clang::QualType GetQualType(lldb::opaque_compiler_type_t type) {
+ if (type)
+ return clang::QualType::getFromOpaquePtr(type);
+ return clang::QualType();
+ }
+
+ static clang::QualType
+ GetCanonicalQualType(lldb::opaque_compiler_type_t type) {
+ if (type)
+ return clang::QualType::getFromOpaquePtr(type).getCanonicalType();
+ return clang::QualType();
+ }
+
+ clang::DeclarationName
+ GetDeclarationName(const char *name, const CompilerType &function_clang_type);
+
+private:
+ const clang::ClassTemplateSpecializationDecl *
+ GetAsTemplateSpecialization(lldb::opaque_compiler_type_t type);
+
+ // Classes that inherit from TypeSystemClang can see and modify these
+ std::string m_target_triple;
+ std::unique_ptr<clang::ASTContext> m_ast_up;
+ std::unique_ptr<clang::LangOptions> m_language_options_up;
+ std::unique_ptr<clang::FileManager> m_file_manager_up;
+ std::unique_ptr<clang::SourceManager> m_source_manager_up;
+ std::unique_ptr<clang::DiagnosticsEngine> m_diagnostics_engine_up;
+ std::unique_ptr<clang::DiagnosticConsumer> m_diagnostic_consumer_up;
+ std::shared_ptr<clang::TargetOptions> m_target_options_rp;
+ std::unique_ptr<clang::TargetInfo> m_target_info_up;
+ std::unique_ptr<clang::IdentifierTable> m_identifier_table_up;
+ std::unique_ptr<clang::SelectorTable> m_selector_table_up;
+ std::unique_ptr<clang::Builtin::Context> m_builtins_up;
+ std::unique_ptr<DWARFASTParserClang> m_dwarf_ast_parser_up;
+ std::unique_ptr<PDBASTParser> m_pdb_ast_parser_up;
+ std::unique_ptr<clang::MangleContext> m_mangle_ctx_up;
+ uint32_t m_pointer_byte_size = 0;
+ bool m_ast_owned = false;
+ /// A string describing what this TypeSystemClang represents (e.g.,
+ /// AST for debug information, an expression, some other utility ClangAST).
+ /// Useful for logging and debugging.
+ std::string m_display_name;
+
+ typedef llvm::DenseMap<const clang::Decl *, ClangASTMetadata> DeclMetadataMap;
+ /// Maps Decls to their associated ClangASTMetadata.
+ DeclMetadataMap m_decl_metadata;
+
+ typedef llvm::DenseMap<const clang::Type *, ClangASTMetadata> TypeMetadataMap;
+ /// Maps Types to their associated ClangASTMetadata.
+ TypeMetadataMap m_type_metadata;
+
+ /// The sema associated that is currently used to build this ASTContext.
+ /// May be null if we are already done parsing this ASTContext or the
+ /// ASTContext wasn't created by parsing source code.
+ clang::Sema *m_sema = nullptr;
+
+ // For TypeSystemClang only
+ TypeSystemClang(const TypeSystemClang &);
+ const TypeSystemClang &operator=(const TypeSystemClang &);
+ /// Creates the internal ASTContext.
+ void CreateASTContext();
+ void SetTargetTriple(llvm::StringRef target_triple);
+};
+
+class TypeSystemClangForExpressions : public TypeSystemClang {
+public:
+ TypeSystemClangForExpressions(Target &target, llvm::Triple triple);
+
+ ~TypeSystemClangForExpressions() override = default;
+
+ void Finalize() override;
+
+ UserExpression *
+ GetUserExpression(llvm::StringRef expr, llvm::StringRef prefix,
+ lldb::LanguageType language,
+ Expression::ResultType desired_type,
+ const EvaluateExpressionOptions &options,
+ ValueObject *ctx_obj) override;
+
+ FunctionCaller *GetFunctionCaller(const CompilerType &return_type,
+ const Address &function_address,
+ const ValueList &arg_value_list,
+ const char *name) override;
+
+ UtilityFunction *GetUtilityFunction(const char *text,
+ const char *name) override;
+
+ PersistentExpressionState *GetPersistentExpressionState() override;
+private:
+ lldb::TargetWP m_target_wp;
+ std::unique_ptr<ClangPersistentVariables>
+ m_persistent_variables; // These are the persistent variables associated
+ // with this process for the expression parser
+ std::unique_ptr<ClangASTSource> m_scratch_ast_source_up;
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_TypeSystemClang_h_
add_lldb_library(lldbSymbol
ArmUnwindInfo.cpp
Block.cpp
- TypeSystemClang.cpp
- ClangASTImporter.cpp
- ClangASTMetadata.cpp
- ClangExternalASTSourceCallbacks.cpp
- ClangUtil.cpp
CompactUnwindInfo.cpp
CompileUnit.cpp
CompilerDecl.cpp
CompilerDeclContext.cpp
CompilerType.cpp
- CxxModuleHandler.cpp
DWARFCallFrameInfo.cpp
DebugMacros.cpp
Declaration.cpp
lldbHost
lldbTarget
lldbUtility
- lldbPluginExpressionParserClang
- lldbPluginSymbolFileDWARF
- lldbPluginSymbolFilePDB
lldbPluginObjCLanguage
- lldbPluginObjCRuntime
-
- CLANG_LIBS
- clangAST
- clangBasic
- clangFrontend
LINK_COMPONENTS
Support
+++ /dev/null
-//===-- ClangASTImporter.cpp ----------------------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-#include "lldb/Symbol/ClangASTImporter.h"
-#include "lldb/Core/Module.h"
-#include "lldb/Symbol/TypeSystemClang.h"
-#include "lldb/Symbol/ClangASTMetadata.h"
-#include "lldb/Symbol/ClangUtil.h"
-#include "lldb/Utility/LLDBAssert.h"
-#include "lldb/Utility/Log.h"
-#include "clang/AST/Decl.h"
-#include "clang/AST/DeclCXX.h"
-#include "clang/AST/DeclObjC.h"
-#include "clang/Sema/Lookup.h"
-#include "clang/Sema/Sema.h"
-#include "llvm/Support/raw_ostream.h"
-
-#include <memory>
-
-using namespace lldb_private;
-using namespace clang;
-
-CompilerType ClangASTImporter::CopyType(TypeSystemClang &dst_ast,
- const CompilerType &src_type) {
- clang::ASTContext &dst_clang_ast = dst_ast.getASTContext();
-
- TypeSystemClang *src_ast =
- llvm::dyn_cast_or_null<TypeSystemClang>(src_type.GetTypeSystem());
- if (!src_ast)
- return CompilerType();
-
- clang::ASTContext &src_clang_ast = src_ast->getASTContext();
-
- clang::QualType src_qual_type = ClangUtil::GetQualType(src_type);
-
- ImporterDelegateSP delegate_sp(GetDelegate(&dst_clang_ast, &src_clang_ast));
- if (!delegate_sp)
- return CompilerType();
-
- ASTImporterDelegate::CxxModuleScope std_scope(*delegate_sp, &dst_clang_ast);
-
- llvm::Expected<QualType> ret_or_error = delegate_sp->Import(src_qual_type);
- if (!ret_or_error) {
- Log *log =
- lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS);
- LLDB_LOG_ERROR(log, ret_or_error.takeError(),
- "Couldn't import type: {0}");
- return CompilerType();
- }
-
- lldb::opaque_compiler_type_t dst_clang_type = ret_or_error->getAsOpaquePtr();
-
- if (dst_clang_type)
- return CompilerType(&dst_ast, dst_clang_type);
- return CompilerType();
-}
-
-clang::Decl *ClangASTImporter::CopyDecl(clang::ASTContext *dst_ast,
- clang::Decl *decl) {
- ImporterDelegateSP delegate_sp;
-
- clang::ASTContext *src_ast = &decl->getASTContext();
- delegate_sp = GetDelegate(dst_ast, src_ast);
-
- ASTImporterDelegate::CxxModuleScope std_scope(*delegate_sp, dst_ast);
-
- if (!delegate_sp)
- return nullptr;
-
- llvm::Expected<clang::Decl *> result = delegate_sp->Import(decl);
- if (!result) {
- Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
- LLDB_LOG_ERROR(log, result.takeError(), "Couldn't import decl: {0}");
- if (log) {
- lldb::user_id_t user_id = LLDB_INVALID_UID;
- ClangASTMetadata *metadata = GetDeclMetadata(decl);
- if (metadata)
- user_id = metadata->GetUserID();
-
- if (NamedDecl *named_decl = dyn_cast<NamedDecl>(decl))
- LLDB_LOG(log,
- " [ClangASTImporter] WARNING: Failed to import a {0} "
- "'{1}', metadata {2}",
- decl->getDeclKindName(), named_decl->getNameAsString(),
- user_id);
- else
- LLDB_LOG(log,
- " [ClangASTImporter] WARNING: Failed to import a {0}, "
- "metadata {1}",
- decl->getDeclKindName(), user_id);
- }
- return nullptr;
- }
-
- return *result;
-}
-
-class DeclContextOverride {
-private:
- struct Backup {
- clang::DeclContext *decl_context;
- clang::DeclContext *lexical_decl_context;
- };
-
- llvm::DenseMap<clang::Decl *, Backup> m_backups;
-
- void OverrideOne(clang::Decl *decl) {
- if (m_backups.find(decl) != m_backups.end()) {
- return;
- }
-
- m_backups[decl] = {decl->getDeclContext(), decl->getLexicalDeclContext()};
-
- decl->setDeclContext(decl->getASTContext().getTranslationUnitDecl());
- decl->setLexicalDeclContext(decl->getASTContext().getTranslationUnitDecl());
- }
-
- bool ChainPassesThrough(
- clang::Decl *decl, clang::DeclContext *base,
- clang::DeclContext *(clang::Decl::*contextFromDecl)(),
- clang::DeclContext *(clang::DeclContext::*contextFromContext)()) {
- for (DeclContext *decl_ctx = (decl->*contextFromDecl)(); decl_ctx;
- decl_ctx = (decl_ctx->*contextFromContext)()) {
- if (decl_ctx == base) {
- return true;
- }
- }
-
- return false;
- }
-
- clang::Decl *GetEscapedChild(clang::Decl *decl,
- clang::DeclContext *base = nullptr) {
- if (base) {
- // decl's DeclContext chains must pass through base.
-
- if (!ChainPassesThrough(decl, base, &clang::Decl::getDeclContext,
- &clang::DeclContext::getParent) ||
- !ChainPassesThrough(decl, base, &clang::Decl::getLexicalDeclContext,
- &clang::DeclContext::getLexicalParent)) {
- return decl;
- }
- } else {
- base = clang::dyn_cast<clang::DeclContext>(decl);
-
- if (!base) {
- return nullptr;
- }
- }
-
- if (clang::DeclContext *context =
- clang::dyn_cast<clang::DeclContext>(decl)) {
- for (clang::Decl *decl : context->decls()) {
- if (clang::Decl *escaped_child = GetEscapedChild(decl)) {
- return escaped_child;
- }
- }
- }
-
- return nullptr;
- }
-
- void Override(clang::Decl *decl) {
- if (clang::Decl *escaped_child = GetEscapedChild(decl)) {
- Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
-
- LLDB_LOG(log,
- " [ClangASTImporter] DeclContextOverride couldn't "
- "override ({0}Decl*){1} - its child ({2}Decl*){3} escapes",
- decl->getDeclKindName(), decl, escaped_child->getDeclKindName(),
- escaped_child);
- lldbassert(0 && "Couldn't override!");
- }
-
- OverrideOne(decl);
- }
-
-public:
- DeclContextOverride() {}
-
- void OverrideAllDeclsFromContainingFunction(clang::Decl *decl) {
- for (DeclContext *decl_context = decl->getLexicalDeclContext();
- decl_context; decl_context = decl_context->getLexicalParent()) {
- DeclContext *redecl_context = decl_context->getRedeclContext();
-
- if (llvm::isa<FunctionDecl>(redecl_context) &&
- llvm::isa<TranslationUnitDecl>(redecl_context->getLexicalParent())) {
- for (clang::Decl *child_decl : decl_context->decls()) {
- Override(child_decl);
- }
- }
- }
- }
-
- ~DeclContextOverride() {
- for (const std::pair<clang::Decl *, Backup> &backup : m_backups) {
- backup.first->setDeclContext(backup.second.decl_context);
- backup.first->setLexicalDeclContext(backup.second.lexical_decl_context);
- }
- }
-};
-
-namespace {
-/// Completes all imported TagDecls at the end of the scope.
-///
-/// While in a CompleteTagDeclsScope, every decl that could be completed will
-/// be completed at the end of the scope (including all Decls that are
-/// imported while completing the original Decls).
-class CompleteTagDeclsScope : public ClangASTImporter::NewDeclListener {
- ClangASTImporter::ImporterDelegateSP m_delegate;
- llvm::SmallVector<NamedDecl *, 32> m_decls_to_complete;
- llvm::SmallPtrSet<NamedDecl *, 32> m_decls_already_completed;
- clang::ASTContext *m_dst_ctx;
- clang::ASTContext *m_src_ctx;
- ClangASTImporter &importer;
-
-public:
- /// Constructs a CompleteTagDeclsScope.
- /// \param importer The ClangASTImporter that we should observe.
- /// \param dst_ctx The ASTContext to which Decls are imported.
- /// \param src_ctx The ASTContext from which Decls are imported.
- explicit CompleteTagDeclsScope(ClangASTImporter &importer,
- clang::ASTContext *dst_ctx,
- clang::ASTContext *src_ctx)
- : m_delegate(importer.GetDelegate(dst_ctx, src_ctx)), m_dst_ctx(dst_ctx),
- m_src_ctx(src_ctx), importer(importer) {
- m_delegate->SetImportListener(this);
- }
-
- virtual ~CompleteTagDeclsScope() {
- ClangASTImporter::ASTContextMetadataSP to_context_md =
- importer.GetContextMetadata(m_dst_ctx);
-
- // Complete all decls we collected until now.
- while (!m_decls_to_complete.empty()) {
- NamedDecl *decl = m_decls_to_complete.pop_back_val();
- m_decls_already_completed.insert(decl);
-
- // We should only complete decls coming from the source context.
- assert(to_context_md->m_origins[decl].ctx == m_src_ctx);
-
- Decl *original_decl = to_context_md->m_origins[decl].decl;
-
- // Complete the decl now.
- TypeSystemClang::GetCompleteDecl(m_src_ctx, original_decl);
- if (auto *tag_decl = dyn_cast<TagDecl>(decl)) {
- if (auto *original_tag_decl = dyn_cast<TagDecl>(original_decl)) {
- if (original_tag_decl->isCompleteDefinition()) {
- m_delegate->ImportDefinitionTo(tag_decl, original_tag_decl);
- tag_decl->setCompleteDefinition(true);
- }
- }
-
- tag_decl->setHasExternalLexicalStorage(false);
- tag_decl->setHasExternalVisibleStorage(false);
- } else if (auto *container_decl = dyn_cast<ObjCContainerDecl>(decl)) {
- container_decl->setHasExternalLexicalStorage(false);
- container_decl->setHasExternalVisibleStorage(false);
- }
-
- to_context_md->m_origins.erase(decl);
- }
-
- // Stop listening to imported decls. We do this after clearing the
- // Decls we needed to import to catch all Decls they might have pulled in.
- m_delegate->RemoveImportListener();
- }
-
- void NewDeclImported(clang::Decl *from, clang::Decl *to) override {
- // Filter out decls that we can't complete later.
- if (!isa<TagDecl>(to) && !isa<ObjCInterfaceDecl>(to))
- return;
- RecordDecl *from_record_decl = dyn_cast<RecordDecl>(from);
- // We don't need to complete injected class name decls.
- if (from_record_decl && from_record_decl->isInjectedClassName())
- return;
-
- NamedDecl *to_named_decl = dyn_cast<NamedDecl>(to);
- // Check if we already completed this type.
- if (m_decls_already_completed.count(to_named_decl) != 0)
- return;
- m_decls_to_complete.push_back(to_named_decl);
- }
-};
-} // namespace
-
-CompilerType ClangASTImporter::DeportType(TypeSystemClang &dst,
- const CompilerType &src_type) {
- Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
-
- TypeSystemClang *src_ctxt =
- llvm::cast<TypeSystemClang>(src_type.GetTypeSystem());
-
- LLDB_LOG(log,
- " [ClangASTImporter] DeportType called on ({0}Type*){1} "
- "from (ASTContext*){2} to (ASTContext*){3}",
- src_type.GetTypeName(), src_type.GetOpaqueQualType(),
- &src_ctxt->getASTContext(), &dst.getASTContext());
-
- DeclContextOverride decl_context_override;
-
- if (auto *t = ClangUtil::GetQualType(src_type)->getAs<TagType>())
- decl_context_override.OverrideAllDeclsFromContainingFunction(t->getDecl());
-
- CompleteTagDeclsScope complete_scope(*this, &dst.getASTContext(),
- &src_ctxt->getASTContext());
- return CopyType(dst, src_type);
-}
-
-clang::Decl *ClangASTImporter::DeportDecl(clang::ASTContext *dst_ctx,
- clang::Decl *decl) {
- Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
-
- clang::ASTContext *src_ctx = &decl->getASTContext();
- LLDB_LOG(log,
- " [ClangASTImporter] DeportDecl called on ({0}Decl*){1} from "
- "(ASTContext*){2} to (ASTContext*){3}",
- decl->getDeclKindName(), decl, src_ctx, dst_ctx);
-
- DeclContextOverride decl_context_override;
-
- decl_context_override.OverrideAllDeclsFromContainingFunction(decl);
-
- clang::Decl *result;
- {
- CompleteTagDeclsScope complete_scope(*this, dst_ctx, src_ctx);
- result = CopyDecl(dst_ctx, decl);
- }
-
- if (!result)
- return nullptr;
-
- LLDB_LOG(log,
- " [ClangASTImporter] DeportDecl deported ({0}Decl*){1} to "
- "({2}Decl*){3}",
- decl->getDeclKindName(), decl, result->getDeclKindName(), result);
-
- return result;
-}
-
-bool ClangASTImporter::CanImport(const CompilerType &type) {
- if (!ClangUtil::IsClangType(type))
- return false;
-
- // TODO: remove external completion BOOL
- // CompleteAndFetchChildren should get the Decl out and check for the
-
- clang::QualType qual_type(
- ClangUtil::GetCanonicalQualType(ClangUtil::RemoveFastQualifiers(type)));
-
- const clang::Type::TypeClass type_class = qual_type->getTypeClass();
- switch (type_class) {
- case clang::Type::Record: {
- const clang::CXXRecordDecl *cxx_record_decl =
- qual_type->getAsCXXRecordDecl();
- if (cxx_record_decl) {
- if (GetDeclOrigin(cxx_record_decl).Valid())
- return true;
- }
- } break;
-
- case clang::Type::Enum: {
- clang::EnumDecl *enum_decl =
- llvm::cast<clang::EnumType>(qual_type)->getDecl();
- if (enum_decl) {
- if (GetDeclOrigin(enum_decl).Valid())
- return true;
- }
- } break;
-
- case clang::Type::ObjCObject:
- case clang::Type::ObjCInterface: {
- const clang::ObjCObjectType *objc_class_type =
- llvm::dyn_cast<clang::ObjCObjectType>(qual_type);
- if (objc_class_type) {
- clang::ObjCInterfaceDecl *class_interface_decl =
- objc_class_type->getInterface();
- // We currently can't complete objective C types through the newly added
- // ASTContext because it only supports TagDecl objects right now...
- if (class_interface_decl) {
- if (GetDeclOrigin(class_interface_decl).Valid())
- return true;
- }
- }
- } break;
-
- case clang::Type::Typedef:
- return CanImport(CompilerType(type.GetTypeSystem(),
- llvm::cast<clang::TypedefType>(qual_type)
- ->getDecl()
- ->getUnderlyingType()
- .getAsOpaquePtr()));
-
- case clang::Type::Auto:
- return CanImport(CompilerType(type.GetTypeSystem(),
- llvm::cast<clang::AutoType>(qual_type)
- ->getDeducedType()
- .getAsOpaquePtr()));
-
- case clang::Type::Elaborated:
- return CanImport(CompilerType(type.GetTypeSystem(),
- llvm::cast<clang::ElaboratedType>(qual_type)
- ->getNamedType()
- .getAsOpaquePtr()));
-
- case clang::Type::Paren:
- return CanImport(CompilerType(
- type.GetTypeSystem(),
- llvm::cast<clang::ParenType>(qual_type)->desugar().getAsOpaquePtr()));
-
- default:
- break;
- }
-
- return false;
-}
-
-bool ClangASTImporter::Import(const CompilerType &type) {
- if (!ClangUtil::IsClangType(type))
- return false;
- // TODO: remove external completion BOOL
- // CompleteAndFetchChildren should get the Decl out and check for the
-
- clang::QualType qual_type(
- ClangUtil::GetCanonicalQualType(ClangUtil::RemoveFastQualifiers(type)));
-
- const clang::Type::TypeClass type_class = qual_type->getTypeClass();
- switch (type_class) {
- case clang::Type::Record: {
- const clang::CXXRecordDecl *cxx_record_decl =
- qual_type->getAsCXXRecordDecl();
- if (cxx_record_decl) {
- if (GetDeclOrigin(cxx_record_decl).Valid())
- return CompleteAndFetchChildren(qual_type);
- }
- } break;
-
- case clang::Type::Enum: {
- clang::EnumDecl *enum_decl =
- llvm::cast<clang::EnumType>(qual_type)->getDecl();
- if (enum_decl) {
- if (GetDeclOrigin(enum_decl).Valid())
- return CompleteAndFetchChildren(qual_type);
- }
- } break;
-
- case clang::Type::ObjCObject:
- case clang::Type::ObjCInterface: {
- const clang::ObjCObjectType *objc_class_type =
- llvm::dyn_cast<clang::ObjCObjectType>(qual_type);
- if (objc_class_type) {
- clang::ObjCInterfaceDecl *class_interface_decl =
- objc_class_type->getInterface();
- // We currently can't complete objective C types through the newly added
- // ASTContext because it only supports TagDecl objects right now...
- if (class_interface_decl) {
- if (GetDeclOrigin(class_interface_decl).Valid())
- return CompleteAndFetchChildren(qual_type);
- }
- }
- } break;
-
- case clang::Type::Typedef:
- return Import(CompilerType(type.GetTypeSystem(),
- llvm::cast<clang::TypedefType>(qual_type)
- ->getDecl()
- ->getUnderlyingType()
- .getAsOpaquePtr()));
-
- case clang::Type::Auto:
- return Import(CompilerType(type.GetTypeSystem(),
- llvm::cast<clang::AutoType>(qual_type)
- ->getDeducedType()
- .getAsOpaquePtr()));
-
- case clang::Type::Elaborated:
- return Import(CompilerType(type.GetTypeSystem(),
- llvm::cast<clang::ElaboratedType>(qual_type)
- ->getNamedType()
- .getAsOpaquePtr()));
-
- case clang::Type::Paren:
- return Import(CompilerType(
- type.GetTypeSystem(),
- llvm::cast<clang::ParenType>(qual_type)->desugar().getAsOpaquePtr()));
-
- default:
- break;
- }
- return false;
-}
-
-bool ClangASTImporter::CompleteType(const CompilerType &compiler_type) {
- if (!CanImport(compiler_type))
- return false;
-
- if (Import(compiler_type)) {
- TypeSystemClang::CompleteTagDeclarationDefinition(compiler_type);
- return true;
- }
-
- TypeSystemClang::SetHasExternalStorage(compiler_type.GetOpaqueQualType(),
- false);
- return false;
-}
-
-bool ClangASTImporter::LayoutRecordType(
- const clang::RecordDecl *record_decl, uint64_t &bit_size,
- uint64_t &alignment,
- llvm::DenseMap<const clang::FieldDecl *, uint64_t> &field_offsets,
- llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits>
- &base_offsets,
- llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits>
- &vbase_offsets) {
- RecordDeclToLayoutMap::iterator pos =
- m_record_decl_to_layout_map.find(record_decl);
- bool success = false;
- base_offsets.clear();
- vbase_offsets.clear();
- if (pos != m_record_decl_to_layout_map.end()) {
- bit_size = pos->second.bit_size;
- alignment = pos->second.alignment;
- field_offsets.swap(pos->second.field_offsets);
- base_offsets.swap(pos->second.base_offsets);
- vbase_offsets.swap(pos->second.vbase_offsets);
- m_record_decl_to_layout_map.erase(pos);
- success = true;
- } else {
- bit_size = 0;
- alignment = 0;
- field_offsets.clear();
- }
- return success;
-}
-
-void ClangASTImporter::SetRecordLayout(clang::RecordDecl *decl,
- const LayoutInfo &layout) {
- m_record_decl_to_layout_map.insert(std::make_pair(decl, layout));
-}
-
-bool ClangASTImporter::CompleteTagDecl(clang::TagDecl *decl) {
- DeclOrigin decl_origin = GetDeclOrigin(decl);
-
- if (!decl_origin.Valid())
- return false;
-
- if (!TypeSystemClang::GetCompleteDecl(decl_origin.ctx, decl_origin.decl))
- return false;
-
- ImporterDelegateSP delegate_sp(
- GetDelegate(&decl->getASTContext(), decl_origin.ctx));
-
- ASTImporterDelegate::CxxModuleScope std_scope(*delegate_sp,
- &decl->getASTContext());
- if (delegate_sp)
- delegate_sp->ImportDefinitionTo(decl, decl_origin.decl);
-
- return true;
-}
-
-bool ClangASTImporter::CompleteTagDeclWithOrigin(clang::TagDecl *decl,
- clang::TagDecl *origin_decl) {
- clang::ASTContext *origin_ast_ctx = &origin_decl->getASTContext();
-
- if (!TypeSystemClang::GetCompleteDecl(origin_ast_ctx, origin_decl))
- return false;
-
- ImporterDelegateSP delegate_sp(
- GetDelegate(&decl->getASTContext(), origin_ast_ctx));
-
- if (delegate_sp)
- delegate_sp->ImportDefinitionTo(decl, origin_decl);
-
- ASTContextMetadataSP context_md = GetContextMetadata(&decl->getASTContext());
-
- OriginMap &origins = context_md->m_origins;
-
- origins[decl] = DeclOrigin(origin_ast_ctx, origin_decl);
-
- return true;
-}
-
-bool ClangASTImporter::CompleteObjCInterfaceDecl(
- clang::ObjCInterfaceDecl *interface_decl) {
- DeclOrigin decl_origin = GetDeclOrigin(interface_decl);
-
- if (!decl_origin.Valid())
- return false;
-
- if (!TypeSystemClang::GetCompleteDecl(decl_origin.ctx, decl_origin.decl))
- return false;
-
- ImporterDelegateSP delegate_sp(
- GetDelegate(&interface_decl->getASTContext(), decl_origin.ctx));
-
- if (delegate_sp)
- delegate_sp->ImportDefinitionTo(interface_decl, decl_origin.decl);
-
- if (ObjCInterfaceDecl *super_class = interface_decl->getSuperClass())
- RequireCompleteType(clang::QualType(super_class->getTypeForDecl(), 0));
-
- return true;
-}
-
-bool ClangASTImporter::CompleteAndFetchChildren(clang::QualType type) {
- if (!RequireCompleteType(type))
- return false;
-
- Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS);
-
- if (const TagType *tag_type = type->getAs<TagType>()) {
- TagDecl *tag_decl = tag_type->getDecl();
-
- DeclOrigin decl_origin = GetDeclOrigin(tag_decl);
-
- if (!decl_origin.Valid())
- return false;
-
- ImporterDelegateSP delegate_sp(
- GetDelegate(&tag_decl->getASTContext(), decl_origin.ctx));
-
- ASTImporterDelegate::CxxModuleScope std_scope(*delegate_sp,
- &tag_decl->getASTContext());
-
- TagDecl *origin_tag_decl = llvm::dyn_cast<TagDecl>(decl_origin.decl);
-
- for (Decl *origin_child_decl : origin_tag_decl->decls()) {
- llvm::Expected<Decl *> imported_or_err =
- delegate_sp->Import(origin_child_decl);
- if (!imported_or_err) {
- LLDB_LOG_ERROR(log, imported_or_err.takeError(),
- "Couldn't import decl: {0}");
- return false;
- }
- }
-
- if (RecordDecl *record_decl = dyn_cast<RecordDecl>(origin_tag_decl))
- record_decl->setHasLoadedFieldsFromExternalStorage(true);
-
- return true;
- }
-
- if (const ObjCObjectType *objc_object_type = type->getAs<ObjCObjectType>()) {
- if (ObjCInterfaceDecl *objc_interface_decl =
- objc_object_type->getInterface()) {
- DeclOrigin decl_origin = GetDeclOrigin(objc_interface_decl);
-
- if (!decl_origin.Valid())
- return false;
-
- ImporterDelegateSP delegate_sp(
- GetDelegate(&objc_interface_decl->getASTContext(), decl_origin.ctx));
-
- ObjCInterfaceDecl *origin_interface_decl =
- llvm::dyn_cast<ObjCInterfaceDecl>(decl_origin.decl);
-
- for (Decl *origin_child_decl : origin_interface_decl->decls()) {
- llvm::Expected<Decl *> imported_or_err =
- delegate_sp->Import(origin_child_decl);
- if (!imported_or_err) {
- LLDB_LOG_ERROR(log, imported_or_err.takeError(),
- "Couldn't import decl: {0}");
- return false;
- }
- }
-
- return true;
- }
- return false;
- }
-
- return true;
-}
-
-bool ClangASTImporter::RequireCompleteType(clang::QualType type) {
- if (type.isNull())
- return false;
-
- if (const TagType *tag_type = type->getAs<TagType>()) {
- TagDecl *tag_decl = tag_type->getDecl();
-
- if (tag_decl->getDefinition() || tag_decl->isBeingDefined())
- return true;
-
- return CompleteTagDecl(tag_decl);
- }
- if (const ObjCObjectType *objc_object_type = type->getAs<ObjCObjectType>()) {
- if (ObjCInterfaceDecl *objc_interface_decl =
- objc_object_type->getInterface())
- return CompleteObjCInterfaceDecl(objc_interface_decl);
- return false;
- }
- if (const ArrayType *array_type = type->getAsArrayTypeUnsafe())
- return RequireCompleteType(array_type->getElementType());
- if (const AtomicType *atomic_type = type->getAs<AtomicType>())
- return RequireCompleteType(atomic_type->getPointeeType());
-
- return true;
-}
-
-ClangASTMetadata *ClangASTImporter::GetDeclMetadata(const clang::Decl *decl) {
- DeclOrigin decl_origin = GetDeclOrigin(decl);
-
- if (decl_origin.Valid()) {
- TypeSystemClang *ast = TypeSystemClang::GetASTContext(decl_origin.ctx);
- return ast->GetMetadata(decl_origin.decl);
- }
- TypeSystemClang *ast = TypeSystemClang::GetASTContext(&decl->getASTContext());
- return ast->GetMetadata(decl);
-}
-
-ClangASTImporter::DeclOrigin
-ClangASTImporter::GetDeclOrigin(const clang::Decl *decl) {
- ASTContextMetadataSP context_md = GetContextMetadata(&decl->getASTContext());
-
- OriginMap &origins = context_md->m_origins;
-
- OriginMap::iterator iter = origins.find(decl);
-
- if (iter != origins.end())
- return iter->second;
- return DeclOrigin();
-}
-
-void ClangASTImporter::SetDeclOrigin(const clang::Decl *decl,
- clang::Decl *original_decl) {
- ASTContextMetadataSP context_md = GetContextMetadata(&decl->getASTContext());
-
- OriginMap &origins = context_md->m_origins;
-
- OriginMap::iterator iter = origins.find(decl);
-
- if (iter != origins.end()) {
- iter->second.decl = original_decl;
- iter->second.ctx = &original_decl->getASTContext();
- return;
- }
- origins[decl] = DeclOrigin(&original_decl->getASTContext(), original_decl);
-}
-
-void ClangASTImporter::RegisterNamespaceMap(const clang::NamespaceDecl *decl,
- NamespaceMapSP &namespace_map) {
- ASTContextMetadataSP context_md = GetContextMetadata(&decl->getASTContext());
-
- context_md->m_namespace_maps[decl] = namespace_map;
-}
-
-ClangASTImporter::NamespaceMapSP
-ClangASTImporter::GetNamespaceMap(const clang::NamespaceDecl *decl) {
- ASTContextMetadataSP context_md = GetContextMetadata(&decl->getASTContext());
-
- NamespaceMetaMap &namespace_maps = context_md->m_namespace_maps;
-
- NamespaceMetaMap::iterator iter = namespace_maps.find(decl);
-
- if (iter != namespace_maps.end())
- return iter->second;
- return NamespaceMapSP();
-}
-
-void ClangASTImporter::BuildNamespaceMap(const clang::NamespaceDecl *decl) {
- assert(decl);
- ASTContextMetadataSP context_md = GetContextMetadata(&decl->getASTContext());
-
- const DeclContext *parent_context = decl->getDeclContext();
- const NamespaceDecl *parent_namespace =
- dyn_cast<NamespaceDecl>(parent_context);
- NamespaceMapSP parent_map;
-
- if (parent_namespace)
- parent_map = GetNamespaceMap(parent_namespace);
-
- NamespaceMapSP new_map;
-
- new_map = std::make_shared<NamespaceMap>();
-
- if (context_md->m_map_completer) {
- std::string namespace_string = decl->getDeclName().getAsString();
-
- context_md->m_map_completer->CompleteNamespaceMap(
- new_map, ConstString(namespace_string.c_str()), parent_map);
- }
-
- context_md->m_namespace_maps[decl] = new_map;
-}
-
-void ClangASTImporter::ForgetDestination(clang::ASTContext *dst_ast) {
- Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
-
- LLDB_LOG(log,
- " [ClangASTImporter] Forgetting destination (ASTContext*){0}",
- dst_ast);
-
- m_metadata_map.erase(dst_ast);
-}
-
-void ClangASTImporter::ForgetSource(clang::ASTContext *dst_ast,
- clang::ASTContext *src_ast) {
- ASTContextMetadataSP md = MaybeGetContextMetadata(dst_ast);
-
- Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
-
- LLDB_LOG(log,
- " [ClangASTImporter] Forgetting source->dest "
- "(ASTContext*){0}->(ASTContext*){1}",
- src_ast, dst_ast);
-
- if (!md)
- return;
-
- md->m_delegates.erase(src_ast);
-
- for (OriginMap::iterator iter = md->m_origins.begin();
- iter != md->m_origins.end();) {
- if (iter->second.ctx == src_ast)
- md->m_origins.erase(iter++);
- else
- ++iter;
- }
-}
-
-ClangASTImporter::MapCompleter::~MapCompleter() { return; }
-
-llvm::Expected<Decl *>
-ClangASTImporter::ASTImporterDelegate::ImportImpl(Decl *From) {
- if (m_std_handler) {
- llvm::Optional<Decl *> D = m_std_handler->Import(From);
- if (D) {
- // Make sure we don't use this decl later to map it back to it's original
- // decl. The decl the CxxModuleHandler created has nothing to do with
- // the one from debug info, and linking those two would just cause the
- // ASTImporter to try 'updating' the module decl with the minimal one from
- // the debug info.
- m_decls_to_ignore.insert(*D);
- return *D;
- }
- }
-
- // Check which ASTContext this declaration originally came from.
- DeclOrigin origin = m_master.GetDeclOrigin(From);
- // If it originally came from the target ASTContext then we can just
- // pretend that the original is the one we imported. This can happen for
- // example when inspecting a persistent declaration from the scratch
- // ASTContext (which will provide the declaration when parsing the
- // expression and then we later try to copy the declaration back to the
- // scratch ASTContext to store the result).
- // Without this check we would ask the ASTImporter to import a declaration
- // into the same ASTContext where it came from (which doesn't make a lot of
- // sense).
- if (origin.Valid() && origin.ctx == &getToContext()) {
- RegisterImportedDecl(From, origin.decl);
- return origin.decl;
- }
-
- // This declaration came originally from another ASTContext. Instead of
- // copying our potentially incomplete 'From' Decl we instead go to the
- // original ASTContext and copy the original to the target. This is not
- // only faster than first completing our current decl and then copying it
- // to the target, but it also prevents that indirectly copying the same
- // declaration to the same target requires the ASTImporter to merge all
- // the different decls that appear to come from different ASTContexts (even
- // though all these different source ASTContexts just got a copy from
- // one source AST).
- if (origin.Valid()) {
- auto R = m_master.CopyDecl(&getToContext(), origin.decl);
- if (R) {
- RegisterImportedDecl(From, R);
- return R;
- }
- }
-
- return ASTImporter::ImportImpl(From);
-}
-
-void ClangASTImporter::ASTImporterDelegate::ImportDefinitionTo(
- clang::Decl *to, clang::Decl *from) {
- // We might have a forward declaration from a shared library that we
- // gave external lexical storage so that Clang asks us about the full
- // definition when it needs it. In this case the ASTImporter isn't aware
- // that the forward decl from the shared library is the actual import
- // target but would create a second declaration that would then be defined.
- // We want that 'to' is actually complete after this function so let's
- // tell the ASTImporter that 'to' was imported from 'from'.
- MapImported(from, to);
- ASTImporter::Imported(from, to);
-
- /*
- if (to_objc_interface)
- to_objc_interface->startDefinition();
-
- CXXRecordDecl *to_cxx_record = dyn_cast<CXXRecordDecl>(to);
-
- if (to_cxx_record)
- to_cxx_record->startDefinition();
- */
-
- Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS);
-
- if (llvm::Error err = ImportDefinition(from)) {
- LLDB_LOG_ERROR(log, std::move(err),
- "[ClangASTImporter] Error during importing definition: {0}");
- return;
- }
-
- if (clang::TagDecl *to_tag = dyn_cast<clang::TagDecl>(to)) {
- if (clang::TagDecl *from_tag = dyn_cast<clang::TagDecl>(from)) {
- to_tag->setCompleteDefinition(from_tag->isCompleteDefinition());
-
- if (Log *log_ast =
- lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_AST)) {
- std::string name_string;
- if (NamedDecl *from_named_decl = dyn_cast<clang::NamedDecl>(from)) {
- llvm::raw_string_ostream name_stream(name_string);
- from_named_decl->printName(name_stream);
- name_stream.flush();
- }
- LLDB_LOG(log_ast, "==== [ClangASTImporter][TUDecl: {0}] Imported "
- "({1}Decl*){2}, named {3} (from "
- "(Decl*){4})",
- static_cast<void *>(to->getTranslationUnitDecl()),
- from->getDeclKindName(), static_cast<void *>(to), name_string,
- static_cast<void *>(from));
-
- // Log the AST of the TU.
- std::string ast_string;
- llvm::raw_string_ostream ast_stream(ast_string);
- to->getTranslationUnitDecl()->dump(ast_stream);
- LLDB_LOG(log_ast, "{0}", ast_string);
- }
- }
- }
-
- // If we're dealing with an Objective-C class, ensure that the inheritance
- // has been set up correctly. The ASTImporter may not do this correctly if
- // the class was originally sourced from symbols.
-
- if (ObjCInterfaceDecl *to_objc_interface = dyn_cast<ObjCInterfaceDecl>(to)) {
- do {
- ObjCInterfaceDecl *to_superclass = to_objc_interface->getSuperClass();
-
- if (to_superclass)
- break; // we're not going to override it if it's set
-
- ObjCInterfaceDecl *from_objc_interface =
- dyn_cast<ObjCInterfaceDecl>(from);
-
- if (!from_objc_interface)
- break;
-
- ObjCInterfaceDecl *from_superclass = from_objc_interface->getSuperClass();
-
- if (!from_superclass)
- break;
-
- llvm::Expected<Decl *> imported_from_superclass_decl =
- Import(from_superclass);
-
- if (!imported_from_superclass_decl) {
- LLDB_LOG_ERROR(log, imported_from_superclass_decl.takeError(),
- "Couldn't import decl: {0}");
- break;
- }
-
- ObjCInterfaceDecl *imported_from_superclass =
- dyn_cast<ObjCInterfaceDecl>(*imported_from_superclass_decl);
-
- if (!imported_from_superclass)
- break;
-
- if (!to_objc_interface->hasDefinition())
- to_objc_interface->startDefinition();
-
- to_objc_interface->setSuperClass(m_source_ctx->getTrivialTypeSourceInfo(
- m_source_ctx->getObjCInterfaceType(imported_from_superclass)));
- } while (false);
- }
-}
-
-/// Takes a CXXMethodDecl and completes the return type if necessary. This
-/// is currently only necessary for virtual functions with covariant return
-/// types where Clang's CodeGen expects that the underlying records are already
-/// completed.
-static void MaybeCompleteReturnType(ClangASTImporter &importer,
- CXXMethodDecl *to_method) {
- if (!to_method->isVirtual())
- return;
- QualType return_type = to_method->getReturnType();
- if (!return_type->isPointerType() && !return_type->isReferenceType())
- return;
-
- clang::RecordDecl *rd = return_type->getPointeeType()->getAsRecordDecl();
- if (!rd)
- return;
-
- importer.CompleteTagDecl(rd);
-}
-
-void ClangASTImporter::ASTImporterDelegate::Imported(clang::Decl *from,
- clang::Decl *to) {
- Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
-
- // Some decls shouldn't be tracked here because they were not created by
- // copying 'from' to 'to'. Just exit early for those.
- if (m_decls_to_ignore.find(to) != m_decls_to_ignore.end())
- return clang::ASTImporter::Imported(from, to);
-
- lldb::user_id_t user_id = LLDB_INVALID_UID;
- ClangASTMetadata *metadata = m_master.GetDeclMetadata(from);
- if (metadata)
- user_id = metadata->GetUserID();
-
- if (log) {
- if (NamedDecl *from_named_decl = dyn_cast<clang::NamedDecl>(from)) {
- std::string name_string;
- llvm::raw_string_ostream name_stream(name_string);
- from_named_decl->printName(name_stream);
- name_stream.flush();
-
- LLDB_LOG(log,
- " [ClangASTImporter] Imported ({0}Decl*){1}, named {2} (from "
- "(Decl*){3}), metadata {4}",
- from->getDeclKindName(), to, name_string, from, user_id);
- } else {
- LLDB_LOG(log,
- " [ClangASTImporter] Imported ({0}Decl*){1} (from "
- "(Decl*){2}), metadata {3}",
- from->getDeclKindName(), to, from, user_id);
- }
- }
-
- ASTContextMetadataSP to_context_md =
- m_master.GetContextMetadata(&to->getASTContext());
- ASTContextMetadataSP from_context_md =
- m_master.MaybeGetContextMetadata(m_source_ctx);
-
- if (from_context_md) {
- OriginMap &origins = from_context_md->m_origins;
-
- OriginMap::iterator origin_iter = origins.find(from);
-
- if (origin_iter != origins.end()) {
- if (to_context_md->m_origins.find(to) == to_context_md->m_origins.end() ||
- user_id != LLDB_INVALID_UID) {
- if (origin_iter->second.ctx != &to->getASTContext())
- to_context_md->m_origins[to] = origin_iter->second;
- }
-
- ImporterDelegateSP direct_completer =
- m_master.GetDelegate(&to->getASTContext(), origin_iter->second.ctx);
-
- if (direct_completer.get() != this)
- direct_completer->ASTImporter::Imported(origin_iter->second.decl, to);
-
- LLDB_LOG(log,
- " [ClangASTImporter] Propagated origin "
- "(Decl*){0}/(ASTContext*){1} from (ASTContext*){2} to "
- "(ASTContext*){3}",
- origin_iter->second.decl, origin_iter->second.ctx,
- &from->getASTContext(), &to->getASTContext());
- } else {
- if (m_new_decl_listener)
- m_new_decl_listener->NewDeclImported(from, to);
-
- if (to_context_md->m_origins.find(to) == to_context_md->m_origins.end() ||
- user_id != LLDB_INVALID_UID) {
- to_context_md->m_origins[to] = DeclOrigin(m_source_ctx, from);
- }
-
- LLDB_LOG(log,
- " [ClangASTImporter] Decl has no origin information in "
- "(ASTContext*){0}",
- &from->getASTContext());
- }
-
- if (auto *to_namespace = dyn_cast<clang::NamespaceDecl>(to)) {
- auto *from_namespace = cast<clang::NamespaceDecl>(from);
-
- NamespaceMetaMap &namespace_maps = from_context_md->m_namespace_maps;
-
- NamespaceMetaMap::iterator namespace_map_iter =
- namespace_maps.find(from_namespace);
-
- if (namespace_map_iter != namespace_maps.end())
- to_context_md->m_namespace_maps[to_namespace] =
- namespace_map_iter->second;
- }
- } else {
- to_context_md->m_origins[to] = DeclOrigin(m_source_ctx, from);
-
- LLDB_LOG(log,
- " [ClangASTImporter] Sourced origin "
- "(Decl*){0}/(ASTContext*){1} into (ASTContext*){2}",
- from, m_source_ctx, &to->getASTContext());
- }
-
- if (auto *to_tag_decl = dyn_cast<TagDecl>(to)) {
- to_tag_decl->setHasExternalLexicalStorage();
- to_tag_decl->getPrimaryContext()->setMustBuildLookupTable();
- auto from_tag_decl = cast<TagDecl>(from);
-
- LLDB_LOG(
- log,
- " [ClangASTImporter] To is a TagDecl - attributes {0}{1} [{2}->{3}]",
- (to_tag_decl->hasExternalLexicalStorage() ? " Lexical" : ""),
- (to_tag_decl->hasExternalVisibleStorage() ? " Visible" : ""),
- (from_tag_decl->isCompleteDefinition() ? "complete" : "incomplete"),
- (to_tag_decl->isCompleteDefinition() ? "complete" : "incomplete"));
- }
-
- if (auto *to_namespace_decl = dyn_cast<NamespaceDecl>(to)) {
- m_master.BuildNamespaceMap(to_namespace_decl);
- to_namespace_decl->setHasExternalVisibleStorage();
- }
-
- if (auto *to_container_decl = dyn_cast<ObjCContainerDecl>(to)) {
- to_container_decl->setHasExternalLexicalStorage();
- to_container_decl->setHasExternalVisibleStorage();
-
- if (log) {
- if (ObjCInterfaceDecl *to_interface_decl =
- llvm::dyn_cast<ObjCInterfaceDecl>(to_container_decl)) {
- LLDB_LOG(
- log,
- " [ClangASTImporter] To is an ObjCInterfaceDecl - attributes "
- "{0}{1}{2}",
- (to_interface_decl->hasExternalLexicalStorage() ? " Lexical" : ""),
- (to_interface_decl->hasExternalVisibleStorage() ? " Visible" : ""),
- (to_interface_decl->hasDefinition() ? " HasDefinition" : ""));
- } else {
- LLDB_LOG(
- log, " [ClangASTImporter] To is an {0}Decl - attributes {1}{2}",
- ((Decl *)to_container_decl)->getDeclKindName(),
- (to_container_decl->hasExternalLexicalStorage() ? " Lexical" : ""),
- (to_container_decl->hasExternalVisibleStorage() ? " Visible" : ""));
- }
- }
- }
-
- if (clang::CXXMethodDecl *to_method = dyn_cast<CXXMethodDecl>(to))
- MaybeCompleteReturnType(m_master, to_method);
-}
-
-clang::Decl *
-ClangASTImporter::ASTImporterDelegate::GetOriginalDecl(clang::Decl *To) {
- return m_master.GetDeclOrigin(To).decl;
-}
+++ /dev/null
-//===-- ClangASTMetadata.cpp ----------------------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-#include "lldb/Symbol/ClangASTMetadata.h"
-#include "lldb/Utility/Stream.h"
-
-using namespace lldb_private;
-
-void ClangASTMetadata::Dump(Stream *s) {
- lldb::user_id_t uid = GetUserID();
-
- if (uid != LLDB_INVALID_UID) {
- s->Printf("uid=0x%" PRIx64, uid);
- }
-
- uint64_t isa_ptr = GetISAPtr();
- if (isa_ptr != 0) {
- s->Printf("isa_ptr=0x%" PRIx64, isa_ptr);
- }
-
- const char *obj_ptr_name = GetObjectPtrName();
- if (obj_ptr_name) {
- s->Printf("obj_ptr_name=\"%s\" ", obj_ptr_name);
- }
-
- if (m_is_dynamic_cxx) {
- s->Printf("is_dynamic_cxx=%i ", m_is_dynamic_cxx);
- }
- s->EOL();
-}
+++ /dev/null
-//===-- ClangExternalASTSourceCallbacks.cpp -------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-#include "lldb/Symbol/ClangExternalASTSourceCallbacks.h"
-#include "lldb/Symbol/TypeSystemClang.h"
-
-#include "clang/AST/Decl.h"
-
-using namespace lldb_private;
-
-void ClangExternalASTSourceCallbacks::CompleteType(clang::TagDecl *tag_decl) {
- m_ast.CompleteTagDecl(tag_decl);
-}
-
-void ClangExternalASTSourceCallbacks::CompleteType(
- clang::ObjCInterfaceDecl *objc_decl) {
- m_ast.CompleteObjCInterfaceDecl(objc_decl);
-}
-
-bool ClangExternalASTSourceCallbacks::layoutRecordType(
- const clang::RecordDecl *Record, uint64_t &Size, uint64_t &Alignment,
- llvm::DenseMap<const clang::FieldDecl *, uint64_t> &FieldOffsets,
- llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits> &BaseOffsets,
- llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits>
- &VirtualBaseOffsets) {
- return m_ast.LayoutRecordType(Record, Size, Alignment, FieldOffsets,
- BaseOffsets, VirtualBaseOffsets);
-}
-
-void ClangExternalASTSourceCallbacks::FindExternalLexicalDecls(
- const clang::DeclContext *decl_ctx,
- llvm::function_ref<bool(clang::Decl::Kind)> IsKindWeWant,
- llvm::SmallVectorImpl<clang::Decl *> &decls) {
- if (decl_ctx) {
- clang::TagDecl *tag_decl = llvm::dyn_cast<clang::TagDecl>(
- const_cast<clang::DeclContext *>(decl_ctx));
- if (tag_decl)
- CompleteType(tag_decl);
- }
-}
+++ /dev/null
-//===-- ClangUtil.cpp -----------------------------------------------------===//
-//
-// 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
-//
-// A collection of helper methods and data structures for manipulating clang
-// types and decls.
-//===----------------------------------------------------------------------===//
-
-#include "lldb/Symbol/ClangUtil.h"
-#include "lldb/Symbol/TypeSystemClang.h"
-
-using namespace clang;
-using namespace lldb_private;
-
-bool ClangUtil::IsClangType(const CompilerType &ct) {
- // Invalid types are never Clang types.
- if (!ct)
- return false;
-
- if (llvm::dyn_cast_or_null<TypeSystemClang>(ct.GetTypeSystem()) == nullptr)
- return false;
-
- if (!ct.GetOpaqueQualType())
- return false;
-
- return true;
-}
-
-clang::Decl *ClangUtil::GetDecl(const CompilerDecl &decl) {
- assert(llvm::isa<TypeSystemClang>(decl.GetTypeSystem()));
- return static_cast<clang::Decl *>(decl.GetOpaqueDecl());
-}
-
-QualType ClangUtil::GetQualType(const CompilerType &ct) {
- // Make sure we have a clang type before making a clang::QualType
- if (!IsClangType(ct))
- return QualType();
-
- return QualType::getFromOpaquePtr(ct.GetOpaqueQualType());
-}
-
-QualType ClangUtil::GetCanonicalQualType(const CompilerType &ct) {
- if (!IsClangType(ct))
- return QualType();
-
- return GetQualType(ct).getCanonicalType();
-}
-
-CompilerType ClangUtil::RemoveFastQualifiers(const CompilerType &ct) {
- if (!IsClangType(ct))
- return ct;
-
- QualType qual_type(GetQualType(ct));
- qual_type.removeLocalFastQualifiers();
- return CompilerType(ct.GetTypeSystem(), qual_type.getAsOpaquePtr());
-}
-
-clang::TagDecl *ClangUtil::GetAsTagDecl(const CompilerType &type) {
- clang::QualType qual_type = ClangUtil::GetCanonicalQualType(type);
- if (qual_type.isNull())
- return nullptr;
-
- return qual_type->getAsTagDecl();
-}
-
-std::string ClangUtil::DumpDecl(const clang::Decl *d) {
- if (!d)
- return "nullptr";
-
- std::string result;
- llvm::raw_string_ostream stream(result);
- bool deserialize = false;
- d->dump(stream, deserialize);
-
- stream.flush();
- return result;
-}
-
-std::string ClangUtil::ToString(const clang::Type *t) {
- return clang::QualType(t, 0).getAsString();
-}
-
-std::string ClangUtil::ToString(const CompilerType &c) {
- return ClangUtil::GetQualType(c).getAsString();
-}
+++ /dev/null
-//===-- CxxModuleHandler.cpp ----------------------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-#include "lldb/Symbol/CxxModuleHandler.h"
-
-#include "lldb/Symbol/TypeSystemClang.h"
-#include "lldb/Utility/Log.h"
-#include "clang/Sema/Lookup.h"
-#include "llvm/Support/Error.h"
-
-using namespace lldb_private;
-using namespace clang;
-
-CxxModuleHandler::CxxModuleHandler(ASTImporter &importer, ASTContext *target)
- : m_importer(&importer),
- m_sema(TypeSystemClang::GetASTContext(target)->getSema()) {
-
- std::initializer_list<const char *> supported_names = {
- // containers
- "deque",
- "forward_list",
- "list",
- "queue",
- "stack",
- "vector",
- // pointers
- "shared_ptr",
- "unique_ptr",
- "weak_ptr",
- // utility
- "allocator",
- };
- m_supported_templates.insert(supported_names.begin(), supported_names.end());
-}
-
-/// Builds a list of scopes that point into the given context.
-///
-/// \param sema The sema that will be using the scopes.
-/// \param ctxt The context that the scope should look into.
-/// \param result A list of scopes. The scopes need to be freed by the caller
-/// (except the TUScope which is owned by the sema).
-static void makeScopes(Sema &sema, DeclContext *ctxt,
- std::vector<Scope *> &result) {
- // FIXME: The result should be a list of unique_ptrs, but the TUScope makes
- // this currently impossible as it's owned by the Sema.
-
- if (auto parent = ctxt->getParent()) {
- makeScopes(sema, parent, result);
-
- Scope *scope =
- new Scope(result.back(), Scope::DeclScope, sema.getDiagnostics());
- scope->setEntity(ctxt);
- result.push_back(scope);
- } else
- result.push_back(sema.TUScope);
-}
-
-/// Uses the Sema to look up the given name in the given DeclContext.
-static std::unique_ptr<LookupResult>
-emulateLookupInCtxt(Sema &sema, llvm::StringRef name, DeclContext *ctxt) {
- IdentifierInfo &ident = sema.getASTContext().Idents.get(name);
-
- std::unique_ptr<LookupResult> lookup_result;
- lookup_result.reset(new LookupResult(sema, DeclarationName(&ident),
- SourceLocation(),
- Sema::LookupOrdinaryName));
-
- // Usually during parsing we already encountered the scopes we would use. But
- // here don't have these scopes so we have to emulate the behavior of the
- // Sema during parsing.
- std::vector<Scope *> scopes;
- makeScopes(sema, ctxt, scopes);
-
- // Now actually perform the lookup with the sema.
- sema.LookupName(*lookup_result, scopes.back());
-
- // Delete all the allocated scopes beside the translation unit scope (which
- // has depth 0).
- for (Scope *s : scopes)
- if (s->getDepth() != 0)
- delete s;
-
- return lookup_result;
-}
-
-/// Error class for handling problems when finding a certain DeclContext.
-struct MissingDeclContext : public llvm::ErrorInfo<MissingDeclContext> {
-
- static char ID;
-
- MissingDeclContext(DeclContext *context, std::string error)
- : m_context(context), m_error(error) {}
-
- DeclContext *m_context;
- std::string m_error;
-
- void log(llvm::raw_ostream &OS) const override {
- OS << llvm::formatv("error when reconstructing context of kind {0}:{1}",
- m_context->getDeclKindName(), m_error);
- }
-
- std::error_code convertToErrorCode() const override {
- return llvm::inconvertibleErrorCode();
- }
-};
-
-char MissingDeclContext::ID = 0;
-
-/// Given a foreign decl context, this function finds the equivalent local
-/// decl context in the ASTContext of the given Sema. Potentially deserializes
-/// decls from the 'std' module if necessary.
-static llvm::Expected<DeclContext *>
-getEqualLocalDeclContext(Sema &sema, DeclContext *foreign_ctxt) {
-
- // Inline namespaces don't matter for lookups, so let's skip them.
- while (foreign_ctxt && foreign_ctxt->isInlineNamespace())
- foreign_ctxt = foreign_ctxt->getParent();
-
- // If the foreign context is the TU, we just return the local TU.
- if (foreign_ctxt->isTranslationUnit())
- return sema.getASTContext().getTranslationUnitDecl();
-
- // Recursively find/build the parent DeclContext.
- llvm::Expected<DeclContext *> parent =
- getEqualLocalDeclContext(sema, foreign_ctxt->getParent());
- if (!parent)
- return parent;
-
- // We currently only support building namespaces.
- if (foreign_ctxt->isNamespace()) {
- NamedDecl *ns = llvm::dyn_cast<NamedDecl>(foreign_ctxt);
- llvm::StringRef ns_name = ns->getName();
-
- auto lookup_result = emulateLookupInCtxt(sema, ns_name, *parent);
- for (NamedDecl *named_decl : *lookup_result) {
- if (DeclContext *DC = llvm::dyn_cast<DeclContext>(named_decl))
- return DC->getPrimaryContext();
- }
- return llvm::make_error<MissingDeclContext>(
- foreign_ctxt,
- "Couldn't find namespace " + ns->getQualifiedNameAsString());
- }
-
- return llvm::make_error<MissingDeclContext>(foreign_ctxt, "Unknown context ");
-}
-
-/// Returns true iff tryInstantiateStdTemplate supports instantiating a template
-/// with the given template arguments.
-static bool templateArgsAreSupported(ArrayRef<TemplateArgument> a) {
- for (const TemplateArgument &arg : a) {
- switch (arg.getKind()) {
- case TemplateArgument::Type:
- case TemplateArgument::Integral:
- break;
- default:
- // TemplateArgument kind hasn't been handled yet.
- return false;
- }
- }
- return true;
-}
-
-/// Constructor function for Clang declarations. Ensures that the created
-/// declaration is registered with the ASTImporter.
-template <typename T, typename... Args>
-T *createDecl(ASTImporter &importer, Decl *from_d, Args &&... args) {
- T *to_d = T::Create(std::forward<Args>(args)...);
- importer.RegisterImportedDecl(from_d, to_d);
- return to_d;
-}
-
-llvm::Optional<Decl *> CxxModuleHandler::tryInstantiateStdTemplate(Decl *d) {
- Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS);
-
- // If we don't have a template to instiantiate, then there is nothing to do.
- auto td = dyn_cast<ClassTemplateSpecializationDecl>(d);
- if (!td)
- return {};
-
- // We only care about templates in the std namespace.
- if (!td->getDeclContext()->isStdNamespace())
- return {};
-
- // We have a whitelist of supported template names.
- if (m_supported_templates.find(td->getName()) == m_supported_templates.end())
- return {};
-
- // Early check if we even support instantiating this template. We do this
- // before we import anything into the target AST.
- auto &foreign_args = td->getTemplateInstantiationArgs();
- if (!templateArgsAreSupported(foreign_args.asArray()))
- return {};
-
- // Find the local DeclContext that corresponds to the DeclContext of our
- // decl we want to import.
- llvm::Expected<DeclContext *> to_context =
- getEqualLocalDeclContext(*m_sema, td->getDeclContext());
- if (!to_context) {
- LLDB_LOG_ERROR(log, to_context.takeError(),
- "Got error while searching equal local DeclContext for decl "
- "'{1}':\n{0}",
- td->getName());
- return {};
- }
-
- // Look up the template in our local context.
- std::unique_ptr<LookupResult> lookup =
- emulateLookupInCtxt(*m_sema, td->getName(), *to_context);
-
- ClassTemplateDecl *new_class_template = nullptr;
- for (auto LD : *lookup) {
- if ((new_class_template = dyn_cast<ClassTemplateDecl>(LD)))
- break;
- }
- if (!new_class_template)
- return {};
-
- // Import the foreign template arguments.
- llvm::SmallVector<TemplateArgument, 4> imported_args;
-
- // If this logic is changed, also update templateArgsAreSupported.
- for (const TemplateArgument &arg : foreign_args.asArray()) {
- switch (arg.getKind()) {
- case TemplateArgument::Type: {
- llvm::Expected<QualType> type = m_importer->Import(arg.getAsType());
- if (!type) {
- LLDB_LOG_ERROR(log, type.takeError(), "Couldn't import type: {0}");
- return {};
- }
- imported_args.push_back(TemplateArgument(*type));
- break;
- }
- case TemplateArgument::Integral: {
- llvm::APSInt integral = arg.getAsIntegral();
- llvm::Expected<QualType> type =
- m_importer->Import(arg.getIntegralType());
- if (!type) {
- LLDB_LOG_ERROR(log, type.takeError(), "Couldn't import type: {0}");
- return {};
- }
- imported_args.push_back(
- TemplateArgument(d->getASTContext(), integral, *type));
- break;
- }
- default:
- assert(false && "templateArgsAreSupported not updated?");
- }
- }
-
- // Find the class template specialization declaration that
- // corresponds to these arguments.
- void *InsertPos = nullptr;
- ClassTemplateSpecializationDecl *result =
- new_class_template->findSpecialization(imported_args, InsertPos);
-
- if (result) {
- // We found an existing specialization in the module that fits our arguments
- // so we can treat it as the result and register it with the ASTImporter.
- m_importer->RegisterImportedDecl(d, result);
- return result;
- }
-
- // Instantiate the template.
- result = createDecl<ClassTemplateSpecializationDecl>(
- *m_importer, d, m_sema->getASTContext(),
- new_class_template->getTemplatedDecl()->getTagKind(),
- new_class_template->getDeclContext(),
- new_class_template->getTemplatedDecl()->getLocation(),
- new_class_template->getLocation(), new_class_template, imported_args,
- nullptr);
-
- new_class_template->AddSpecialization(result, InsertPos);
- if (new_class_template->isOutOfLine())
- result->setLexicalDeclContext(
- new_class_template->getLexicalDeclContext());
- return result;
-}
-
-llvm::Optional<Decl *> CxxModuleHandler::Import(Decl *d) {
- if (!isValid())
- return {};
-
- return tryInstantiateStdTemplate(d);
-}
+++ /dev/null
-//===-- TypeSystemClang.cpp -----------------------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-#include "lldb/Symbol/TypeSystemClang.h"
-
-#include "llvm/Support/FormatAdapters.h"
-#include "llvm/Support/FormatVariadic.h"
-
-#include <mutex>
-#include <string>
-#include <vector>
-
-#include "clang/AST/ASTContext.h"
-#include "clang/AST/ASTImporter.h"
-#include "clang/AST/Attr.h"
-#include "clang/AST/CXXInheritance.h"
-#include "clang/AST/DeclObjC.h"
-#include "clang/AST/DeclTemplate.h"
-#include "clang/AST/Mangle.h"
-#include "clang/AST/RecordLayout.h"
-#include "clang/AST/Type.h"
-#include "clang/AST/VTableBuilder.h"
-#include "clang/Basic/Builtins.h"
-#include "clang/Basic/Diagnostic.h"
-#include "clang/Basic/FileManager.h"
-#include "clang/Basic/FileSystemOptions.h"
-#include "clang/Basic/LangStandard.h"
-#include "clang/Basic/SourceManager.h"
-#include "clang/Basic/TargetInfo.h"
-#include "clang/Basic/TargetOptions.h"
-#include "clang/Frontend/FrontendOptions.h"
-#include "clang/Sema/Sema.h"
-
-#include "llvm/Support/Signals.h"
-#include "llvm/Support/Threading.h"
-
-#include "Plugins/ExpressionParser/Clang/ClangFunctionCaller.h"
-#include "Plugins/ExpressionParser/Clang/ClangPersistentVariables.h"
-#include "Plugins/ExpressionParser/Clang/ClangUserExpression.h"
-#include "Plugins/ExpressionParser/Clang/ClangUtilityFunction.h"
-#include "lldb/Utility/ArchSpec.h"
-#include "lldb/Utility/Flags.h"
-
-#include "lldb/Core/DumpDataExtractor.h"
-#include "lldb/Core/Module.h"
-#include "lldb/Core/PluginManager.h"
-#include "lldb/Core/StreamFile.h"
-#include "lldb/Core/ThreadSafeDenseMap.h"
-#include "lldb/Core/UniqueCStringMap.h"
-#include "lldb/Symbol/ClangASTImporter.h"
-#include "lldb/Symbol/ClangASTMetadata.h"
-#include "lldb/Symbol/ClangExternalASTSourceCallbacks.h"
-#include "lldb/Symbol/ClangUtil.h"
-#include "lldb/Symbol/ObjectFile.h"
-#include "lldb/Symbol/SymbolFile.h"
-#include "lldb/Target/ExecutionContext.h"
-#include "lldb/Target/Language.h"
-#include "lldb/Target/Process.h"
-#include "lldb/Target/Target.h"
-#include "lldb/Utility/DataExtractor.h"
-#include "lldb/Utility/LLDBAssert.h"
-#include "lldb/Utility/Log.h"
-#include "lldb/Utility/RegularExpression.h"
-#include "lldb/Utility/Scalar.h"
-
-#include "Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h"
-#include "Plugins/SymbolFile/DWARF/DWARFASTParserClang.h"
-#include "Plugins/SymbolFile/PDB/PDBASTParser.h"
-
-#include <stdio.h>
-
-#include <mutex>
-
-using namespace lldb;
-using namespace lldb_private;
-using namespace clang;
-using llvm::StringSwitch;
-
-namespace {
-#ifdef LLDB_CONFIGURATION_DEBUG
-static void VerifyDecl(clang::Decl *decl) {
- assert(decl && "VerifyDecl called with nullptr?");
- decl->getAccess();
-}
-#endif
-
-static inline bool
-TypeSystemClangSupportsLanguage(lldb::LanguageType language) {
- return language == eLanguageTypeUnknown || // Clang is the default type system
- lldb_private::Language::LanguageIsC(language) ||
- lldb_private::Language::LanguageIsCPlusPlus(language) ||
- lldb_private::Language::LanguageIsObjC(language) ||
- lldb_private::Language::LanguageIsPascal(language) ||
- // Use Clang for Rust until there is a proper language plugin for it
- language == eLanguageTypeRust ||
- language == eLanguageTypeExtRenderScript ||
- // Use Clang for D until there is a proper language plugin for it
- language == eLanguageTypeD ||
- // Open Dylan compiler debug info is designed to be Clang-compatible
- language == eLanguageTypeDylan;
-}
-
-// Checks whether m1 is an overload of m2 (as opposed to an override). This is
-// called by addOverridesForMethod to distinguish overrides (which share a
-// vtable entry) from overloads (which require distinct entries).
-bool isOverload(clang::CXXMethodDecl *m1, clang::CXXMethodDecl *m2) {
- // FIXME: This should detect covariant return types, but currently doesn't.
- lldbassert(&m1->getASTContext() == &m2->getASTContext() &&
- "Methods should have the same AST context");
- clang::ASTContext &context = m1->getASTContext();
-
- const auto *m1Type = llvm::cast<clang::FunctionProtoType>(
- context.getCanonicalType(m1->getType()));
-
- const auto *m2Type = llvm::cast<clang::FunctionProtoType>(
- context.getCanonicalType(m2->getType()));
-
- auto compareArgTypes = [&context](const clang::QualType &m1p,
- const clang::QualType &m2p) {
- return context.hasSameType(m1p.getUnqualifiedType(),
- m2p.getUnqualifiedType());
- };
-
- // FIXME: In C++14 and later, we can just pass m2Type->param_type_end()
- // as a fourth parameter to std::equal().
- return (m1->getNumParams() != m2->getNumParams()) ||
- !std::equal(m1Type->param_type_begin(), m1Type->param_type_end(),
- m2Type->param_type_begin(), compareArgTypes);
-}
-
-// If decl is a virtual method, walk the base classes looking for methods that
-// decl overrides. This table of overridden methods is used by IRGen to
-// determine the vtable layout for decl's parent class.
-void addOverridesForMethod(clang::CXXMethodDecl *decl) {
- if (!decl->isVirtual())
- return;
-
- clang::CXXBasePaths paths;
-
- auto find_overridden_methods =
- [decl](const clang::CXXBaseSpecifier *specifier,
- clang::CXXBasePath &path) {
- if (auto *base_record = llvm::dyn_cast<clang::CXXRecordDecl>(
- specifier->getType()->getAs<clang::RecordType>()->getDecl())) {
-
- clang::DeclarationName name = decl->getDeclName();
-
- // If this is a destructor, check whether the base class destructor is
- // virtual.
- if (name.getNameKind() == clang::DeclarationName::CXXDestructorName)
- if (auto *baseDtorDecl = base_record->getDestructor()) {
- if (baseDtorDecl->isVirtual()) {
- path.Decls = baseDtorDecl;
- return true;
- } else
- return false;
- }
-
- // Otherwise, search for name in the base class.
- for (path.Decls = base_record->lookup(name); !path.Decls.empty();
- path.Decls = path.Decls.slice(1)) {
- if (auto *method_decl =
- llvm::dyn_cast<clang::CXXMethodDecl>(path.Decls.front()))
- if (method_decl->isVirtual() && !isOverload(decl, method_decl)) {
- path.Decls = method_decl;
- return true;
- }
- }
- }
-
- return false;
- };
-
- if (decl->getParent()->lookupInBases(find_overridden_methods, paths)) {
- for (auto *overridden_decl : paths.found_decls())
- decl->addOverriddenMethod(
- llvm::cast<clang::CXXMethodDecl>(overridden_decl));
- }
-}
-}
-
-static lldb::addr_t GetVTableAddress(Process &process,
- VTableContextBase &vtable_ctx,
- ValueObject &valobj,
- const ASTRecordLayout &record_layout) {
- // Retrieve type info
- CompilerType pointee_type;
- CompilerType this_type(valobj.GetCompilerType());
- uint32_t type_info = this_type.GetTypeInfo(&pointee_type);
- if (!type_info)
- return LLDB_INVALID_ADDRESS;
-
- // Check if it's a pointer or reference
- bool ptr_or_ref = false;
- if (type_info & (eTypeIsPointer | eTypeIsReference)) {
- ptr_or_ref = true;
- type_info = pointee_type.GetTypeInfo();
- }
-
- // We process only C++ classes
- const uint32_t cpp_class = eTypeIsClass | eTypeIsCPlusPlus;
- if ((type_info & cpp_class) != cpp_class)
- return LLDB_INVALID_ADDRESS;
-
- // Calculate offset to VTable pointer
- lldb::offset_t vbtable_ptr_offset =
- vtable_ctx.isMicrosoft() ? record_layout.getVBPtrOffset().getQuantity()
- : 0;
-
- if (ptr_or_ref) {
- // We have a pointer / ref to object, so read
- // VTable pointer from process memory
-
- if (valobj.GetAddressTypeOfChildren() != eAddressTypeLoad)
- return LLDB_INVALID_ADDRESS;
-
- auto vbtable_ptr_addr = valobj.GetValueAsUnsigned(LLDB_INVALID_ADDRESS);
- if (vbtable_ptr_addr == LLDB_INVALID_ADDRESS)
- return LLDB_INVALID_ADDRESS;
-
- vbtable_ptr_addr += vbtable_ptr_offset;
-
- Status err;
- return process.ReadPointerFromMemory(vbtable_ptr_addr, err);
- }
-
- // We have an object already read from process memory,
- // so just extract VTable pointer from it
-
- DataExtractor data;
- Status err;
- auto size = valobj.GetData(data, err);
- if (err.Fail() || vbtable_ptr_offset + data.GetAddressByteSize() > size)
- return LLDB_INVALID_ADDRESS;
-
- return data.GetPointer(&vbtable_ptr_offset);
-}
-
-static int64_t ReadVBaseOffsetFromVTable(Process &process,
- VTableContextBase &vtable_ctx,
- lldb::addr_t vtable_ptr,
- const CXXRecordDecl *cxx_record_decl,
- const CXXRecordDecl *base_class_decl) {
- if (vtable_ctx.isMicrosoft()) {
- clang::MicrosoftVTableContext &msoft_vtable_ctx =
- static_cast<clang::MicrosoftVTableContext &>(vtable_ctx);
-
- // Get the index into the virtual base table. The
- // index is the index in uint32_t from vbtable_ptr
- const unsigned vbtable_index =
- msoft_vtable_ctx.getVBTableIndex(cxx_record_decl, base_class_decl);
- const lldb::addr_t base_offset_addr = vtable_ptr + vbtable_index * 4;
- Status err;
- return process.ReadSignedIntegerFromMemory(base_offset_addr, 4, INT64_MAX,
- err);
- }
-
- clang::ItaniumVTableContext &itanium_vtable_ctx =
- static_cast<clang::ItaniumVTableContext &>(vtable_ctx);
-
- clang::CharUnits base_offset_offset =
- itanium_vtable_ctx.getVirtualBaseOffsetOffset(cxx_record_decl,
- base_class_decl);
- const lldb::addr_t base_offset_addr =
- vtable_ptr + base_offset_offset.getQuantity();
- const uint32_t base_offset_size = process.GetAddressByteSize();
- Status err;
- return process.ReadSignedIntegerFromMemory(base_offset_addr, base_offset_size,
- INT64_MAX, err);
-}
-
-static bool GetVBaseBitOffset(VTableContextBase &vtable_ctx,
- ValueObject &valobj,
- const ASTRecordLayout &record_layout,
- const CXXRecordDecl *cxx_record_decl,
- const CXXRecordDecl *base_class_decl,
- int32_t &bit_offset) {
- ExecutionContext exe_ctx(valobj.GetExecutionContextRef());
- Process *process = exe_ctx.GetProcessPtr();
- if (!process)
- return false;
-
- lldb::addr_t vtable_ptr =
- GetVTableAddress(*process, vtable_ctx, valobj, record_layout);
- if (vtable_ptr == LLDB_INVALID_ADDRESS)
- return false;
-
- auto base_offset = ReadVBaseOffsetFromVTable(
- *process, vtable_ctx, vtable_ptr, cxx_record_decl, base_class_decl);
- if (base_offset == INT64_MAX)
- return false;
-
- bit_offset = base_offset * 8;
-
- return true;
-}
-
-typedef lldb_private::ThreadSafeDenseMap<clang::ASTContext *, TypeSystemClang *>
- ClangASTMap;
-
-static ClangASTMap &GetASTMap() {
- static ClangASTMap *g_map_ptr = nullptr;
- static llvm::once_flag g_once_flag;
- llvm::call_once(g_once_flag, []() {
- g_map_ptr = new ClangASTMap(); // leaked on purpose to avoid spins
- });
- return *g_map_ptr;
-}
-
-char TypeSystemClang::ID;
-
-bool TypeSystemClang::IsOperator(llvm::StringRef name,
- clang::OverloadedOperatorKind &op_kind) {
- // All operators have to start with "operator".
- if (!name.consume_front("operator"))
- return false;
-
- // Remember if there was a space after "operator". This is necessary to
- // check for collisions with strangely named functions like "operatorint()".
- bool space_after_operator = name.consume_front(" ");
-
- op_kind = StringSwitch<clang::OverloadedOperatorKind>(name)
- .Case("+", clang::OO_Plus)
- .Case("+=", clang::OO_PlusEqual)
- .Case("++", clang::OO_PlusPlus)
- .Case("-", clang::OO_Minus)
- .Case("-=", clang::OO_MinusEqual)
- .Case("--", clang::OO_MinusMinus)
- .Case("->", clang::OO_Arrow)
- .Case("->*", clang::OO_ArrowStar)
- .Case("*", clang::OO_Star)
- .Case("*=", clang::OO_StarEqual)
- .Case("/", clang::OO_Slash)
- .Case("/=", clang::OO_SlashEqual)
- .Case("%", clang::OO_Percent)
- .Case("%=", clang::OO_PercentEqual)
- .Case("^", clang::OO_Caret)
- .Case("^=", clang::OO_CaretEqual)
- .Case("&", clang::OO_Amp)
- .Case("&=", clang::OO_AmpEqual)
- .Case("&&", clang::OO_AmpAmp)
- .Case("|", clang::OO_Pipe)
- .Case("|=", clang::OO_PipeEqual)
- .Case("||", clang::OO_PipePipe)
- .Case("~", clang::OO_Tilde)
- .Case("!", clang::OO_Exclaim)
- .Case("!=", clang::OO_ExclaimEqual)
- .Case("=", clang::OO_Equal)
- .Case("==", clang::OO_EqualEqual)
- .Case("<", clang::OO_Less)
- .Case("<<", clang::OO_LessLess)
- .Case("<<=", clang::OO_LessLessEqual)
- .Case("<=", clang::OO_LessEqual)
- .Case(">", clang::OO_Greater)
- .Case(">>", clang::OO_GreaterGreater)
- .Case(">>=", clang::OO_GreaterGreaterEqual)
- .Case(">=", clang::OO_GreaterEqual)
- .Case("()", clang::OO_Call)
- .Case("[]", clang::OO_Subscript)
- .Case(",", clang::OO_Comma)
- .Default(clang::NUM_OVERLOADED_OPERATORS);
-
- // We found a fitting operator, so we can exit now.
- if (op_kind != clang::NUM_OVERLOADED_OPERATORS)
- return true;
-
- // After the "operator " or "operator" part is something unknown. This means
- // it's either one of the named operators (new/delete), a conversion operator
- // (e.g. operator bool) or a function which name starts with "operator"
- // (e.g. void operatorbool).
-
- // If it's a function that starts with operator it can't have a space after
- // "operator" because identifiers can't contain spaces.
- // E.g. "operator int" (conversion operator)
- // vs. "operatorint" (function with colliding name).
- if (!space_after_operator)
- return false; // not an operator.
-
- // Now the operator is either one of the named operators or a conversion
- // operator.
- op_kind = StringSwitch<clang::OverloadedOperatorKind>(name)
- .Case("new", clang::OO_New)
- .Case("new[]", clang::OO_Array_New)
- .Case("delete", clang::OO_Delete)
- .Case("delete[]", clang::OO_Array_Delete)
- // conversion operators hit this case.
- .Default(clang::NUM_OVERLOADED_OPERATORS);
-
- return true;
-}
-
-clang::AccessSpecifier
-TypeSystemClang::ConvertAccessTypeToAccessSpecifier(AccessType access) {
- switch (access) {
- default:
- break;
- case eAccessNone:
- return AS_none;
- case eAccessPublic:
- return AS_public;
- case eAccessPrivate:
- return AS_private;
- case eAccessProtected:
- return AS_protected;
- }
- return AS_none;
-}
-
-static void ParseLangArgs(LangOptions &Opts, InputKind IK, const char *triple) {
- // FIXME: Cleanup per-file based stuff.
-
- // Set some properties which depend solely on the input kind; it would be
- // nice to move these to the language standard, and have the driver resolve
- // the input kind + language standard.
- if (IK.getLanguage() == clang::Language::Asm) {
- Opts.AsmPreprocessor = 1;
- } else if (IK.isObjectiveC()) {
- Opts.ObjC = 1;
- }
-
- LangStandard::Kind LangStd = LangStandard::lang_unspecified;
-
- if (LangStd == LangStandard::lang_unspecified) {
- // Based on the base language, pick one.
- switch (IK.getLanguage()) {
- case clang::Language::Unknown:
- case clang::Language::LLVM_IR:
- case clang::Language::RenderScript:
- llvm_unreachable("Invalid input kind!");
- case clang::Language::OpenCL:
- LangStd = LangStandard::lang_opencl10;
- break;
- case clang::Language::CUDA:
- LangStd = LangStandard::lang_cuda;
- break;
- case clang::Language::Asm:
- case clang::Language::C:
- case clang::Language::ObjC:
- LangStd = LangStandard::lang_gnu99;
- break;
- case clang::Language::CXX:
- case clang::Language::ObjCXX:
- LangStd = LangStandard::lang_gnucxx98;
- break;
- case clang::Language::HIP:
- LangStd = LangStandard::lang_hip;
- break;
- }
- }
-
- const LangStandard &Std = LangStandard::getLangStandardForKind(LangStd);
- Opts.LineComment = Std.hasLineComments();
- Opts.C99 = Std.isC99();
- Opts.CPlusPlus = Std.isCPlusPlus();
- Opts.CPlusPlus11 = Std.isCPlusPlus11();
- Opts.Digraphs = Std.hasDigraphs();
- Opts.GNUMode = Std.isGNUMode();
- Opts.GNUInline = !Std.isC99();
- Opts.HexFloats = Std.hasHexFloats();
- Opts.ImplicitInt = Std.hasImplicitInt();
-
- Opts.WChar = true;
-
- // OpenCL has some additional defaults.
- if (LangStd == LangStandard::lang_opencl10) {
- Opts.OpenCL = 1;
- Opts.AltiVec = 1;
- Opts.CXXOperatorNames = 1;
- Opts.setLaxVectorConversions(LangOptions::LaxVectorConversionKind::All);
- }
-
- // OpenCL and C++ both have bool, true, false keywords.
- Opts.Bool = Opts.OpenCL || Opts.CPlusPlus;
-
- Opts.setValueVisibilityMode(DefaultVisibility);
-
- // Mimicing gcc's behavior, trigraphs are only enabled if -trigraphs is
- // specified, or -std is set to a conforming mode.
- Opts.Trigraphs = !Opts.GNUMode;
- Opts.CharIsSigned = ArchSpec(triple).CharIsSignedByDefault();
- Opts.OptimizeSize = 0;
-
- // FIXME: Eliminate this dependency.
- // unsigned Opt =
- // Args.hasArg(OPT_Os) ? 2 : getLastArgIntValue(Args, OPT_O, 0, Diags);
- // Opts.Optimize = Opt != 0;
- unsigned Opt = 0;
-
- // This is the __NO_INLINE__ define, which just depends on things like the
- // optimization level and -fno-inline, not actually whether the backend has
- // inlining enabled.
- //
- // FIXME: This is affected by other options (-fno-inline).
- Opts.NoInlineDefine = !Opt;
-}
-
-TypeSystemClang::TypeSystemClang(llvm::StringRef name,
- llvm::Triple target_triple) {
- m_display_name = name.str();
- if (!target_triple.str().empty())
- SetTargetTriple(target_triple.str());
- // The caller didn't pass an ASTContext so create a new one for this
- // TypeSystemClang.
- CreateASTContext();
-}
-
-TypeSystemClang::TypeSystemClang(llvm::StringRef name,
- ASTContext &existing_ctxt) {
- m_display_name = name.str();
- SetTargetTriple(existing_ctxt.getTargetInfo().getTriple().str());
-
- m_ast_up.reset(&existing_ctxt);
- GetASTMap().Insert(&existing_ctxt, this);
-}
-
-// Destructor
-TypeSystemClang::~TypeSystemClang() { Finalize(); }
-
-ConstString TypeSystemClang::GetPluginNameStatic() {
- return ConstString("clang");
-}
-
-ConstString TypeSystemClang::GetPluginName() {
- return TypeSystemClang::GetPluginNameStatic();
-}
-
-uint32_t TypeSystemClang::GetPluginVersion() { return 1; }
-
-lldb::TypeSystemSP TypeSystemClang::CreateInstance(lldb::LanguageType language,
- lldb_private::Module *module,
- Target *target) {
- if (!TypeSystemClangSupportsLanguage(language))
- return lldb::TypeSystemSP();
- ArchSpec arch;
- if (module)
- arch = module->GetArchitecture();
- else if (target)
- arch = target->GetArchitecture();
-
- if (!arch.IsValid())
- return lldb::TypeSystemSP();
-
- llvm::Triple triple = arch.GetTriple();
- // LLVM wants this to be set to iOS or MacOSX; if we're working on
- // a bare-boards type image, change the triple for llvm's benefit.
- if (triple.getVendor() == llvm::Triple::Apple &&
- triple.getOS() == llvm::Triple::UnknownOS) {
- if (triple.getArch() == llvm::Triple::arm ||
- triple.getArch() == llvm::Triple::aarch64 ||
- triple.getArch() == llvm::Triple::aarch64_32 ||
- triple.getArch() == llvm::Triple::thumb) {
- triple.setOS(llvm::Triple::IOS);
- } else {
- triple.setOS(llvm::Triple::MacOSX);
- }
- }
-
- if (module) {
- std::string ast_name =
- "ASTContext for '" + module->GetFileSpec().GetPath() + "'";
- return std::make_shared<TypeSystemClang>(ast_name, triple);
- } else if (target && target->IsValid())
- return std::make_shared<TypeSystemClangForExpressions>(*target, triple);
- return lldb::TypeSystemSP();
-}
-
-LanguageSet TypeSystemClang::GetSupportedLanguagesForTypes() {
- LanguageSet languages;
- languages.Insert(lldb::eLanguageTypeC89);
- languages.Insert(lldb::eLanguageTypeC);
- languages.Insert(lldb::eLanguageTypeC11);
- languages.Insert(lldb::eLanguageTypeC_plus_plus);
- languages.Insert(lldb::eLanguageTypeC99);
- languages.Insert(lldb::eLanguageTypeObjC);
- languages.Insert(lldb::eLanguageTypeObjC_plus_plus);
- languages.Insert(lldb::eLanguageTypeC_plus_plus_03);
- languages.Insert(lldb::eLanguageTypeC_plus_plus_11);
- languages.Insert(lldb::eLanguageTypeC11);
- languages.Insert(lldb::eLanguageTypeC_plus_plus_14);
- return languages;
-}
-
-LanguageSet TypeSystemClang::GetSupportedLanguagesForExpressions() {
- LanguageSet languages;
- languages.Insert(lldb::eLanguageTypeC_plus_plus);
- languages.Insert(lldb::eLanguageTypeObjC_plus_plus);
- languages.Insert(lldb::eLanguageTypeC_plus_plus_03);
- languages.Insert(lldb::eLanguageTypeC_plus_plus_11);
- languages.Insert(lldb::eLanguageTypeC_plus_plus_14);
- return languages;
-}
-
-void TypeSystemClang::Initialize() {
- PluginManager::RegisterPlugin(
- GetPluginNameStatic(), "clang base AST context plug-in", CreateInstance,
- GetSupportedLanguagesForTypes(), GetSupportedLanguagesForExpressions());
-}
-
-void TypeSystemClang::Terminate() {
- PluginManager::UnregisterPlugin(CreateInstance);
-}
-
-void TypeSystemClang::Finalize() {
- assert(m_ast_up);
- GetASTMap().Erase(m_ast_up.get());
- if (!m_ast_owned)
- m_ast_up.release();
-
- m_builtins_up.reset();
- m_selector_table_up.reset();
- m_identifier_table_up.reset();
- m_target_info_up.reset();
- m_target_options_rp.reset();
- m_diagnostics_engine_up.reset();
- m_source_manager_up.reset();
- m_language_options_up.reset();
-}
-
-void TypeSystemClang::setSema(Sema *s) {
- // Ensure that the new sema actually belongs to our ASTContext.
- assert(s == nullptr || &s->getASTContext() == m_ast_up.get());
- m_sema = s;
-}
-
-const char *TypeSystemClang::GetTargetTriple() {
- return m_target_triple.c_str();
-}
-
-void TypeSystemClang::SetTargetTriple(llvm::StringRef target_triple) {
- m_target_triple = target_triple.str();
-}
-
-void TypeSystemClang::SetExternalSource(
- llvm::IntrusiveRefCntPtr<ExternalASTSource> &ast_source_up) {
- ASTContext &ast = getASTContext();
- ast.setExternalSource(ast_source_up);
- ast.getTranslationUnitDecl()->setHasExternalLexicalStorage(true);
-}
-
-ASTContext &TypeSystemClang::getASTContext() {
- assert(m_ast_up);
- return *m_ast_up;
-}
-
-class NullDiagnosticConsumer : public DiagnosticConsumer {
-public:
- NullDiagnosticConsumer() {
- m_log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS);
- }
-
- void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
- const clang::Diagnostic &info) override {
- if (m_log) {
- llvm::SmallVector<char, 32> diag_str(10);
- info.FormatDiagnostic(diag_str);
- diag_str.push_back('\0');
- LLDB_LOGF(m_log, "Compiler diagnostic: %s\n", diag_str.data());
- }
- }
-
- DiagnosticConsumer *clone(DiagnosticsEngine &Diags) const {
- return new NullDiagnosticConsumer();
- }
-
-private:
- Log *m_log;
-};
-
-void TypeSystemClang::CreateASTContext() {
- assert(!m_ast_up);
- m_ast_owned = true;
-
- m_language_options_up.reset(new LangOptions());
- ParseLangArgs(*m_language_options_up, clang::Language::ObjCXX,
- GetTargetTriple());
-
- m_identifier_table_up.reset(
- new IdentifierTable(*m_language_options_up, nullptr));
- m_builtins_up.reset(new Builtin::Context());
-
- m_selector_table_up.reset(new SelectorTable());
-
- clang::FileSystemOptions file_system_options;
- m_file_manager_up.reset(new clang::FileManager(
- file_system_options, FileSystem::Instance().GetVirtualFileSystem()));
-
- llvm::IntrusiveRefCntPtr<DiagnosticIDs> diag_id_sp(new DiagnosticIDs());
- m_diagnostics_engine_up.reset(
- new DiagnosticsEngine(diag_id_sp, new DiagnosticOptions()));
-
- m_source_manager_up.reset(
- new clang::SourceManager(*m_diagnostics_engine_up, *m_file_manager_up));
- m_ast_up.reset(new ASTContext(*m_language_options_up, *m_source_manager_up,
- *m_identifier_table_up, *m_selector_table_up,
- *m_builtins_up));
-
- m_diagnostic_consumer_up.reset(new NullDiagnosticConsumer);
- m_ast_up->getDiagnostics().setClient(m_diagnostic_consumer_up.get(), false);
-
- // This can be NULL if we don't know anything about the architecture or if
- // the target for an architecture isn't enabled in the llvm/clang that we
- // built
- TargetInfo *target_info = getTargetInfo();
- if (target_info)
- m_ast_up->InitBuiltinTypes(*target_info);
-
- GetASTMap().Insert(m_ast_up.get(), this);
-
- llvm::IntrusiveRefCntPtr<clang::ExternalASTSource> ast_source_up(
- new ClangExternalASTSourceCallbacks(*this));
- SetExternalSource(ast_source_up);
-}
-
-TypeSystemClang *TypeSystemClang::GetASTContext(clang::ASTContext *ast) {
- TypeSystemClang *clang_ast = GetASTMap().Lookup(ast);
- return clang_ast;
-}
-
-clang::MangleContext *TypeSystemClang::getMangleContext() {
- if (m_mangle_ctx_up == nullptr)
- m_mangle_ctx_up.reset(getASTContext().createMangleContext());
- return m_mangle_ctx_up.get();
-}
-
-std::shared_ptr<clang::TargetOptions> &TypeSystemClang::getTargetOptions() {
- if (m_target_options_rp == nullptr && !m_target_triple.empty()) {
- m_target_options_rp = std::make_shared<clang::TargetOptions>();
- if (m_target_options_rp != nullptr)
- m_target_options_rp->Triple = m_target_triple;
- }
- return m_target_options_rp;
-}
-
-TargetInfo *TypeSystemClang::getTargetInfo() {
- // target_triple should be something like "x86_64-apple-macosx"
- if (m_target_info_up == nullptr && !m_target_triple.empty())
- m_target_info_up.reset(TargetInfo::CreateTargetInfo(
- getASTContext().getDiagnostics(), getTargetOptions()));
- return m_target_info_up.get();
-}
-
-#pragma mark Basic Types
-
-static inline bool QualTypeMatchesBitSize(const uint64_t bit_size,
- ASTContext &ast, QualType qual_type) {
- uint64_t qual_type_bit_size = ast.getTypeSize(qual_type);
- return qual_type_bit_size == bit_size;
-}
-
-CompilerType
-TypeSystemClang::GetBuiltinTypeForEncodingAndBitSize(Encoding encoding,
- size_t bit_size) {
- ASTContext &ast = getASTContext();
- switch (encoding) {
- case eEncodingInvalid:
- if (QualTypeMatchesBitSize(bit_size, ast, ast.VoidPtrTy))
- return GetType(ast.VoidPtrTy);
- break;
-
- case eEncodingUint:
- if (QualTypeMatchesBitSize(bit_size, ast, ast.UnsignedCharTy))
- return GetType(ast.UnsignedCharTy);
- if (QualTypeMatchesBitSize(bit_size, ast, ast.UnsignedShortTy))
- return GetType(ast.UnsignedShortTy);
- if (QualTypeMatchesBitSize(bit_size, ast, ast.UnsignedIntTy))
- return GetType(ast.UnsignedIntTy);
- if (QualTypeMatchesBitSize(bit_size, ast, ast.UnsignedLongTy))
- return GetType(ast.UnsignedLongTy);
- if (QualTypeMatchesBitSize(bit_size, ast, ast.UnsignedLongLongTy))
- return GetType(ast.UnsignedLongLongTy);
- if (QualTypeMatchesBitSize(bit_size, ast, ast.UnsignedInt128Ty))
- return GetType(ast.UnsignedInt128Ty);
- break;
-
- case eEncodingSint:
- if (QualTypeMatchesBitSize(bit_size, ast, ast.SignedCharTy))
- return GetType(ast.SignedCharTy);
- if (QualTypeMatchesBitSize(bit_size, ast, ast.ShortTy))
- return GetType(ast.ShortTy);
- if (QualTypeMatchesBitSize(bit_size, ast, ast.IntTy))
- return GetType(ast.IntTy);
- if (QualTypeMatchesBitSize(bit_size, ast, ast.LongTy))
- return GetType(ast.LongTy);
- if (QualTypeMatchesBitSize(bit_size, ast, ast.LongLongTy))
- return GetType(ast.LongLongTy);
- if (QualTypeMatchesBitSize(bit_size, ast, ast.Int128Ty))
- return GetType(ast.Int128Ty);
- break;
-
- case eEncodingIEEE754:
- if (QualTypeMatchesBitSize(bit_size, ast, ast.FloatTy))
- return GetType(ast.FloatTy);
- if (QualTypeMatchesBitSize(bit_size, ast, ast.DoubleTy))
- return GetType(ast.DoubleTy);
- if (QualTypeMatchesBitSize(bit_size, ast, ast.LongDoubleTy))
- return GetType(ast.LongDoubleTy);
- if (QualTypeMatchesBitSize(bit_size, ast, ast.HalfTy))
- return GetType(ast.HalfTy);
- break;
-
- case eEncodingVector:
- // Sanity check that bit_size is a multiple of 8's.
- if (bit_size && !(bit_size & 0x7u))
- return GetType(ast.getExtVectorType(ast.UnsignedCharTy, bit_size / 8));
- break;
- }
-
- return CompilerType();
-}
-
-lldb::BasicType
-TypeSystemClang::GetBasicTypeEnumeration(ConstString name) {
- if (name) {
- typedef UniqueCStringMap<lldb::BasicType> TypeNameToBasicTypeMap;
- static TypeNameToBasicTypeMap g_type_map;
- static llvm::once_flag g_once_flag;
- llvm::call_once(g_once_flag, []() {
- // "void"
- g_type_map.Append(ConstString("void"), eBasicTypeVoid);
-
- // "char"
- g_type_map.Append(ConstString("char"), eBasicTypeChar);
- g_type_map.Append(ConstString("signed char"), eBasicTypeSignedChar);
- g_type_map.Append(ConstString("unsigned char"), eBasicTypeUnsignedChar);
- g_type_map.Append(ConstString("wchar_t"), eBasicTypeWChar);
- g_type_map.Append(ConstString("signed wchar_t"), eBasicTypeSignedWChar);
- g_type_map.Append(ConstString("unsigned wchar_t"),
- eBasicTypeUnsignedWChar);
- // "short"
- g_type_map.Append(ConstString("short"), eBasicTypeShort);
- g_type_map.Append(ConstString("short int"), eBasicTypeShort);
- g_type_map.Append(ConstString("unsigned short"), eBasicTypeUnsignedShort);
- g_type_map.Append(ConstString("unsigned short int"),
- eBasicTypeUnsignedShort);
-
- // "int"
- g_type_map.Append(ConstString("int"), eBasicTypeInt);
- g_type_map.Append(ConstString("signed int"), eBasicTypeInt);
- g_type_map.Append(ConstString("unsigned int"), eBasicTypeUnsignedInt);
- g_type_map.Append(ConstString("unsigned"), eBasicTypeUnsignedInt);
-
- // "long"
- g_type_map.Append(ConstString("long"), eBasicTypeLong);
- g_type_map.Append(ConstString("long int"), eBasicTypeLong);
- g_type_map.Append(ConstString("unsigned long"), eBasicTypeUnsignedLong);
- g_type_map.Append(ConstString("unsigned long int"),
- eBasicTypeUnsignedLong);
-
- // "long long"
- g_type_map.Append(ConstString("long long"), eBasicTypeLongLong);
- g_type_map.Append(ConstString("long long int"), eBasicTypeLongLong);
- g_type_map.Append(ConstString("unsigned long long"),
- eBasicTypeUnsignedLongLong);
- g_type_map.Append(ConstString("unsigned long long int"),
- eBasicTypeUnsignedLongLong);
-
- // "int128"
- g_type_map.Append(ConstString("__int128_t"), eBasicTypeInt128);
- g_type_map.Append(ConstString("__uint128_t"), eBasicTypeUnsignedInt128);
-
- // Miscellaneous
- g_type_map.Append(ConstString("bool"), eBasicTypeBool);
- g_type_map.Append(ConstString("float"), eBasicTypeFloat);
- g_type_map.Append(ConstString("double"), eBasicTypeDouble);
- g_type_map.Append(ConstString("long double"), eBasicTypeLongDouble);
- g_type_map.Append(ConstString("id"), eBasicTypeObjCID);
- g_type_map.Append(ConstString("SEL"), eBasicTypeObjCSel);
- g_type_map.Append(ConstString("nullptr"), eBasicTypeNullPtr);
- g_type_map.Sort();
- });
-
- return g_type_map.Find(name, eBasicTypeInvalid);
- }
- return eBasicTypeInvalid;
-}
-
-uint32_t TypeSystemClang::GetPointerByteSize() {
- if (m_pointer_byte_size == 0)
- if (auto size = GetBasicType(lldb::eBasicTypeVoid)
- .GetPointerType()
- .GetByteSize(nullptr))
- m_pointer_byte_size = *size;
- return m_pointer_byte_size;
-}
-
-CompilerType TypeSystemClang::GetBasicType(lldb::BasicType basic_type) {
- clang::ASTContext &ast = getASTContext();
-
- lldb::opaque_compiler_type_t clang_type =
- GetOpaqueCompilerType(&ast, basic_type);
-
- if (clang_type)
- return CompilerType(this, clang_type);
- return CompilerType();
-}
-
-CompilerType TypeSystemClang::GetBuiltinTypeForDWARFEncodingAndBitSize(
- llvm::StringRef type_name, uint32_t dw_ate, uint32_t bit_size) {
- ASTContext &ast = getASTContext();
-
- switch (dw_ate) {
- default:
- break;
-
- case DW_ATE_address:
- if (QualTypeMatchesBitSize(bit_size, ast, ast.VoidPtrTy))
- return GetType(ast.VoidPtrTy);
- break;
-
- case DW_ATE_boolean:
- if (QualTypeMatchesBitSize(bit_size, ast, ast.BoolTy))
- return GetType(ast.BoolTy);
- if (QualTypeMatchesBitSize(bit_size, ast, ast.UnsignedCharTy))
- return GetType(ast.UnsignedCharTy);
- if (QualTypeMatchesBitSize(bit_size, ast, ast.UnsignedShortTy))
- return GetType(ast.UnsignedShortTy);
- if (QualTypeMatchesBitSize(bit_size, ast, ast.UnsignedIntTy))
- return GetType(ast.UnsignedIntTy);
- break;
-
- case DW_ATE_lo_user:
- // This has been seen to mean DW_AT_complex_integer
- if (type_name.contains("complex")) {
- CompilerType complex_int_clang_type =
- GetBuiltinTypeForDWARFEncodingAndBitSize("int", DW_ATE_signed,
- bit_size / 2);
- return GetType(
- ast.getComplexType(ClangUtil::GetQualType(complex_int_clang_type)));
- }
- break;
-
- case DW_ATE_complex_float:
- if (QualTypeMatchesBitSize(bit_size, ast, ast.FloatComplexTy))
- return GetType(ast.FloatComplexTy);
- else if (QualTypeMatchesBitSize(bit_size, ast, ast.DoubleComplexTy))
- return GetType(ast.DoubleComplexTy);
- else if (QualTypeMatchesBitSize(bit_size, ast, ast.LongDoubleComplexTy))
- return GetType(ast.LongDoubleComplexTy);
- else {
- CompilerType complex_float_clang_type =
- GetBuiltinTypeForDWARFEncodingAndBitSize("float", DW_ATE_float,
- bit_size / 2);
- return GetType(
- ast.getComplexType(ClangUtil::GetQualType(complex_float_clang_type)));
- }
- break;
-
- case DW_ATE_float:
- if (type_name == "float" &&
- QualTypeMatchesBitSize(bit_size, ast, ast.FloatTy))
- return GetType(ast.FloatTy);
- if (type_name == "double" &&
- QualTypeMatchesBitSize(bit_size, ast, ast.DoubleTy))
- return GetType(ast.DoubleTy);
- if (type_name == "long double" &&
- QualTypeMatchesBitSize(bit_size, ast, ast.LongDoubleTy))
- return GetType(ast.LongDoubleTy);
- // Fall back to not requiring a name match
- if (QualTypeMatchesBitSize(bit_size, ast, ast.FloatTy))
- return GetType(ast.FloatTy);
- if (QualTypeMatchesBitSize(bit_size, ast, ast.DoubleTy))
- return GetType(ast.DoubleTy);
- if (QualTypeMatchesBitSize(bit_size, ast, ast.LongDoubleTy))
- return GetType(ast.LongDoubleTy);
- if (QualTypeMatchesBitSize(bit_size, ast, ast.HalfTy))
- return GetType(ast.HalfTy);
- break;
-
- case DW_ATE_signed:
- if (!type_name.empty()) {
- if (type_name == "wchar_t" &&
- QualTypeMatchesBitSize(bit_size, ast, ast.WCharTy) &&
- (getTargetInfo() &&
- TargetInfo::isTypeSigned(getTargetInfo()->getWCharType())))
- return GetType(ast.WCharTy);
- if (type_name == "void" &&
- QualTypeMatchesBitSize(bit_size, ast, ast.VoidTy))
- return GetType(ast.VoidTy);
- if (type_name.contains("long long") &&
- QualTypeMatchesBitSize(bit_size, ast, ast.LongLongTy))
- return GetType(ast.LongLongTy);
- if (type_name.contains("long") &&
- QualTypeMatchesBitSize(bit_size, ast, ast.LongTy))
- return GetType(ast.LongTy);
- if (type_name.contains("short") &&
- QualTypeMatchesBitSize(bit_size, ast, ast.ShortTy))
- return GetType(ast.ShortTy);
- if (type_name.contains("char")) {
- if (QualTypeMatchesBitSize(bit_size, ast, ast.CharTy))
- return GetType(ast.CharTy);
- if (QualTypeMatchesBitSize(bit_size, ast, ast.SignedCharTy))
- return GetType(ast.SignedCharTy);
- }
- if (type_name.contains("int")) {
- if (QualTypeMatchesBitSize(bit_size, ast, ast.IntTy))
- return GetType(ast.IntTy);
- if (QualTypeMatchesBitSize(bit_size, ast, ast.Int128Ty))
- return GetType(ast.Int128Ty);
- }
- }
- // We weren't able to match up a type name, just search by size
- if (QualTypeMatchesBitSize(bit_size, ast, ast.CharTy))
- return GetType(ast.CharTy);
- if (QualTypeMatchesBitSize(bit_size, ast, ast.ShortTy))
- return GetType(ast.ShortTy);
- if (QualTypeMatchesBitSize(bit_size, ast, ast.IntTy))
- return GetType(ast.IntTy);
- if (QualTypeMatchesBitSize(bit_size, ast, ast.LongTy))
- return GetType(ast.LongTy);
- if (QualTypeMatchesBitSize(bit_size, ast, ast.LongLongTy))
- return GetType(ast.LongLongTy);
- if (QualTypeMatchesBitSize(bit_size, ast, ast.Int128Ty))
- return GetType(ast.Int128Ty);
- break;
-
- case DW_ATE_signed_char:
- if (ast.getLangOpts().CharIsSigned && type_name == "char") {
- if (QualTypeMatchesBitSize(bit_size, ast, ast.CharTy))
- return GetType(ast.CharTy);
- }
- if (QualTypeMatchesBitSize(bit_size, ast, ast.SignedCharTy))
- return GetType(ast.SignedCharTy);
- break;
-
- case DW_ATE_unsigned:
- if (!type_name.empty()) {
- if (type_name == "wchar_t") {
- if (QualTypeMatchesBitSize(bit_size, ast, ast.WCharTy)) {
- if (!(getTargetInfo() &&
- TargetInfo::isTypeSigned(getTargetInfo()->getWCharType())))
- return GetType(ast.WCharTy);
- }
- }
- if (type_name.contains("long long")) {
- if (QualTypeMatchesBitSize(bit_size, ast, ast.UnsignedLongLongTy))
- return GetType(ast.UnsignedLongLongTy);
- } else if (type_name.contains("long")) {
- if (QualTypeMatchesBitSize(bit_size, ast, ast.UnsignedLongTy))
- return GetType(ast.UnsignedLongTy);
- } else if (type_name.contains("short")) {
- if (QualTypeMatchesBitSize(bit_size, ast, ast.UnsignedShortTy))
- return GetType(ast.UnsignedShortTy);
- } else if (type_name.contains("char")) {
- if (QualTypeMatchesBitSize(bit_size, ast, ast.UnsignedCharTy))
- return GetType(ast.UnsignedCharTy);
- } else if (type_name.contains("int")) {
- if (QualTypeMatchesBitSize(bit_size, ast, ast.UnsignedIntTy))
- return GetType(ast.UnsignedIntTy);
- if (QualTypeMatchesBitSize(bit_size, ast, ast.UnsignedInt128Ty))
- return GetType(ast.UnsignedInt128Ty);
- }
- }
- // We weren't able to match up a type name, just search by size
- if (QualTypeMatchesBitSize(bit_size, ast, ast.UnsignedCharTy))
- return GetType(ast.UnsignedCharTy);
- if (QualTypeMatchesBitSize(bit_size, ast, ast.UnsignedShortTy))
- return GetType(ast.UnsignedShortTy);
- if (QualTypeMatchesBitSize(bit_size, ast, ast.UnsignedIntTy))
- return GetType(ast.UnsignedIntTy);
- if (QualTypeMatchesBitSize(bit_size, ast, ast.UnsignedLongTy))
- return GetType(ast.UnsignedLongTy);
- if (QualTypeMatchesBitSize(bit_size, ast, ast.UnsignedLongLongTy))
- return GetType(ast.UnsignedLongLongTy);
- if (QualTypeMatchesBitSize(bit_size, ast, ast.UnsignedInt128Ty))
- return GetType(ast.UnsignedInt128Ty);
- break;
-
- case DW_ATE_unsigned_char:
- if (!ast.getLangOpts().CharIsSigned && type_name == "char") {
- if (QualTypeMatchesBitSize(bit_size, ast, ast.CharTy))
- return GetType(ast.CharTy);
- }
- if (QualTypeMatchesBitSize(bit_size, ast, ast.UnsignedCharTy))
- return GetType(ast.UnsignedCharTy);
- if (QualTypeMatchesBitSize(bit_size, ast, ast.UnsignedShortTy))
- return GetType(ast.UnsignedShortTy);
- break;
-
- case DW_ATE_imaginary_float:
- break;
-
- case DW_ATE_UTF:
- if (!type_name.empty()) {
- if (type_name == "char16_t")
- return GetType(ast.Char16Ty);
- if (type_name == "char32_t")
- return GetType(ast.Char32Ty);
- if (type_name == "char8_t")
- return GetType(ast.Char8Ty);
- }
- break;
- }
- // This assert should fire for anything that we don't catch above so we know
- // to fix any issues we run into.
- if (!type_name.empty()) {
- std::string type_name_str = type_name.str();
- Host::SystemLog(Host::eSystemLogError,
- "error: need to add support for DW_TAG_base_type '%s' "
- "encoded with DW_ATE = 0x%x, bit_size = %u\n",
- type_name_str.c_str(), dw_ate, bit_size);
- } else {
- Host::SystemLog(Host::eSystemLogError, "error: need to add support for "
- "DW_TAG_base_type encoded with "
- "DW_ATE = 0x%x, bit_size = %u\n",
- dw_ate, bit_size);
- }
- return CompilerType();
-}
-
-CompilerType TypeSystemClang::GetCStringType(bool is_const) {
- ASTContext &ast = getASTContext();
- QualType char_type(ast.CharTy);
-
- if (is_const)
- char_type.addConst();
-
- return GetType(ast.getPointerType(char_type));
-}
-
-bool TypeSystemClang::AreTypesSame(CompilerType type1, CompilerType type2,
- bool ignore_qualifiers) {
- TypeSystemClang *ast =
- llvm::dyn_cast_or_null<TypeSystemClang>(type1.GetTypeSystem());
- if (!ast || ast != type2.GetTypeSystem())
- return false;
-
- if (type1.GetOpaqueQualType() == type2.GetOpaqueQualType())
- return true;
-
- QualType type1_qual = ClangUtil::GetQualType(type1);
- QualType type2_qual = ClangUtil::GetQualType(type2);
-
- if (ignore_qualifiers) {
- type1_qual = type1_qual.getUnqualifiedType();
- type2_qual = type2_qual.getUnqualifiedType();
- }
-
- return ast->getASTContext().hasSameType(type1_qual, type2_qual);
-}
-
-CompilerType TypeSystemClang::GetTypeForDecl(void *opaque_decl) {
- if (!opaque_decl)
- return CompilerType();
-
- clang::Decl *decl = static_cast<clang::Decl *>(opaque_decl);
- if (auto *named_decl = llvm::dyn_cast<clang::NamedDecl>(decl))
- return GetTypeForDecl(named_decl);
- return CompilerType();
-}
-
-CompilerDeclContext TypeSystemClang::CreateDeclContext(DeclContext *ctx) {
- // Check that the DeclContext actually belongs to this ASTContext.
- assert(&ctx->getParentASTContext() == &getASTContext());
- return CompilerDeclContext(this, ctx);
-}
-
-CompilerType TypeSystemClang::GetTypeForDecl(clang::NamedDecl *decl) {
- if (clang::ObjCInterfaceDecl *interface_decl =
- llvm::dyn_cast<clang::ObjCInterfaceDecl>(decl))
- return GetTypeForDecl(interface_decl);
- if (clang::TagDecl *tag_decl = llvm::dyn_cast<clang::TagDecl>(decl))
- return GetTypeForDecl(tag_decl);
- return CompilerType();
-}
-
-CompilerType TypeSystemClang::GetTypeForDecl(TagDecl *decl) {
- return GetType(getASTContext().getTagDeclType(decl));
-}
-
-CompilerType TypeSystemClang::GetTypeForDecl(ObjCInterfaceDecl *decl) {
- return GetType(getASTContext().getObjCInterfaceType(decl));
-}
-
-#pragma mark Structure, Unions, Classes
-
-CompilerType TypeSystemClang::CreateRecordType(DeclContext *decl_ctx,
- AccessType access_type,
- llvm::StringRef name, int kind,
- LanguageType language,
- ClangASTMetadata *metadata,
- bool exports_symbols) {
- ASTContext &ast = getASTContext();
-
- if (decl_ctx == nullptr)
- decl_ctx = ast.getTranslationUnitDecl();
-
- if (language == eLanguageTypeObjC ||
- language == eLanguageTypeObjC_plus_plus) {
- bool isForwardDecl = true;
- bool isInternal = false;
- return CreateObjCClass(name, decl_ctx, isForwardDecl, isInternal, metadata);
- }
-
- // NOTE: Eventually CXXRecordDecl will be merged back into RecordDecl and
- // we will need to update this code. I was told to currently always use the
- // CXXRecordDecl class since we often don't know from debug information if
- // something is struct or a class, so we default to always use the more
- // complete definition just in case.
-
- bool has_name = !name.empty();
-
- CXXRecordDecl *decl = CXXRecordDecl::Create(
- ast, (TagDecl::TagKind)kind, decl_ctx, SourceLocation(), SourceLocation(),
- has_name ? &ast.Idents.get(name) : nullptr);
-
- if (!has_name) {
- // In C++ a lambda is also represented as an unnamed class. This is
- // different from an *anonymous class* that the user wrote:
- //
- // struct A {
- // // anonymous class (GNU/MSVC extension)
- // struct {
- // int x;
- // };
- // // unnamed class within a class
- // struct {
- // int y;
- // } B;
- // };
- //
- // void f() {
- // // unammed class outside of a class
- // struct {
- // int z;
- // } C;
- // }
- //
- // Anonymous classes is a GNU/MSVC extension that clang supports. It
- // requires the anonymous class be embedded within a class. So the new
- // heuristic verifies this condition.
- if (isa<CXXRecordDecl>(decl_ctx) && exports_symbols)
- decl->setAnonymousStructOrUnion(true);
- }
-
- if (decl) {
- if (metadata)
- SetMetadata(decl, *metadata);
-
- if (access_type != eAccessNone)
- decl->setAccess(ConvertAccessTypeToAccessSpecifier(access_type));
-
- if (decl_ctx)
- decl_ctx->addDecl(decl);
-
- return GetType(ast.getTagDeclType(decl));
- }
- return CompilerType();
-}
-
-namespace {
- bool IsValueParam(const clang::TemplateArgument &argument) {
- return argument.getKind() == TemplateArgument::Integral;
- }
-}
-
-static TemplateParameterList *CreateTemplateParameterList(
- ASTContext *ast,
- const TypeSystemClang::TemplateParameterInfos &template_param_infos,
- llvm::SmallVector<NamedDecl *, 8> &template_param_decls) {
- const bool parameter_pack = false;
- const bool is_typename = false;
- const unsigned depth = 0;
- const size_t num_template_params = template_param_infos.args.size();
- DeclContext *const decl_context =
- ast->getTranslationUnitDecl(); // Is this the right decl context?,
- for (size_t i = 0; i < num_template_params; ++i) {
- const char *name = template_param_infos.names[i];
-
- IdentifierInfo *identifier_info = nullptr;
- if (name && name[0])
- identifier_info = &ast->Idents.get(name);
- if (IsValueParam(template_param_infos.args[i])) {
- template_param_decls.push_back(NonTypeTemplateParmDecl::Create(
- *ast, decl_context,
- SourceLocation(), SourceLocation(), depth, i, identifier_info,
- template_param_infos.args[i].getIntegralType(), parameter_pack,
- nullptr));
-
- } else {
- template_param_decls.push_back(TemplateTypeParmDecl::Create(
- *ast, decl_context,
- SourceLocation(), SourceLocation(), depth, i, identifier_info,
- is_typename, parameter_pack));
- }
- }
-
- if (template_param_infos.packed_args) {
- IdentifierInfo *identifier_info = nullptr;
- if (template_param_infos.pack_name && template_param_infos.pack_name[0])
- identifier_info = &ast->Idents.get(template_param_infos.pack_name);
- const bool parameter_pack_true = true;
-
- if (!template_param_infos.packed_args->args.empty() &&
- IsValueParam(template_param_infos.packed_args->args[0])) {
- template_param_decls.push_back(NonTypeTemplateParmDecl::Create(
- *ast, decl_context, SourceLocation(), SourceLocation(), depth,
- num_template_params, identifier_info,
- template_param_infos.packed_args->args[0].getIntegralType(),
- parameter_pack_true, nullptr));
- } else {
- template_param_decls.push_back(TemplateTypeParmDecl::Create(
- *ast, decl_context, SourceLocation(), SourceLocation(), depth,
- num_template_params, identifier_info, is_typename,
- parameter_pack_true));
- }
- }
- clang::Expr *const requires_clause = nullptr; // TODO: Concepts
- TemplateParameterList *template_param_list = TemplateParameterList::Create(
- *ast, SourceLocation(), SourceLocation(), template_param_decls,
- SourceLocation(), requires_clause);
- return template_param_list;
-}
-
-clang::FunctionTemplateDecl *TypeSystemClang::CreateFunctionTemplateDecl(
- clang::DeclContext *decl_ctx, clang::FunctionDecl *func_decl,
- const char *name, const TemplateParameterInfos &template_param_infos) {
- // /// Create a function template node.
- ASTContext &ast = getASTContext();
-
- llvm::SmallVector<NamedDecl *, 8> template_param_decls;
-
- TemplateParameterList *template_param_list = CreateTemplateParameterList(
- &ast, template_param_infos, template_param_decls);
- FunctionTemplateDecl *func_tmpl_decl = FunctionTemplateDecl::Create(
- ast, decl_ctx, func_decl->getLocation(), func_decl->getDeclName(),
- template_param_list, func_decl);
-
- for (size_t i = 0, template_param_decl_count = template_param_decls.size();
- i < template_param_decl_count; ++i) {
- // TODO: verify which decl context we should put template_param_decls into..
- template_param_decls[i]->setDeclContext(func_decl);
- }
- // Function templates inside a record need to have an access specifier.
- // It doesn't matter what access specifier we give the template as LLDB
- // anyway allows accessing everything inside a record.
- if (decl_ctx->isRecord())
- func_tmpl_decl->setAccess(clang::AccessSpecifier::AS_public);
-
- return func_tmpl_decl;
-}
-
-void TypeSystemClang::CreateFunctionTemplateSpecializationInfo(
- FunctionDecl *func_decl, clang::FunctionTemplateDecl *func_tmpl_decl,
- const TemplateParameterInfos &infos) {
- TemplateArgumentList *template_args_ptr =
- TemplateArgumentList::CreateCopy(func_decl->getASTContext(), infos.args);
-
- func_decl->setFunctionTemplateSpecialization(func_tmpl_decl,
- template_args_ptr, nullptr);
-}
-
-ClassTemplateDecl *TypeSystemClang::CreateClassTemplateDecl(
- DeclContext *decl_ctx, lldb::AccessType access_type, const char *class_name,
- int kind, const TemplateParameterInfos &template_param_infos) {
- ASTContext &ast = getASTContext();
-
- ClassTemplateDecl *class_template_decl = nullptr;
- if (decl_ctx == nullptr)
- decl_ctx = ast.getTranslationUnitDecl();
-
- IdentifierInfo &identifier_info = ast.Idents.get(class_name);
- DeclarationName decl_name(&identifier_info);
-
- clang::DeclContext::lookup_result result = decl_ctx->lookup(decl_name);
-
- for (NamedDecl *decl : result) {
- class_template_decl = dyn_cast<clang::ClassTemplateDecl>(decl);
- if (class_template_decl)
- return class_template_decl;
- }
-
- llvm::SmallVector<NamedDecl *, 8> template_param_decls;
-
- TemplateParameterList *template_param_list = CreateTemplateParameterList(
- &ast, template_param_infos, template_param_decls);
-
- CXXRecordDecl *template_cxx_decl = CXXRecordDecl::Create(
- ast, (TagDecl::TagKind)kind,
- decl_ctx, // What decl context do we use here? TU? The actual decl
- // context?
- SourceLocation(), SourceLocation(), &identifier_info);
-
- for (size_t i = 0, template_param_decl_count = template_param_decls.size();
- i < template_param_decl_count; ++i) {
- template_param_decls[i]->setDeclContext(template_cxx_decl);
- }
-
- // With templated classes, we say that a class is templated with
- // specializations, but that the bare class has no functions.
- // template_cxx_decl->startDefinition();
- // template_cxx_decl->completeDefinition();
-
- class_template_decl = ClassTemplateDecl::Create(
- ast,
- decl_ctx, // What decl context do we use here? TU? The actual decl
- // context?
- SourceLocation(), decl_name, template_param_list, template_cxx_decl);
- template_cxx_decl->setDescribedClassTemplate(class_template_decl);
-
- if (class_template_decl) {
- if (access_type != eAccessNone)
- class_template_decl->setAccess(
- ConvertAccessTypeToAccessSpecifier(access_type));
-
- // if (TagDecl *ctx_tag_decl = dyn_cast<TagDecl>(decl_ctx))
- // CompleteTagDeclarationDefinition(GetTypeForDecl(ctx_tag_decl));
-
- decl_ctx->addDecl(class_template_decl);
-
-#ifdef LLDB_CONFIGURATION_DEBUG
- VerifyDecl(class_template_decl);
-#endif
- }
-
- return class_template_decl;
-}
-
-TemplateTemplateParmDecl *
-TypeSystemClang::CreateTemplateTemplateParmDecl(const char *template_name) {
- ASTContext &ast = getASTContext();
-
- auto *decl_ctx = ast.getTranslationUnitDecl();
-
- IdentifierInfo &identifier_info = ast.Idents.get(template_name);
- llvm::SmallVector<NamedDecl *, 8> template_param_decls;
-
- TypeSystemClang::TemplateParameterInfos template_param_infos;
- TemplateParameterList *template_param_list = CreateTemplateParameterList(
- &ast, template_param_infos, template_param_decls);
-
- // LLDB needs to create those decls only to be able to display a
- // type that includes a template template argument. Only the name matters for
- // this purpose, so we use dummy values for the other characterisitcs of the
- // type.
- return TemplateTemplateParmDecl::Create(
- ast, decl_ctx, SourceLocation(),
- /*Depth*/ 0, /*Position*/ 0,
- /*IsParameterPack*/ false, &identifier_info, template_param_list);
-}
-
-ClassTemplateSpecializationDecl *
-TypeSystemClang::CreateClassTemplateSpecializationDecl(
- DeclContext *decl_ctx, ClassTemplateDecl *class_template_decl, int kind,
- const TemplateParameterInfos &template_param_infos) {
- ASTContext &ast = getASTContext();
- llvm::SmallVector<clang::TemplateArgument, 2> args(
- template_param_infos.args.size() +
- (template_param_infos.packed_args ? 1 : 0));
- std::copy(template_param_infos.args.begin(), template_param_infos.args.end(),
- args.begin());
- if (template_param_infos.packed_args) {
- args[args.size() - 1] = TemplateArgument::CreatePackCopy(
- ast, template_param_infos.packed_args->args);
- }
- ClassTemplateSpecializationDecl *class_template_specialization_decl =
- ClassTemplateSpecializationDecl::Create(
- ast, (TagDecl::TagKind)kind, decl_ctx, SourceLocation(),
- SourceLocation(), class_template_decl, args, nullptr);
-
- class_template_specialization_decl->setSpecializationKind(
- TSK_ExplicitSpecialization);
-
- return class_template_specialization_decl;
-}
-
-CompilerType TypeSystemClang::CreateClassTemplateSpecializationType(
- ClassTemplateSpecializationDecl *class_template_specialization_decl) {
- if (class_template_specialization_decl) {
- ASTContext &ast = getASTContext();
- return GetType(ast.getTagDeclType(class_template_specialization_decl));
- }
- return CompilerType();
-}
-
-static inline bool check_op_param(bool is_method,
- clang::OverloadedOperatorKind op_kind,
- bool unary, bool binary,
- uint32_t num_params) {
- // Special-case call since it can take any number of operands
- if (op_kind == OO_Call)
- return true;
-
- // The parameter count doesn't include "this"
- if (is_method)
- ++num_params;
- if (num_params == 1)
- return unary;
- if (num_params == 2)
- return binary;
- else
- return false;
-}
-
-bool TypeSystemClang::CheckOverloadedOperatorKindParameterCount(
- bool is_method, clang::OverloadedOperatorKind op_kind,
- uint32_t num_params) {
- switch (op_kind) {
- default:
- break;
- // C++ standard allows any number of arguments to new/delete
- case OO_New:
- case OO_Array_New:
- case OO_Delete:
- case OO_Array_Delete:
- return true;
- }
-
-#define OVERLOADED_OPERATOR(Name, Spelling, Token, Unary, Binary, MemberOnly) \
- case OO_##Name: \
- return check_op_param(is_method, op_kind, Unary, Binary, num_params);
- switch (op_kind) {
-#include "clang/Basic/OperatorKinds.def"
- default:
- break;
- }
- return false;
-}
-
-clang::AccessSpecifier
-TypeSystemClang::UnifyAccessSpecifiers(clang::AccessSpecifier lhs,
- clang::AccessSpecifier rhs) {
- // Make the access equal to the stricter of the field and the nested field's
- // access
- if (lhs == AS_none || rhs == AS_none)
- return AS_none;
- if (lhs == AS_private || rhs == AS_private)
- return AS_private;
- if (lhs == AS_protected || rhs == AS_protected)
- return AS_protected;
- return AS_public;
-}
-
-bool TypeSystemClang::FieldIsBitfield(FieldDecl *field,
- uint32_t &bitfield_bit_size) {
- ASTContext &ast = getASTContext();
- if (field == nullptr)
- return false;
-
- if (field->isBitField()) {
- Expr *bit_width_expr = field->getBitWidth();
- if (bit_width_expr) {
- llvm::APSInt bit_width_apsint;
- if (bit_width_expr->isIntegerConstantExpr(bit_width_apsint, ast)) {
- bitfield_bit_size = bit_width_apsint.getLimitedValue(UINT32_MAX);
- return true;
- }
- }
- }
- return false;
-}
-
-bool TypeSystemClang::RecordHasFields(const RecordDecl *record_decl) {
- if (record_decl == nullptr)
- return false;
-
- if (!record_decl->field_empty())
- return true;
-
- // No fields, lets check this is a CXX record and check the base classes
- const CXXRecordDecl *cxx_record_decl = dyn_cast<CXXRecordDecl>(record_decl);
- if (cxx_record_decl) {
- CXXRecordDecl::base_class_const_iterator base_class, base_class_end;
- for (base_class = cxx_record_decl->bases_begin(),
- base_class_end = cxx_record_decl->bases_end();
- base_class != base_class_end; ++base_class) {
- const CXXRecordDecl *base_class_decl = cast<CXXRecordDecl>(
- base_class->getType()->getAs<RecordType>()->getDecl());
- if (RecordHasFields(base_class_decl))
- return true;
- }
- }
- return false;
-}
-
-#pragma mark Objective-C Classes
-
-CompilerType TypeSystemClang::CreateObjCClass(llvm::StringRef name,
- DeclContext *decl_ctx,
- bool isForwardDecl,
- bool isInternal,
- ClangASTMetadata *metadata) {
- ASTContext &ast = getASTContext();
- assert(!name.empty());
- if (decl_ctx == nullptr)
- decl_ctx = ast.getTranslationUnitDecl();
-
- ObjCInterfaceDecl *decl = ObjCInterfaceDecl::Create(
- ast, decl_ctx, SourceLocation(), &ast.Idents.get(name), nullptr, nullptr,
- SourceLocation(),
- /*isForwardDecl,*/
- isInternal);
-
- if (decl && metadata)
- SetMetadata(decl, *metadata);
-
- return GetType(ast.getObjCInterfaceType(decl));
-}
-
-static inline bool BaseSpecifierIsEmpty(const CXXBaseSpecifier *b) {
- return !TypeSystemClang::RecordHasFields(b->getType()->getAsCXXRecordDecl());
-}
-
-uint32_t
-TypeSystemClang::GetNumBaseClasses(const CXXRecordDecl *cxx_record_decl,
- bool omit_empty_base_classes) {
- uint32_t num_bases = 0;
- if (cxx_record_decl) {
- if (omit_empty_base_classes) {
- CXXRecordDecl::base_class_const_iterator base_class, base_class_end;
- for (base_class = cxx_record_decl->bases_begin(),
- base_class_end = cxx_record_decl->bases_end();
- base_class != base_class_end; ++base_class) {
- // Skip empty base classes
- if (omit_empty_base_classes) {
- if (BaseSpecifierIsEmpty(base_class))
- continue;
- }
- ++num_bases;
- }
- } else
- num_bases = cxx_record_decl->getNumBases();
- }
- return num_bases;
-}
-
-#pragma mark Namespace Declarations
-
-NamespaceDecl *TypeSystemClang::GetUniqueNamespaceDeclaration(
- const char *name, DeclContext *decl_ctx, bool is_inline) {
- NamespaceDecl *namespace_decl = nullptr;
- ASTContext &ast = getASTContext();
- TranslationUnitDecl *translation_unit_decl = ast.getTranslationUnitDecl();
- if (decl_ctx == nullptr)
- decl_ctx = translation_unit_decl;
-
- if (name) {
- IdentifierInfo &identifier_info = ast.Idents.get(name);
- DeclarationName decl_name(&identifier_info);
- clang::DeclContext::lookup_result result = decl_ctx->lookup(decl_name);
- for (NamedDecl *decl : result) {
- namespace_decl = dyn_cast<clang::NamespaceDecl>(decl);
- if (namespace_decl)
- return namespace_decl;
- }
-
- namespace_decl =
- NamespaceDecl::Create(ast, decl_ctx, is_inline, SourceLocation(),
- SourceLocation(), &identifier_info, nullptr);
-
- decl_ctx->addDecl(namespace_decl);
- } else {
- if (decl_ctx == translation_unit_decl) {
- namespace_decl = translation_unit_decl->getAnonymousNamespace();
- if (namespace_decl)
- return namespace_decl;
-
- namespace_decl =
- NamespaceDecl::Create(ast, decl_ctx, false, SourceLocation(),
- SourceLocation(), nullptr, nullptr);
- translation_unit_decl->setAnonymousNamespace(namespace_decl);
- translation_unit_decl->addDecl(namespace_decl);
- assert(namespace_decl == translation_unit_decl->getAnonymousNamespace());
- } else {
- NamespaceDecl *parent_namespace_decl = cast<NamespaceDecl>(decl_ctx);
- if (parent_namespace_decl) {
- namespace_decl = parent_namespace_decl->getAnonymousNamespace();
- if (namespace_decl)
- return namespace_decl;
- namespace_decl =
- NamespaceDecl::Create(ast, decl_ctx, false, SourceLocation(),
- SourceLocation(), nullptr, nullptr);
- parent_namespace_decl->setAnonymousNamespace(namespace_decl);
- parent_namespace_decl->addDecl(namespace_decl);
- assert(namespace_decl ==
- parent_namespace_decl->getAnonymousNamespace());
- } else {
- assert(false && "GetUniqueNamespaceDeclaration called with no name and "
- "no namespace as decl_ctx");
- }
- }
- }
-#ifdef LLDB_CONFIGURATION_DEBUG
- VerifyDecl(namespace_decl);
-#endif
- return namespace_decl;
-}
-
-clang::BlockDecl *
-TypeSystemClang::CreateBlockDeclaration(clang::DeclContext *ctx) {
- if (ctx != nullptr) {
- clang::BlockDecl *decl =
- clang::BlockDecl::Create(getASTContext(), ctx, clang::SourceLocation());
- ctx->addDecl(decl);
- return decl;
- }
- return nullptr;
-}
-
-clang::DeclContext *FindLCABetweenDecls(clang::DeclContext *left,
- clang::DeclContext *right,
- clang::DeclContext *root) {
- if (root == nullptr)
- return nullptr;
-
- std::set<clang::DeclContext *> path_left;
- for (clang::DeclContext *d = left; d != nullptr; d = d->getParent())
- path_left.insert(d);
-
- for (clang::DeclContext *d = right; d != nullptr; d = d->getParent())
- if (path_left.find(d) != path_left.end())
- return d;
-
- return nullptr;
-}
-
-clang::UsingDirectiveDecl *TypeSystemClang::CreateUsingDirectiveDeclaration(
- clang::DeclContext *decl_ctx, clang::NamespaceDecl *ns_decl) {
- if (decl_ctx != nullptr && ns_decl != nullptr) {
- auto *translation_unit = getASTContext().getTranslationUnitDecl();
- clang::UsingDirectiveDecl *using_decl = clang::UsingDirectiveDecl::Create(
- getASTContext(), decl_ctx, clang::SourceLocation(),
- clang::SourceLocation(), clang::NestedNameSpecifierLoc(),
- clang::SourceLocation(), ns_decl,
- FindLCABetweenDecls(decl_ctx, ns_decl, translation_unit));
- decl_ctx->addDecl(using_decl);
- return using_decl;
- }
- return nullptr;
-}
-
-clang::UsingDecl *
-TypeSystemClang::CreateUsingDeclaration(clang::DeclContext *current_decl_ctx,
- clang::NamedDecl *target) {
- if (current_decl_ctx != nullptr && target != nullptr) {
- clang::UsingDecl *using_decl = clang::UsingDecl::Create(
- getASTContext(), current_decl_ctx, clang::SourceLocation(),
- clang::NestedNameSpecifierLoc(), clang::DeclarationNameInfo(), false);
- clang::UsingShadowDecl *shadow_decl = clang::UsingShadowDecl::Create(
- getASTContext(), current_decl_ctx, clang::SourceLocation(), using_decl,
- target);
- using_decl->addShadowDecl(shadow_decl);
- current_decl_ctx->addDecl(using_decl);
- return using_decl;
- }
- return nullptr;
-}
-
-clang::VarDecl *TypeSystemClang::CreateVariableDeclaration(
- clang::DeclContext *decl_context, const char *name, clang::QualType type) {
- if (decl_context != nullptr) {
- clang::VarDecl *var_decl = clang::VarDecl::Create(
- getASTContext(), decl_context, clang::SourceLocation(),
- clang::SourceLocation(),
- name && name[0] ? &getASTContext().Idents.getOwn(name) : nullptr, type,
- nullptr, clang::SC_None);
- var_decl->setAccess(clang::AS_public);
- decl_context->addDecl(var_decl);
- return var_decl;
- }
- return nullptr;
-}
-
-lldb::opaque_compiler_type_t
-TypeSystemClang::GetOpaqueCompilerType(clang::ASTContext *ast,
- lldb::BasicType basic_type) {
- switch (basic_type) {
- case eBasicTypeVoid:
- return ast->VoidTy.getAsOpaquePtr();
- case eBasicTypeChar:
- return ast->CharTy.getAsOpaquePtr();
- case eBasicTypeSignedChar:
- return ast->SignedCharTy.getAsOpaquePtr();
- case eBasicTypeUnsignedChar:
- return ast->UnsignedCharTy.getAsOpaquePtr();
- case eBasicTypeWChar:
- return ast->getWCharType().getAsOpaquePtr();
- case eBasicTypeSignedWChar:
- return ast->getSignedWCharType().getAsOpaquePtr();
- case eBasicTypeUnsignedWChar:
- return ast->getUnsignedWCharType().getAsOpaquePtr();
- case eBasicTypeChar16:
- return ast->Char16Ty.getAsOpaquePtr();
- case eBasicTypeChar32:
- return ast->Char32Ty.getAsOpaquePtr();
- case eBasicTypeShort:
- return ast->ShortTy.getAsOpaquePtr();
- case eBasicTypeUnsignedShort:
- return ast->UnsignedShortTy.getAsOpaquePtr();
- case eBasicTypeInt:
- return ast->IntTy.getAsOpaquePtr();
- case eBasicTypeUnsignedInt:
- return ast->UnsignedIntTy.getAsOpaquePtr();
- case eBasicTypeLong:
- return ast->LongTy.getAsOpaquePtr();
- case eBasicTypeUnsignedLong:
- return ast->UnsignedLongTy.getAsOpaquePtr();
- case eBasicTypeLongLong:
- return ast->LongLongTy.getAsOpaquePtr();
- case eBasicTypeUnsignedLongLong:
- return ast->UnsignedLongLongTy.getAsOpaquePtr();
- case eBasicTypeInt128:
- return ast->Int128Ty.getAsOpaquePtr();
- case eBasicTypeUnsignedInt128:
- return ast->UnsignedInt128Ty.getAsOpaquePtr();
- case eBasicTypeBool:
- return ast->BoolTy.getAsOpaquePtr();
- case eBasicTypeHalf:
- return ast->HalfTy.getAsOpaquePtr();
- case eBasicTypeFloat:
- return ast->FloatTy.getAsOpaquePtr();
- case eBasicTypeDouble:
- return ast->DoubleTy.getAsOpaquePtr();
- case eBasicTypeLongDouble:
- return ast->LongDoubleTy.getAsOpaquePtr();
- case eBasicTypeFloatComplex:
- return ast->FloatComplexTy.getAsOpaquePtr();
- case eBasicTypeDoubleComplex:
- return ast->DoubleComplexTy.getAsOpaquePtr();
- case eBasicTypeLongDoubleComplex:
- return ast->LongDoubleComplexTy.getAsOpaquePtr();
- case eBasicTypeObjCID:
- return ast->getObjCIdType().getAsOpaquePtr();
- case eBasicTypeObjCClass:
- return ast->getObjCClassType().getAsOpaquePtr();
- case eBasicTypeObjCSel:
- return ast->getObjCSelType().getAsOpaquePtr();
- case eBasicTypeNullPtr:
- return ast->NullPtrTy.getAsOpaquePtr();
- default:
- return nullptr;
- }
-}
-
-#pragma mark Function Types
-
-clang::DeclarationName
-TypeSystemClang::GetDeclarationName(const char *name,
- const CompilerType &function_clang_type) {
- if (!name || !name[0])
- return clang::DeclarationName();
-
- clang::OverloadedOperatorKind op_kind = clang::NUM_OVERLOADED_OPERATORS;
- if (!IsOperator(name, op_kind) || op_kind == clang::NUM_OVERLOADED_OPERATORS)
- return DeclarationName(&getASTContext().Idents.get(
- name)); // Not operator, but a regular function.
-
- // Check the number of operator parameters. Sometimes we have seen bad DWARF
- // that doesn't correctly describe operators and if we try to create a method
- // and add it to the class, clang will assert and crash, so we need to make
- // sure things are acceptable.
- clang::QualType method_qual_type(ClangUtil::GetQualType(function_clang_type));
- const clang::FunctionProtoType *function_type =
- llvm::dyn_cast<clang::FunctionProtoType>(method_qual_type.getTypePtr());
- if (function_type == nullptr)
- return clang::DeclarationName();
-
- const bool is_method = false;
- const unsigned int num_params = function_type->getNumParams();
- if (!TypeSystemClang::CheckOverloadedOperatorKindParameterCount(
- is_method, op_kind, num_params))
- return clang::DeclarationName();
-
- return getASTContext().DeclarationNames.getCXXOperatorName(op_kind);
-}
-
-FunctionDecl *TypeSystemClang::CreateFunctionDeclaration(
- DeclContext *decl_ctx, const char *name,
- const CompilerType &function_clang_type, int storage, bool is_inline) {
- FunctionDecl *func_decl = nullptr;
- ASTContext &ast = getASTContext();
- if (decl_ctx == nullptr)
- decl_ctx = ast.getTranslationUnitDecl();
-
- const bool hasWrittenPrototype = true;
- const bool isConstexprSpecified = false;
-
- clang::DeclarationName declarationName =
- GetDeclarationName(name, function_clang_type);
- func_decl = FunctionDecl::Create(
- ast, decl_ctx, SourceLocation(), SourceLocation(), declarationName,
- ClangUtil::GetQualType(function_clang_type), nullptr,
- (clang::StorageClass)storage, is_inline, hasWrittenPrototype,
- isConstexprSpecified ? CSK_constexpr : CSK_unspecified);
- if (func_decl)
- decl_ctx->addDecl(func_decl);
-
-#ifdef LLDB_CONFIGURATION_DEBUG
- VerifyDecl(func_decl);
-#endif
-
- return func_decl;
-}
-
-CompilerType
-TypeSystemClang::CreateFunctionType(const CompilerType &result_type,
- const CompilerType *args, unsigned num_args,
- bool is_variadic, unsigned type_quals,
- clang::CallingConv cc) {
- if (!result_type || !ClangUtil::IsClangType(result_type))
- return CompilerType(); // invalid return type
-
- std::vector<QualType> qual_type_args;
- if (num_args > 0 && args == nullptr)
- return CompilerType(); // invalid argument array passed in
-
- // Verify that all arguments are valid and the right type
- for (unsigned i = 0; i < num_args; ++i) {
- if (args[i]) {
- // Make sure we have a clang type in args[i] and not a type from another
- // language whose name might match
- const bool is_clang_type = ClangUtil::IsClangType(args[i]);
- lldbassert(is_clang_type);
- if (is_clang_type)
- qual_type_args.push_back(ClangUtil::GetQualType(args[i]));
- else
- return CompilerType(); // invalid argument type (must be a clang type)
- } else
- return CompilerType(); // invalid argument type (empty)
- }
-
- // TODO: Detect calling convention in DWARF?
- FunctionProtoType::ExtProtoInfo proto_info;
- proto_info.ExtInfo = cc;
- proto_info.Variadic = is_variadic;
- proto_info.ExceptionSpec = EST_None;
- proto_info.TypeQuals = clang::Qualifiers::fromFastMask(type_quals);
- proto_info.RefQualifier = RQ_None;
-
- return GetType(getASTContext().getFunctionType(
- ClangUtil::GetQualType(result_type), qual_type_args, proto_info));
-}
-
-ParmVarDecl *TypeSystemClang::CreateParameterDeclaration(
- clang::DeclContext *decl_ctx, const char *name,
- const CompilerType ¶m_type, int storage, bool add_decl) {
- ASTContext &ast = getASTContext();
- auto *decl =
- ParmVarDecl::Create(ast, decl_ctx, SourceLocation(), SourceLocation(),
- name && name[0] ? &ast.Idents.get(name) : nullptr,
- ClangUtil::GetQualType(param_type), nullptr,
- (clang::StorageClass)storage, nullptr);
- if (add_decl)
- decl_ctx->addDecl(decl);
-
- return decl;
-}
-
-void TypeSystemClang::SetFunctionParameters(FunctionDecl *function_decl,
- ParmVarDecl **params,
- unsigned num_params) {
- if (function_decl)
- function_decl->setParams(ArrayRef<ParmVarDecl *>(params, num_params));
-}
-
-CompilerType
-TypeSystemClang::CreateBlockPointerType(const CompilerType &function_type) {
- QualType block_type = m_ast_up->getBlockPointerType(
- clang::QualType::getFromOpaquePtr(function_type.GetOpaqueQualType()));
-
- return GetType(block_type);
-}
-
-#pragma mark Array Types
-
-CompilerType TypeSystemClang::CreateArrayType(const CompilerType &element_type,
- size_t element_count,
- bool is_vector) {
- if (element_type.IsValid()) {
- ASTContext &ast = getASTContext();
-
- if (is_vector) {
- return GetType(ast.getExtVectorType(ClangUtil::GetQualType(element_type),
- element_count));
- } else {
-
- llvm::APInt ap_element_count(64, element_count);
- if (element_count == 0) {
- return GetType(ast.getIncompleteArrayType(
- ClangUtil::GetQualType(element_type), clang::ArrayType::Normal, 0));
- } else {
- return GetType(ast.getConstantArrayType(
- ClangUtil::GetQualType(element_type), ap_element_count, nullptr,
- clang::ArrayType::Normal, 0));
- }
- }
- }
- return CompilerType();
-}
-
-CompilerType TypeSystemClang::CreateStructForIdentifier(
- ConstString type_name,
- const std::initializer_list<std::pair<const char *, CompilerType>>
- &type_fields,
- bool packed) {
- CompilerType type;
- if (!type_name.IsEmpty() &&
- (type = GetTypeForIdentifier<clang::CXXRecordDecl>(type_name))
- .IsValid()) {
- lldbassert(0 && "Trying to create a type for an existing name");
- return type;
- }
-
- type = CreateRecordType(nullptr, lldb::eAccessPublic, type_name.GetCString(),
- clang::TTK_Struct, lldb::eLanguageTypeC);
- StartTagDeclarationDefinition(type);
- for (const auto &field : type_fields)
- AddFieldToRecordType(type, field.first, field.second, lldb::eAccessPublic,
- 0);
- if (packed)
- SetIsPacked(type);
- CompleteTagDeclarationDefinition(type);
- return type;
-}
-
-CompilerType TypeSystemClang::GetOrCreateStructForIdentifier(
- ConstString type_name,
- const std::initializer_list<std::pair<const char *, CompilerType>>
- &type_fields,
- bool packed) {
- CompilerType type;
- if ((type = GetTypeForIdentifier<clang::CXXRecordDecl>(type_name)).IsValid())
- return type;
-
- return CreateStructForIdentifier(type_name, type_fields, packed);
-}
-
-#pragma mark Enumeration Types
-
-CompilerType
-TypeSystemClang::CreateEnumerationType(const char *name, DeclContext *decl_ctx,
- const Declaration &decl,
- const CompilerType &integer_clang_type,
- bool is_scoped) {
- // TODO: Do something intelligent with the Declaration object passed in
- // like maybe filling in the SourceLocation with it...
- ASTContext &ast = getASTContext();
-
- // TODO: ask about these...
- // const bool IsFixed = false;
-
- EnumDecl *enum_decl = EnumDecl::Create(
- ast, decl_ctx, SourceLocation(), SourceLocation(),
- name && name[0] ? &ast.Idents.get(name) : nullptr, nullptr,
- is_scoped, // IsScoped
- is_scoped, // IsScopedUsingClassTag
- false); // IsFixed
-
- if (enum_decl) {
- if (decl_ctx)
- decl_ctx->addDecl(enum_decl);
-
- // TODO: check if we should be setting the promotion type too?
- enum_decl->setIntegerType(ClangUtil::GetQualType(integer_clang_type));
-
- enum_decl->setAccess(AS_public); // TODO respect what's in the debug info
-
- return GetType(ast.getTagDeclType(enum_decl));
- }
- return CompilerType();
-}
-
-CompilerType TypeSystemClang::GetIntTypeFromBitSize(size_t bit_size,
- bool is_signed) {
- clang::ASTContext &ast = getASTContext();
-
- if (is_signed) {
- if (bit_size == ast.getTypeSize(ast.SignedCharTy))
- return GetType(ast.SignedCharTy);
-
- if (bit_size == ast.getTypeSize(ast.ShortTy))
- return GetType(ast.ShortTy);
-
- if (bit_size == ast.getTypeSize(ast.IntTy))
- return GetType(ast.IntTy);
-
- if (bit_size == ast.getTypeSize(ast.LongTy))
- return GetType(ast.LongTy);
-
- if (bit_size == ast.getTypeSize(ast.LongLongTy))
- return GetType(ast.LongLongTy);
-
- if (bit_size == ast.getTypeSize(ast.Int128Ty))
- return GetType(ast.Int128Ty);
- } else {
- if (bit_size == ast.getTypeSize(ast.UnsignedCharTy))
- return GetType(ast.UnsignedCharTy);
-
- if (bit_size == ast.getTypeSize(ast.UnsignedShortTy))
- return GetType(ast.UnsignedShortTy);
-
- if (bit_size == ast.getTypeSize(ast.UnsignedIntTy))
- return GetType(ast.UnsignedIntTy);
-
- if (bit_size == ast.getTypeSize(ast.UnsignedLongTy))
- return GetType(ast.UnsignedLongTy);
-
- if (bit_size == ast.getTypeSize(ast.UnsignedLongLongTy))
- return GetType(ast.UnsignedLongLongTy);
-
- if (bit_size == ast.getTypeSize(ast.UnsignedInt128Ty))
- return GetType(ast.UnsignedInt128Ty);
- }
- return CompilerType();
-}
-
-CompilerType TypeSystemClang::GetPointerSizedIntType(bool is_signed) {
- return GetIntTypeFromBitSize(
- getASTContext().getTypeSize(getASTContext().VoidPtrTy), is_signed);
-}
-
-void TypeSystemClang::DumpDeclContextHiearchy(clang::DeclContext *decl_ctx) {
- if (decl_ctx) {
- DumpDeclContextHiearchy(decl_ctx->getParent());
-
- clang::NamedDecl *named_decl = llvm::dyn_cast<clang::NamedDecl>(decl_ctx);
- if (named_decl) {
- printf("%20s: %s\n", decl_ctx->getDeclKindName(),
- named_decl->getDeclName().getAsString().c_str());
- } else {
- printf("%20s\n", decl_ctx->getDeclKindName());
- }
- }
-}
-
-void TypeSystemClang::DumpDeclHiearchy(clang::Decl *decl) {
- if (decl == nullptr)
- return;
- DumpDeclContextHiearchy(decl->getDeclContext());
-
- clang::RecordDecl *record_decl = llvm::dyn_cast<clang::RecordDecl>(decl);
- if (record_decl) {
- printf("%20s: %s%s\n", decl->getDeclKindName(),
- record_decl->getDeclName().getAsString().c_str(),
- record_decl->isInjectedClassName() ? " (injected class name)" : "");
-
- } else {
- clang::NamedDecl *named_decl = llvm::dyn_cast<clang::NamedDecl>(decl);
- if (named_decl) {
- printf("%20s: %s\n", decl->getDeclKindName(),
- named_decl->getDeclName().getAsString().c_str());
- } else {
- printf("%20s\n", decl->getDeclKindName());
- }
- }
-}
-
-bool TypeSystemClang::DeclsAreEquivalent(clang::Decl *lhs_decl,
- clang::Decl *rhs_decl) {
- if (lhs_decl && rhs_decl) {
- // Make sure the decl kinds match first
- const clang::Decl::Kind lhs_decl_kind = lhs_decl->getKind();
- const clang::Decl::Kind rhs_decl_kind = rhs_decl->getKind();
-
- if (lhs_decl_kind == rhs_decl_kind) {
- // Now check that the decl contexts kinds are all equivalent before we
- // have to check any names of the decl contexts...
- clang::DeclContext *lhs_decl_ctx = lhs_decl->getDeclContext();
- clang::DeclContext *rhs_decl_ctx = rhs_decl->getDeclContext();
- if (lhs_decl_ctx && rhs_decl_ctx) {
- while (true) {
- if (lhs_decl_ctx && rhs_decl_ctx) {
- const clang::Decl::Kind lhs_decl_ctx_kind =
- lhs_decl_ctx->getDeclKind();
- const clang::Decl::Kind rhs_decl_ctx_kind =
- rhs_decl_ctx->getDeclKind();
- if (lhs_decl_ctx_kind == rhs_decl_ctx_kind) {
- lhs_decl_ctx = lhs_decl_ctx->getParent();
- rhs_decl_ctx = rhs_decl_ctx->getParent();
-
- if (lhs_decl_ctx == nullptr && rhs_decl_ctx == nullptr)
- break;
- } else
- return false;
- } else
- return false;
- }
-
- // Now make sure the name of the decls match
- clang::NamedDecl *lhs_named_decl =
- llvm::dyn_cast<clang::NamedDecl>(lhs_decl);
- clang::NamedDecl *rhs_named_decl =
- llvm::dyn_cast<clang::NamedDecl>(rhs_decl);
- if (lhs_named_decl && rhs_named_decl) {
- clang::DeclarationName lhs_decl_name = lhs_named_decl->getDeclName();
- clang::DeclarationName rhs_decl_name = rhs_named_decl->getDeclName();
- if (lhs_decl_name.getNameKind() == rhs_decl_name.getNameKind()) {
- if (lhs_decl_name.getAsString() != rhs_decl_name.getAsString())
- return false;
- } else
- return false;
- } else
- return false;
-
- // We know that the decl context kinds all match, so now we need to
- // make sure the names match as well
- lhs_decl_ctx = lhs_decl->getDeclContext();
- rhs_decl_ctx = rhs_decl->getDeclContext();
- while (true) {
- switch (lhs_decl_ctx->getDeclKind()) {
- case clang::Decl::TranslationUnit:
- // We don't care about the translation unit names
- return true;
- default: {
- clang::NamedDecl *lhs_named_decl =
- llvm::dyn_cast<clang::NamedDecl>(lhs_decl_ctx);
- clang::NamedDecl *rhs_named_decl =
- llvm::dyn_cast<clang::NamedDecl>(rhs_decl_ctx);
- if (lhs_named_decl && rhs_named_decl) {
- clang::DeclarationName lhs_decl_name =
- lhs_named_decl->getDeclName();
- clang::DeclarationName rhs_decl_name =
- rhs_named_decl->getDeclName();
- if (lhs_decl_name.getNameKind() == rhs_decl_name.getNameKind()) {
- if (lhs_decl_name.getAsString() != rhs_decl_name.getAsString())
- return false;
- } else
- return false;
- } else
- return false;
- } break;
- }
- lhs_decl_ctx = lhs_decl_ctx->getParent();
- rhs_decl_ctx = rhs_decl_ctx->getParent();
- }
- }
- }
- }
- return false;
-}
-bool TypeSystemClang::GetCompleteDecl(clang::ASTContext *ast,
- clang::Decl *decl) {
- if (!decl)
- return false;
-
- ExternalASTSource *ast_source = ast->getExternalSource();
-
- if (!ast_source)
- return false;
-
- if (clang::TagDecl *tag_decl = llvm::dyn_cast<clang::TagDecl>(decl)) {
- if (tag_decl->isCompleteDefinition())
- return true;
-
- if (!tag_decl->hasExternalLexicalStorage())
- return false;
-
- ast_source->CompleteType(tag_decl);
-
- return !tag_decl->getTypeForDecl()->isIncompleteType();
- } else if (clang::ObjCInterfaceDecl *objc_interface_decl =
- llvm::dyn_cast<clang::ObjCInterfaceDecl>(decl)) {
- if (objc_interface_decl->getDefinition())
- return true;
-
- if (!objc_interface_decl->hasExternalLexicalStorage())
- return false;
-
- ast_source->CompleteType(objc_interface_decl);
-
- return !objc_interface_decl->getTypeForDecl()->isIncompleteType();
- } else {
- return false;
- }
-}
-
-void TypeSystemClang::SetMetadataAsUserID(const clang::Decl *decl,
- user_id_t user_id) {
- ClangASTMetadata meta_data;
- meta_data.SetUserID(user_id);
- SetMetadata(decl, meta_data);
-}
-
-void TypeSystemClang::SetMetadataAsUserID(const clang::Type *type,
- user_id_t user_id) {
- ClangASTMetadata meta_data;
- meta_data.SetUserID(user_id);
- SetMetadata(type, meta_data);
-}
-
-void TypeSystemClang::SetMetadata(const clang::Decl *object,
- ClangASTMetadata &metadata) {
- m_decl_metadata[object] = metadata;
-}
-
-void TypeSystemClang::SetMetadata(const clang::Type *object,
- ClangASTMetadata &metadata) {
- m_type_metadata[object] = metadata;
-}
-
-ClangASTMetadata *TypeSystemClang::GetMetadata(const clang::Decl *object) {
- auto It = m_decl_metadata.find(object);
- if (It != m_decl_metadata.end())
- return &It->second;
- return nullptr;
-}
-
-ClangASTMetadata *TypeSystemClang::GetMetadata(const clang::Type *object) {
- auto It = m_type_metadata.find(object);
- if (It != m_type_metadata.end())
- return &It->second;
- return nullptr;
-}
-
-bool TypeSystemClang::SetTagTypeKind(clang::QualType tag_qual_type,
- int kind) const {
- const clang::Type *clang_type = tag_qual_type.getTypePtr();
- if (clang_type) {
- const clang::TagType *tag_type = llvm::dyn_cast<clang::TagType>(clang_type);
- if (tag_type) {
- clang::TagDecl *tag_decl =
- llvm::dyn_cast<clang::TagDecl>(tag_type->getDecl());
- if (tag_decl) {
- tag_decl->setTagKind((clang::TagDecl::TagKind)kind);
- return true;
- }
- }
- }
- return false;
-}
-
-bool TypeSystemClang::SetDefaultAccessForRecordFields(
- clang::RecordDecl *record_decl, int default_accessibility,
- int *assigned_accessibilities, size_t num_assigned_accessibilities) {
- if (record_decl) {
- uint32_t field_idx;
- clang::RecordDecl::field_iterator field, field_end;
- for (field = record_decl->field_begin(),
- field_end = record_decl->field_end(), field_idx = 0;
- field != field_end; ++field, ++field_idx) {
- // If no accessibility was assigned, assign the correct one
- if (field_idx < num_assigned_accessibilities &&
- assigned_accessibilities[field_idx] == clang::AS_none)
- field->setAccess((clang::AccessSpecifier)default_accessibility);
- }
- return true;
- }
- return false;
-}
-
-clang::DeclContext *
-TypeSystemClang::GetDeclContextForType(const CompilerType &type) {
- return GetDeclContextForType(ClangUtil::GetQualType(type));
-}
-
-/// Aggressively desugar the provided type, skipping past various kinds of
-/// syntactic sugar and other constructs one typically wants to ignore.
-/// The \p mask argument allows one to skip certain kinds of simplifications,
-/// when one wishes to handle a certain kind of type directly.
-static QualType
-RemoveWrappingTypes(QualType type, ArrayRef<clang::Type::TypeClass> mask = {}) {
- while (true) {
- if (find(mask, type->getTypeClass()) != mask.end())
- return type;
- switch (type->getTypeClass()) {
- // This is not fully correct as _Atomic is more than sugar, but it is
- // sufficient for the purposes we care about.
- case clang::Type::Atomic:
- type = cast<clang::AtomicType>(type)->getValueType();
- break;
- case clang::Type::Auto:
- case clang::Type::Decltype:
- case clang::Type::Elaborated:
- case clang::Type::Paren:
- case clang::Type::Typedef:
- case clang::Type::TypeOf:
- case clang::Type::TypeOfExpr:
- type = type->getLocallyUnqualifiedSingleStepDesugaredType();
- break;
- default:
- return type;
- }
- }
-}
-
-clang::DeclContext *
-TypeSystemClang::GetDeclContextForType(clang::QualType type) {
- if (type.isNull())
- return nullptr;
-
- clang::QualType qual_type = RemoveWrappingTypes(type.getCanonicalType());
- const clang::Type::TypeClass type_class = qual_type->getTypeClass();
- switch (type_class) {
- case clang::Type::ObjCInterface:
- return llvm::cast<clang::ObjCObjectType>(qual_type.getTypePtr())
- ->getInterface();
- case clang::Type::ObjCObjectPointer:
- return GetDeclContextForType(
- llvm::cast<clang::ObjCObjectPointerType>(qual_type.getTypePtr())
- ->getPointeeType());
- case clang::Type::Record:
- return llvm::cast<clang::RecordType>(qual_type)->getDecl();
- case clang::Type::Enum:
- return llvm::cast<clang::EnumType>(qual_type)->getDecl();
- default:
- break;
- }
- // No DeclContext in this type...
- return nullptr;
-}
-
-static bool GetCompleteQualType(clang::ASTContext *ast,
- clang::QualType qual_type,
- bool allow_completion = true) {
- qual_type = RemoveWrappingTypes(qual_type);
- const clang::Type::TypeClass type_class = qual_type->getTypeClass();
- switch (type_class) {
- case clang::Type::ConstantArray:
- case clang::Type::IncompleteArray:
- case clang::Type::VariableArray: {
- const clang::ArrayType *array_type =
- llvm::dyn_cast<clang::ArrayType>(qual_type.getTypePtr());
-
- if (array_type)
- return GetCompleteQualType(ast, array_type->getElementType(),
- allow_completion);
- } break;
- case clang::Type::Record: {
- clang::CXXRecordDecl *cxx_record_decl = qual_type->getAsCXXRecordDecl();
- if (cxx_record_decl) {
- if (cxx_record_decl->hasExternalLexicalStorage()) {
- const bool is_complete = cxx_record_decl->isCompleteDefinition();
- const bool fields_loaded =
- cxx_record_decl->hasLoadedFieldsFromExternalStorage();
- if (is_complete && fields_loaded)
- return true;
-
- if (!allow_completion)
- return false;
-
- // Call the field_begin() accessor to for it to use the external source
- // to load the fields...
- clang::ExternalASTSource *external_ast_source =
- ast->getExternalSource();
- if (external_ast_source) {
- external_ast_source->CompleteType(cxx_record_decl);
- if (cxx_record_decl->isCompleteDefinition()) {
- cxx_record_decl->field_begin();
- cxx_record_decl->setHasLoadedFieldsFromExternalStorage(true);
- }
- }
- }
- }
- const clang::TagType *tag_type =
- llvm::cast<clang::TagType>(qual_type.getTypePtr());
- return !tag_type->isIncompleteType();
- } break;
-
- case clang::Type::Enum: {
- const clang::TagType *tag_type =
- llvm::dyn_cast<clang::TagType>(qual_type.getTypePtr());
- if (tag_type) {
- clang::TagDecl *tag_decl = tag_type->getDecl();
- if (tag_decl) {
- if (tag_decl->getDefinition())
- return true;
-
- if (!allow_completion)
- return false;
-
- if (tag_decl->hasExternalLexicalStorage()) {
- if (ast) {
- clang::ExternalASTSource *external_ast_source =
- ast->getExternalSource();
- if (external_ast_source) {
- external_ast_source->CompleteType(tag_decl);
- return !tag_type->isIncompleteType();
- }
- }
- }
- return false;
- }
- }
-
- } break;
- case clang::Type::ObjCObject:
- case clang::Type::ObjCInterface: {
- const clang::ObjCObjectType *objc_class_type =
- llvm::dyn_cast<clang::ObjCObjectType>(qual_type);
- if (objc_class_type) {
- clang::ObjCInterfaceDecl *class_interface_decl =
- objc_class_type->getInterface();
- // We currently can't complete objective C types through the newly added
- // ASTContext because it only supports TagDecl objects right now...
- if (class_interface_decl) {
- if (class_interface_decl->getDefinition())
- return true;
-
- if (!allow_completion)
- return false;
-
- if (class_interface_decl->hasExternalLexicalStorage()) {
- if (ast) {
- clang::ExternalASTSource *external_ast_source =
- ast->getExternalSource();
- if (external_ast_source) {
- external_ast_source->CompleteType(class_interface_decl);
- return !objc_class_type->isIncompleteType();
- }
- }
- }
- return false;
- }
- }
- } break;
-
- case clang::Type::Attributed:
- return GetCompleteQualType(
- ast, llvm::cast<clang::AttributedType>(qual_type)->getModifiedType(),
- allow_completion);
-
- default:
- break;
- }
-
- return true;
-}
-
-static clang::ObjCIvarDecl::AccessControl
-ConvertAccessTypeToObjCIvarAccessControl(AccessType access) {
- switch (access) {
- case eAccessNone:
- return clang::ObjCIvarDecl::None;
- case eAccessPublic:
- return clang::ObjCIvarDecl::Public;
- case eAccessPrivate:
- return clang::ObjCIvarDecl::Private;
- case eAccessProtected:
- return clang::ObjCIvarDecl::Protected;
- case eAccessPackage:
- return clang::ObjCIvarDecl::Package;
- }
- return clang::ObjCIvarDecl::None;
-}
-
-// Tests
-
-bool TypeSystemClang::IsAggregateType(lldb::opaque_compiler_type_t type) {
- clang::QualType qual_type(RemoveWrappingTypes(GetCanonicalQualType(type)));
-
- const clang::Type::TypeClass type_class = qual_type->getTypeClass();
- switch (type_class) {
- case clang::Type::IncompleteArray:
- case clang::Type::VariableArray:
- case clang::Type::ConstantArray:
- case clang::Type::ExtVector:
- case clang::Type::Vector:
- case clang::Type::Record:
- case clang::Type::ObjCObject:
- case clang::Type::ObjCInterface:
- return true;
- default:
- break;
- }
- // The clang type does have a value
- return false;
-}
-
-bool TypeSystemClang::IsAnonymousType(lldb::opaque_compiler_type_t type) {
- clang::QualType qual_type(RemoveWrappingTypes(GetCanonicalQualType(type)));
-
- const clang::Type::TypeClass type_class = qual_type->getTypeClass();
- switch (type_class) {
- case clang::Type::Record: {
- if (const clang::RecordType *record_type =
- llvm::dyn_cast_or_null<clang::RecordType>(
- qual_type.getTypePtrOrNull())) {
- if (const clang::RecordDecl *record_decl = record_type->getDecl()) {
- return record_decl->isAnonymousStructOrUnion();
- }
- }
- break;
- }
- default:
- break;
- }
- // The clang type does have a value
- return false;
-}
-
-bool TypeSystemClang::IsArrayType(lldb::opaque_compiler_type_t type,
- CompilerType *element_type_ptr,
- uint64_t *size, bool *is_incomplete) {
- clang::QualType qual_type(RemoveWrappingTypes(GetCanonicalQualType(type)));
-
- const clang::Type::TypeClass type_class = qual_type->getTypeClass();
- switch (type_class) {
- default:
- break;
-
- case clang::Type::ConstantArray:
- if (element_type_ptr)
- element_type_ptr->SetCompilerType(
- this, llvm::cast<clang::ConstantArrayType>(qual_type)
- ->getElementType()
- .getAsOpaquePtr());
- if (size)
- *size = llvm::cast<clang::ConstantArrayType>(qual_type)
- ->getSize()
- .getLimitedValue(ULLONG_MAX);
- if (is_incomplete)
- *is_incomplete = false;
- return true;
-
- case clang::Type::IncompleteArray:
- if (element_type_ptr)
- element_type_ptr->SetCompilerType(
- this, llvm::cast<clang::IncompleteArrayType>(qual_type)
- ->getElementType()
- .getAsOpaquePtr());
- if (size)
- *size = 0;
- if (is_incomplete)
- *is_incomplete = true;
- return true;
-
- case clang::Type::VariableArray:
- if (element_type_ptr)
- element_type_ptr->SetCompilerType(
- this, llvm::cast<clang::VariableArrayType>(qual_type)
- ->getElementType()
- .getAsOpaquePtr());
- if (size)
- *size = 0;
- if (is_incomplete)
- *is_incomplete = false;
- return true;
-
- case clang::Type::DependentSizedArray:
- if (element_type_ptr)
- element_type_ptr->SetCompilerType(
- this, llvm::cast<clang::DependentSizedArrayType>(qual_type)
- ->getElementType()
- .getAsOpaquePtr());
- if (size)
- *size = 0;
- if (is_incomplete)
- *is_incomplete = false;
- return true;
- }
- if (element_type_ptr)
- element_type_ptr->Clear();
- if (size)
- *size = 0;
- if (is_incomplete)
- *is_incomplete = false;
- return false;
-}
-
-bool TypeSystemClang::IsVectorType(lldb::opaque_compiler_type_t type,
- CompilerType *element_type, uint64_t *size) {
- clang::QualType qual_type(GetCanonicalQualType(type));
-
- const clang::Type::TypeClass type_class = qual_type->getTypeClass();
- switch (type_class) {
- case clang::Type::Vector: {
- const clang::VectorType *vector_type =
- qual_type->getAs<clang::VectorType>();
- if (vector_type) {
- if (size)
- *size = vector_type->getNumElements();
- if (element_type)
- *element_type = GetType(vector_type->getElementType());
- }
- return true;
- } break;
- case clang::Type::ExtVector: {
- const clang::ExtVectorType *ext_vector_type =
- qual_type->getAs<clang::ExtVectorType>();
- if (ext_vector_type) {
- if (size)
- *size = ext_vector_type->getNumElements();
- if (element_type)
- *element_type =
- CompilerType(this, ext_vector_type->getElementType().getAsOpaquePtr());
- }
- return true;
- }
- default:
- break;
- }
- return false;
-}
-
-bool TypeSystemClang::IsRuntimeGeneratedType(
- lldb::opaque_compiler_type_t type) {
- clang::DeclContext *decl_ctx = GetDeclContextForType(GetQualType(type));
- if (!decl_ctx)
- return false;
-
- if (!llvm::isa<clang::ObjCInterfaceDecl>(decl_ctx))
- return false;
-
- clang::ObjCInterfaceDecl *result_iface_decl =
- llvm::dyn_cast<clang::ObjCInterfaceDecl>(decl_ctx);
-
- ClangASTMetadata *ast_metadata = GetMetadata(result_iface_decl);
- if (!ast_metadata)
- return false;
- return (ast_metadata->GetISAPtr() != 0);
-}
-
-bool TypeSystemClang::IsCharType(lldb::opaque_compiler_type_t type) {
- return GetQualType(type).getUnqualifiedType()->isCharType();
-}
-
-bool TypeSystemClang::IsCompleteType(lldb::opaque_compiler_type_t type) {
- const bool allow_completion = false;
- return GetCompleteQualType(&getASTContext(), GetQualType(type),
- allow_completion);
-}
-
-bool TypeSystemClang::IsConst(lldb::opaque_compiler_type_t type) {
- return GetQualType(type).isConstQualified();
-}
-
-bool TypeSystemClang::IsCStringType(lldb::opaque_compiler_type_t type,
- uint32_t &length) {
- CompilerType pointee_or_element_clang_type;
- length = 0;
- Flags type_flags(GetTypeInfo(type, &pointee_or_element_clang_type));
-
- if (!pointee_or_element_clang_type.IsValid())
- return false;
-
- if (type_flags.AnySet(eTypeIsArray | eTypeIsPointer)) {
- if (pointee_or_element_clang_type.IsCharType()) {
- if (type_flags.Test(eTypeIsArray)) {
- // We know the size of the array and it could be a C string since it is
- // an array of characters
- length = llvm::cast<clang::ConstantArrayType>(
- GetCanonicalQualType(type).getTypePtr())
- ->getSize()
- .getLimitedValue();
- }
- return true;
- }
- }
- return false;
-}
-
-bool TypeSystemClang::IsFunctionType(lldb::opaque_compiler_type_t type,
- bool *is_variadic_ptr) {
- if (type) {
- clang::QualType qual_type = RemoveWrappingTypes(GetCanonicalQualType(type));
-
- if (qual_type->isFunctionType()) {
- if (is_variadic_ptr) {
- const clang::FunctionProtoType *function_proto_type =
- llvm::dyn_cast<clang::FunctionProtoType>(qual_type.getTypePtr());
- if (function_proto_type)
- *is_variadic_ptr = function_proto_type->isVariadic();
- else
- *is_variadic_ptr = false;
- }
- return true;
- }
-
- const clang::Type::TypeClass type_class = qual_type->getTypeClass();
- switch (type_class) {
- default:
- break;
- case clang::Type::LValueReference:
- case clang::Type::RValueReference: {
- const clang::ReferenceType *reference_type =
- llvm::cast<clang::ReferenceType>(qual_type.getTypePtr());
- if (reference_type)
- return IsFunctionType(reference_type->getPointeeType().getAsOpaquePtr(),
- nullptr);
- } break;
- }
- }
- return false;
-}
-
-// Used to detect "Homogeneous Floating-point Aggregates"
-uint32_t
-TypeSystemClang::IsHomogeneousAggregate(lldb::opaque_compiler_type_t type,
- CompilerType *base_type_ptr) {
- if (!type)
- return 0;
-
- clang::QualType qual_type(RemoveWrappingTypes(GetCanonicalQualType(type)));
- const clang::Type::TypeClass type_class = qual_type->getTypeClass();
- switch (type_class) {
- case clang::Type::Record:
- if (GetCompleteType(type)) {
- const clang::CXXRecordDecl *cxx_record_decl =
- qual_type->getAsCXXRecordDecl();
- if (cxx_record_decl) {
- if (cxx_record_decl->getNumBases() || cxx_record_decl->isDynamicClass())
- return 0;
- }
- const clang::RecordType *record_type =
- llvm::cast<clang::RecordType>(qual_type.getTypePtr());
- if (record_type) {
- const clang::RecordDecl *record_decl = record_type->getDecl();
- if (record_decl) {
- // We are looking for a structure that contains only floating point
- // types
- clang::RecordDecl::field_iterator field_pos,
- field_end = record_decl->field_end();
- uint32_t num_fields = 0;
- bool is_hva = false;
- bool is_hfa = false;
- clang::QualType base_qual_type;
- uint64_t base_bitwidth = 0;
- for (field_pos = record_decl->field_begin(); field_pos != field_end;
- ++field_pos) {
- clang::QualType field_qual_type = field_pos->getType();
- uint64_t field_bitwidth = getASTContext().getTypeSize(qual_type);
- if (field_qual_type->isFloatingType()) {
- if (field_qual_type->isComplexType())
- return 0;
- else {
- if (num_fields == 0)
- base_qual_type = field_qual_type;
- else {
- if (is_hva)
- return 0;
- is_hfa = true;
- if (field_qual_type.getTypePtr() !=
- base_qual_type.getTypePtr())
- return 0;
- }
- }
- } else if (field_qual_type->isVectorType() ||
- field_qual_type->isExtVectorType()) {
- if (num_fields == 0) {
- base_qual_type = field_qual_type;
- base_bitwidth = field_bitwidth;
- } else {
- if (is_hfa)
- return 0;
- is_hva = true;
- if (base_bitwidth != field_bitwidth)
- return 0;
- if (field_qual_type.getTypePtr() != base_qual_type.getTypePtr())
- return 0;
- }
- } else
- return 0;
- ++num_fields;
- }
- if (base_type_ptr)
- *base_type_ptr = CompilerType(this, base_qual_type.getAsOpaquePtr());
- return num_fields;
- }
- }
- }
- break;
-
- default:
- break;
- }
- return 0;
-}
-
-size_t TypeSystemClang::GetNumberOfFunctionArguments(
- lldb::opaque_compiler_type_t type) {
- if (type) {
- clang::QualType qual_type(GetCanonicalQualType(type));
- const clang::FunctionProtoType *func =
- llvm::dyn_cast<clang::FunctionProtoType>(qual_type.getTypePtr());
- if (func)
- return func->getNumParams();
- }
- return 0;
-}
-
-CompilerType
-TypeSystemClang::GetFunctionArgumentAtIndex(lldb::opaque_compiler_type_t type,
- const size_t index) {
- if (type) {
- clang::QualType qual_type(GetQualType(type));
- const clang::FunctionProtoType *func =
- llvm::dyn_cast<clang::FunctionProtoType>(qual_type.getTypePtr());
- if (func) {
- if (index < func->getNumParams())
- return CompilerType(this, func->getParamType(index).getAsOpaquePtr());
- }
- }
- return CompilerType();
-}
-
-bool TypeSystemClang::IsFunctionPointerType(lldb::opaque_compiler_type_t type) {
- if (type) {
- clang::QualType qual_type = RemoveWrappingTypes(GetCanonicalQualType(type));
-
- if (qual_type->isFunctionPointerType())
- return true;
-
- const clang::Type::TypeClass type_class = qual_type->getTypeClass();
- switch (type_class) {
- default:
- break;
-
- case clang::Type::LValueReference:
- case clang::Type::RValueReference: {
- const clang::ReferenceType *reference_type =
- llvm::cast<clang::ReferenceType>(qual_type.getTypePtr());
- if (reference_type)
- return IsFunctionPointerType(
- reference_type->getPointeeType().getAsOpaquePtr());
- } break;
- }
- }
- return false;
-}
-
-bool TypeSystemClang::IsBlockPointerType(
- lldb::opaque_compiler_type_t type,
- CompilerType *function_pointer_type_ptr) {
- if (type) {
- clang::QualType qual_type = RemoveWrappingTypes(GetCanonicalQualType(type));
-
- if (qual_type->isBlockPointerType()) {
- if (function_pointer_type_ptr) {
- const clang::BlockPointerType *block_pointer_type =
- qual_type->getAs<clang::BlockPointerType>();
- QualType pointee_type = block_pointer_type->getPointeeType();
- QualType function_pointer_type = m_ast_up->getPointerType(pointee_type);
- *function_pointer_type_ptr =
- CompilerType(this, function_pointer_type.getAsOpaquePtr());
- }
- return true;
- }
-
- const clang::Type::TypeClass type_class = qual_type->getTypeClass();
- switch (type_class) {
- default:
- break;
-
- case clang::Type::LValueReference:
- case clang::Type::RValueReference: {
- const clang::ReferenceType *reference_type =
- llvm::cast<clang::ReferenceType>(qual_type.getTypePtr());
- if (reference_type)
- return IsBlockPointerType(
- reference_type->getPointeeType().getAsOpaquePtr(),
- function_pointer_type_ptr);
- } break;
- }
- }
- return false;
-}
-
-bool TypeSystemClang::IsIntegerType(lldb::opaque_compiler_type_t type,
- bool &is_signed) {
- if (!type)
- return false;
-
- clang::QualType qual_type(GetCanonicalQualType(type));
- const clang::BuiltinType *builtin_type =
- llvm::dyn_cast<clang::BuiltinType>(qual_type->getCanonicalTypeInternal());
-
- if (builtin_type) {
- if (builtin_type->isInteger()) {
- is_signed = builtin_type->isSignedInteger();
- return true;
- }
- }
-
- return false;
-}
-
-bool TypeSystemClang::IsEnumerationType(lldb::opaque_compiler_type_t type,
- bool &is_signed) {
- if (type) {
- const clang::EnumType *enum_type = llvm::dyn_cast<clang::EnumType>(
- GetCanonicalQualType(type)->getCanonicalTypeInternal());
-
- if (enum_type) {
- IsIntegerType(enum_type->getDecl()->getIntegerType().getAsOpaquePtr(),
- is_signed);
- return true;
- }
- }
-
- return false;
-}
-
-bool TypeSystemClang::IsPointerType(lldb::opaque_compiler_type_t type,
- CompilerType *pointee_type) {
- if (type) {
- clang::QualType qual_type = RemoveWrappingTypes(GetCanonicalQualType(type));
- const clang::Type::TypeClass type_class = qual_type->getTypeClass();
- switch (type_class) {
- case clang::Type::Builtin:
- switch (llvm::cast<clang::BuiltinType>(qual_type)->getKind()) {
- default:
- break;
- case clang::BuiltinType::ObjCId:
- case clang::BuiltinType::ObjCClass:
- return true;
- }
- return false;
- case clang::Type::ObjCObjectPointer:
- if (pointee_type)
- pointee_type->SetCompilerType(
- this, llvm::cast<clang::ObjCObjectPointerType>(qual_type)
- ->getPointeeType()
- .getAsOpaquePtr());
- return true;
- case clang::Type::BlockPointer:
- if (pointee_type)
- pointee_type->SetCompilerType(
- this, llvm::cast<clang::BlockPointerType>(qual_type)
- ->getPointeeType()
- .getAsOpaquePtr());
- return true;
- case clang::Type::Pointer:
- if (pointee_type)
- pointee_type->SetCompilerType(this,
- llvm::cast<clang::PointerType>(qual_type)
- ->getPointeeType()
- .getAsOpaquePtr());
- return true;
- case clang::Type::MemberPointer:
- if (pointee_type)
- pointee_type->SetCompilerType(
- this, llvm::cast<clang::MemberPointerType>(qual_type)
- ->getPointeeType()
- .getAsOpaquePtr());
- return true;
- default:
- break;
- }
- }
- if (pointee_type)
- pointee_type->Clear();
- return false;
-}
-
-bool TypeSystemClang::IsPointerOrReferenceType(
- lldb::opaque_compiler_type_t type, CompilerType *pointee_type) {
- if (type) {
- clang::QualType qual_type = RemoveWrappingTypes(GetCanonicalQualType(type));
- const clang::Type::TypeClass type_class = qual_type->getTypeClass();
- switch (type_class) {
- case clang::Type::Builtin:
- switch (llvm::cast<clang::BuiltinType>(qual_type)->getKind()) {
- default:
- break;
- case clang::BuiltinType::ObjCId:
- case clang::BuiltinType::ObjCClass:
- return true;
- }
- return false;
- case clang::Type::ObjCObjectPointer:
- if (pointee_type)
- pointee_type->SetCompilerType(
- this, llvm::cast<clang::ObjCObjectPointerType>(qual_type)
- ->getPointeeType().getAsOpaquePtr());
- return true;
- case clang::Type::BlockPointer:
- if (pointee_type)
- pointee_type->SetCompilerType(
- this, llvm::cast<clang::BlockPointerType>(qual_type)
- ->getPointeeType()
- .getAsOpaquePtr());
- return true;
- case clang::Type::Pointer:
- if (pointee_type)
- pointee_type->SetCompilerType(this,
- llvm::cast<clang::PointerType>(qual_type)
- ->getPointeeType()
- .getAsOpaquePtr());
- return true;
- case clang::Type::MemberPointer:
- if (pointee_type)
- pointee_type->SetCompilerType(
- this, llvm::cast<clang::MemberPointerType>(qual_type)
- ->getPointeeType()
- .getAsOpaquePtr());
- return true;
- case clang::Type::LValueReference:
- if (pointee_type)
- pointee_type->SetCompilerType(
- this, llvm::cast<clang::LValueReferenceType>(qual_type)
- ->desugar()
- .getAsOpaquePtr());
- return true;
- case clang::Type::RValueReference:
- if (pointee_type)
- pointee_type->SetCompilerType(
- this, llvm::cast<clang::RValueReferenceType>(qual_type)
- ->desugar()
- .getAsOpaquePtr());
- return true;
- default:
- break;
- }
- }
- if (pointee_type)
- pointee_type->Clear();
- return false;
-}
-
-bool TypeSystemClang::IsReferenceType(lldb::opaque_compiler_type_t type,
- CompilerType *pointee_type,
- bool *is_rvalue) {
- if (type) {
- clang::QualType qual_type = RemoveWrappingTypes(GetCanonicalQualType(type));
- const clang::Type::TypeClass type_class = qual_type->getTypeClass();
-
- switch (type_class) {
- case clang::Type::LValueReference:
- if (pointee_type)
- pointee_type->SetCompilerType(
- this, llvm::cast<clang::LValueReferenceType>(qual_type)
- ->desugar()
- .getAsOpaquePtr());
- if (is_rvalue)
- *is_rvalue = false;
- return true;
- case clang::Type::RValueReference:
- if (pointee_type)
- pointee_type->SetCompilerType(
- this, llvm::cast<clang::RValueReferenceType>(qual_type)
- ->desugar()
- .getAsOpaquePtr());
- if (is_rvalue)
- *is_rvalue = true;
- return true;
-
- default:
- break;
- }
- }
- if (pointee_type)
- pointee_type->Clear();
- return false;
-}
-
-bool TypeSystemClang::IsFloatingPointType(lldb::opaque_compiler_type_t type,
- uint32_t &count, bool &is_complex) {
- if (type) {
- clang::QualType qual_type(GetCanonicalQualType(type));
-
- if (const clang::BuiltinType *BT = llvm::dyn_cast<clang::BuiltinType>(
- qual_type->getCanonicalTypeInternal())) {
- clang::BuiltinType::Kind kind = BT->getKind();
- if (kind >= clang::BuiltinType::Float &&
- kind <= clang::BuiltinType::LongDouble) {
- count = 1;
- is_complex = false;
- return true;
- }
- } else if (const clang::ComplexType *CT =
- llvm::dyn_cast<clang::ComplexType>(
- qual_type->getCanonicalTypeInternal())) {
- if (IsFloatingPointType(CT->getElementType().getAsOpaquePtr(), count,
- is_complex)) {
- count = 2;
- is_complex = true;
- return true;
- }
- } else if (const clang::VectorType *VT = llvm::dyn_cast<clang::VectorType>(
- qual_type->getCanonicalTypeInternal())) {
- if (IsFloatingPointType(VT->getElementType().getAsOpaquePtr(), count,
- is_complex)) {
- count = VT->getNumElements();
- is_complex = false;
- return true;
- }
- }
- }
- count = 0;
- is_complex = false;
- return false;
-}
-
-bool TypeSystemClang::IsDefined(lldb::opaque_compiler_type_t type) {
- if (!type)
- return false;
-
- clang::QualType qual_type(GetQualType(type));
- const clang::TagType *tag_type =
- llvm::dyn_cast<clang::TagType>(qual_type.getTypePtr());
- if (tag_type) {
- clang::TagDecl *tag_decl = tag_type->getDecl();
- if (tag_decl)
- return tag_decl->isCompleteDefinition();
- return false;
- } else {
- const clang::ObjCObjectType *objc_class_type =
- llvm::dyn_cast<clang::ObjCObjectType>(qual_type);
- if (objc_class_type) {
- clang::ObjCInterfaceDecl *class_interface_decl =
- objc_class_type->getInterface();
- if (class_interface_decl)
- return class_interface_decl->getDefinition() != nullptr;
- return false;
- }
- }
- return true;
-}
-
-bool TypeSystemClang::IsObjCClassType(const CompilerType &type) {
- if (ClangUtil::IsClangType(type)) {
- clang::QualType qual_type(ClangUtil::GetCanonicalQualType(type));
-
- const clang::ObjCObjectPointerType *obj_pointer_type =
- llvm::dyn_cast<clang::ObjCObjectPointerType>(qual_type);
-
- if (obj_pointer_type)
- return obj_pointer_type->isObjCClassType();
- }
- return false;
-}
-
-bool TypeSystemClang::IsObjCObjectOrInterfaceType(const CompilerType &type) {
- if (ClangUtil::IsClangType(type))
- return ClangUtil::GetCanonicalQualType(type)->isObjCObjectOrInterfaceType();
- return false;
-}
-
-bool TypeSystemClang::IsClassType(lldb::opaque_compiler_type_t type) {
- if (!type)
- return false;
- clang::QualType qual_type(GetCanonicalQualType(type));
- const clang::Type::TypeClass type_class = qual_type->getTypeClass();
- return (type_class == clang::Type::Record);
-}
-
-bool TypeSystemClang::IsEnumType(lldb::opaque_compiler_type_t type) {
- if (!type)
- return false;
- clang::QualType qual_type(GetCanonicalQualType(type));
- const clang::Type::TypeClass type_class = qual_type->getTypeClass();
- return (type_class == clang::Type::Enum);
-}
-
-bool TypeSystemClang::IsPolymorphicClass(lldb::opaque_compiler_type_t type) {
- if (type) {
- clang::QualType qual_type(GetCanonicalQualType(type));
- const clang::Type::TypeClass type_class = qual_type->getTypeClass();
- switch (type_class) {
- case clang::Type::Record:
- if (GetCompleteType(type)) {
- const clang::RecordType *record_type =
- llvm::cast<clang::RecordType>(qual_type.getTypePtr());
- const clang::RecordDecl *record_decl = record_type->getDecl();
- if (record_decl) {
- const clang::CXXRecordDecl *cxx_record_decl =
- llvm::dyn_cast<clang::CXXRecordDecl>(record_decl);
- if (cxx_record_decl)
- return cxx_record_decl->isPolymorphic();
- }
- }
- break;
-
- default:
- break;
- }
- }
- return false;
-}
-
-bool TypeSystemClang::IsPossibleDynamicType(lldb::opaque_compiler_type_t type,
- CompilerType *dynamic_pointee_type,
- bool check_cplusplus,
- bool check_objc) {
- clang::QualType pointee_qual_type;
- if (type) {
- clang::QualType qual_type = RemoveWrappingTypes(GetCanonicalQualType(type));
- bool success = false;
- const clang::Type::TypeClass type_class = qual_type->getTypeClass();
- switch (type_class) {
- case clang::Type::Builtin:
- if (check_objc &&
- llvm::cast<clang::BuiltinType>(qual_type)->getKind() ==
- clang::BuiltinType::ObjCId) {
- if (dynamic_pointee_type)
- dynamic_pointee_type->SetCompilerType(this, type);
- return true;
- }
- break;
-
- case clang::Type::ObjCObjectPointer:
- if (check_objc) {
- if (auto objc_pointee_type =
- qual_type->getPointeeType().getTypePtrOrNull()) {
- if (auto objc_object_type =
- llvm::dyn_cast_or_null<clang::ObjCObjectType>(
- objc_pointee_type)) {
- if (objc_object_type->isObjCClass())
- return false;
- }
- }
- if (dynamic_pointee_type)
- dynamic_pointee_type->SetCompilerType(
- this, llvm::cast<clang::ObjCObjectPointerType>(qual_type)
- ->getPointeeType()
- .getAsOpaquePtr());
- return true;
- }
- break;
-
- case clang::Type::Pointer:
- pointee_qual_type =
- llvm::cast<clang::PointerType>(qual_type)->getPointeeType();
- success = true;
- break;
-
- case clang::Type::LValueReference:
- case clang::Type::RValueReference:
- pointee_qual_type =
- llvm::cast<clang::ReferenceType>(qual_type)->getPointeeType();
- success = true;
- break;
-
- default:
- break;
- }
-
- if (success) {
- // Check to make sure what we are pointing too is a possible dynamic C++
- // type We currently accept any "void *" (in case we have a class that
- // has been watered down to an opaque pointer) and virtual C++ classes.
- const clang::Type::TypeClass pointee_type_class =
- pointee_qual_type.getCanonicalType()->getTypeClass();
- switch (pointee_type_class) {
- case clang::Type::Builtin:
- switch (llvm::cast<clang::BuiltinType>(pointee_qual_type)->getKind()) {
- case clang::BuiltinType::UnknownAny:
- case clang::BuiltinType::Void:
- if (dynamic_pointee_type)
- dynamic_pointee_type->SetCompilerType(
- this, pointee_qual_type.getAsOpaquePtr());
- return true;
- default:
- break;
- }
- break;
-
- case clang::Type::Record:
- if (check_cplusplus) {
- clang::CXXRecordDecl *cxx_record_decl =
- pointee_qual_type->getAsCXXRecordDecl();
- if (cxx_record_decl) {
- bool is_complete = cxx_record_decl->isCompleteDefinition();
-
- if (is_complete)
- success = cxx_record_decl->isDynamicClass();
- else {
- ClangASTMetadata *metadata = GetMetadata(cxx_record_decl);
- if (metadata)
- success = metadata->GetIsDynamicCXXType();
- else {
- is_complete = GetType(pointee_qual_type).GetCompleteType();
- if (is_complete)
- success = cxx_record_decl->isDynamicClass();
- else
- success = false;
- }
- }
-
- if (success) {
- if (dynamic_pointee_type)
- dynamic_pointee_type->SetCompilerType(
- this, pointee_qual_type.getAsOpaquePtr());
- return true;
- }
- }
- }
- break;
-
- case clang::Type::ObjCObject:
- case clang::Type::ObjCInterface:
- if (check_objc) {
- if (dynamic_pointee_type)
- dynamic_pointee_type->SetCompilerType(
- this, pointee_qual_type.getAsOpaquePtr());
- return true;
- }
- break;
-
- default:
- break;
- }
- }
- }
- if (dynamic_pointee_type)
- dynamic_pointee_type->Clear();
- return false;
-}
-
-bool TypeSystemClang::IsScalarType(lldb::opaque_compiler_type_t type) {
- if (!type)
- return false;
-
- return (GetTypeInfo(type, nullptr) & eTypeIsScalar) != 0;
-}
-
-bool TypeSystemClang::IsTypedefType(lldb::opaque_compiler_type_t type) {
- if (!type)
- return false;
- return GetQualType(type)->getTypeClass() == clang::Type::Typedef;
-}
-
-bool TypeSystemClang::IsVoidType(lldb::opaque_compiler_type_t type) {
- if (!type)
- return false;
- return GetCanonicalQualType(type)->isVoidType();
-}
-
-bool TypeSystemClang::CanPassInRegisters(const CompilerType &type) {
- if (auto *record_decl =
- TypeSystemClang::GetAsRecordDecl(type)) {
- return record_decl->canPassInRegisters();
- }
- return false;
-}
-
-bool TypeSystemClang::SupportsLanguage(lldb::LanguageType language) {
- return TypeSystemClangSupportsLanguage(language);
-}
-
-Optional<std::string>
-TypeSystemClang::GetCXXClassName(const CompilerType &type) {
- if (!type)
- return llvm::None;
-
- clang::QualType qual_type(ClangUtil::GetCanonicalQualType(type));
- if (qual_type.isNull())
- return llvm::None;
-
- clang::CXXRecordDecl *cxx_record_decl = qual_type->getAsCXXRecordDecl();
- if (!cxx_record_decl)
- return llvm::None;
-
- return std::string(cxx_record_decl->getIdentifier()->getNameStart());
-}
-
-bool TypeSystemClang::IsCXXClassType(const CompilerType &type) {
- if (!type)
- return false;
-
- clang::QualType qual_type(ClangUtil::GetCanonicalQualType(type));
- return !qual_type.isNull() && qual_type->getAsCXXRecordDecl() != nullptr;
-}
-
-bool TypeSystemClang::IsBeingDefined(lldb::opaque_compiler_type_t type) {
- if (!type)
- return false;
- clang::QualType qual_type(GetCanonicalQualType(type));
- const clang::TagType *tag_type = llvm::dyn_cast<clang::TagType>(qual_type);
- if (tag_type)
- return tag_type->isBeingDefined();
- return false;
-}
-
-bool TypeSystemClang::IsObjCObjectPointerType(const CompilerType &type,
- CompilerType *class_type_ptr) {
- if (!ClangUtil::IsClangType(type))
- return false;
-
- clang::QualType qual_type(ClangUtil::GetCanonicalQualType(type));
-
- if (!qual_type.isNull() && qual_type->isObjCObjectPointerType()) {
- if (class_type_ptr) {
- if (!qual_type->isObjCClassType() && !qual_type->isObjCIdType()) {
- const clang::ObjCObjectPointerType *obj_pointer_type =
- llvm::dyn_cast<clang::ObjCObjectPointerType>(qual_type);
- if (obj_pointer_type == nullptr)
- class_type_ptr->Clear();
- else
- class_type_ptr->SetCompilerType(
- type.GetTypeSystem(),
- clang::QualType(obj_pointer_type->getInterfaceType(), 0)
- .getAsOpaquePtr());
- }
- }
- return true;
- }
- if (class_type_ptr)
- class_type_ptr->Clear();
- return false;
-}
-
-// Type Completion
-
-bool TypeSystemClang::GetCompleteType(lldb::opaque_compiler_type_t type) {
- if (!type)
- return false;
- const bool allow_completion = true;
- return GetCompleteQualType(&getASTContext(), GetQualType(type),
- allow_completion);
-}
-
-ConstString TypeSystemClang::GetTypeName(lldb::opaque_compiler_type_t type) {
- std::string type_name;
- if (type) {
- clang::PrintingPolicy printing_policy(getASTContext().getPrintingPolicy());
- clang::QualType qual_type(GetQualType(type));
- printing_policy.SuppressTagKeyword = true;
- const clang::TypedefType *typedef_type =
- qual_type->getAs<clang::TypedefType>();
- if (typedef_type) {
- const clang::TypedefNameDecl *typedef_decl = typedef_type->getDecl();
- type_name = typedef_decl->getQualifiedNameAsString();
- } else {
- type_name = qual_type.getAsString(printing_policy);
- }
- }
- return ConstString(type_name);
-}
-
-uint32_t
-TypeSystemClang::GetTypeInfo(lldb::opaque_compiler_type_t type,
- CompilerType *pointee_or_element_clang_type) {
- if (!type)
- return 0;
-
- if (pointee_or_element_clang_type)
- pointee_or_element_clang_type->Clear();
-
- clang::QualType qual_type =
- RemoveWrappingTypes(GetQualType(type), {clang::Type::Typedef});
-
- const clang::Type::TypeClass type_class = qual_type->getTypeClass();
- switch (type_class) {
- case clang::Type::Attributed:
- return GetTypeInfo(
- qual_type->getAs<clang::AttributedType>()
- ->getModifiedType().getAsOpaquePtr(),
- pointee_or_element_clang_type);
- case clang::Type::Builtin: {
- const clang::BuiltinType *builtin_type = llvm::dyn_cast<clang::BuiltinType>(
- qual_type->getCanonicalTypeInternal());
-
- uint32_t builtin_type_flags = eTypeIsBuiltIn | eTypeHasValue;
- switch (builtin_type->getKind()) {
- case clang::BuiltinType::ObjCId:
- case clang::BuiltinType::ObjCClass:
- if (pointee_or_element_clang_type)
- pointee_or_element_clang_type->SetCompilerType(
- this, getASTContext().ObjCBuiltinClassTy.getAsOpaquePtr());
- builtin_type_flags |= eTypeIsPointer | eTypeIsObjC;
- break;
-
- case clang::BuiltinType::ObjCSel:
- if (pointee_or_element_clang_type)
- pointee_or_element_clang_type->SetCompilerType(
- this, getASTContext().CharTy.getAsOpaquePtr());
- builtin_type_flags |= eTypeIsPointer | eTypeIsObjC;
- break;
-
- case clang::BuiltinType::Bool:
- case clang::BuiltinType::Char_U:
- case clang::BuiltinType::UChar:
- case clang::BuiltinType::WChar_U:
- case clang::BuiltinType::Char16:
- case clang::BuiltinType::Char32:
- case clang::BuiltinType::UShort:
- case clang::BuiltinType::UInt:
- case clang::BuiltinType::ULong:
- case clang::BuiltinType::ULongLong:
- case clang::BuiltinType::UInt128:
- case clang::BuiltinType::Char_S:
- case clang::BuiltinType::SChar:
- case clang::BuiltinType::WChar_S:
- case clang::BuiltinType::Short:
- case clang::BuiltinType::Int:
- case clang::BuiltinType::Long:
- case clang::BuiltinType::LongLong:
- case clang::BuiltinType::Int128:
- case clang::BuiltinType::Float:
- case clang::BuiltinType::Double:
- case clang::BuiltinType::LongDouble:
- builtin_type_flags |= eTypeIsScalar;
- if (builtin_type->isInteger()) {
- builtin_type_flags |= eTypeIsInteger;
- if (builtin_type->isSignedInteger())
- builtin_type_flags |= eTypeIsSigned;
- } else if (builtin_type->isFloatingPoint())
- builtin_type_flags |= eTypeIsFloat;
- break;
- default:
- break;
- }
- return builtin_type_flags;
- }
-
- case clang::Type::BlockPointer:
- if (pointee_or_element_clang_type)
- pointee_or_element_clang_type->SetCompilerType(
- this, qual_type->getPointeeType().getAsOpaquePtr());
- return eTypeIsPointer | eTypeHasChildren | eTypeIsBlock;
-
- case clang::Type::Complex: {
- uint32_t complex_type_flags =
- eTypeIsBuiltIn | eTypeHasValue | eTypeIsComplex;
- const clang::ComplexType *complex_type = llvm::dyn_cast<clang::ComplexType>(
- qual_type->getCanonicalTypeInternal());
- if (complex_type) {
- clang::QualType complex_element_type(complex_type->getElementType());
- if (complex_element_type->isIntegerType())
- complex_type_flags |= eTypeIsFloat;
- else if (complex_element_type->isFloatingType())
- complex_type_flags |= eTypeIsInteger;
- }
- return complex_type_flags;
- } break;
-
- case clang::Type::ConstantArray:
- case clang::Type::DependentSizedArray:
- case clang::Type::IncompleteArray:
- case clang::Type::VariableArray:
- if (pointee_or_element_clang_type)
- pointee_or_element_clang_type->SetCompilerType(
- this, llvm::cast<clang::ArrayType>(qual_type.getTypePtr())
- ->getElementType()
- .getAsOpaquePtr());
- return eTypeHasChildren | eTypeIsArray;
-
- case clang::Type::DependentName:
- return 0;
- case clang::Type::DependentSizedExtVector:
- return eTypeHasChildren | eTypeIsVector;
- case clang::Type::DependentTemplateSpecialization:
- return eTypeIsTemplate;
-
- case clang::Type::Enum:
- if (pointee_or_element_clang_type)
- pointee_or_element_clang_type->SetCompilerType(
- this, llvm::cast<clang::EnumType>(qual_type)
- ->getDecl()
- ->getIntegerType()
- .getAsOpaquePtr());
- return eTypeIsEnumeration | eTypeHasValue;
-
- case clang::Type::FunctionProto:
- return eTypeIsFuncPrototype | eTypeHasValue;
- case clang::Type::FunctionNoProto:
- return eTypeIsFuncPrototype | eTypeHasValue;
- case clang::Type::InjectedClassName:
- return 0;
-
- case clang::Type::LValueReference:
- case clang::Type::RValueReference:
- if (pointee_or_element_clang_type)
- pointee_or_element_clang_type->SetCompilerType(
- this, llvm::cast<clang::ReferenceType>(qual_type.getTypePtr())
- ->getPointeeType()
- .getAsOpaquePtr());
- return eTypeHasChildren | eTypeIsReference | eTypeHasValue;
-
- case clang::Type::MemberPointer:
- return eTypeIsPointer | eTypeIsMember | eTypeHasValue;
-
- case clang::Type::ObjCObjectPointer:
- if (pointee_or_element_clang_type)
- pointee_or_element_clang_type->SetCompilerType(
- this, qual_type->getPointeeType().getAsOpaquePtr());
- return eTypeHasChildren | eTypeIsObjC | eTypeIsClass | eTypeIsPointer |
- eTypeHasValue;
-
- case clang::Type::ObjCObject:
- return eTypeHasChildren | eTypeIsObjC | eTypeIsClass;
- case clang::Type::ObjCInterface:
- return eTypeHasChildren | eTypeIsObjC | eTypeIsClass;
-
- case clang::Type::Pointer:
- if (pointee_or_element_clang_type)
- pointee_or_element_clang_type->SetCompilerType(
- this, qual_type->getPointeeType().getAsOpaquePtr());
- return eTypeHasChildren | eTypeIsPointer | eTypeHasValue;
-
- case clang::Type::Record:
- if (qual_type->getAsCXXRecordDecl())
- return eTypeHasChildren | eTypeIsClass | eTypeIsCPlusPlus;
- else
- return eTypeHasChildren | eTypeIsStructUnion;
- break;
- case clang::Type::SubstTemplateTypeParm:
- return eTypeIsTemplate;
- case clang::Type::TemplateTypeParm:
- return eTypeIsTemplate;
- case clang::Type::TemplateSpecialization:
- return eTypeIsTemplate;
-
- case clang::Type::Typedef:
- return eTypeIsTypedef | GetType(llvm::cast<clang::TypedefType>(qual_type)
- ->getDecl()
- ->getUnderlyingType())
- .GetTypeInfo(pointee_or_element_clang_type);
- case clang::Type::UnresolvedUsing:
- return 0;
-
- case clang::Type::ExtVector:
- case clang::Type::Vector: {
- uint32_t vector_type_flags = eTypeHasChildren | eTypeIsVector;
- const clang::VectorType *vector_type = llvm::dyn_cast<clang::VectorType>(
- qual_type->getCanonicalTypeInternal());
- if (vector_type) {
- if (vector_type->isIntegerType())
- vector_type_flags |= eTypeIsFloat;
- else if (vector_type->isFloatingType())
- vector_type_flags |= eTypeIsInteger;
- }
- return vector_type_flags;
- }
- default:
- return 0;
- }
- return 0;
-}
-
-lldb::LanguageType
-TypeSystemClang::GetMinimumLanguage(lldb::opaque_compiler_type_t type) {
- if (!type)
- return lldb::eLanguageTypeC;
-
- // If the type is a reference, then resolve it to what it refers to first:
- clang::QualType qual_type(GetCanonicalQualType(type).getNonReferenceType());
- if (qual_type->isAnyPointerType()) {
- if (qual_type->isObjCObjectPointerType())
- return lldb::eLanguageTypeObjC;
- if (qual_type->getPointeeCXXRecordDecl())
- return lldb::eLanguageTypeC_plus_plus;
-
- clang::QualType pointee_type(qual_type->getPointeeType());
- if (pointee_type->getPointeeCXXRecordDecl())
- return lldb::eLanguageTypeC_plus_plus;
- if (pointee_type->isObjCObjectOrInterfaceType())
- return lldb::eLanguageTypeObjC;
- if (pointee_type->isObjCClassType())
- return lldb::eLanguageTypeObjC;
- if (pointee_type.getTypePtr() ==
- getASTContext().ObjCBuiltinIdTy.getTypePtr())
- return lldb::eLanguageTypeObjC;
- } else {
- if (qual_type->isObjCObjectOrInterfaceType())
- return lldb::eLanguageTypeObjC;
- if (qual_type->getAsCXXRecordDecl())
- return lldb::eLanguageTypeC_plus_plus;
- switch (qual_type->getTypeClass()) {
- default:
- break;
- case clang::Type::Builtin:
- switch (llvm::cast<clang::BuiltinType>(qual_type)->getKind()) {
- default:
- case clang::BuiltinType::Void:
- case clang::BuiltinType::Bool:
- case clang::BuiltinType::Char_U:
- case clang::BuiltinType::UChar:
- case clang::BuiltinType::WChar_U:
- case clang::BuiltinType::Char16:
- case clang::BuiltinType::Char32:
- case clang::BuiltinType::UShort:
- case clang::BuiltinType::UInt:
- case clang::BuiltinType::ULong:
- case clang::BuiltinType::ULongLong:
- case clang::BuiltinType::UInt128:
- case clang::BuiltinType::Char_S:
- case clang::BuiltinType::SChar:
- case clang::BuiltinType::WChar_S:
- case clang::BuiltinType::Short:
- case clang::BuiltinType::Int:
- case clang::BuiltinType::Long:
- case clang::BuiltinType::LongLong:
- case clang::BuiltinType::Int128:
- case clang::BuiltinType::Float:
- case clang::BuiltinType::Double:
- case clang::BuiltinType::LongDouble:
- break;
-
- case clang::BuiltinType::NullPtr:
- return eLanguageTypeC_plus_plus;
-
- case clang::BuiltinType::ObjCId:
- case clang::BuiltinType::ObjCClass:
- case clang::BuiltinType::ObjCSel:
- return eLanguageTypeObjC;
-
- case clang::BuiltinType::Dependent:
- case clang::BuiltinType::Overload:
- case clang::BuiltinType::BoundMember:
- case clang::BuiltinType::UnknownAny:
- break;
- }
- break;
- case clang::Type::Typedef:
- return GetType(llvm::cast<clang::TypedefType>(qual_type)
- ->getDecl()
- ->getUnderlyingType())
- .GetMinimumLanguage();
- }
- }
- return lldb::eLanguageTypeC;
-}
-
-lldb::TypeClass
-TypeSystemClang::GetTypeClass(lldb::opaque_compiler_type_t type) {
- if (!type)
- return lldb::eTypeClassInvalid;
-
- clang::QualType qual_type =
- RemoveWrappingTypes(GetQualType(type), {clang::Type::Typedef});
-
- switch (qual_type->getTypeClass()) {
- case clang::Type::Atomic:
- case clang::Type::Auto:
- case clang::Type::Decltype:
- case clang::Type::Elaborated:
- case clang::Type::Paren:
- case clang::Type::TypeOf:
- case clang::Type::TypeOfExpr:
- llvm_unreachable("Handled in RemoveWrappingTypes!");
- case clang::Type::UnaryTransform:
- break;
- case clang::Type::FunctionNoProto:
- return lldb::eTypeClassFunction;
- case clang::Type::FunctionProto:
- return lldb::eTypeClassFunction;
- case clang::Type::IncompleteArray:
- return lldb::eTypeClassArray;
- case clang::Type::VariableArray:
- return lldb::eTypeClassArray;
- case clang::Type::ConstantArray:
- return lldb::eTypeClassArray;
- case clang::Type::DependentSizedArray:
- return lldb::eTypeClassArray;
- case clang::Type::DependentSizedExtVector:
- return lldb::eTypeClassVector;
- case clang::Type::DependentVector:
- return lldb::eTypeClassVector;
- case clang::Type::ExtVector:
- return lldb::eTypeClassVector;
- case clang::Type::Vector:
- return lldb::eTypeClassVector;
- case clang::Type::Builtin:
- return lldb::eTypeClassBuiltin;
- case clang::Type::ObjCObjectPointer:
- return lldb::eTypeClassObjCObjectPointer;
- case clang::Type::BlockPointer:
- return lldb::eTypeClassBlockPointer;
- case clang::Type::Pointer:
- return lldb::eTypeClassPointer;
- case clang::Type::LValueReference:
- return lldb::eTypeClassReference;
- case clang::Type::RValueReference:
- return lldb::eTypeClassReference;
- case clang::Type::MemberPointer:
- return lldb::eTypeClassMemberPointer;
- case clang::Type::Complex:
- if (qual_type->isComplexType())
- return lldb::eTypeClassComplexFloat;
- else
- return lldb::eTypeClassComplexInteger;
- case clang::Type::ObjCObject:
- return lldb::eTypeClassObjCObject;
- case clang::Type::ObjCInterface:
- return lldb::eTypeClassObjCInterface;
- case clang::Type::Record: {
- const clang::RecordType *record_type =
- llvm::cast<clang::RecordType>(qual_type.getTypePtr());
- const clang::RecordDecl *record_decl = record_type->getDecl();
- if (record_decl->isUnion())
- return lldb::eTypeClassUnion;
- else if (record_decl->isStruct())
- return lldb::eTypeClassStruct;
- else
- return lldb::eTypeClassClass;
- } break;
- case clang::Type::Enum:
- return lldb::eTypeClassEnumeration;
- case clang::Type::Typedef:
- return lldb::eTypeClassTypedef;
- case clang::Type::UnresolvedUsing:
- break;
-
- case clang::Type::Attributed:
- break;
- case clang::Type::TemplateTypeParm:
- break;
- case clang::Type::SubstTemplateTypeParm:
- break;
- case clang::Type::SubstTemplateTypeParmPack:
- break;
- case clang::Type::InjectedClassName:
- break;
- case clang::Type::DependentName:
- break;
- case clang::Type::DependentTemplateSpecialization:
- break;
- case clang::Type::PackExpansion:
- break;
-
- case clang::Type::TemplateSpecialization:
- break;
- case clang::Type::DeducedTemplateSpecialization:
- break;
- case clang::Type::Pipe:
- break;
-
- // pointer type decayed from an array or function type.
- case clang::Type::Decayed:
- break;
- case clang::Type::Adjusted:
- break;
- case clang::Type::ObjCTypeParam:
- break;
-
- case clang::Type::DependentAddressSpace:
- break;
- case clang::Type::MacroQualified:
- break;
- }
- // We don't know hot to display this type...
- return lldb::eTypeClassOther;
-}
-
-unsigned TypeSystemClang::GetTypeQualifiers(lldb::opaque_compiler_type_t type) {
- if (type)
- return GetQualType(type).getQualifiers().getCVRQualifiers();
- return 0;
-}
-
-// Creating related types
-
-CompilerType
-TypeSystemClang::GetArrayElementType(lldb::opaque_compiler_type_t type,
- uint64_t *stride) {
- if (type) {
- clang::QualType qual_type(GetQualType(type));
-
- const clang::Type *array_eletype =
- qual_type.getTypePtr()->getArrayElementTypeNoTypeQual();
-
- if (!array_eletype)
- return CompilerType();
-
- CompilerType element_type = GetType(clang::QualType(array_eletype, 0));
-
- // TODO: the real stride will be >= this value.. find the real one!
- if (stride)
- if (Optional<uint64_t> size = element_type.GetByteSize(nullptr))
- *stride = *size;
-
- return element_type;
- }
- return CompilerType();
-}
-
-CompilerType TypeSystemClang::GetArrayType(lldb::opaque_compiler_type_t type,
- uint64_t size) {
- if (type) {
- clang::QualType qual_type(GetCanonicalQualType(type));
- clang::ASTContext &ast_ctx = getASTContext();
- if (size != 0)
- return GetType(ast_ctx.getConstantArrayType(
- qual_type, llvm::APInt(64, size), nullptr,
- clang::ArrayType::ArraySizeModifier::Normal, 0));
- else
- return GetType(ast_ctx.getIncompleteArrayType(
- qual_type, clang::ArrayType::ArraySizeModifier::Normal, 0));
- }
-
- return CompilerType();
-}
-
-CompilerType
-TypeSystemClang::GetCanonicalType(lldb::opaque_compiler_type_t type) {
- if (type)
- return GetType(GetCanonicalQualType(type));
- return CompilerType();
-}
-
-static clang::QualType GetFullyUnqualifiedType_Impl(clang::ASTContext *ast,
- clang::QualType qual_type) {
- if (qual_type->isPointerType())
- qual_type = ast->getPointerType(
- GetFullyUnqualifiedType_Impl(ast, qual_type->getPointeeType()));
- else
- qual_type = qual_type.getUnqualifiedType();
- qual_type.removeLocalConst();
- qual_type.removeLocalRestrict();
- qual_type.removeLocalVolatile();
- return qual_type;
-}
-
-CompilerType
-TypeSystemClang::GetFullyUnqualifiedType(lldb::opaque_compiler_type_t type) {
- if (type)
- return GetType(
- GetFullyUnqualifiedType_Impl(&getASTContext(), GetQualType(type)));
- return CompilerType();
-}
-
-int TypeSystemClang::GetFunctionArgumentCount(
- lldb::opaque_compiler_type_t type) {
- if (type) {
- const clang::FunctionProtoType *func =
- llvm::dyn_cast<clang::FunctionProtoType>(GetCanonicalQualType(type));
- if (func)
- return func->getNumParams();
- }
- return -1;
-}
-
-CompilerType TypeSystemClang::GetFunctionArgumentTypeAtIndex(
- lldb::opaque_compiler_type_t type, size_t idx) {
- if (type) {
- const clang::FunctionProtoType *func =
- llvm::dyn_cast<clang::FunctionProtoType>(GetQualType(type));
- if (func) {
- const uint32_t num_args = func->getNumParams();
- if (idx < num_args)
- return GetType(func->getParamType(idx));
- }
- }
- return CompilerType();
-}
-
-CompilerType
-TypeSystemClang::GetFunctionReturnType(lldb::opaque_compiler_type_t type) {
- if (type) {
- clang::QualType qual_type(GetQualType(type));
- const clang::FunctionProtoType *func =
- llvm::dyn_cast<clang::FunctionProtoType>(qual_type.getTypePtr());
- if (func)
- return GetType(func->getReturnType());
- }
- return CompilerType();
-}
-
-size_t
-TypeSystemClang::GetNumMemberFunctions(lldb::opaque_compiler_type_t type) {
- size_t num_functions = 0;
- if (type) {
- clang::QualType qual_type = RemoveWrappingTypes(GetCanonicalQualType(type));
- switch (qual_type->getTypeClass()) {
- case clang::Type::Record:
- if (GetCompleteQualType(&getASTContext(), qual_type)) {
- const clang::RecordType *record_type =
- llvm::cast<clang::RecordType>(qual_type.getTypePtr());
- const clang::RecordDecl *record_decl = record_type->getDecl();
- assert(record_decl);
- const clang::CXXRecordDecl *cxx_record_decl =
- llvm::dyn_cast<clang::CXXRecordDecl>(record_decl);
- if (cxx_record_decl)
- num_functions = std::distance(cxx_record_decl->method_begin(),
- cxx_record_decl->method_end());
- }
- break;
-
- case clang::Type::ObjCObjectPointer: {
- const clang::ObjCObjectPointerType *objc_class_type =
- qual_type->getAs<clang::ObjCObjectPointerType>();
- const clang::ObjCInterfaceType *objc_interface_type =
- objc_class_type->getInterfaceType();
- if (objc_interface_type &&
- GetCompleteType(static_cast<lldb::opaque_compiler_type_t>(
- const_cast<clang::ObjCInterfaceType *>(objc_interface_type)))) {
- clang::ObjCInterfaceDecl *class_interface_decl =
- objc_interface_type->getDecl();
- if (class_interface_decl) {
- num_functions = std::distance(class_interface_decl->meth_begin(),
- class_interface_decl->meth_end());
- }
- }
- break;
- }
-
- case clang::Type::ObjCObject:
- case clang::Type::ObjCInterface:
- if (GetCompleteType(type)) {
- const clang::ObjCObjectType *objc_class_type =
- llvm::dyn_cast<clang::ObjCObjectType>(qual_type.getTypePtr());
- if (objc_class_type) {
- clang::ObjCInterfaceDecl *class_interface_decl =
- objc_class_type->getInterface();
- if (class_interface_decl)
- num_functions = std::distance(class_interface_decl->meth_begin(),
- class_interface_decl->meth_end());
- }
- }
- break;
-
- default:
- break;
- }
- }
- return num_functions;
-}
-
-TypeMemberFunctionImpl
-TypeSystemClang::GetMemberFunctionAtIndex(lldb::opaque_compiler_type_t type,
- size_t idx) {
- std::string name;
- MemberFunctionKind kind(MemberFunctionKind::eMemberFunctionKindUnknown);
- CompilerType clang_type;
- CompilerDecl clang_decl;
- if (type) {
- clang::QualType qual_type = RemoveWrappingTypes(GetCanonicalQualType(type));
- switch (qual_type->getTypeClass()) {
- case clang::Type::Record:
- if (GetCompleteQualType(&getASTContext(), qual_type)) {
- const clang::RecordType *record_type =
- llvm::cast<clang::RecordType>(qual_type.getTypePtr());
- const clang::RecordDecl *record_decl = record_type->getDecl();
- assert(record_decl);
- const clang::CXXRecordDecl *cxx_record_decl =
- llvm::dyn_cast<clang::CXXRecordDecl>(record_decl);
- if (cxx_record_decl) {
- auto method_iter = cxx_record_decl->method_begin();
- auto method_end = cxx_record_decl->method_end();
- if (idx <
- static_cast<size_t>(std::distance(method_iter, method_end))) {
- std::advance(method_iter, idx);
- clang::CXXMethodDecl *cxx_method_decl =
- method_iter->getCanonicalDecl();
- if (cxx_method_decl) {
- name = cxx_method_decl->getDeclName().getAsString();
- if (cxx_method_decl->isStatic())
- kind = lldb::eMemberFunctionKindStaticMethod;
- else if (llvm::isa<clang::CXXConstructorDecl>(cxx_method_decl))
- kind = lldb::eMemberFunctionKindConstructor;
- else if (llvm::isa<clang::CXXDestructorDecl>(cxx_method_decl))
- kind = lldb::eMemberFunctionKindDestructor;
- else
- kind = lldb::eMemberFunctionKindInstanceMethod;
- clang_type = GetType(cxx_method_decl->getType());
- clang_decl = GetCompilerDecl(cxx_method_decl);
- }
- }
- }
- }
- break;
-
- case clang::Type::ObjCObjectPointer: {
- const clang::ObjCObjectPointerType *objc_class_type =
- qual_type->getAs<clang::ObjCObjectPointerType>();
- const clang::ObjCInterfaceType *objc_interface_type =
- objc_class_type->getInterfaceType();
- if (objc_interface_type &&
- GetCompleteType(static_cast<lldb::opaque_compiler_type_t>(
- const_cast<clang::ObjCInterfaceType *>(objc_interface_type)))) {
- clang::ObjCInterfaceDecl *class_interface_decl =
- objc_interface_type->getDecl();
- if (class_interface_decl) {
- auto method_iter = class_interface_decl->meth_begin();
- auto method_end = class_interface_decl->meth_end();
- if (idx <
- static_cast<size_t>(std::distance(method_iter, method_end))) {
- std::advance(method_iter, idx);
- clang::ObjCMethodDecl *objc_method_decl =
- method_iter->getCanonicalDecl();
- if (objc_method_decl) {
- clang_decl = GetCompilerDecl(objc_method_decl);
- name = objc_method_decl->getSelector().getAsString();
- if (objc_method_decl->isClassMethod())
- kind = lldb::eMemberFunctionKindStaticMethod;
- else
- kind = lldb::eMemberFunctionKindInstanceMethod;
- }
- }
- }
- }
- break;
- }
-
- case clang::Type::ObjCObject:
- case clang::Type::ObjCInterface:
- if (GetCompleteType(type)) {
- const clang::ObjCObjectType *objc_class_type =
- llvm::dyn_cast<clang::ObjCObjectType>(qual_type.getTypePtr());
- if (objc_class_type) {
- clang::ObjCInterfaceDecl *class_interface_decl =
- objc_class_type->getInterface();
- if (class_interface_decl) {
- auto method_iter = class_interface_decl->meth_begin();
- auto method_end = class_interface_decl->meth_end();
- if (idx <
- static_cast<size_t>(std::distance(method_iter, method_end))) {
- std::advance(method_iter, idx);
- clang::ObjCMethodDecl *objc_method_decl =
- method_iter->getCanonicalDecl();
- if (objc_method_decl) {
- clang_decl = GetCompilerDecl(objc_method_decl);
- name = objc_method_decl->getSelector().getAsString();
- if (objc_method_decl->isClassMethod())
- kind = lldb::eMemberFunctionKindStaticMethod;
- else
- kind = lldb::eMemberFunctionKindInstanceMethod;
- }
- }
- }
- }
- }
- break;
-
- default:
- break;
- }
- }
-
- if (kind == eMemberFunctionKindUnknown)
- return TypeMemberFunctionImpl();
- else
- return TypeMemberFunctionImpl(clang_type, clang_decl, name, kind);
-}
-
-CompilerType
-TypeSystemClang::GetNonReferenceType(lldb::opaque_compiler_type_t type) {
- if (type)
- return GetType(GetQualType(type).getNonReferenceType());
- return CompilerType();
-}
-
-CompilerType TypeSystemClang::CreateTypedefType(
- const CompilerType &type, const char *typedef_name,
- const CompilerDeclContext &compiler_decl_ctx) {
- if (type && typedef_name && typedef_name[0]) {
- TypeSystemClang *ast =
- llvm::dyn_cast<TypeSystemClang>(type.GetTypeSystem());
- if (!ast)
- return CompilerType();
- clang::ASTContext &clang_ast = ast->getASTContext();
- clang::QualType qual_type(ClangUtil::GetQualType(type));
-
- clang::DeclContext *decl_ctx =
- TypeSystemClang::DeclContextGetAsDeclContext(compiler_decl_ctx);
- if (decl_ctx == nullptr)
- decl_ctx = ast->getASTContext().getTranslationUnitDecl();
-
- clang::TypedefDecl *decl = clang::TypedefDecl::Create(
- clang_ast, decl_ctx, clang::SourceLocation(), clang::SourceLocation(),
- &clang_ast.Idents.get(typedef_name),
- clang_ast.getTrivialTypeSourceInfo(qual_type));
-
- decl->setAccess(clang::AS_public); // TODO respect proper access specifier
-
- decl_ctx->addDecl(decl);
-
- // Get a uniqued clang::QualType for the typedef decl type
- return ast->GetType(clang_ast.getTypedefType(decl));
- }
- return CompilerType();
-}
-
-CompilerType
-TypeSystemClang::GetPointeeType(lldb::opaque_compiler_type_t type) {
- if (type) {
- clang::QualType qual_type(GetQualType(type));
- return GetType(qual_type.getTypePtr()->getPointeeType());
- }
- return CompilerType();
-}
-
-CompilerType
-TypeSystemClang::GetPointerType(lldb::opaque_compiler_type_t type) {
- if (type) {
- clang::QualType qual_type(GetQualType(type));
-
- const clang::Type::TypeClass type_class = qual_type->getTypeClass();
- switch (type_class) {
- case clang::Type::ObjCObject:
- case clang::Type::ObjCInterface:
- return GetType(getASTContext().getObjCObjectPointerType(qual_type));
-
- default:
- return GetType(getASTContext().getPointerType(qual_type));
- }
- }
- return CompilerType();
-}
-
-CompilerType
-TypeSystemClang::GetLValueReferenceType(lldb::opaque_compiler_type_t type) {
- if (type)
- return GetType(getASTContext().getLValueReferenceType(GetQualType(type)));
- else
- return CompilerType();
-}
-
-CompilerType
-TypeSystemClang::GetRValueReferenceType(lldb::opaque_compiler_type_t type) {
- if (type)
- return GetType(getASTContext().getRValueReferenceType(GetQualType(type)));
- else
- return CompilerType();
-}
-
-CompilerType TypeSystemClang::GetAtomicType(lldb::opaque_compiler_type_t type) {
- if (!type)
- return CompilerType();
- return GetType(getASTContext().getAtomicType(GetQualType(type)));
-}
-
-CompilerType
-TypeSystemClang::AddConstModifier(lldb::opaque_compiler_type_t type) {
- if (type) {
- clang::QualType result(GetQualType(type));
- result.addConst();
- return GetType(result);
- }
- return CompilerType();
-}
-
-CompilerType
-TypeSystemClang::AddVolatileModifier(lldb::opaque_compiler_type_t type) {
- if (type) {
- clang::QualType result(GetQualType(type));
- result.addVolatile();
- return GetType(result);
- }
- return CompilerType();
-}
-
-CompilerType
-TypeSystemClang::AddRestrictModifier(lldb::opaque_compiler_type_t type) {
- if (type) {
- clang::QualType result(GetQualType(type));
- result.addRestrict();
- return GetType(result);
- }
- return CompilerType();
-}
-
-CompilerType
-TypeSystemClang::CreateTypedef(lldb::opaque_compiler_type_t type,
- const char *typedef_name,
- const CompilerDeclContext &compiler_decl_ctx) {
- if (type) {
- clang::ASTContext &clang_ast = getASTContext();
- clang::QualType qual_type(GetQualType(type));
-
- clang::DeclContext *decl_ctx =
- TypeSystemClang::DeclContextGetAsDeclContext(compiler_decl_ctx);
- if (decl_ctx == nullptr)
- decl_ctx = getASTContext().getTranslationUnitDecl();
-
- clang::TypedefDecl *decl = clang::TypedefDecl::Create(
- clang_ast, decl_ctx, clang::SourceLocation(), clang::SourceLocation(),
- &clang_ast.Idents.get(typedef_name),
- clang_ast.getTrivialTypeSourceInfo(qual_type));
-
- clang::TagDecl *tdecl = nullptr;
- if (!qual_type.isNull()) {
- if (const clang::RecordType *rt = qual_type->getAs<clang::RecordType>())
- tdecl = rt->getDecl();
- if (const clang::EnumType *et = qual_type->getAs<clang::EnumType>())
- tdecl = et->getDecl();
- }
-
- // Check whether this declaration is an anonymous struct, union, or enum,
- // hidden behind a typedef. If so, we try to check whether we have a
- // typedef tag to attach to the original record declaration
- if (tdecl && !tdecl->getIdentifier() && !tdecl->getTypedefNameForAnonDecl())
- tdecl->setTypedefNameForAnonDecl(decl);
-
- decl->setAccess(clang::AS_public); // TODO respect proper access specifier
-
- // Get a uniqued clang::QualType for the typedef decl type
- return GetType(clang_ast.getTypedefType(decl));
- }
- return CompilerType();
-}
-
-CompilerType
-TypeSystemClang::GetTypedefedType(lldb::opaque_compiler_type_t type) {
- if (type) {
- const clang::TypedefType *typedef_type =
- llvm::dyn_cast<clang::TypedefType>(GetQualType(type));
- if (typedef_type)
- return GetType(typedef_type->getDecl()->getUnderlyingType());
- }
- return CompilerType();
-}
-
-// Create related types using the current type's AST
-
-CompilerType TypeSystemClang::GetBasicTypeFromAST(lldb::BasicType basic_type) {
- return TypeSystemClang::GetBasicType(basic_type);
-}
-// Exploring the type
-
-const llvm::fltSemantics &
-TypeSystemClang::GetFloatTypeSemantics(size_t byte_size) {
- clang::ASTContext &ast = getASTContext();
- const size_t bit_size = byte_size * 8;
- if (bit_size == ast.getTypeSize(ast.FloatTy))
- return ast.getFloatTypeSemantics(ast.FloatTy);
- else if (bit_size == ast.getTypeSize(ast.DoubleTy))
- return ast.getFloatTypeSemantics(ast.DoubleTy);
- else if (bit_size == ast.getTypeSize(ast.LongDoubleTy))
- return ast.getFloatTypeSemantics(ast.LongDoubleTy);
- else if (bit_size == ast.getTypeSize(ast.HalfTy))
- return ast.getFloatTypeSemantics(ast.HalfTy);
- return llvm::APFloatBase::Bogus();
-}
-
-Optional<uint64_t>
-TypeSystemClang::GetBitSize(lldb::opaque_compiler_type_t type,
- ExecutionContextScope *exe_scope) {
- if (GetCompleteType(type)) {
- clang::QualType qual_type(GetCanonicalQualType(type));
- const clang::Type::TypeClass type_class = qual_type->getTypeClass();
- switch (type_class) {
- case clang::Type::Record:
- if (GetCompleteType(type))
- return getASTContext().getTypeSize(qual_type);
- else
- return None;
- break;
-
- case clang::Type::ObjCInterface:
- case clang::Type::ObjCObject: {
- ExecutionContext exe_ctx(exe_scope);
- Process *process = exe_ctx.GetProcessPtr();
- if (process) {
- ObjCLanguageRuntime *objc_runtime = ObjCLanguageRuntime::Get(*process);
- if (objc_runtime) {
- uint64_t bit_size = 0;
- if (objc_runtime->GetTypeBitSize(GetType(qual_type), bit_size))
- return bit_size;
- }
- } else {
- static bool g_printed = false;
- if (!g_printed) {
- StreamString s;
- DumpTypeDescription(type, &s);
-
- llvm::outs() << "warning: trying to determine the size of type ";
- llvm::outs() << s.GetString() << "\n";
- llvm::outs() << "without a valid ExecutionContext. this is not "
- "reliable. please file a bug against LLDB.\n";
- llvm::outs() << "backtrace:\n";
- llvm::sys::PrintStackTrace(llvm::outs());
- llvm::outs() << "\n";
- g_printed = true;
- }
- }
- }
- LLVM_FALLTHROUGH;
- default:
- const uint32_t bit_size = getASTContext().getTypeSize(qual_type);
- if (bit_size == 0) {
- if (qual_type->isIncompleteArrayType())
- return getASTContext().getTypeSize(
- qual_type->getArrayElementTypeNoTypeQual()
- ->getCanonicalTypeUnqualified());
- }
- if (qual_type->isObjCObjectOrInterfaceType())
- return bit_size +
- getASTContext().getTypeSize(getASTContext().ObjCBuiltinClassTy);
- // Function types actually have a size of 0, that's not an error.
- if (qual_type->isFunctionProtoType())
- return bit_size;
- if (bit_size)
- return bit_size;
- }
- }
- return None;
-}
-
-llvm::Optional<size_t>
-TypeSystemClang::GetTypeBitAlign(lldb::opaque_compiler_type_t type,
- ExecutionContextScope *exe_scope) {
- if (GetCompleteType(type))
- return getASTContext().getTypeAlign(GetQualType(type));
- return {};
-}
-
-lldb::Encoding TypeSystemClang::GetEncoding(lldb::opaque_compiler_type_t type,
- uint64_t &count) {
- if (!type)
- return lldb::eEncodingInvalid;
-
- count = 1;
- clang::QualType qual_type = RemoveWrappingTypes(GetCanonicalQualType(type));
-
- switch (qual_type->getTypeClass()) {
- case clang::Type::Atomic:
- case clang::Type::Auto:
- case clang::Type::Decltype:
- case clang::Type::Elaborated:
- case clang::Type::Paren:
- case clang::Type::Typedef:
- case clang::Type::TypeOf:
- case clang::Type::TypeOfExpr:
- llvm_unreachable("Handled in RemoveWrappingTypes!");
-
- case clang::Type::UnaryTransform:
- break;
-
- case clang::Type::FunctionNoProto:
- case clang::Type::FunctionProto:
- break;
-
- case clang::Type::IncompleteArray:
- case clang::Type::VariableArray:
- break;
-
- case clang::Type::ConstantArray:
- break;
-
- case clang::Type::DependentVector:
- case clang::Type::ExtVector:
- case clang::Type::Vector:
- // TODO: Set this to more than one???
- break;
-
- case clang::Type::Builtin:
- switch (llvm::cast<clang::BuiltinType>(qual_type)->getKind()) {
- case clang::BuiltinType::Void:
- break;
-
- case clang::BuiltinType::Bool:
- case clang::BuiltinType::Char_S:
- case clang::BuiltinType::SChar:
- case clang::BuiltinType::WChar_S:
- case clang::BuiltinType::Short:
- case clang::BuiltinType::Int:
- case clang::BuiltinType::Long:
- case clang::BuiltinType::LongLong:
- case clang::BuiltinType::Int128:
- return lldb::eEncodingSint;
-
- case clang::BuiltinType::Char_U:
- case clang::BuiltinType::UChar:
- case clang::BuiltinType::WChar_U:
- case clang::BuiltinType::Char8:
- case clang::BuiltinType::Char16:
- case clang::BuiltinType::Char32:
- case clang::BuiltinType::UShort:
- case clang::BuiltinType::UInt:
- case clang::BuiltinType::ULong:
- case clang::BuiltinType::ULongLong:
- case clang::BuiltinType::UInt128:
- return lldb::eEncodingUint;
-
- // Fixed point types. Note that they are currently ignored.
- case clang::BuiltinType::ShortAccum:
- case clang::BuiltinType::Accum:
- case clang::BuiltinType::LongAccum:
- case clang::BuiltinType::UShortAccum:
- case clang::BuiltinType::UAccum:
- case clang::BuiltinType::ULongAccum:
- case clang::BuiltinType::ShortFract:
- case clang::BuiltinType::Fract:
- case clang::BuiltinType::LongFract:
- case clang::BuiltinType::UShortFract:
- case clang::BuiltinType::UFract:
- case clang::BuiltinType::ULongFract:
- case clang::BuiltinType::SatShortAccum:
- case clang::BuiltinType::SatAccum:
- case clang::BuiltinType::SatLongAccum:
- case clang::BuiltinType::SatUShortAccum:
- case clang::BuiltinType::SatUAccum:
- case clang::BuiltinType::SatULongAccum:
- case clang::BuiltinType::SatShortFract:
- case clang::BuiltinType::SatFract:
- case clang::BuiltinType::SatLongFract:
- case clang::BuiltinType::SatUShortFract:
- case clang::BuiltinType::SatUFract:
- case clang::BuiltinType::SatULongFract:
- break;
-
- case clang::BuiltinType::Half:
- case clang::BuiltinType::Float:
- case clang::BuiltinType::Float16:
- case clang::BuiltinType::Float128:
- case clang::BuiltinType::Double:
- case clang::BuiltinType::LongDouble:
- return lldb::eEncodingIEEE754;
-
- case clang::BuiltinType::ObjCClass:
- case clang::BuiltinType::ObjCId:
- case clang::BuiltinType::ObjCSel:
- return lldb::eEncodingUint;
-
- case clang::BuiltinType::NullPtr:
- return lldb::eEncodingUint;
-
- case clang::BuiltinType::Kind::ARCUnbridgedCast:
- case clang::BuiltinType::Kind::BoundMember:
- case clang::BuiltinType::Kind::BuiltinFn:
- case clang::BuiltinType::Kind::Dependent:
- case clang::BuiltinType::Kind::OCLClkEvent:
- case clang::BuiltinType::Kind::OCLEvent:
- case clang::BuiltinType::Kind::OCLImage1dRO:
- case clang::BuiltinType::Kind::OCLImage1dWO:
- case clang::BuiltinType::Kind::OCLImage1dRW:
- case clang::BuiltinType::Kind::OCLImage1dArrayRO:
- case clang::BuiltinType::Kind::OCLImage1dArrayWO:
- case clang::BuiltinType::Kind::OCLImage1dArrayRW:
- case clang::BuiltinType::Kind::OCLImage1dBufferRO:
- case clang::BuiltinType::Kind::OCLImage1dBufferWO:
- case clang::BuiltinType::Kind::OCLImage1dBufferRW:
- case clang::BuiltinType::Kind::OCLImage2dRO:
- case clang::BuiltinType::Kind::OCLImage2dWO:
- case clang::BuiltinType::Kind::OCLImage2dRW:
- case clang::BuiltinType::Kind::OCLImage2dArrayRO:
- case clang::BuiltinType::Kind::OCLImage2dArrayWO:
- case clang::BuiltinType::Kind::OCLImage2dArrayRW:
- case clang::BuiltinType::Kind::OCLImage2dArrayDepthRO:
- case clang::BuiltinType::Kind::OCLImage2dArrayDepthWO:
- case clang::BuiltinType::Kind::OCLImage2dArrayDepthRW:
- case clang::BuiltinType::Kind::OCLImage2dArrayMSAARO:
- case clang::BuiltinType::Kind::OCLImage2dArrayMSAAWO:
- case clang::BuiltinType::Kind::OCLImage2dArrayMSAARW:
- case clang::BuiltinType::Kind::OCLImage2dArrayMSAADepthRO:
- case clang::BuiltinType::Kind::OCLImage2dArrayMSAADepthWO:
- case clang::BuiltinType::Kind::OCLImage2dArrayMSAADepthRW:
- case clang::BuiltinType::Kind::OCLImage2dDepthRO:
- case clang::BuiltinType::Kind::OCLImage2dDepthWO:
- case clang::BuiltinType::Kind::OCLImage2dDepthRW:
- case clang::BuiltinType::Kind::OCLImage2dMSAARO:
- case clang::BuiltinType::Kind::OCLImage2dMSAAWO:
- case clang::BuiltinType::Kind::OCLImage2dMSAARW:
- case clang::BuiltinType::Kind::OCLImage2dMSAADepthRO:
- case clang::BuiltinType::Kind::OCLImage2dMSAADepthWO:
- case clang::BuiltinType::Kind::OCLImage2dMSAADepthRW:
- case clang::BuiltinType::Kind::OCLImage3dRO:
- case clang::BuiltinType::Kind::OCLImage3dWO:
- case clang::BuiltinType::Kind::OCLImage3dRW:
- case clang::BuiltinType::Kind::OCLQueue:
- case clang::BuiltinType::Kind::OCLReserveID:
- case clang::BuiltinType::Kind::OCLSampler:
- case clang::BuiltinType::Kind::OMPArraySection:
- case clang::BuiltinType::Kind::Overload:
- case clang::BuiltinType::Kind::PseudoObject:
- case clang::BuiltinType::Kind::UnknownAny:
- break;
-
- case clang::BuiltinType::OCLIntelSubgroupAVCMcePayload:
- case clang::BuiltinType::OCLIntelSubgroupAVCImePayload:
- case clang::BuiltinType::OCLIntelSubgroupAVCRefPayload:
- case clang::BuiltinType::OCLIntelSubgroupAVCSicPayload:
- case clang::BuiltinType::OCLIntelSubgroupAVCMceResult:
- case clang::BuiltinType::OCLIntelSubgroupAVCImeResult:
- case clang::BuiltinType::OCLIntelSubgroupAVCRefResult:
- case clang::BuiltinType::OCLIntelSubgroupAVCSicResult:
- case clang::BuiltinType::OCLIntelSubgroupAVCImeResultSingleRefStreamout:
- case clang::BuiltinType::OCLIntelSubgroupAVCImeResultDualRefStreamout:
- case clang::BuiltinType::OCLIntelSubgroupAVCImeSingleRefStreamin:
- case clang::BuiltinType::OCLIntelSubgroupAVCImeDualRefStreamin:
- break;
-
- case clang::BuiltinType::SveBool:
- case clang::BuiltinType::SveInt8:
- case clang::BuiltinType::SveInt16:
- case clang::BuiltinType::SveInt32:
- case clang::BuiltinType::SveInt64:
- case clang::BuiltinType::SveUint8:
- case clang::BuiltinType::SveUint16:
- case clang::BuiltinType::SveUint32:
- case clang::BuiltinType::SveUint64:
- case clang::BuiltinType::SveFloat16:
- case clang::BuiltinType::SveFloat32:
- case clang::BuiltinType::SveFloat64:
- break;
- }
- break;
- // All pointer types are represented as unsigned integer encodings. We may
- // nee to add a eEncodingPointer if we ever need to know the difference
- case clang::Type::ObjCObjectPointer:
- case clang::Type::BlockPointer:
- case clang::Type::Pointer:
- case clang::Type::LValueReference:
- case clang::Type::RValueReference:
- case clang::Type::MemberPointer:
- return lldb::eEncodingUint;
- case clang::Type::Complex: {
- lldb::Encoding encoding = lldb::eEncodingIEEE754;
- if (qual_type->isComplexType())
- encoding = lldb::eEncodingIEEE754;
- else {
- const clang::ComplexType *complex_type =
- qual_type->getAsComplexIntegerType();
- if (complex_type)
- encoding = GetType(complex_type->getElementType()).GetEncoding(count);
- else
- encoding = lldb::eEncodingSint;
- }
- count = 2;
- return encoding;
- }
-
- case clang::Type::ObjCInterface:
- break;
- case clang::Type::Record:
- break;
- case clang::Type::Enum:
- return lldb::eEncodingSint;
- case clang::Type::DependentSizedArray:
- case clang::Type::DependentSizedExtVector:
- case clang::Type::UnresolvedUsing:
- case clang::Type::Attributed:
- case clang::Type::TemplateTypeParm:
- case clang::Type::SubstTemplateTypeParm:
- case clang::Type::SubstTemplateTypeParmPack:
- case clang::Type::InjectedClassName:
- case clang::Type::DependentName:
- case clang::Type::DependentTemplateSpecialization:
- case clang::Type::PackExpansion:
- case clang::Type::ObjCObject:
-
- case clang::Type::TemplateSpecialization:
- case clang::Type::DeducedTemplateSpecialization:
- case clang::Type::Adjusted:
- case clang::Type::Pipe:
- break;
-
- // pointer type decayed from an array or function type.
- case clang::Type::Decayed:
- break;
- case clang::Type::ObjCTypeParam:
- break;
-
- case clang::Type::DependentAddressSpace:
- break;
- case clang::Type::MacroQualified:
- break;
- }
- count = 0;
- return lldb::eEncodingInvalid;
-}
-
-lldb::Format TypeSystemClang::GetFormat(lldb::opaque_compiler_type_t type) {
- if (!type)
- return lldb::eFormatDefault;
-
- clang::QualType qual_type = RemoveWrappingTypes(GetCanonicalQualType(type));
-
- switch (qual_type->getTypeClass()) {
- case clang::Type::Atomic:
- case clang::Type::Auto:
- case clang::Type::Decltype:
- case clang::Type::Elaborated:
- case clang::Type::Paren:
- case clang::Type::Typedef:
- case clang::Type::TypeOf:
- case clang::Type::TypeOfExpr:
- llvm_unreachable("Handled in RemoveWrappingTypes!");
- case clang::Type::UnaryTransform:
- break;
-
- case clang::Type::FunctionNoProto:
- case clang::Type::FunctionProto:
- break;
-
- case clang::Type::IncompleteArray:
- case clang::Type::VariableArray:
- break;
-
- case clang::Type::ConstantArray:
- return lldb::eFormatVoid; // no value
-
- case clang::Type::DependentVector:
- case clang::Type::ExtVector:
- case clang::Type::Vector:
- break;
-
- case clang::Type::Builtin:
- switch (llvm::cast<clang::BuiltinType>(qual_type)->getKind()) {
- // default: assert(0 && "Unknown builtin type!");
- case clang::BuiltinType::UnknownAny:
- case clang::BuiltinType::Void:
- case clang::BuiltinType::BoundMember:
- break;
-
- case clang::BuiltinType::Bool:
- return lldb::eFormatBoolean;
- case clang::BuiltinType::Char_S:
- case clang::BuiltinType::SChar:
- case clang::BuiltinType::WChar_S:
- case clang::BuiltinType::Char_U:
- case clang::BuiltinType::UChar:
- case clang::BuiltinType::WChar_U:
- return lldb::eFormatChar;
- case clang::BuiltinType::Char16:
- return lldb::eFormatUnicode16;
- case clang::BuiltinType::Char32:
- return lldb::eFormatUnicode32;
- case clang::BuiltinType::UShort:
- return lldb::eFormatUnsigned;
- case clang::BuiltinType::Short:
- return lldb::eFormatDecimal;
- case clang::BuiltinType::UInt:
- return lldb::eFormatUnsigned;
- case clang::BuiltinType::Int:
- return lldb::eFormatDecimal;
- case clang::BuiltinType::ULong:
- return lldb::eFormatUnsigned;
- case clang::BuiltinType::Long:
- return lldb::eFormatDecimal;
- case clang::BuiltinType::ULongLong:
- return lldb::eFormatUnsigned;
- case clang::BuiltinType::LongLong:
- return lldb::eFormatDecimal;
- case clang::BuiltinType::UInt128:
- return lldb::eFormatUnsigned;
- case clang::BuiltinType::Int128:
- return lldb::eFormatDecimal;
- case clang::BuiltinType::Half:
- case clang::BuiltinType::Float:
- case clang::BuiltinType::Double:
- case clang::BuiltinType::LongDouble:
- return lldb::eFormatFloat;
- default:
- return lldb::eFormatHex;
- }
- break;
- case clang::Type::ObjCObjectPointer:
- return lldb::eFormatHex;
- case clang::Type::BlockPointer:
- return lldb::eFormatHex;
- case clang::Type::Pointer:
- return lldb::eFormatHex;
- case clang::Type::LValueReference:
- case clang::Type::RValueReference:
- return lldb::eFormatHex;
- case clang::Type::MemberPointer:
- break;
- case clang::Type::Complex: {
- if (qual_type->isComplexType())
- return lldb::eFormatComplex;
- else
- return lldb::eFormatComplexInteger;
- }
- case clang::Type::ObjCInterface:
- break;
- case clang::Type::Record:
- break;
- case clang::Type::Enum:
- return lldb::eFormatEnum;
- case clang::Type::DependentSizedArray:
- case clang::Type::DependentSizedExtVector:
- case clang::Type::UnresolvedUsing:
- case clang::Type::Attributed:
- case clang::Type::TemplateTypeParm:
- case clang::Type::SubstTemplateTypeParm:
- case clang::Type::SubstTemplateTypeParmPack:
- case clang::Type::InjectedClassName:
- case clang::Type::DependentName:
- case clang::Type::DependentTemplateSpecialization:
- case clang::Type::PackExpansion:
- case clang::Type::ObjCObject:
-
- case clang::Type::TemplateSpecialization:
- case clang::Type::DeducedTemplateSpecialization:
- case clang::Type::Adjusted:
- case clang::Type::Pipe:
- break;
-
- // pointer type decayed from an array or function type.
- case clang::Type::Decayed:
- break;
- case clang::Type::ObjCTypeParam:
- break;
-
- case clang::Type::DependentAddressSpace:
- break;
- case clang::Type::MacroQualified:
- break;
- }
- // We don't know hot to display this type...
- return lldb::eFormatBytes;
-}
-
-static bool ObjCDeclHasIVars(clang::ObjCInterfaceDecl *class_interface_decl,
- bool check_superclass) {
- while (class_interface_decl) {
- if (class_interface_decl->ivar_size() > 0)
- return true;
-
- if (check_superclass)
- class_interface_decl = class_interface_decl->getSuperClass();
- else
- break;
- }
- return false;
-}
-
-static Optional<SymbolFile::ArrayInfo>
-GetDynamicArrayInfo(TypeSystemClang &ast, SymbolFile *sym_file,
- clang::QualType qual_type,
- const ExecutionContext *exe_ctx) {
- if (qual_type->isIncompleteArrayType())
- if (auto *metadata = ast.GetMetadata(qual_type.getTypePtr()))
- return sym_file->GetDynamicArrayInfoForUID(metadata->GetUserID(),
- exe_ctx);
- return llvm::None;
-}
-
-uint32_t TypeSystemClang::GetNumChildren(lldb::opaque_compiler_type_t type,
- bool omit_empty_base_classes,
- const ExecutionContext *exe_ctx) {
- if (!type)
- return 0;
-
- uint32_t num_children = 0;
- clang::QualType qual_type(RemoveWrappingTypes(GetQualType(type)));
- const clang::Type::TypeClass type_class = qual_type->getTypeClass();
- switch (type_class) {
- case clang::Type::Builtin:
- switch (llvm::cast<clang::BuiltinType>(qual_type)->getKind()) {
- case clang::BuiltinType::ObjCId: // child is Class
- case clang::BuiltinType::ObjCClass: // child is Class
- num_children = 1;
- break;
-
- default:
- break;
- }
- break;
-
- case clang::Type::Complex:
- return 0;
- case clang::Type::Record:
- if (GetCompleteQualType(&getASTContext(), qual_type)) {
- const clang::RecordType *record_type =
- llvm::cast<clang::RecordType>(qual_type.getTypePtr());
- const clang::RecordDecl *record_decl = record_type->getDecl();
- assert(record_decl);
- const clang::CXXRecordDecl *cxx_record_decl =
- llvm::dyn_cast<clang::CXXRecordDecl>(record_decl);
- if (cxx_record_decl) {
- if (omit_empty_base_classes) {
- // Check each base classes to see if it or any of its base classes
- // contain any fields. This can help limit the noise in variable
- // views by not having to show base classes that contain no members.
- clang::CXXRecordDecl::base_class_const_iterator base_class,
- base_class_end;
- for (base_class = cxx_record_decl->bases_begin(),
- base_class_end = cxx_record_decl->bases_end();
- base_class != base_class_end; ++base_class) {
- const clang::CXXRecordDecl *base_class_decl =
- llvm::cast<clang::CXXRecordDecl>(
- base_class->getType()
- ->getAs<clang::RecordType>()
- ->getDecl());
-
- // Skip empty base classes
- if (!TypeSystemClang::RecordHasFields(base_class_decl))
- continue;
-
- num_children++;
- }
- } else {
- // Include all base classes
- num_children += cxx_record_decl->getNumBases();
- }
- }
- clang::RecordDecl::field_iterator field, field_end;
- for (field = record_decl->field_begin(),
- field_end = record_decl->field_end();
- field != field_end; ++field)
- ++num_children;
- }
- break;
-
- case clang::Type::ObjCObject:
- case clang::Type::ObjCInterface:
- if (GetCompleteQualType(&getASTContext(), qual_type)) {
- const clang::ObjCObjectType *objc_class_type =
- llvm::dyn_cast<clang::ObjCObjectType>(qual_type.getTypePtr());
- assert(objc_class_type);
- if (objc_class_type) {
- clang::ObjCInterfaceDecl *class_interface_decl =
- objc_class_type->getInterface();
-
- if (class_interface_decl) {
-
- clang::ObjCInterfaceDecl *superclass_interface_decl =
- class_interface_decl->getSuperClass();
- if (superclass_interface_decl) {
- if (omit_empty_base_classes) {
- if (ObjCDeclHasIVars(superclass_interface_decl, true))
- ++num_children;
- } else
- ++num_children;
- }
-
- num_children += class_interface_decl->ivar_size();
- }
- }
- }
- break;
-
- case clang::Type::ObjCObjectPointer: {
- const clang::ObjCObjectPointerType *pointer_type =
- llvm::cast<clang::ObjCObjectPointerType>(qual_type.getTypePtr());
- clang::QualType pointee_type = pointer_type->getPointeeType();
- uint32_t num_pointee_children =
- GetType(pointee_type).GetNumChildren(omit_empty_base_classes, exe_ctx);
- // If this type points to a simple type, then it has 1 child
- if (num_pointee_children == 0)
- num_children = 1;
- else
- num_children = num_pointee_children;
- } break;
-
- case clang::Type::Vector:
- case clang::Type::ExtVector:
- num_children =
- llvm::cast<clang::VectorType>(qual_type.getTypePtr())->getNumElements();
- break;
-
- case clang::Type::ConstantArray:
- num_children = llvm::cast<clang::ConstantArrayType>(qual_type.getTypePtr())
- ->getSize()
- .getLimitedValue();
- break;
- case clang::Type::IncompleteArray:
- if (auto array_info =
- GetDynamicArrayInfo(*this, GetSymbolFile(), qual_type, exe_ctx))
- // Only 1-dimensional arrays are supported.
- num_children = array_info->element_orders.size()
- ? array_info->element_orders.back()
- : 0;
- break;
-
- case clang::Type::Pointer: {
- const clang::PointerType *pointer_type =
- llvm::cast<clang::PointerType>(qual_type.getTypePtr());
- clang::QualType pointee_type(pointer_type->getPointeeType());
- uint32_t num_pointee_children =
- GetType(pointee_type).GetNumChildren(omit_empty_base_classes, exe_ctx);
- if (num_pointee_children == 0) {
- // We have a pointer to a pointee type that claims it has no children. We
- // will want to look at
- num_children = GetNumPointeeChildren(pointee_type);
- } else
- num_children = num_pointee_children;
- } break;
-
- case clang::Type::LValueReference:
- case clang::Type::RValueReference: {
- const clang::ReferenceType *reference_type =
- llvm::cast<clang::ReferenceType>(qual_type.getTypePtr());
- clang::QualType pointee_type = reference_type->getPointeeType();
- uint32_t num_pointee_children =
- GetType(pointee_type).GetNumChildren(omit_empty_base_classes, exe_ctx);
- // If this type points to a simple type, then it has 1 child
- if (num_pointee_children == 0)
- num_children = 1;
- else
- num_children = num_pointee_children;
- } break;
-
- default:
- break;
- }
- return num_children;
-}
-
-CompilerType TypeSystemClang::GetBuiltinTypeByName(ConstString name) {
- return GetBasicType(GetBasicTypeEnumeration(name));
-}
-
-lldb::BasicType
-TypeSystemClang::GetBasicTypeEnumeration(lldb::opaque_compiler_type_t type) {
- if (type) {
- clang::QualType qual_type(GetQualType(type));
- const clang::Type::TypeClass type_class = qual_type->getTypeClass();
- if (type_class == clang::Type::Builtin) {
- switch (llvm::cast<clang::BuiltinType>(qual_type)->getKind()) {
- case clang::BuiltinType::Void:
- return eBasicTypeVoid;
- case clang::BuiltinType::Bool:
- return eBasicTypeBool;
- case clang::BuiltinType::Char_S:
- return eBasicTypeSignedChar;
- case clang::BuiltinType::Char_U:
- return eBasicTypeUnsignedChar;
- case clang::BuiltinType::Char16:
- return eBasicTypeChar16;
- case clang::BuiltinType::Char32:
- return eBasicTypeChar32;
- case clang::BuiltinType::UChar:
- return eBasicTypeUnsignedChar;
- case clang::BuiltinType::SChar:
- return eBasicTypeSignedChar;
- case clang::BuiltinType::WChar_S:
- return eBasicTypeSignedWChar;
- case clang::BuiltinType::WChar_U:
- return eBasicTypeUnsignedWChar;
- case clang::BuiltinType::Short:
- return eBasicTypeShort;
- case clang::BuiltinType::UShort:
- return eBasicTypeUnsignedShort;
- case clang::BuiltinType::Int:
- return eBasicTypeInt;
- case clang::BuiltinType::UInt:
- return eBasicTypeUnsignedInt;
- case clang::BuiltinType::Long:
- return eBasicTypeLong;
- case clang::BuiltinType::ULong:
- return eBasicTypeUnsignedLong;
- case clang::BuiltinType::LongLong:
- return eBasicTypeLongLong;
- case clang::BuiltinType::ULongLong:
- return eBasicTypeUnsignedLongLong;
- case clang::BuiltinType::Int128:
- return eBasicTypeInt128;
- case clang::BuiltinType::UInt128:
- return eBasicTypeUnsignedInt128;
-
- case clang::BuiltinType::Half:
- return eBasicTypeHalf;
- case clang::BuiltinType::Float:
- return eBasicTypeFloat;
- case clang::BuiltinType::Double:
- return eBasicTypeDouble;
- case clang::BuiltinType::LongDouble:
- return eBasicTypeLongDouble;
-
- case clang::BuiltinType::NullPtr:
- return eBasicTypeNullPtr;
- case clang::BuiltinType::ObjCId:
- return eBasicTypeObjCID;
- case clang::BuiltinType::ObjCClass:
- return eBasicTypeObjCClass;
- case clang::BuiltinType::ObjCSel:
- return eBasicTypeObjCSel;
- default:
- return eBasicTypeOther;
- }
- }
- }
- return eBasicTypeInvalid;
-}
-
-void TypeSystemClang::ForEachEnumerator(
- lldb::opaque_compiler_type_t type,
- std::function<bool(const CompilerType &integer_type,
- ConstString name,
- const llvm::APSInt &value)> const &callback) {
- const clang::EnumType *enum_type =
- llvm::dyn_cast<clang::EnumType>(GetCanonicalQualType(type));
- if (enum_type) {
- const clang::EnumDecl *enum_decl = enum_type->getDecl();
- if (enum_decl) {
- CompilerType integer_type = GetType(enum_decl->getIntegerType());
-
- clang::EnumDecl::enumerator_iterator enum_pos, enum_end_pos;
- for (enum_pos = enum_decl->enumerator_begin(),
- enum_end_pos = enum_decl->enumerator_end();
- enum_pos != enum_end_pos; ++enum_pos) {
- ConstString name(enum_pos->getNameAsString().c_str());
- if (!callback(integer_type, name, enum_pos->getInitVal()))
- break;
- }
- }
- }
-}
-
-#pragma mark Aggregate Types
-
-uint32_t TypeSystemClang::GetNumFields(lldb::opaque_compiler_type_t type) {
- if (!type)
- return 0;
-
- uint32_t count = 0;
- clang::QualType qual_type(RemoveWrappingTypes(GetCanonicalQualType(type)));
- const clang::Type::TypeClass type_class = qual_type->getTypeClass();
- switch (type_class) {
- case clang::Type::Record:
- if (GetCompleteType(type)) {
- const clang::RecordType *record_type =
- llvm::dyn_cast<clang::RecordType>(qual_type.getTypePtr());
- if (record_type) {
- clang::RecordDecl *record_decl = record_type->getDecl();
- if (record_decl) {
- uint32_t field_idx = 0;
- clang::RecordDecl::field_iterator field, field_end;
- for (field = record_decl->field_begin(),
- field_end = record_decl->field_end();
- field != field_end; ++field)
- ++field_idx;
- count = field_idx;
- }
- }
- }
- break;
-
- case clang::Type::ObjCObjectPointer: {
- const clang::ObjCObjectPointerType *objc_class_type =
- qual_type->getAs<clang::ObjCObjectPointerType>();
- const clang::ObjCInterfaceType *objc_interface_type =
- objc_class_type->getInterfaceType();
- if (objc_interface_type &&
- GetCompleteType(static_cast<lldb::opaque_compiler_type_t>(
- const_cast<clang::ObjCInterfaceType *>(objc_interface_type)))) {
- clang::ObjCInterfaceDecl *class_interface_decl =
- objc_interface_type->getDecl();
- if (class_interface_decl) {
- count = class_interface_decl->ivar_size();
- }
- }
- break;
- }
-
- case clang::Type::ObjCObject:
- case clang::Type::ObjCInterface:
- if (GetCompleteType(type)) {
- const clang::ObjCObjectType *objc_class_type =
- llvm::dyn_cast<clang::ObjCObjectType>(qual_type.getTypePtr());
- if (objc_class_type) {
- clang::ObjCInterfaceDecl *class_interface_decl =
- objc_class_type->getInterface();
-
- if (class_interface_decl)
- count = class_interface_decl->ivar_size();
- }
- }
- break;
-
- default:
- break;
- }
- return count;
-}
-
-static lldb::opaque_compiler_type_t
-GetObjCFieldAtIndex(clang::ASTContext *ast,
- clang::ObjCInterfaceDecl *class_interface_decl, size_t idx,
- std::string &name, uint64_t *bit_offset_ptr,
- uint32_t *bitfield_bit_size_ptr, bool *is_bitfield_ptr) {
- if (class_interface_decl) {
- if (idx < (class_interface_decl->ivar_size())) {
- clang::ObjCInterfaceDecl::ivar_iterator ivar_pos,
- ivar_end = class_interface_decl->ivar_end();
- uint32_t ivar_idx = 0;
-
- for (ivar_pos = class_interface_decl->ivar_begin(); ivar_pos != ivar_end;
- ++ivar_pos, ++ivar_idx) {
- if (ivar_idx == idx) {
- const clang::ObjCIvarDecl *ivar_decl = *ivar_pos;
-
- clang::QualType ivar_qual_type(ivar_decl->getType());
-
- name.assign(ivar_decl->getNameAsString());
-
- if (bit_offset_ptr) {
- const clang::ASTRecordLayout &interface_layout =
- ast->getASTObjCInterfaceLayout(class_interface_decl);
- *bit_offset_ptr = interface_layout.getFieldOffset(ivar_idx);
- }
-
- const bool is_bitfield = ivar_pos->isBitField();
-
- if (bitfield_bit_size_ptr) {
- *bitfield_bit_size_ptr = 0;
-
- if (is_bitfield && ast) {
- clang::Expr *bitfield_bit_size_expr = ivar_pos->getBitWidth();
- clang::Expr::EvalResult result;
- if (bitfield_bit_size_expr &&
- bitfield_bit_size_expr->EvaluateAsInt(result, *ast)) {
- llvm::APSInt bitfield_apsint = result.Val.getInt();
- *bitfield_bit_size_ptr = bitfield_apsint.getLimitedValue();
- }
- }
- }
- if (is_bitfield_ptr)
- *is_bitfield_ptr = is_bitfield;
-
- return ivar_qual_type.getAsOpaquePtr();
- }
- }
- }
- }
- return nullptr;
-}
-
-CompilerType TypeSystemClang::GetFieldAtIndex(lldb::opaque_compiler_type_t type,
- size_t idx, std::string &name,
- uint64_t *bit_offset_ptr,
- uint32_t *bitfield_bit_size_ptr,
- bool *is_bitfield_ptr) {
- if (!type)
- return CompilerType();
-
- clang::QualType qual_type(RemoveWrappingTypes(GetCanonicalQualType(type)));
- const clang::Type::TypeClass type_class = qual_type->getTypeClass();
- switch (type_class) {
- case clang::Type::Record:
- if (GetCompleteType(type)) {
- const clang::RecordType *record_type =
- llvm::cast<clang::RecordType>(qual_type.getTypePtr());
- const clang::RecordDecl *record_decl = record_type->getDecl();
- uint32_t field_idx = 0;
- clang::RecordDecl::field_iterator field, field_end;
- for (field = record_decl->field_begin(),
- field_end = record_decl->field_end();
- field != field_end; ++field, ++field_idx) {
- if (idx == field_idx) {
- // Print the member type if requested
- // Print the member name and equal sign
- name.assign(field->getNameAsString());
-
- // Figure out the type byte size (field_type_info.first) and
- // alignment (field_type_info.second) from the AST context.
- if (bit_offset_ptr) {
- const clang::ASTRecordLayout &record_layout =
- getASTContext().getASTRecordLayout(record_decl);
- *bit_offset_ptr = record_layout.getFieldOffset(field_idx);
- }
-
- const bool is_bitfield = field->isBitField();
-
- if (bitfield_bit_size_ptr) {
- *bitfield_bit_size_ptr = 0;
-
- if (is_bitfield) {
- clang::Expr *bitfield_bit_size_expr = field->getBitWidth();
- clang::Expr::EvalResult result;
- if (bitfield_bit_size_expr &&
- bitfield_bit_size_expr->EvaluateAsInt(result,
- getASTContext())) {
- llvm::APSInt bitfield_apsint = result.Val.getInt();
- *bitfield_bit_size_ptr = bitfield_apsint.getLimitedValue();
- }
- }
- }
- if (is_bitfield_ptr)
- *is_bitfield_ptr = is_bitfield;
-
- return GetType(field->getType());
- }
- }
- }
- break;
-
- case clang::Type::ObjCObjectPointer: {
- const clang::ObjCObjectPointerType *objc_class_type =
- qual_type->getAs<clang::ObjCObjectPointerType>();
- const clang::ObjCInterfaceType *objc_interface_type =
- objc_class_type->getInterfaceType();
- if (objc_interface_type &&
- GetCompleteType(static_cast<lldb::opaque_compiler_type_t>(
- const_cast<clang::ObjCInterfaceType *>(objc_interface_type)))) {
- clang::ObjCInterfaceDecl *class_interface_decl =
- objc_interface_type->getDecl();
- if (class_interface_decl) {
- return CompilerType(
- this, GetObjCFieldAtIndex(&getASTContext(), class_interface_decl,
- idx, name, bit_offset_ptr,
- bitfield_bit_size_ptr, is_bitfield_ptr));
- }
- }
- break;
- }
-
- case clang::Type::ObjCObject:
- case clang::Type::ObjCInterface:
- if (GetCompleteType(type)) {
- const clang::ObjCObjectType *objc_class_type =
- llvm::dyn_cast<clang::ObjCObjectType>(qual_type.getTypePtr());
- assert(objc_class_type);
- if (objc_class_type) {
- clang::ObjCInterfaceDecl *class_interface_decl =
- objc_class_type->getInterface();
- return CompilerType(
- this, GetObjCFieldAtIndex(&getASTContext(), class_interface_decl,
- idx, name, bit_offset_ptr,
- bitfield_bit_size_ptr, is_bitfield_ptr));
- }
- }
- break;
-
- default:
- break;
- }
- return CompilerType();
-}
-
-uint32_t
-TypeSystemClang::GetNumDirectBaseClasses(lldb::opaque_compiler_type_t type) {
- uint32_t count = 0;
- clang::QualType qual_type = RemoveWrappingTypes(GetCanonicalQualType(type));
- const clang::Type::TypeClass type_class = qual_type->getTypeClass();
- switch (type_class) {
- case clang::Type::Record:
- if (GetCompleteType(type)) {
- const clang::CXXRecordDecl *cxx_record_decl =
- qual_type->getAsCXXRecordDecl();
- if (cxx_record_decl)
- count = cxx_record_decl->getNumBases();
- }
- break;
-
- case clang::Type::ObjCObjectPointer:
- count = GetPointeeType(type).GetNumDirectBaseClasses();
- break;
-
- case clang::Type::ObjCObject:
- if (GetCompleteType(type)) {
- const clang::ObjCObjectType *objc_class_type =
- qual_type->getAsObjCQualifiedInterfaceType();
- if (objc_class_type) {
- clang::ObjCInterfaceDecl *class_interface_decl =
- objc_class_type->getInterface();
-
- if (class_interface_decl && class_interface_decl->getSuperClass())
- count = 1;
- }
- }
- break;
- case clang::Type::ObjCInterface:
- if (GetCompleteType(type)) {
- const clang::ObjCInterfaceType *objc_interface_type =
- qual_type->getAs<clang::ObjCInterfaceType>();
- if (objc_interface_type) {
- clang::ObjCInterfaceDecl *class_interface_decl =
- objc_interface_type->getInterface();
-
- if (class_interface_decl && class_interface_decl->getSuperClass())
- count = 1;
- }
- }
- break;
-
- default:
- break;
- }
- return count;
-}
-
-uint32_t
-TypeSystemClang::GetNumVirtualBaseClasses(lldb::opaque_compiler_type_t type) {
- uint32_t count = 0;
- clang::QualType qual_type = RemoveWrappingTypes(GetCanonicalQualType(type));
- const clang::Type::TypeClass type_class = qual_type->getTypeClass();
- switch (type_class) {
- case clang::Type::Record:
- if (GetCompleteType(type)) {
- const clang::CXXRecordDecl *cxx_record_decl =
- qual_type->getAsCXXRecordDecl();
- if (cxx_record_decl)
- count = cxx_record_decl->getNumVBases();
- }
- break;
-
- default:
- break;
- }
- return count;
-}
-
-CompilerType TypeSystemClang::GetDirectBaseClassAtIndex(
- lldb::opaque_compiler_type_t type, size_t idx, uint32_t *bit_offset_ptr) {
- clang::QualType qual_type = RemoveWrappingTypes(GetCanonicalQualType(type));
- const clang::Type::TypeClass type_class = qual_type->getTypeClass();
- switch (type_class) {
- case clang::Type::Record:
- if (GetCompleteType(type)) {
- const clang::CXXRecordDecl *cxx_record_decl =
- qual_type->getAsCXXRecordDecl();
- if (cxx_record_decl) {
- uint32_t curr_idx = 0;
- clang::CXXRecordDecl::base_class_const_iterator base_class,
- base_class_end;
- for (base_class = cxx_record_decl->bases_begin(),
- base_class_end = cxx_record_decl->bases_end();
- base_class != base_class_end; ++base_class, ++curr_idx) {
- if (curr_idx == idx) {
- if (bit_offset_ptr) {
- const clang::ASTRecordLayout &record_layout =
- getASTContext().getASTRecordLayout(cxx_record_decl);
- const clang::CXXRecordDecl *base_class_decl =
- llvm::cast<clang::CXXRecordDecl>(
- base_class->getType()
- ->getAs<clang::RecordType>()
- ->getDecl());
- if (base_class->isVirtual())
- *bit_offset_ptr =
- record_layout.getVBaseClassOffset(base_class_decl)
- .getQuantity() *
- 8;
- else
- *bit_offset_ptr =
- record_layout.getBaseClassOffset(base_class_decl)
- .getQuantity() *
- 8;
- }
- return GetType(base_class->getType());
- }
- }
- }
- }
- break;
-
- case clang::Type::ObjCObjectPointer:
- return GetPointeeType(type).GetDirectBaseClassAtIndex(idx, bit_offset_ptr);
-
- case clang::Type::ObjCObject:
- if (idx == 0 && GetCompleteType(type)) {
- const clang::ObjCObjectType *objc_class_type =
- qual_type->getAsObjCQualifiedInterfaceType();
- if (objc_class_type) {
- clang::ObjCInterfaceDecl *class_interface_decl =
- objc_class_type->getInterface();
-
- if (class_interface_decl) {
- clang::ObjCInterfaceDecl *superclass_interface_decl =
- class_interface_decl->getSuperClass();
- if (superclass_interface_decl) {
- if (bit_offset_ptr)
- *bit_offset_ptr = 0;
- return GetType(getASTContext().getObjCInterfaceType(
- superclass_interface_decl));
- }
- }
- }
- }
- break;
- case clang::Type::ObjCInterface:
- if (idx == 0 && GetCompleteType(type)) {
- const clang::ObjCObjectType *objc_interface_type =
- qual_type->getAs<clang::ObjCInterfaceType>();
- if (objc_interface_type) {
- clang::ObjCInterfaceDecl *class_interface_decl =
- objc_interface_type->getInterface();
-
- if (class_interface_decl) {
- clang::ObjCInterfaceDecl *superclass_interface_decl =
- class_interface_decl->getSuperClass();
- if (superclass_interface_decl) {
- if (bit_offset_ptr)
- *bit_offset_ptr = 0;
- return GetType(getASTContext().getObjCInterfaceType(
- superclass_interface_decl));
- }
- }
- }
- }
- break;
-
- default:
- break;
- }
- return CompilerType();
-}
-
-CompilerType TypeSystemClang::GetVirtualBaseClassAtIndex(
- lldb::opaque_compiler_type_t type, size_t idx, uint32_t *bit_offset_ptr) {
- clang::QualType qual_type = RemoveWrappingTypes(GetCanonicalQualType(type));
- const clang::Type::TypeClass type_class = qual_type->getTypeClass();
- switch (type_class) {
- case clang::Type::Record:
- if (GetCompleteType(type)) {
- const clang::CXXRecordDecl *cxx_record_decl =
- qual_type->getAsCXXRecordDecl();
- if (cxx_record_decl) {
- uint32_t curr_idx = 0;
- clang::CXXRecordDecl::base_class_const_iterator base_class,
- base_class_end;
- for (base_class = cxx_record_decl->vbases_begin(),
- base_class_end = cxx_record_decl->vbases_end();
- base_class != base_class_end; ++base_class, ++curr_idx) {
- if (curr_idx == idx) {
- if (bit_offset_ptr) {
- const clang::ASTRecordLayout &record_layout =
- getASTContext().getASTRecordLayout(cxx_record_decl);
- const clang::CXXRecordDecl *base_class_decl =
- llvm::cast<clang::CXXRecordDecl>(
- base_class->getType()
- ->getAs<clang::RecordType>()
- ->getDecl());
- *bit_offset_ptr =
- record_layout.getVBaseClassOffset(base_class_decl)
- .getQuantity() *
- 8;
- }
- return GetType(base_class->getType());
- }
- }
- }
- }
- break;
-
- default:
- break;
- }
- return CompilerType();
-}
-
-// If a pointer to a pointee type (the clang_type arg) says that it has no
-// children, then we either need to trust it, or override it and return a
-// different result. For example, an "int *" has one child that is an integer,
-// but a function pointer doesn't have any children. Likewise if a Record type
-// claims it has no children, then there really is nothing to show.
-uint32_t TypeSystemClang::GetNumPointeeChildren(clang::QualType type) {
- if (type.isNull())
- return 0;
-
- clang::QualType qual_type = RemoveWrappingTypes(type.getCanonicalType());
- const clang::Type::TypeClass type_class = qual_type->getTypeClass();
- switch (type_class) {
- case clang::Type::Builtin:
- switch (llvm::cast<clang::BuiltinType>(qual_type)->getKind()) {
- case clang::BuiltinType::UnknownAny:
- case clang::BuiltinType::Void:
- case clang::BuiltinType::NullPtr:
- case clang::BuiltinType::OCLEvent:
- case clang::BuiltinType::OCLImage1dRO:
- case clang::BuiltinType::OCLImage1dWO:
- case clang::BuiltinType::OCLImage1dRW:
- case clang::BuiltinType::OCLImage1dArrayRO:
- case clang::BuiltinType::OCLImage1dArrayWO:
- case clang::BuiltinType::OCLImage1dArrayRW:
- case clang::BuiltinType::OCLImage1dBufferRO:
- case clang::BuiltinType::OCLImage1dBufferWO:
- case clang::BuiltinType::OCLImage1dBufferRW:
- case clang::BuiltinType::OCLImage2dRO:
- case clang::BuiltinType::OCLImage2dWO:
- case clang::BuiltinType::OCLImage2dRW:
- case clang::BuiltinType::OCLImage2dArrayRO:
- case clang::BuiltinType::OCLImage2dArrayWO:
- case clang::BuiltinType::OCLImage2dArrayRW:
- case clang::BuiltinType::OCLImage3dRO:
- case clang::BuiltinType::OCLImage3dWO:
- case clang::BuiltinType::OCLImage3dRW:
- case clang::BuiltinType::OCLSampler:
- return 0;
- case clang::BuiltinType::Bool:
- case clang::BuiltinType::Char_U:
- case clang::BuiltinType::UChar:
- case clang::BuiltinType::WChar_U:
- case clang::BuiltinType::Char16:
- case clang::BuiltinType::Char32:
- case clang::BuiltinType::UShort:
- case clang::BuiltinType::UInt:
- case clang::BuiltinType::ULong:
- case clang::BuiltinType::ULongLong:
- case clang::BuiltinType::UInt128:
- case clang::BuiltinType::Char_S:
- case clang::BuiltinType::SChar:
- case clang::BuiltinType::WChar_S:
- case clang::BuiltinType::Short:
- case clang::BuiltinType::Int:
- case clang::BuiltinType::Long:
- case clang::BuiltinType::LongLong:
- case clang::BuiltinType::Int128:
- case clang::BuiltinType::Float:
- case clang::BuiltinType::Double:
- case clang::BuiltinType::LongDouble:
- case clang::BuiltinType::Dependent:
- case clang::BuiltinType::Overload:
- case clang::BuiltinType::ObjCId:
- case clang::BuiltinType::ObjCClass:
- case clang::BuiltinType::ObjCSel:
- case clang::BuiltinType::BoundMember:
- case clang::BuiltinType::Half:
- case clang::BuiltinType::ARCUnbridgedCast:
- case clang::BuiltinType::PseudoObject:
- case clang::BuiltinType::BuiltinFn:
- case clang::BuiltinType::OMPArraySection:
- return 1;
- default:
- return 0;
- }
- break;
-
- case clang::Type::Complex:
- return 1;
- case clang::Type::Pointer:
- return 1;
- case clang::Type::BlockPointer:
- return 0; // If block pointers don't have debug info, then no children for
- // them
- case clang::Type::LValueReference:
- return 1;
- case clang::Type::RValueReference:
- return 1;
- case clang::Type::MemberPointer:
- return 0;
- case clang::Type::ConstantArray:
- return 0;
- case clang::Type::IncompleteArray:
- return 0;
- case clang::Type::VariableArray:
- return 0;
- case clang::Type::DependentSizedArray:
- return 0;
- case clang::Type::DependentSizedExtVector:
- return 0;
- case clang::Type::Vector:
- return 0;
- case clang::Type::ExtVector:
- return 0;
- case clang::Type::FunctionProto:
- return 0; // When we function pointers, they have no children...
- case clang::Type::FunctionNoProto:
- return 0; // When we function pointers, they have no children...
- case clang::Type::UnresolvedUsing:
- return 0;
- case clang::Type::Record:
- return 0;
- case clang::Type::Enum:
- return 1;
- case clang::Type::TemplateTypeParm:
- return 1;
- case clang::Type::SubstTemplateTypeParm:
- return 1;
- case clang::Type::TemplateSpecialization:
- return 1;
- case clang::Type::InjectedClassName:
- return 0;
- case clang::Type::DependentName:
- return 1;
- case clang::Type::DependentTemplateSpecialization:
- return 1;
- case clang::Type::ObjCObject:
- return 0;
- case clang::Type::ObjCInterface:
- return 0;
- case clang::Type::ObjCObjectPointer:
- return 1;
- default:
- break;
- }
- return 0;
-}
-
-CompilerType TypeSystemClang::GetChildCompilerTypeAtIndex(
- lldb::opaque_compiler_type_t type, ExecutionContext *exe_ctx, size_t idx,
- bool transparent_pointers, bool omit_empty_base_classes,
- bool ignore_array_bounds, std::string &child_name,
- uint32_t &child_byte_size, int32_t &child_byte_offset,
- uint32_t &child_bitfield_bit_size, uint32_t &child_bitfield_bit_offset,
- bool &child_is_base_class, bool &child_is_deref_of_parent,
- ValueObject *valobj, uint64_t &language_flags) {
- if (!type)
- return CompilerType();
-
- auto get_exe_scope = [&exe_ctx]() {
- return exe_ctx ? exe_ctx->GetBestExecutionContextScope() : nullptr;
- };
-
- clang::QualType parent_qual_type(
- RemoveWrappingTypes(GetCanonicalQualType(type)));
- const clang::Type::TypeClass parent_type_class =
- parent_qual_type->getTypeClass();
- child_bitfield_bit_size = 0;
- child_bitfield_bit_offset = 0;
- child_is_base_class = false;
- language_flags = 0;
-
- const bool idx_is_valid =
- idx < GetNumChildren(type, omit_empty_base_classes, exe_ctx);
- int32_t bit_offset;
- switch (parent_type_class) {
- case clang::Type::Builtin:
- if (idx_is_valid) {
- switch (llvm::cast<clang::BuiltinType>(parent_qual_type)->getKind()) {
- case clang::BuiltinType::ObjCId:
- case clang::BuiltinType::ObjCClass:
- child_name = "isa";
- child_byte_size =
- getASTContext().getTypeSize(getASTContext().ObjCBuiltinClassTy) /
- CHAR_BIT;
- return GetType(getASTContext().ObjCBuiltinClassTy);
-
- default:
- break;
- }
- }
- break;
-
- case clang::Type::Record:
- if (idx_is_valid && GetCompleteType(type)) {
- const clang::RecordType *record_type =
- llvm::cast<clang::RecordType>(parent_qual_type.getTypePtr());
- const clang::RecordDecl *record_decl = record_type->getDecl();
- assert(record_decl);
- const clang::ASTRecordLayout &record_layout =
- getASTContext().getASTRecordLayout(record_decl);
- uint32_t child_idx = 0;
-
- const clang::CXXRecordDecl *cxx_record_decl =
- llvm::dyn_cast<clang::CXXRecordDecl>(record_decl);
- if (cxx_record_decl) {
- // We might have base classes to print out first
- clang::CXXRecordDecl::base_class_const_iterator base_class,
- base_class_end;
- for (base_class = cxx_record_decl->bases_begin(),
- base_class_end = cxx_record_decl->bases_end();
- base_class != base_class_end; ++base_class) {
- const clang::CXXRecordDecl *base_class_decl = nullptr;
-
- // Skip empty base classes
- if (omit_empty_base_classes) {
- base_class_decl = llvm::cast<clang::CXXRecordDecl>(
- base_class->getType()->getAs<clang::RecordType>()->getDecl());
- if (!TypeSystemClang::RecordHasFields(base_class_decl))
- continue;
- }
-
- if (idx == child_idx) {
- if (base_class_decl == nullptr)
- base_class_decl = llvm::cast<clang::CXXRecordDecl>(
- base_class->getType()->getAs<clang::RecordType>()->getDecl());
-
- if (base_class->isVirtual()) {
- bool handled = false;
- if (valobj) {
- clang::VTableContextBase *vtable_ctx =
- getASTContext().getVTableContext();
- if (vtable_ctx)
- handled = GetVBaseBitOffset(*vtable_ctx, *valobj,
- record_layout, cxx_record_decl,
- base_class_decl, bit_offset);
- }
- if (!handled)
- bit_offset = record_layout.getVBaseClassOffset(base_class_decl)
- .getQuantity() *
- 8;
- } else
- bit_offset = record_layout.getBaseClassOffset(base_class_decl)
- .getQuantity() *
- 8;
-
- // Base classes should be a multiple of 8 bits in size
- child_byte_offset = bit_offset / 8;
- CompilerType base_class_clang_type = GetType(base_class->getType());
- child_name = base_class_clang_type.GetTypeName().AsCString("");
- Optional<uint64_t> size =
- base_class_clang_type.GetBitSize(get_exe_scope());
- if (!size)
- return {};
- uint64_t base_class_clang_type_bit_size = *size;
-
- // Base classes bit sizes should be a multiple of 8 bits in size
- assert(base_class_clang_type_bit_size % 8 == 0);
- child_byte_size = base_class_clang_type_bit_size / 8;
- child_is_base_class = true;
- return base_class_clang_type;
- }
- // We don't increment the child index in the for loop since we might
- // be skipping empty base classes
- ++child_idx;
- }
- }
- // Make sure index is in range...
- uint32_t field_idx = 0;
- clang::RecordDecl::field_iterator field, field_end;
- for (field = record_decl->field_begin(),
- field_end = record_decl->field_end();
- field != field_end; ++field, ++field_idx, ++child_idx) {
- if (idx == child_idx) {
- // Print the member type if requested
- // Print the member name and equal sign
- child_name.assign(field->getNameAsString());
-
- // Figure out the type byte size (field_type_info.first) and
- // alignment (field_type_info.second) from the AST context.
- CompilerType field_clang_type = GetType(field->getType());
- assert(field_idx < record_layout.getFieldCount());
- Optional<uint64_t> size =
- field_clang_type.GetByteSize(get_exe_scope());
- if (!size)
- return {};
- child_byte_size = *size;
- const uint32_t child_bit_size = child_byte_size * 8;
-
- // Figure out the field offset within the current struct/union/class
- // type
- bit_offset = record_layout.getFieldOffset(field_idx);
- if (FieldIsBitfield(*field, child_bitfield_bit_size)) {
- child_bitfield_bit_offset = bit_offset % child_bit_size;
- const uint32_t child_bit_offset =
- bit_offset - child_bitfield_bit_offset;
- child_byte_offset = child_bit_offset / 8;
- } else {
- child_byte_offset = bit_offset / 8;
- }
-
- return field_clang_type;
- }
- }
- }
- break;
-
- case clang::Type::ObjCObject:
- case clang::Type::ObjCInterface:
- if (idx_is_valid && GetCompleteType(type)) {
- const clang::ObjCObjectType *objc_class_type =
- llvm::dyn_cast<clang::ObjCObjectType>(parent_qual_type.getTypePtr());
- assert(objc_class_type);
- if (objc_class_type) {
- uint32_t child_idx = 0;
- clang::ObjCInterfaceDecl *class_interface_decl =
- objc_class_type->getInterface();
-
- if (class_interface_decl) {
-
- const clang::ASTRecordLayout &interface_layout =
- getASTContext().getASTObjCInterfaceLayout(class_interface_decl);
- clang::ObjCInterfaceDecl *superclass_interface_decl =
- class_interface_decl->getSuperClass();
- if (superclass_interface_decl) {
- if (omit_empty_base_classes) {
- CompilerType base_class_clang_type =
- GetType(getASTContext().getObjCInterfaceType(
- superclass_interface_decl));
- if (base_class_clang_type.GetNumChildren(omit_empty_base_classes,
- exe_ctx) > 0) {
- if (idx == 0) {
- clang::QualType ivar_qual_type(
- getASTContext().getObjCInterfaceType(
- superclass_interface_decl));
-
- child_name.assign(
- superclass_interface_decl->getNameAsString());
-
- clang::TypeInfo ivar_type_info =
- getASTContext().getTypeInfo(ivar_qual_type.getTypePtr());
-
- child_byte_size = ivar_type_info.Width / 8;
- child_byte_offset = 0;
- child_is_base_class = true;
-
- return GetType(ivar_qual_type);
- }
-
- ++child_idx;
- }
- } else
- ++child_idx;
- }
-
- const uint32_t superclass_idx = child_idx;
-
- if (idx < (child_idx + class_interface_decl->ivar_size())) {
- clang::ObjCInterfaceDecl::ivar_iterator ivar_pos,
- ivar_end = class_interface_decl->ivar_end();
-
- for (ivar_pos = class_interface_decl->ivar_begin();
- ivar_pos != ivar_end; ++ivar_pos) {
- if (child_idx == idx) {
- clang::ObjCIvarDecl *ivar_decl = *ivar_pos;
-
- clang::QualType ivar_qual_type(ivar_decl->getType());
-
- child_name.assign(ivar_decl->getNameAsString());
-
- clang::TypeInfo ivar_type_info =
- getASTContext().getTypeInfo(ivar_qual_type.getTypePtr());
-
- child_byte_size = ivar_type_info.Width / 8;
-
- // Figure out the field offset within the current
- // struct/union/class type For ObjC objects, we can't trust the
- // bit offset we get from the Clang AST, since that doesn't
- // account for the space taken up by unbacked properties, or
- // from the changing size of base classes that are newer than
- // this class. So if we have a process around that we can ask
- // about this object, do so.
- child_byte_offset = LLDB_INVALID_IVAR_OFFSET;
- Process *process = nullptr;
- if (exe_ctx)
- process = exe_ctx->GetProcessPtr();
- if (process) {
- ObjCLanguageRuntime *objc_runtime =
- ObjCLanguageRuntime::Get(*process);
- if (objc_runtime != nullptr) {
- CompilerType parent_ast_type = GetType(parent_qual_type);
- child_byte_offset = objc_runtime->GetByteOffsetForIvar(
- parent_ast_type, ivar_decl->getNameAsString().c_str());
- }
- }
-
- // Setting this to INT32_MAX to make sure we don't compute it
- // twice...
- bit_offset = INT32_MAX;
-
- if (child_byte_offset ==
- static_cast<int32_t>(LLDB_INVALID_IVAR_OFFSET)) {
- bit_offset = interface_layout.getFieldOffset(child_idx -
- superclass_idx);
- child_byte_offset = bit_offset / 8;
- }
-
- // Note, the ObjC Ivar Byte offset is just that, it doesn't
- // account for the bit offset of a bitfield within its
- // containing object. So regardless of where we get the byte
- // offset from, we still need to get the bit offset for
- // bitfields from the layout.
-
- if (FieldIsBitfield(ivar_decl, child_bitfield_bit_size)) {
- if (bit_offset == INT32_MAX)
- bit_offset = interface_layout.getFieldOffset(
- child_idx - superclass_idx);
-
- child_bitfield_bit_offset = bit_offset % 8;
- }
- return GetType(ivar_qual_type);
- }
- ++child_idx;
- }
- }
- }
- }
- }
- break;
-
- case clang::Type::ObjCObjectPointer:
- if (idx_is_valid) {
- CompilerType pointee_clang_type(GetPointeeType(type));
-
- if (transparent_pointers && pointee_clang_type.IsAggregateType()) {
- child_is_deref_of_parent = false;
- bool tmp_child_is_deref_of_parent = false;
- return pointee_clang_type.GetChildCompilerTypeAtIndex(
- exe_ctx, idx, transparent_pointers, omit_empty_base_classes,
- ignore_array_bounds, child_name, child_byte_size, child_byte_offset,
- child_bitfield_bit_size, child_bitfield_bit_offset,
- child_is_base_class, tmp_child_is_deref_of_parent, valobj,
- language_flags);
- } else {
- child_is_deref_of_parent = true;
- const char *parent_name =
- valobj ? valobj->GetName().GetCString() : nullptr;
- if (parent_name) {
- child_name.assign(1, '*');
- child_name += parent_name;
- }
-
- // We have a pointer to an simple type
- if (idx == 0 && pointee_clang_type.GetCompleteType()) {
- if (Optional<uint64_t> size =
- pointee_clang_type.GetByteSize(get_exe_scope())) {
- child_byte_size = *size;
- child_byte_offset = 0;
- return pointee_clang_type;
- }
- }
- }
- }
- break;
-
- case clang::Type::Vector:
- case clang::Type::ExtVector:
- if (idx_is_valid) {
- const clang::VectorType *array =
- llvm::cast<clang::VectorType>(parent_qual_type.getTypePtr());
- if (array) {
- CompilerType element_type = GetType(array->getElementType());
- if (element_type.GetCompleteType()) {
- char element_name[64];
- ::snprintf(element_name, sizeof(element_name), "[%" PRIu64 "]",
- static_cast<uint64_t>(idx));
- child_name.assign(element_name);
- if (Optional<uint64_t> size =
- element_type.GetByteSize(get_exe_scope())) {
- child_byte_size = *size;
- child_byte_offset = (int32_t)idx * (int32_t)child_byte_size;
- return element_type;
- }
- }
- }
- }
- break;
-
- case clang::Type::ConstantArray:
- case clang::Type::IncompleteArray:
- if (ignore_array_bounds || idx_is_valid) {
- const clang::ArrayType *array = GetQualType(type)->getAsArrayTypeUnsafe();
- if (array) {
- CompilerType element_type = GetType(array->getElementType());
- if (element_type.GetCompleteType()) {
- child_name = std::string(llvm::formatv("[{0}]", idx));
- if (Optional<uint64_t> size =
- element_type.GetByteSize(get_exe_scope())) {
- child_byte_size = *size;
- child_byte_offset = (int32_t)idx * (int32_t)child_byte_size;
- return element_type;
- }
- }
- }
- }
- break;
-
- case clang::Type::Pointer: {
- CompilerType pointee_clang_type(GetPointeeType(type));
-
- // Don't dereference "void *" pointers
- if (pointee_clang_type.IsVoidType())
- return CompilerType();
-
- if (transparent_pointers && pointee_clang_type.IsAggregateType()) {
- child_is_deref_of_parent = false;
- bool tmp_child_is_deref_of_parent = false;
- return pointee_clang_type.GetChildCompilerTypeAtIndex(
- exe_ctx, idx, transparent_pointers, omit_empty_base_classes,
- ignore_array_bounds, child_name, child_byte_size, child_byte_offset,
- child_bitfield_bit_size, child_bitfield_bit_offset,
- child_is_base_class, tmp_child_is_deref_of_parent, valobj,
- language_flags);
- } else {
- child_is_deref_of_parent = true;
-
- const char *parent_name =
- valobj ? valobj->GetName().GetCString() : nullptr;
- if (parent_name) {
- child_name.assign(1, '*');
- child_name += parent_name;
- }
-
- // We have a pointer to an simple type
- if (idx == 0) {
- if (Optional<uint64_t> size =
- pointee_clang_type.GetByteSize(get_exe_scope())) {
- child_byte_size = *size;
- child_byte_offset = 0;
- return pointee_clang_type;
- }
- }
- }
- break;
- }
-
- case clang::Type::LValueReference:
- case clang::Type::RValueReference:
- if (idx_is_valid) {
- const clang::ReferenceType *reference_type =
- llvm::cast<clang::ReferenceType>(parent_qual_type.getTypePtr());
- CompilerType pointee_clang_type =
- GetType(reference_type->getPointeeType());
- if (transparent_pointers && pointee_clang_type.IsAggregateType()) {
- child_is_deref_of_parent = false;
- bool tmp_child_is_deref_of_parent = false;
- return pointee_clang_type.GetChildCompilerTypeAtIndex(
- exe_ctx, idx, transparent_pointers, omit_empty_base_classes,
- ignore_array_bounds, child_name, child_byte_size, child_byte_offset,
- child_bitfield_bit_size, child_bitfield_bit_offset,
- child_is_base_class, tmp_child_is_deref_of_parent, valobj,
- language_flags);
- } else {
- const char *parent_name =
- valobj ? valobj->GetName().GetCString() : nullptr;
- if (parent_name) {
- child_name.assign(1, '&');
- child_name += parent_name;
- }
-
- // We have a pointer to an simple type
- if (idx == 0) {
- if (Optional<uint64_t> size =
- pointee_clang_type.GetByteSize(get_exe_scope())) {
- child_byte_size = *size;
- child_byte_offset = 0;
- return pointee_clang_type;
- }
- }
- }
- }
- break;
-
- default:
- break;
- }
- return CompilerType();
-}
-
-static uint32_t GetIndexForRecordBase(const clang::RecordDecl *record_decl,
- const clang::CXXBaseSpecifier *base_spec,
- bool omit_empty_base_classes) {
- uint32_t child_idx = 0;
-
- const clang::CXXRecordDecl *cxx_record_decl =
- llvm::dyn_cast<clang::CXXRecordDecl>(record_decl);
-
- // const char *super_name = record_decl->getNameAsCString();
- // const char *base_name =
- // base_spec->getType()->getAs<clang::RecordType>()->getDecl()->getNameAsCString();
- // printf ("GetIndexForRecordChild (%s, %s)\n", super_name, base_name);
- //
- if (cxx_record_decl) {
- clang::CXXRecordDecl::base_class_const_iterator base_class, base_class_end;
- for (base_class = cxx_record_decl->bases_begin(),
- base_class_end = cxx_record_decl->bases_end();
- base_class != base_class_end; ++base_class) {
- if (omit_empty_base_classes) {
- if (BaseSpecifierIsEmpty(base_class))
- continue;
- }
-
- // printf ("GetIndexForRecordChild (%s, %s) base[%u] = %s\n",
- // super_name, base_name,
- // child_idx,
- // base_class->getType()->getAs<clang::RecordType>()->getDecl()->getNameAsCString());
- //
- //
- if (base_class == base_spec)
- return child_idx;
- ++child_idx;
- }
- }
-
- return UINT32_MAX;
-}
-
-static uint32_t GetIndexForRecordChild(const clang::RecordDecl *record_decl,
- clang::NamedDecl *canonical_decl,
- bool omit_empty_base_classes) {
- uint32_t child_idx = TypeSystemClang::GetNumBaseClasses(
- llvm::dyn_cast<clang::CXXRecordDecl>(record_decl),
- omit_empty_base_classes);
-
- clang::RecordDecl::field_iterator field, field_end;
- for (field = record_decl->field_begin(), field_end = record_decl->field_end();
- field != field_end; ++field, ++child_idx) {
- if (field->getCanonicalDecl() == canonical_decl)
- return child_idx;
- }
-
- return UINT32_MAX;
-}
-
-// Look for a child member (doesn't include base classes, but it does include
-// their members) in the type hierarchy. Returns an index path into
-// "clang_type" on how to reach the appropriate member.
-//
-// class A
-// {
-// public:
-// int m_a;
-// int m_b;
-// };
-//
-// class B
-// {
-// };
-//
-// class C :
-// public B,
-// public A
-// {
-// };
-//
-// If we have a clang type that describes "class C", and we wanted to looked
-// "m_b" in it:
-//
-// With omit_empty_base_classes == false we would get an integer array back
-// with: { 1, 1 } The first index 1 is the child index for "class A" within
-// class C The second index 1 is the child index for "m_b" within class A
-//
-// With omit_empty_base_classes == true we would get an integer array back
-// with: { 0, 1 } The first index 0 is the child index for "class A" within
-// class C (since class B doesn't have any members it doesn't count) The second
-// index 1 is the child index for "m_b" within class A
-
-size_t TypeSystemClang::GetIndexOfChildMemberWithName(
- lldb::opaque_compiler_type_t type, const char *name,
- bool omit_empty_base_classes, std::vector<uint32_t> &child_indexes) {
- if (type && name && name[0]) {
- clang::QualType qual_type = RemoveWrappingTypes(GetCanonicalQualType(type));
- const clang::Type::TypeClass type_class = qual_type->getTypeClass();
- switch (type_class) {
- case clang::Type::Record:
- if (GetCompleteType(type)) {
- const clang::RecordType *record_type =
- llvm::cast<clang::RecordType>(qual_type.getTypePtr());
- const clang::RecordDecl *record_decl = record_type->getDecl();
-
- assert(record_decl);
- uint32_t child_idx = 0;
-
- const clang::CXXRecordDecl *cxx_record_decl =
- llvm::dyn_cast<clang::CXXRecordDecl>(record_decl);
-
- // Try and find a field that matches NAME
- clang::RecordDecl::field_iterator field, field_end;
- llvm::StringRef name_sref(name);
- for (field = record_decl->field_begin(),
- field_end = record_decl->field_end();
- field != field_end; ++field, ++child_idx) {
- llvm::StringRef field_name = field->getName();
- if (field_name.empty()) {
- CompilerType field_type = GetType(field->getType());
- child_indexes.push_back(child_idx);
- if (field_type.GetIndexOfChildMemberWithName(
- name, omit_empty_base_classes, child_indexes))
- return child_indexes.size();
- child_indexes.pop_back();
-
- } else if (field_name.equals(name_sref)) {
- // We have to add on the number of base classes to this index!
- child_indexes.push_back(
- child_idx + TypeSystemClang::GetNumBaseClasses(
- cxx_record_decl, omit_empty_base_classes));
- return child_indexes.size();
- }
- }
-
- if (cxx_record_decl) {
- const clang::RecordDecl *parent_record_decl = cxx_record_decl;
-
- // printf ("parent = %s\n", parent_record_decl->getNameAsCString());
-
- // const Decl *root_cdecl = cxx_record_decl->getCanonicalDecl();
- // Didn't find things easily, lets let clang do its thang...
- clang::IdentifierInfo &ident_ref =
- getASTContext().Idents.get(name_sref);
- clang::DeclarationName decl_name(&ident_ref);
-
- clang::CXXBasePaths paths;
- if (cxx_record_decl->lookupInBases(
- [decl_name](const clang::CXXBaseSpecifier *specifier,
- clang::CXXBasePath &path) {
- return clang::CXXRecordDecl::FindOrdinaryMember(
- specifier, path, decl_name);
- },
- paths)) {
- clang::CXXBasePaths::const_paths_iterator path,
- path_end = paths.end();
- for (path = paths.begin(); path != path_end; ++path) {
- const size_t num_path_elements = path->size();
- for (size_t e = 0; e < num_path_elements; ++e) {
- clang::CXXBasePathElement elem = (*path)[e];
-
- child_idx = GetIndexForRecordBase(parent_record_decl, elem.Base,
- omit_empty_base_classes);
- if (child_idx == UINT32_MAX) {
- child_indexes.clear();
- return 0;
- } else {
- child_indexes.push_back(child_idx);
- parent_record_decl = llvm::cast<clang::RecordDecl>(
- elem.Base->getType()
- ->getAs<clang::RecordType>()
- ->getDecl());
- }
- }
- for (clang::NamedDecl *path_decl : path->Decls) {
- child_idx = GetIndexForRecordChild(
- parent_record_decl, path_decl, omit_empty_base_classes);
- if (child_idx == UINT32_MAX) {
- child_indexes.clear();
- return 0;
- } else {
- child_indexes.push_back(child_idx);
- }
- }
- }
- return child_indexes.size();
- }
- }
- }
- break;
-
- case clang::Type::ObjCObject:
- case clang::Type::ObjCInterface:
- if (GetCompleteType(type)) {
- llvm::StringRef name_sref(name);
- const clang::ObjCObjectType *objc_class_type =
- llvm::dyn_cast<clang::ObjCObjectType>(qual_type.getTypePtr());
- assert(objc_class_type);
- if (objc_class_type) {
- uint32_t child_idx = 0;
- clang::ObjCInterfaceDecl *class_interface_decl =
- objc_class_type->getInterface();
-
- if (class_interface_decl) {
- clang::ObjCInterfaceDecl::ivar_iterator ivar_pos,
- ivar_end = class_interface_decl->ivar_end();
- clang::ObjCInterfaceDecl *superclass_interface_decl =
- class_interface_decl->getSuperClass();
-
- for (ivar_pos = class_interface_decl->ivar_begin();
- ivar_pos != ivar_end; ++ivar_pos, ++child_idx) {
- const clang::ObjCIvarDecl *ivar_decl = *ivar_pos;
-
- if (ivar_decl->getName().equals(name_sref)) {
- if ((!omit_empty_base_classes && superclass_interface_decl) ||
- (omit_empty_base_classes &&
- ObjCDeclHasIVars(superclass_interface_decl, true)))
- ++child_idx;
-
- child_indexes.push_back(child_idx);
- return child_indexes.size();
- }
- }
-
- if (superclass_interface_decl) {
- // The super class index is always zero for ObjC classes, so we
- // push it onto the child indexes in case we find an ivar in our
- // superclass...
- child_indexes.push_back(0);
-
- CompilerType superclass_clang_type =
- GetType(getASTContext().getObjCInterfaceType(
- superclass_interface_decl));
- if (superclass_clang_type.GetIndexOfChildMemberWithName(
- name, omit_empty_base_classes, child_indexes)) {
- // We did find an ivar in a superclass so just return the
- // results!
- return child_indexes.size();
- }
-
- // We didn't find an ivar matching "name" in our superclass, pop
- // the superclass zero index that we pushed on above.
- child_indexes.pop_back();
- }
- }
- }
- }
- break;
-
- case clang::Type::ObjCObjectPointer: {
- CompilerType objc_object_clang_type = GetType(
- llvm::cast<clang::ObjCObjectPointerType>(qual_type.getTypePtr())
- ->getPointeeType());
- return objc_object_clang_type.GetIndexOfChildMemberWithName(
- name, omit_empty_base_classes, child_indexes);
- } break;
-
- case clang::Type::ConstantArray: {
- // const clang::ConstantArrayType *array =
- // llvm::cast<clang::ConstantArrayType>(parent_qual_type.getTypePtr());
- // const uint64_t element_count =
- // array->getSize().getLimitedValue();
- //
- // if (idx < element_count)
- // {
- // std::pair<uint64_t, unsigned> field_type_info =
- // ast->getTypeInfo(array->getElementType());
- //
- // char element_name[32];
- // ::snprintf (element_name, sizeof (element_name),
- // "%s[%u]", parent_name ? parent_name : "", idx);
- //
- // child_name.assign(element_name);
- // assert(field_type_info.first % 8 == 0);
- // child_byte_size = field_type_info.first / 8;
- // child_byte_offset = idx * child_byte_size;
- // return array->getElementType().getAsOpaquePtr();
- // }
- } break;
-
- // case clang::Type::MemberPointerType:
- // {
- // MemberPointerType *mem_ptr_type =
- // llvm::cast<MemberPointerType>(qual_type.getTypePtr());
- // clang::QualType pointee_type =
- // mem_ptr_type->getPointeeType();
- //
- // if (TypeSystemClang::IsAggregateType
- // (pointee_type.getAsOpaquePtr()))
- // {
- // return GetIndexOfChildWithName (ast,
- // mem_ptr_type->getPointeeType().getAsOpaquePtr(),
- // name);
- // }
- // }
- // break;
- //
- case clang::Type::LValueReference:
- case clang::Type::RValueReference: {
- const clang::ReferenceType *reference_type =
- llvm::cast<clang::ReferenceType>(qual_type.getTypePtr());
- clang::QualType pointee_type(reference_type->getPointeeType());
- CompilerType pointee_clang_type = GetType(pointee_type);
-
- if (pointee_clang_type.IsAggregateType()) {
- return pointee_clang_type.GetIndexOfChildMemberWithName(
- name, omit_empty_base_classes, child_indexes);
- }
- } break;
-
- case clang::Type::Pointer: {
- CompilerType pointee_clang_type(GetPointeeType(type));
-
- if (pointee_clang_type.IsAggregateType()) {
- return pointee_clang_type.GetIndexOfChildMemberWithName(
- name, omit_empty_base_classes, child_indexes);
- }
- } break;
-
- default:
- break;
- }
- }
- return 0;
-}
-
-// Get the index of the child of "clang_type" whose name matches. This function
-// doesn't descend into the children, but only looks one level deep and name
-// matches can include base class names.
-
-uint32_t
-TypeSystemClang::GetIndexOfChildWithName(lldb::opaque_compiler_type_t type,
- const char *name,
- bool omit_empty_base_classes) {
- if (type && name && name[0]) {
- clang::QualType qual_type = RemoveWrappingTypes(GetCanonicalQualType(type));
-
- const clang::Type::TypeClass type_class = qual_type->getTypeClass();
-
- switch (type_class) {
- case clang::Type::Record:
- if (GetCompleteType(type)) {
- const clang::RecordType *record_type =
- llvm::cast<clang::RecordType>(qual_type.getTypePtr());
- const clang::RecordDecl *record_decl = record_type->getDecl();
-
- assert(record_decl);
- uint32_t child_idx = 0;
-
- const clang::CXXRecordDecl *cxx_record_decl =
- llvm::dyn_cast<clang::CXXRecordDecl>(record_decl);
-
- if (cxx_record_decl) {
- clang::CXXRecordDecl::base_class_const_iterator base_class,
- base_class_end;
- for (base_class = cxx_record_decl->bases_begin(),
- base_class_end = cxx_record_decl->bases_end();
- base_class != base_class_end; ++base_class) {
- // Skip empty base classes
- clang::CXXRecordDecl *base_class_decl =
- llvm::cast<clang::CXXRecordDecl>(
- base_class->getType()
- ->getAs<clang::RecordType>()
- ->getDecl());
- if (omit_empty_base_classes &&
- !TypeSystemClang::RecordHasFields(base_class_decl))
- continue;
-
- CompilerType base_class_clang_type = GetType(base_class->getType());
- std::string base_class_type_name(
- base_class_clang_type.GetTypeName().AsCString(""));
- if (base_class_type_name == name)
- return child_idx;
- ++child_idx;
- }
- }
-
- // Try and find a field that matches NAME
- clang::RecordDecl::field_iterator field, field_end;
- llvm::StringRef name_sref(name);
- for (field = record_decl->field_begin(),
- field_end = record_decl->field_end();
- field != field_end; ++field, ++child_idx) {
- if (field->getName().equals(name_sref))
- return child_idx;
- }
- }
- break;
-
- case clang::Type::ObjCObject:
- case clang::Type::ObjCInterface:
- if (GetCompleteType(type)) {
- llvm::StringRef name_sref(name);
- const clang::ObjCObjectType *objc_class_type =
- llvm::dyn_cast<clang::ObjCObjectType>(qual_type.getTypePtr());
- assert(objc_class_type);
- if (objc_class_type) {
- uint32_t child_idx = 0;
- clang::ObjCInterfaceDecl *class_interface_decl =
- objc_class_type->getInterface();
-
- if (class_interface_decl) {
- clang::ObjCInterfaceDecl::ivar_iterator ivar_pos,
- ivar_end = class_interface_decl->ivar_end();
- clang::ObjCInterfaceDecl *superclass_interface_decl =
- class_interface_decl->getSuperClass();
-
- for (ivar_pos = class_interface_decl->ivar_begin();
- ivar_pos != ivar_end; ++ivar_pos, ++child_idx) {
- const clang::ObjCIvarDecl *ivar_decl = *ivar_pos;
-
- if (ivar_decl->getName().equals(name_sref)) {
- if ((!omit_empty_base_classes && superclass_interface_decl) ||
- (omit_empty_base_classes &&
- ObjCDeclHasIVars(superclass_interface_decl, true)))
- ++child_idx;
-
- return child_idx;
- }
- }
-
- if (superclass_interface_decl) {
- if (superclass_interface_decl->getName().equals(name_sref))
- return 0;
- }
- }
- }
- }
- break;
-
- case clang::Type::ObjCObjectPointer: {
- CompilerType pointee_clang_type = GetType(
- llvm::cast<clang::ObjCObjectPointerType>(qual_type.getTypePtr())
- ->getPointeeType());
- return pointee_clang_type.GetIndexOfChildWithName(
- name, omit_empty_base_classes);
- } break;
-
- case clang::Type::ConstantArray: {
- // const clang::ConstantArrayType *array =
- // llvm::cast<clang::ConstantArrayType>(parent_qual_type.getTypePtr());
- // const uint64_t element_count =
- // array->getSize().getLimitedValue();
- //
- // if (idx < element_count)
- // {
- // std::pair<uint64_t, unsigned> field_type_info =
- // ast->getTypeInfo(array->getElementType());
- //
- // char element_name[32];
- // ::snprintf (element_name, sizeof (element_name),
- // "%s[%u]", parent_name ? parent_name : "", idx);
- //
- // child_name.assign(element_name);
- // assert(field_type_info.first % 8 == 0);
- // child_byte_size = field_type_info.first / 8;
- // child_byte_offset = idx * child_byte_size;
- // return array->getElementType().getAsOpaquePtr();
- // }
- } break;
-
- // case clang::Type::MemberPointerType:
- // {
- // MemberPointerType *mem_ptr_type =
- // llvm::cast<MemberPointerType>(qual_type.getTypePtr());
- // clang::QualType pointee_type =
- // mem_ptr_type->getPointeeType();
- //
- // if (TypeSystemClang::IsAggregateType
- // (pointee_type.getAsOpaquePtr()))
- // {
- // return GetIndexOfChildWithName (ast,
- // mem_ptr_type->getPointeeType().getAsOpaquePtr(),
- // name);
- // }
- // }
- // break;
- //
- case clang::Type::LValueReference:
- case clang::Type::RValueReference: {
- const clang::ReferenceType *reference_type =
- llvm::cast<clang::ReferenceType>(qual_type.getTypePtr());
- CompilerType pointee_type = GetType(reference_type->getPointeeType());
-
- if (pointee_type.IsAggregateType()) {
- return pointee_type.GetIndexOfChildWithName(name,
- omit_empty_base_classes);
- }
- } break;
-
- case clang::Type::Pointer: {
- const clang::PointerType *pointer_type =
- llvm::cast<clang::PointerType>(qual_type.getTypePtr());
- CompilerType pointee_type = GetType(pointer_type->getPointeeType());
-
- if (pointee_type.IsAggregateType()) {
- return pointee_type.GetIndexOfChildWithName(name,
- omit_empty_base_classes);
- } else {
- // if (parent_name)
- // {
- // child_name.assign(1, '*');
- // child_name += parent_name;
- // }
- //
- // // We have a pointer to an simple type
- // if (idx == 0)
- // {
- // std::pair<uint64_t, unsigned> clang_type_info
- // = ast->getTypeInfo(pointee_type);
- // assert(clang_type_info.first % 8 == 0);
- // child_byte_size = clang_type_info.first / 8;
- // child_byte_offset = 0;
- // return pointee_type.getAsOpaquePtr();
- // }
- }
- } break;
-
- default:
- break;
- }
- }
- return UINT32_MAX;
-}
-
-size_t
-TypeSystemClang::GetNumTemplateArguments(lldb::opaque_compiler_type_t type) {
- if (!type)
- return 0;
-
- clang::QualType qual_type = RemoveWrappingTypes(GetCanonicalQualType(type));
- const clang::Type::TypeClass type_class = qual_type->getTypeClass();
- switch (type_class) {
- case clang::Type::Record:
- if (GetCompleteType(type)) {
- const clang::CXXRecordDecl *cxx_record_decl =
- qual_type->getAsCXXRecordDecl();
- if (cxx_record_decl) {
- const clang::ClassTemplateSpecializationDecl *template_decl =
- llvm::dyn_cast<clang::ClassTemplateSpecializationDecl>(
- cxx_record_decl);
- if (template_decl)
- return template_decl->getTemplateArgs().size();
- }
- }
- break;
-
- default:
- break;
- }
-
- return 0;
-}
-
-const clang::ClassTemplateSpecializationDecl *
-TypeSystemClang::GetAsTemplateSpecialization(
- lldb::opaque_compiler_type_t type) {
- if (!type)
- return nullptr;
-
- clang::QualType qual_type(RemoveWrappingTypes(GetCanonicalQualType(type)));
- const clang::Type::TypeClass type_class = qual_type->getTypeClass();
- switch (type_class) {
- case clang::Type::Record: {
- if (! GetCompleteType(type))
- return nullptr;
- const clang::CXXRecordDecl *cxx_record_decl =
- qual_type->getAsCXXRecordDecl();
- if (!cxx_record_decl)
- return nullptr;
- return llvm::dyn_cast<clang::ClassTemplateSpecializationDecl>(
- cxx_record_decl);
- }
-
- default:
- return nullptr;
- }
-}
-
-lldb::TemplateArgumentKind
-TypeSystemClang::GetTemplateArgumentKind(lldb::opaque_compiler_type_t type,
- size_t arg_idx) {
- const clang::ClassTemplateSpecializationDecl *template_decl =
- GetAsTemplateSpecialization(type);
- if (! template_decl || arg_idx >= template_decl->getTemplateArgs().size())
- return eTemplateArgumentKindNull;
-
- switch (template_decl->getTemplateArgs()[arg_idx].getKind()) {
- case clang::TemplateArgument::Null:
- return eTemplateArgumentKindNull;
-
- case clang::TemplateArgument::NullPtr:
- return eTemplateArgumentKindNullPtr;
-
- case clang::TemplateArgument::Type:
- return eTemplateArgumentKindType;
-
- case clang::TemplateArgument::Declaration:
- return eTemplateArgumentKindDeclaration;
-
- case clang::TemplateArgument::Integral:
- return eTemplateArgumentKindIntegral;
-
- case clang::TemplateArgument::Template:
- return eTemplateArgumentKindTemplate;
-
- case clang::TemplateArgument::TemplateExpansion:
- return eTemplateArgumentKindTemplateExpansion;
-
- case clang::TemplateArgument::Expression:
- return eTemplateArgumentKindExpression;
-
- case clang::TemplateArgument::Pack:
- return eTemplateArgumentKindPack;
- }
- llvm_unreachable("Unhandled clang::TemplateArgument::ArgKind");
-}
-
-CompilerType
-TypeSystemClang::GetTypeTemplateArgument(lldb::opaque_compiler_type_t type,
- size_t idx) {
- const clang::ClassTemplateSpecializationDecl *template_decl =
- GetAsTemplateSpecialization(type);
- if (!template_decl || idx >= template_decl->getTemplateArgs().size())
- return CompilerType();
-
- const clang::TemplateArgument &template_arg =
- template_decl->getTemplateArgs()[idx];
- if (template_arg.getKind() != clang::TemplateArgument::Type)
- return CompilerType();
-
- return GetType(template_arg.getAsType());
-}
-
-Optional<CompilerType::IntegralTemplateArgument>
-TypeSystemClang::GetIntegralTemplateArgument(lldb::opaque_compiler_type_t type,
- size_t idx) {
- const clang::ClassTemplateSpecializationDecl *template_decl =
- GetAsTemplateSpecialization(type);
- if (! template_decl || idx >= template_decl->getTemplateArgs().size())
- return llvm::None;
-
- const clang::TemplateArgument &template_arg =
- template_decl->getTemplateArgs()[idx];
- if (template_arg.getKind() != clang::TemplateArgument::Integral)
- return llvm::None;
-
- return {
- {template_arg.getAsIntegral(), GetType(template_arg.getIntegralType())}};
-}
-
-CompilerType TypeSystemClang::GetTypeForFormatters(void *type) {
- if (type)
- return ClangUtil::RemoveFastQualifiers(CompilerType(this, type));
- return CompilerType();
-}
-
-clang::EnumDecl *TypeSystemClang::GetAsEnumDecl(const CompilerType &type) {
- const clang::EnumType *enutype =
- llvm::dyn_cast<clang::EnumType>(ClangUtil::GetCanonicalQualType(type));
- if (enutype)
- return enutype->getDecl();
- return nullptr;
-}
-
-clang::RecordDecl *TypeSystemClang::GetAsRecordDecl(const CompilerType &type) {
- const clang::RecordType *record_type =
- llvm::dyn_cast<clang::RecordType>(ClangUtil::GetCanonicalQualType(type));
- if (record_type)
- return record_type->getDecl();
- return nullptr;
-}
-
-clang::TagDecl *TypeSystemClang::GetAsTagDecl(const CompilerType &type) {
- return ClangUtil::GetAsTagDecl(type);
-}
-
-clang::TypedefNameDecl *
-TypeSystemClang::GetAsTypedefDecl(const CompilerType &type) {
- const clang::TypedefType *typedef_type =
- llvm::dyn_cast<clang::TypedefType>(ClangUtil::GetQualType(type));
- if (typedef_type)
- return typedef_type->getDecl();
- return nullptr;
-}
-
-clang::CXXRecordDecl *
-TypeSystemClang::GetAsCXXRecordDecl(lldb::opaque_compiler_type_t type) {
- return GetCanonicalQualType(type)->getAsCXXRecordDecl();
-}
-
-clang::ObjCInterfaceDecl *
-TypeSystemClang::GetAsObjCInterfaceDecl(const CompilerType &type) {
- const clang::ObjCObjectType *objc_class_type =
- llvm::dyn_cast<clang::ObjCObjectType>(
- ClangUtil::GetCanonicalQualType(type));
- if (objc_class_type)
- return objc_class_type->getInterface();
- return nullptr;
-}
-
-clang::FieldDecl *TypeSystemClang::AddFieldToRecordType(
- const CompilerType &type, llvm::StringRef name,
- const CompilerType &field_clang_type, AccessType access,
- uint32_t bitfield_bit_size) {
- if (!type.IsValid() || !field_clang_type.IsValid())
- return nullptr;
- TypeSystemClang *ast =
- llvm::dyn_cast_or_null<TypeSystemClang>(type.GetTypeSystem());
- if (!ast)
- return nullptr;
- clang::ASTContext &clang_ast = ast->getASTContext();
- clang::IdentifierInfo *ident = nullptr;
- if (!name.empty())
- ident = &clang_ast.Idents.get(name);
-
- clang::FieldDecl *field = nullptr;
-
- clang::Expr *bit_width = nullptr;
- if (bitfield_bit_size != 0) {
- llvm::APInt bitfield_bit_size_apint(clang_ast.getTypeSize(clang_ast.IntTy),
- bitfield_bit_size);
- bit_width = new (clang_ast)
- clang::IntegerLiteral(clang_ast, bitfield_bit_size_apint,
- clang_ast.IntTy, clang::SourceLocation());
- }
-
- clang::RecordDecl *record_decl = ast->GetAsRecordDecl(type);
- if (record_decl) {
- field = clang::FieldDecl::Create(
- clang_ast, record_decl, clang::SourceLocation(),
- clang::SourceLocation(),
- ident, // Identifier
- ClangUtil::GetQualType(field_clang_type), // Field type
- nullptr, // TInfo *
- bit_width, // BitWidth
- false, // Mutable
- clang::ICIS_NoInit); // HasInit
-
- if (name.empty()) {
- // Determine whether this field corresponds to an anonymous struct or
- // union.
- if (const clang::TagType *TagT =
- field->getType()->getAs<clang::TagType>()) {
- if (clang::RecordDecl *Rec =
- llvm::dyn_cast<clang::RecordDecl>(TagT->getDecl()))
- if (!Rec->getDeclName()) {
- Rec->setAnonymousStructOrUnion(true);
- field->setImplicit();
- }
- }
- }
-
- if (field) {
- field->setAccess(
- TypeSystemClang::ConvertAccessTypeToAccessSpecifier(access));
-
- record_decl->addDecl(field);
-
-#ifdef LLDB_CONFIGURATION_DEBUG
- VerifyDecl(field);
-#endif
- }
- } else {
- clang::ObjCInterfaceDecl *class_interface_decl =
- ast->GetAsObjCInterfaceDecl(type);
-
- if (class_interface_decl) {
- const bool is_synthesized = false;
-
- field_clang_type.GetCompleteType();
-
- field = clang::ObjCIvarDecl::Create(
- clang_ast, class_interface_decl, clang::SourceLocation(),
- clang::SourceLocation(),
- ident, // Identifier
- ClangUtil::GetQualType(field_clang_type), // Field type
- nullptr, // TypeSourceInfo *
- ConvertAccessTypeToObjCIvarAccessControl(access), bit_width,
- is_synthesized);
-
- if (field) {
- class_interface_decl->addDecl(field);
-
-#ifdef LLDB_CONFIGURATION_DEBUG
- VerifyDecl(field);
-#endif
- }
- }
- }
- return field;
-}
-
-void TypeSystemClang::BuildIndirectFields(const CompilerType &type) {
- if (!type)
- return;
-
- TypeSystemClang *ast = llvm::dyn_cast<TypeSystemClang>(type.GetTypeSystem());
- if (!ast)
- return;
-
- clang::RecordDecl *record_decl = ast->GetAsRecordDecl(type);
-
- if (!record_decl)
- return;
-
- typedef llvm::SmallVector<clang::IndirectFieldDecl *, 1> IndirectFieldVector;
-
- IndirectFieldVector indirect_fields;
- clang::RecordDecl::field_iterator field_pos;
- clang::RecordDecl::field_iterator field_end_pos = record_decl->field_end();
- clang::RecordDecl::field_iterator last_field_pos = field_end_pos;
- for (field_pos = record_decl->field_begin(); field_pos != field_end_pos;
- last_field_pos = field_pos++) {
- if (field_pos->isAnonymousStructOrUnion()) {
- clang::QualType field_qual_type = field_pos->getType();
-
- const clang::RecordType *field_record_type =
- field_qual_type->getAs<clang::RecordType>();
-
- if (!field_record_type)
- continue;
-
- clang::RecordDecl *field_record_decl = field_record_type->getDecl();
-
- if (!field_record_decl)
- continue;
-
- for (clang::RecordDecl::decl_iterator
- di = field_record_decl->decls_begin(),
- de = field_record_decl->decls_end();
- di != de; ++di) {
- if (clang::FieldDecl *nested_field_decl =
- llvm::dyn_cast<clang::FieldDecl>(*di)) {
- clang::NamedDecl **chain =
- new (ast->getASTContext()) clang::NamedDecl *[2];
- chain[0] = *field_pos;
- chain[1] = nested_field_decl;
- clang::IndirectFieldDecl *indirect_field =
- clang::IndirectFieldDecl::Create(
- ast->getASTContext(), record_decl, clang::SourceLocation(),
- nested_field_decl->getIdentifier(),
- nested_field_decl->getType(), {chain, 2});
-
- indirect_field->setImplicit();
-
- indirect_field->setAccess(TypeSystemClang::UnifyAccessSpecifiers(
- field_pos->getAccess(), nested_field_decl->getAccess()));
-
- indirect_fields.push_back(indirect_field);
- } else if (clang::IndirectFieldDecl *nested_indirect_field_decl =
- llvm::dyn_cast<clang::IndirectFieldDecl>(*di)) {
- size_t nested_chain_size =
- nested_indirect_field_decl->getChainingSize();
- clang::NamedDecl **chain = new (ast->getASTContext())
- clang::NamedDecl *[nested_chain_size + 1];
- chain[0] = *field_pos;
-
- int chain_index = 1;
- for (clang::IndirectFieldDecl::chain_iterator
- nci = nested_indirect_field_decl->chain_begin(),
- nce = nested_indirect_field_decl->chain_end();
- nci < nce; ++nci) {
- chain[chain_index] = *nci;
- chain_index++;
- }
-
- clang::IndirectFieldDecl *indirect_field =
- clang::IndirectFieldDecl::Create(
- ast->getASTContext(), record_decl, clang::SourceLocation(),
- nested_indirect_field_decl->getIdentifier(),
- nested_indirect_field_decl->getType(),
- {chain, nested_chain_size + 1});
-
- indirect_field->setImplicit();
-
- indirect_field->setAccess(TypeSystemClang::UnifyAccessSpecifiers(
- field_pos->getAccess(), nested_indirect_field_decl->getAccess()));
-
- indirect_fields.push_back(indirect_field);
- }
- }
- }
- }
-
- // Check the last field to see if it has an incomplete array type as its last
- // member and if it does, the tell the record decl about it
- if (last_field_pos != field_end_pos) {
- if (last_field_pos->getType()->isIncompleteArrayType())
- record_decl->hasFlexibleArrayMember();
- }
-
- for (IndirectFieldVector::iterator ifi = indirect_fields.begin(),
- ife = indirect_fields.end();
- ifi < ife; ++ifi) {
- record_decl->addDecl(*ifi);
- }
-}
-
-void TypeSystemClang::SetIsPacked(const CompilerType &type) {
- if (type) {
- TypeSystemClang *ast =
- llvm::dyn_cast<TypeSystemClang>(type.GetTypeSystem());
- if (ast) {
- clang::RecordDecl *record_decl = GetAsRecordDecl(type);
-
- if (!record_decl)
- return;
-
- record_decl->addAttr(
- clang::PackedAttr::CreateImplicit(ast->getASTContext()));
- }
- }
-}
-
-clang::VarDecl *TypeSystemClang::AddVariableToRecordType(
- const CompilerType &type, llvm::StringRef name,
- const CompilerType &var_type, AccessType access) {
- if (!type.IsValid() || !var_type.IsValid())
- return nullptr;
-
- TypeSystemClang *ast = llvm::dyn_cast<TypeSystemClang>(type.GetTypeSystem());
- if (!ast)
- return nullptr;
-
- clang::RecordDecl *record_decl = ast->GetAsRecordDecl(type);
- if (!record_decl)
- return nullptr;
-
- clang::VarDecl *var_decl = nullptr;
- clang::IdentifierInfo *ident = nullptr;
- if (!name.empty())
- ident = &ast->getASTContext().Idents.get(name);
-
- var_decl = clang::VarDecl::Create(
- ast->getASTContext(), // ASTContext &
- record_decl, // DeclContext *
- clang::SourceLocation(), // clang::SourceLocation StartLoc
- clang::SourceLocation(), // clang::SourceLocation IdLoc
- ident, // clang::IdentifierInfo *
- ClangUtil::GetQualType(var_type), // Variable clang::QualType
- nullptr, // TypeSourceInfo *
- clang::SC_Static); // StorageClass
- if (!var_decl)
- return nullptr;
-
- var_decl->setAccess(
- TypeSystemClang::ConvertAccessTypeToAccessSpecifier(access));
- record_decl->addDecl(var_decl);
-
-#ifdef LLDB_CONFIGURATION_DEBUG
- VerifyDecl(var_decl);
-#endif
-
- return var_decl;
-}
-
-clang::CXXMethodDecl *TypeSystemClang::AddMethodToCXXRecordType(
- lldb::opaque_compiler_type_t type, llvm::StringRef name,
- const char *mangled_name, const CompilerType &method_clang_type,
- lldb::AccessType access, bool is_virtual, bool is_static, bool is_inline,
- bool is_explicit, bool is_attr_used, bool is_artificial) {
- if (!type || !method_clang_type.IsValid() || name.empty())
- return nullptr;
-
- clang::QualType record_qual_type(GetCanonicalQualType(type));
-
- clang::CXXRecordDecl *cxx_record_decl =
- record_qual_type->getAsCXXRecordDecl();
-
- if (cxx_record_decl == nullptr)
- return nullptr;
-
- clang::QualType method_qual_type(ClangUtil::GetQualType(method_clang_type));
-
- clang::CXXMethodDecl *cxx_method_decl = nullptr;
-
- clang::DeclarationName decl_name(&getASTContext().Idents.get(name));
-
- const clang::FunctionType *function_type =
- llvm::dyn_cast<clang::FunctionType>(method_qual_type.getTypePtr());
-
- if (function_type == nullptr)
- return nullptr;
-
- const clang::FunctionProtoType *method_function_prototype(
- llvm::dyn_cast<clang::FunctionProtoType>(function_type));
-
- if (!method_function_prototype)
- return nullptr;
-
- unsigned int num_params = method_function_prototype->getNumParams();
-
- clang::CXXDestructorDecl *cxx_dtor_decl(nullptr);
- clang::CXXConstructorDecl *cxx_ctor_decl(nullptr);
-
- if (is_artificial)
- return nullptr; // skip everything artificial
-
- const clang::ExplicitSpecifier explicit_spec(
- nullptr /*expr*/, is_explicit
- ? clang::ExplicitSpecKind::ResolvedTrue
- : clang::ExplicitSpecKind::ResolvedFalse);
- if (name.startswith("~")) {
- cxx_dtor_decl = clang::CXXDestructorDecl::Create(
- getASTContext(), cxx_record_decl, clang::SourceLocation(),
- clang::DeclarationNameInfo(
- getASTContext().DeclarationNames.getCXXDestructorName(
- getASTContext().getCanonicalType(record_qual_type)),
- clang::SourceLocation()),
- method_qual_type, nullptr, is_inline, is_artificial,
- ConstexprSpecKind::CSK_unspecified);
- cxx_method_decl = cxx_dtor_decl;
- } else if (decl_name == cxx_record_decl->getDeclName()) {
- cxx_ctor_decl = clang::CXXConstructorDecl::Create(
- getASTContext(), cxx_record_decl, clang::SourceLocation(),
- clang::DeclarationNameInfo(
- getASTContext().DeclarationNames.getCXXConstructorName(
- getASTContext().getCanonicalType(record_qual_type)),
- clang::SourceLocation()),
- method_qual_type,
- nullptr, // TypeSourceInfo *
- explicit_spec, is_inline, is_artificial, CSK_unspecified);
- cxx_method_decl = cxx_ctor_decl;
- } else {
- clang::StorageClass SC = is_static ? clang::SC_Static : clang::SC_None;
- clang::OverloadedOperatorKind op_kind = clang::NUM_OVERLOADED_OPERATORS;
-
- if (IsOperator(name, op_kind)) {
- if (op_kind != clang::NUM_OVERLOADED_OPERATORS) {
- // Check the number of operator parameters. Sometimes we have seen bad
- // DWARF that doesn't correctly describe operators and if we try to
- // create a method and add it to the class, clang will assert and
- // crash, so we need to make sure things are acceptable.
- const bool is_method = true;
- if (!TypeSystemClang::CheckOverloadedOperatorKindParameterCount(
- is_method, op_kind, num_params))
- return nullptr;
- cxx_method_decl = clang::CXXMethodDecl::Create(
- getASTContext(), cxx_record_decl, clang::SourceLocation(),
- clang::DeclarationNameInfo(
- getASTContext().DeclarationNames.getCXXOperatorName(op_kind),
- clang::SourceLocation()),
- method_qual_type,
- nullptr, // TypeSourceInfo *
- SC, is_inline, CSK_unspecified, clang::SourceLocation());
- } else if (num_params == 0) {
- // Conversion operators don't take params...
- cxx_method_decl = clang::CXXConversionDecl::Create(
- getASTContext(), cxx_record_decl, clang::SourceLocation(),
- clang::DeclarationNameInfo(
- getASTContext().DeclarationNames.getCXXConversionFunctionName(
- getASTContext().getCanonicalType(
- function_type->getReturnType())),
- clang::SourceLocation()),
- method_qual_type,
- nullptr, // TypeSourceInfo *
- is_inline, explicit_spec, CSK_unspecified, clang::SourceLocation());
- }
- }
-
- if (cxx_method_decl == nullptr) {
- cxx_method_decl = clang::CXXMethodDecl::Create(
- getASTContext(), cxx_record_decl, clang::SourceLocation(),
- clang::DeclarationNameInfo(decl_name, clang::SourceLocation()),
- method_qual_type,
- nullptr, // TypeSourceInfo *
- SC, is_inline, CSK_unspecified, clang::SourceLocation());
- }
- }
-
- clang::AccessSpecifier access_specifier =
- TypeSystemClang::ConvertAccessTypeToAccessSpecifier(access);
-
- cxx_method_decl->setAccess(access_specifier);
- cxx_method_decl->setVirtualAsWritten(is_virtual);
-
- if (is_attr_used)
- cxx_method_decl->addAttr(clang::UsedAttr::CreateImplicit(getASTContext()));
-
- if (mangled_name != nullptr) {
- cxx_method_decl->addAttr(clang::AsmLabelAttr::CreateImplicit(
- getASTContext(), mangled_name, /*literal=*/false));
- }
-
- // Populate the method decl with parameter decls
-
- llvm::SmallVector<clang::ParmVarDecl *, 12> params;
-
- for (unsigned param_index = 0; param_index < num_params; ++param_index) {
- params.push_back(clang::ParmVarDecl::Create(
- getASTContext(), cxx_method_decl, clang::SourceLocation(),
- clang::SourceLocation(),
- nullptr, // anonymous
- method_function_prototype->getParamType(param_index), nullptr,
- clang::SC_None, nullptr));
- }
-
- cxx_method_decl->setParams(llvm::ArrayRef<clang::ParmVarDecl *>(params));
-
- cxx_record_decl->addDecl(cxx_method_decl);
-
- // Sometimes the debug info will mention a constructor (default/copy/move),
- // destructor, or assignment operator (copy/move) but there won't be any
- // version of this in the code. So we check if the function was artificially
- // generated and if it is trivial and this lets the compiler/backend know
- // that it can inline the IR for these when it needs to and we can avoid a
- // "missing function" error when running expressions.
-
- if (is_artificial) {
- if (cxx_ctor_decl && ((cxx_ctor_decl->isDefaultConstructor() &&
- cxx_record_decl->hasTrivialDefaultConstructor()) ||
- (cxx_ctor_decl->isCopyConstructor() &&
- cxx_record_decl->hasTrivialCopyConstructor()) ||
- (cxx_ctor_decl->isMoveConstructor() &&
- cxx_record_decl->hasTrivialMoveConstructor()))) {
- cxx_ctor_decl->setDefaulted();
- cxx_ctor_decl->setTrivial(true);
- } else if (cxx_dtor_decl) {
- if (cxx_record_decl->hasTrivialDestructor()) {
- cxx_dtor_decl->setDefaulted();
- cxx_dtor_decl->setTrivial(true);
- }
- } else if ((cxx_method_decl->isCopyAssignmentOperator() &&
- cxx_record_decl->hasTrivialCopyAssignment()) ||
- (cxx_method_decl->isMoveAssignmentOperator() &&
- cxx_record_decl->hasTrivialMoveAssignment())) {
- cxx_method_decl->setDefaulted();
- cxx_method_decl->setTrivial(true);
- }
- }
-
-#ifdef LLDB_CONFIGURATION_DEBUG
- VerifyDecl(cxx_method_decl);
-#endif
-
- return cxx_method_decl;
-}
-
-void TypeSystemClang::AddMethodOverridesForCXXRecordType(
- lldb::opaque_compiler_type_t type) {
- if (auto *record = GetAsCXXRecordDecl(type))
- for (auto *method : record->methods())
- addOverridesForMethod(method);
-}
-
-#pragma mark C++ Base Classes
-
-std::unique_ptr<clang::CXXBaseSpecifier>
-TypeSystemClang::CreateBaseClassSpecifier(lldb::opaque_compiler_type_t type,
- AccessType access, bool is_virtual,
- bool base_of_class) {
- if (!type)
- return nullptr;
-
- return std::make_unique<clang::CXXBaseSpecifier>(
- clang::SourceRange(), is_virtual, base_of_class,
- TypeSystemClang::ConvertAccessTypeToAccessSpecifier(access),
- getASTContext().getTrivialTypeSourceInfo(GetQualType(type)),
- clang::SourceLocation());
-}
-
-bool TypeSystemClang::TransferBaseClasses(
- lldb::opaque_compiler_type_t type,
- std::vector<std::unique_ptr<clang::CXXBaseSpecifier>> bases) {
- if (!type)
- return false;
- clang::CXXRecordDecl *cxx_record_decl = GetAsCXXRecordDecl(type);
- if (!cxx_record_decl)
- return false;
- std::vector<clang::CXXBaseSpecifier *> raw_bases;
- raw_bases.reserve(bases.size());
-
- // Clang will make a copy of them, so it's ok that we pass pointers that we're
- // about to destroy.
- for (auto &b : bases)
- raw_bases.push_back(b.get());
- cxx_record_decl->setBases(raw_bases.data(), raw_bases.size());
- return true;
-}
-
-bool TypeSystemClang::SetObjCSuperClass(
- const CompilerType &type, const CompilerType &superclass_clang_type) {
- TypeSystemClang *ast =
- llvm::dyn_cast_or_null<TypeSystemClang>(type.GetTypeSystem());
- if (!ast)
- return false;
- clang::ASTContext &clang_ast = ast->getASTContext();
-
- if (type && superclass_clang_type.IsValid() &&
- superclass_clang_type.GetTypeSystem() == type.GetTypeSystem()) {
- clang::ObjCInterfaceDecl *class_interface_decl =
- GetAsObjCInterfaceDecl(type);
- clang::ObjCInterfaceDecl *super_interface_decl =
- GetAsObjCInterfaceDecl(superclass_clang_type);
- if (class_interface_decl && super_interface_decl) {
- class_interface_decl->setSuperClass(clang_ast.getTrivialTypeSourceInfo(
- clang_ast.getObjCInterfaceType(super_interface_decl)));
- return true;
- }
- }
- return false;
-}
-
-bool TypeSystemClang::AddObjCClassProperty(
- const CompilerType &type, const char *property_name,
- const CompilerType &property_clang_type, clang::ObjCIvarDecl *ivar_decl,
- const char *property_setter_name, const char *property_getter_name,
- uint32_t property_attributes, ClangASTMetadata *metadata) {
- if (!type || !property_clang_type.IsValid() || property_name == nullptr ||
- property_name[0] == '\0')
- return false;
- TypeSystemClang *ast = llvm::dyn_cast<TypeSystemClang>(type.GetTypeSystem());
- if (!ast)
- return false;
- clang::ASTContext &clang_ast = ast->getASTContext();
-
- clang::ObjCInterfaceDecl *class_interface_decl = GetAsObjCInterfaceDecl(type);
- if (!class_interface_decl)
- return false;
-
- CompilerType property_clang_type_to_access;
-
- if (property_clang_type.IsValid())
- property_clang_type_to_access = property_clang_type;
- else if (ivar_decl)
- property_clang_type_to_access = ast->GetType(ivar_decl->getType());
-
- if (!class_interface_decl || !property_clang_type_to_access.IsValid())
- return false;
-
- clang::TypeSourceInfo *prop_type_source;
- if (ivar_decl)
- prop_type_source = clang_ast.getTrivialTypeSourceInfo(ivar_decl->getType());
- else
- prop_type_source = clang_ast.getTrivialTypeSourceInfo(
- ClangUtil::GetQualType(property_clang_type));
-
- clang::ObjCPropertyDecl *property_decl = clang::ObjCPropertyDecl::Create(
- clang_ast, class_interface_decl,
- clang::SourceLocation(), // Source Location
- &clang_ast.Idents.get(property_name),
- clang::SourceLocation(), // Source Location for AT
- clang::SourceLocation(), // Source location for (
- ivar_decl ? ivar_decl->getType()
- : ClangUtil::GetQualType(property_clang_type),
- prop_type_source);
-
- if (!property_decl)
- return false;
-
- if (metadata)
- ast->SetMetadata(property_decl, *metadata);
-
- class_interface_decl->addDecl(property_decl);
-
- clang::Selector setter_sel, getter_sel;
-
- if (property_setter_name) {
- std::string property_setter_no_colon(property_setter_name,
- strlen(property_setter_name) - 1);
- clang::IdentifierInfo *setter_ident =
- &clang_ast.Idents.get(property_setter_no_colon);
- setter_sel = clang_ast.Selectors.getSelector(1, &setter_ident);
- } else if (!(property_attributes & DW_APPLE_PROPERTY_readonly)) {
- std::string setter_sel_string("set");
- setter_sel_string.push_back(::toupper(property_name[0]));
- setter_sel_string.append(&property_name[1]);
- clang::IdentifierInfo *setter_ident =
- &clang_ast.Idents.get(setter_sel_string);
- setter_sel = clang_ast.Selectors.getSelector(1, &setter_ident);
- }
- property_decl->setSetterName(setter_sel);
- property_decl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_setter);
-
- if (property_getter_name != nullptr) {
- clang::IdentifierInfo *getter_ident =
- &clang_ast.Idents.get(property_getter_name);
- getter_sel = clang_ast.Selectors.getSelector(0, &getter_ident);
- } else {
- clang::IdentifierInfo *getter_ident = &clang_ast.Idents.get(property_name);
- getter_sel = clang_ast.Selectors.getSelector(0, &getter_ident);
- }
- property_decl->setGetterName(getter_sel);
- property_decl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_getter);
-
- if (ivar_decl)
- property_decl->setPropertyIvarDecl(ivar_decl);
-
- if (property_attributes & DW_APPLE_PROPERTY_readonly)
- property_decl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_readonly);
- if (property_attributes & DW_APPLE_PROPERTY_readwrite)
- property_decl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_readwrite);
- if (property_attributes & DW_APPLE_PROPERTY_assign)
- property_decl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_assign);
- if (property_attributes & DW_APPLE_PROPERTY_retain)
- property_decl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_retain);
- if (property_attributes & DW_APPLE_PROPERTY_copy)
- property_decl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_copy);
- if (property_attributes & DW_APPLE_PROPERTY_nonatomic)
- property_decl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_nonatomic);
- if (property_attributes & ObjCPropertyDecl::OBJC_PR_nullability)
- property_decl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_nullability);
- if (property_attributes & ObjCPropertyDecl::OBJC_PR_null_resettable)
- property_decl->setPropertyAttributes(
- ObjCPropertyDecl::OBJC_PR_null_resettable);
- if (property_attributes & ObjCPropertyDecl::OBJC_PR_class)
- property_decl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_class);
-
- const bool isInstance =
- (property_attributes & ObjCPropertyDecl::OBJC_PR_class) == 0;
-
- clang::ObjCMethodDecl *getter = nullptr;
- if (!getter_sel.isNull())
- getter = isInstance ? class_interface_decl->lookupInstanceMethod(getter_sel)
- : class_interface_decl->lookupClassMethod(getter_sel);
- if (!getter_sel.isNull() && !getter) {
- const bool isVariadic = false;
- const bool isPropertyAccessor = false;
- const bool isSynthesizedAccessorStub = false;
- const bool isImplicitlyDeclared = true;
- const bool isDefined = false;
- const clang::ObjCMethodDecl::ImplementationControl impControl =
- clang::ObjCMethodDecl::None;
- const bool HasRelatedResultType = false;
-
- getter = clang::ObjCMethodDecl::Create(
- clang_ast, clang::SourceLocation(), clang::SourceLocation(), getter_sel,
- ClangUtil::GetQualType(property_clang_type_to_access), nullptr,
- class_interface_decl, isInstance, isVariadic, isPropertyAccessor,
- isSynthesizedAccessorStub, isImplicitlyDeclared, isDefined, impControl,
- HasRelatedResultType);
-
- if (getter) {
- if (metadata)
- ast->SetMetadata(getter, *metadata);
-
- getter->setMethodParams(clang_ast, llvm::ArrayRef<clang::ParmVarDecl *>(),
- llvm::ArrayRef<clang::SourceLocation>());
- class_interface_decl->addDecl(getter);
- }
- }
- if (getter) {
- getter->setPropertyAccessor(true);
- property_decl->setGetterMethodDecl(getter);
- }
-
- clang::ObjCMethodDecl *setter = nullptr;
- setter = isInstance ? class_interface_decl->lookupInstanceMethod(setter_sel)
- : class_interface_decl->lookupClassMethod(setter_sel);
- if (!setter_sel.isNull() && !setter) {
- clang::QualType result_type = clang_ast.VoidTy;
- const bool isVariadic = false;
- const bool isPropertyAccessor = true;
- const bool isSynthesizedAccessorStub = false;
- const bool isImplicitlyDeclared = true;
- const bool isDefined = false;
- const clang::ObjCMethodDecl::ImplementationControl impControl =
- clang::ObjCMethodDecl::None;
- const bool HasRelatedResultType = false;
-
- setter = clang::ObjCMethodDecl::Create(
- clang_ast, clang::SourceLocation(), clang::SourceLocation(), setter_sel,
- result_type, nullptr, class_interface_decl, isInstance, isVariadic,
- isPropertyAccessor, isSynthesizedAccessorStub, isImplicitlyDeclared,
- isDefined, impControl, HasRelatedResultType);
-
- if (setter) {
- if (metadata)
- ast->SetMetadata(setter, *metadata);
-
- llvm::SmallVector<clang::ParmVarDecl *, 1> params;
- params.push_back(clang::ParmVarDecl::Create(
- clang_ast, setter, clang::SourceLocation(), clang::SourceLocation(),
- nullptr, // anonymous
- ClangUtil::GetQualType(property_clang_type_to_access), nullptr,
- clang::SC_Auto, nullptr));
-
- setter->setMethodParams(clang_ast,
- llvm::ArrayRef<clang::ParmVarDecl *>(params),
- llvm::ArrayRef<clang::SourceLocation>());
-
- class_interface_decl->addDecl(setter);
- }
- }
- if (setter) {
- setter->setPropertyAccessor(true);
- property_decl->setSetterMethodDecl(setter);
- }
-
- return true;
-}
-
-bool TypeSystemClang::IsObjCClassTypeAndHasIVars(const CompilerType &type,
- bool check_superclass) {
- clang::ObjCInterfaceDecl *class_interface_decl = GetAsObjCInterfaceDecl(type);
- if (class_interface_decl)
- return ObjCDeclHasIVars(class_interface_decl, check_superclass);
- return false;
-}
-
-clang::ObjCMethodDecl *TypeSystemClang::AddMethodToObjCObjectType(
- const CompilerType &type,
- const char *name, // the full symbol name as seen in the symbol table
- // (lldb::opaque_compiler_type_t type, "-[NString
- // stringWithCString:]")
- const CompilerType &method_clang_type, lldb::AccessType access,
- bool is_artificial, bool is_variadic, bool is_objc_direct_call) {
- if (!type || !method_clang_type.IsValid())
- return nullptr;
-
- clang::ObjCInterfaceDecl *class_interface_decl = GetAsObjCInterfaceDecl(type);
-
- if (class_interface_decl == nullptr)
- return nullptr;
- TypeSystemClang *lldb_ast =
- llvm::dyn_cast<TypeSystemClang>(type.GetTypeSystem());
- if (lldb_ast == nullptr)
- return nullptr;
- clang::ASTContext &ast = lldb_ast->getASTContext();
-
- const char *selector_start = ::strchr(name, ' ');
- if (selector_start == nullptr)
- return nullptr;
-
- selector_start++;
- llvm::SmallVector<clang::IdentifierInfo *, 12> selector_idents;
-
- size_t len = 0;
- const char *start;
- // printf ("name = '%s'\n", name);
-
- unsigned num_selectors_with_args = 0;
- for (start = selector_start; start && *start != '\0' && *start != ']';
- start += len) {
- len = ::strcspn(start, ":]");
- bool has_arg = (start[len] == ':');
- if (has_arg)
- ++num_selectors_with_args;
- selector_idents.push_back(&ast.Idents.get(llvm::StringRef(start, len)));
- if (has_arg)
- len += 1;
- }
-
- if (selector_idents.size() == 0)
- return nullptr;
-
- clang::Selector method_selector = ast.Selectors.getSelector(
- num_selectors_with_args ? selector_idents.size() : 0,
- selector_idents.data());
-
- clang::QualType method_qual_type(ClangUtil::GetQualType(method_clang_type));
-
- // Populate the method decl with parameter decls
- const clang::Type *method_type(method_qual_type.getTypePtr());
-
- if (method_type == nullptr)
- return nullptr;
-
- const clang::FunctionProtoType *method_function_prototype(
- llvm::dyn_cast<clang::FunctionProtoType>(method_type));
-
- if (!method_function_prototype)
- return nullptr;
-
- const bool isInstance = (name[0] == '-');
- const bool isVariadic = is_variadic;
- const bool isPropertyAccessor = false;
- const bool isSynthesizedAccessorStub = false;
- /// Force this to true because we don't have source locations.
- const bool isImplicitlyDeclared = true;
- const bool isDefined = false;
- const clang::ObjCMethodDecl::ImplementationControl impControl =
- clang::ObjCMethodDecl::None;
- const bool HasRelatedResultType = false;
-
- const unsigned num_args = method_function_prototype->getNumParams();
-
- if (num_args != num_selectors_with_args)
- return nullptr; // some debug information is corrupt. We are not going to
- // deal with it.
-
- clang::ObjCMethodDecl *objc_method_decl = clang::ObjCMethodDecl::Create(
- ast,
- clang::SourceLocation(), // beginLoc,
- clang::SourceLocation(), // endLoc,
- method_selector, method_function_prototype->getReturnType(),
- nullptr, // TypeSourceInfo *ResultTInfo,
- lldb_ast->GetDeclContextForType(ClangUtil::GetQualType(type)), isInstance,
- isVariadic, isPropertyAccessor, isSynthesizedAccessorStub,
- isImplicitlyDeclared, isDefined, impControl, HasRelatedResultType);
-
- if (objc_method_decl == nullptr)
- return nullptr;
-
- if (num_args > 0) {
- llvm::SmallVector<clang::ParmVarDecl *, 12> params;
-
- for (unsigned param_index = 0; param_index < num_args; ++param_index) {
- params.push_back(clang::ParmVarDecl::Create(
- ast, objc_method_decl, clang::SourceLocation(),
- clang::SourceLocation(),
- nullptr, // anonymous
- method_function_prototype->getParamType(param_index), nullptr,
- clang::SC_Auto, nullptr));
- }
-
- objc_method_decl->setMethodParams(
- ast, llvm::ArrayRef<clang::ParmVarDecl *>(params),
- llvm::ArrayRef<clang::SourceLocation>());
- }
-
- if (is_objc_direct_call) {
- // Add a the objc_direct attribute to the declaration we generate that
- // we generate a direct method call for this ObjCMethodDecl.
- objc_method_decl->addAttr(
- clang::ObjCDirectAttr::CreateImplicit(ast, SourceLocation()));
- // Usually Sema is creating implicit parameters (e.g., self) when it
- // parses the method. We don't have a parsing Sema when we build our own
- // AST here so we manually need to create these implicit parameters to
- // make the direct call code generation happy.
- objc_method_decl->createImplicitParams(ast, class_interface_decl);
- }
-
- class_interface_decl->addDecl(objc_method_decl);
-
-#ifdef LLDB_CONFIGURATION_DEBUG
- VerifyDecl(objc_method_decl);
-#endif
-
- return objc_method_decl;
-}
-
-bool TypeSystemClang::SetHasExternalStorage(lldb::opaque_compiler_type_t type,
- bool has_extern) {
- if (!type)
- return false;
-
- clang::QualType qual_type(RemoveWrappingTypes(GetCanonicalQualType(type)));
-
- const clang::Type::TypeClass type_class = qual_type->getTypeClass();
- switch (type_class) {
- case clang::Type::Record: {
- clang::CXXRecordDecl *cxx_record_decl = qual_type->getAsCXXRecordDecl();
- if (cxx_record_decl) {
- cxx_record_decl->setHasExternalLexicalStorage(has_extern);
- cxx_record_decl->setHasExternalVisibleStorage(has_extern);
- return true;
- }
- } break;
-
- case clang::Type::Enum: {
- clang::EnumDecl *enum_decl =
- llvm::cast<clang::EnumType>(qual_type)->getDecl();
- if (enum_decl) {
- enum_decl->setHasExternalLexicalStorage(has_extern);
- enum_decl->setHasExternalVisibleStorage(has_extern);
- return true;
- }
- } break;
-
- case clang::Type::ObjCObject:
- case clang::Type::ObjCInterface: {
- const clang::ObjCObjectType *objc_class_type =
- llvm::dyn_cast<clang::ObjCObjectType>(qual_type.getTypePtr());
- assert(objc_class_type);
- if (objc_class_type) {
- clang::ObjCInterfaceDecl *class_interface_decl =
- objc_class_type->getInterface();
-
- if (class_interface_decl) {
- class_interface_decl->setHasExternalLexicalStorage(has_extern);
- class_interface_decl->setHasExternalVisibleStorage(has_extern);
- return true;
- }
- }
- } break;
-
- default:
- break;
- }
- return false;
-}
-
-#pragma mark TagDecl
-
-bool TypeSystemClang::StartTagDeclarationDefinition(const CompilerType &type) {
- clang::QualType qual_type(ClangUtil::GetQualType(type));
- if (!qual_type.isNull()) {
- const clang::TagType *tag_type = qual_type->getAs<clang::TagType>();
- if (tag_type) {
- clang::TagDecl *tag_decl = tag_type->getDecl();
- if (tag_decl) {
- tag_decl->startDefinition();
- return true;
- }
- }
-
- const clang::ObjCObjectType *object_type =
- qual_type->getAs<clang::ObjCObjectType>();
- if (object_type) {
- clang::ObjCInterfaceDecl *interface_decl = object_type->getInterface();
- if (interface_decl) {
- interface_decl->startDefinition();
- return true;
- }
- }
- }
- return false;
-}
-
-bool TypeSystemClang::CompleteTagDeclarationDefinition(
- const CompilerType &type) {
- clang::QualType qual_type(ClangUtil::GetQualType(type));
- if (qual_type.isNull())
- return false;
-
- // Make sure we use the same methodology as
- // TypeSystemClang::StartTagDeclarationDefinition() as to how we start/end
- // the definition.
- const clang::TagType *tag_type = qual_type->getAs<clang::TagType>();
- if (tag_type) {
- clang::TagDecl *tag_decl = tag_type->getDecl();
-
- if (auto *cxx_record_decl = llvm::dyn_cast<CXXRecordDecl>(tag_decl)) {
- // If we have a move constructor declared but no copy constructor we
- // need to explicitly mark it as deleted. Usually Sema would do this for
- // us in Sema::DeclareImplicitCopyConstructor but we don't have a Sema
- // when building an AST from debug information.
- // See also:
- // C++11 [class.copy]p7, p18:
- // If the class definition declares a move constructor or move assignment
- // operator, an implicitly declared copy constructor or copy assignment
- // operator is defined as deleted.
- if (cxx_record_decl->hasUserDeclaredMoveConstructor() &&
- cxx_record_decl->needsImplicitCopyConstructor())
- cxx_record_decl->setImplicitCopyConstructorIsDeleted();
-
- if (!cxx_record_decl->isCompleteDefinition())
- cxx_record_decl->completeDefinition();
- cxx_record_decl->setHasLoadedFieldsFromExternalStorage(true);
- cxx_record_decl->setHasExternalLexicalStorage(false);
- cxx_record_decl->setHasExternalVisibleStorage(false);
- return true;
- }
- }
-
- const clang::EnumType *enutype = qual_type->getAs<clang::EnumType>();
-
- if (!enutype)
- return false;
- clang::EnumDecl *enum_decl = enutype->getDecl();
-
- if (enum_decl->isCompleteDefinition())
- return true;
-
- TypeSystemClang *lldb_ast =
- llvm::dyn_cast<TypeSystemClang>(type.GetTypeSystem());
- if (lldb_ast == nullptr)
- return false;
- clang::ASTContext &ast = lldb_ast->getASTContext();
-
- /// TODO This really needs to be fixed.
-
- QualType integer_type(enum_decl->getIntegerType());
- if (!integer_type.isNull()) {
- unsigned NumPositiveBits = 1;
- unsigned NumNegativeBits = 0;
-
- clang::QualType promotion_qual_type;
- // If the enum integer type is less than an integer in bit width,
- // then we must promote it to an integer size.
- if (ast.getTypeSize(enum_decl->getIntegerType()) <
- ast.getTypeSize(ast.IntTy)) {
- if (enum_decl->getIntegerType()->isSignedIntegerType())
- promotion_qual_type = ast.IntTy;
- else
- promotion_qual_type = ast.UnsignedIntTy;
- } else
- promotion_qual_type = enum_decl->getIntegerType();
-
- enum_decl->completeDefinition(enum_decl->getIntegerType(),
- promotion_qual_type, NumPositiveBits,
- NumNegativeBits);
- }
- return true;
-}
-
-clang::EnumConstantDecl *TypeSystemClang::AddEnumerationValueToEnumerationType(
- const CompilerType &enum_type, const Declaration &decl, const char *name,
- const llvm::APSInt &value) {
-
- if (!enum_type || ConstString(name).IsEmpty())
- return nullptr;
-
- lldbassert(enum_type.GetTypeSystem() == static_cast<TypeSystem *>(this));
-
- lldb::opaque_compiler_type_t enum_opaque_compiler_type =
- enum_type.GetOpaqueQualType();
-
- if (!enum_opaque_compiler_type)
- return nullptr;
-
- clang::QualType enum_qual_type(
- GetCanonicalQualType(enum_opaque_compiler_type));
-
- const clang::Type *clang_type = enum_qual_type.getTypePtr();
-
- if (!clang_type)
- return nullptr;
-
- const clang::EnumType *enutype = llvm::dyn_cast<clang::EnumType>(clang_type);
-
- if (!enutype)
- return nullptr;
-
- clang::EnumConstantDecl *enumerator_decl = clang::EnumConstantDecl::Create(
- getASTContext(), enutype->getDecl(), clang::SourceLocation(),
- name ? &getASTContext().Idents.get(name) : nullptr, // Identifier
- clang::QualType(enutype, 0), nullptr, value);
-
- if (!enumerator_decl)
- return nullptr;
-
- enutype->getDecl()->addDecl(enumerator_decl);
-
-#ifdef LLDB_CONFIGURATION_DEBUG
- VerifyDecl(enumerator_decl);
-#endif
-
- return enumerator_decl;
-}
-
-clang::EnumConstantDecl *TypeSystemClang::AddEnumerationValueToEnumerationType(
- const CompilerType &enum_type, const Declaration &decl, const char *name,
- int64_t enum_value, uint32_t enum_value_bit_size) {
- CompilerType underlying_type =
- GetEnumerationIntegerType(enum_type.GetOpaqueQualType());
- bool is_signed = false;
- underlying_type.IsIntegerType(is_signed);
-
- llvm::APSInt value(enum_value_bit_size, is_signed);
- value = enum_value;
-
- return AddEnumerationValueToEnumerationType(enum_type, decl, name, value);
-}
-
-CompilerType
-TypeSystemClang::GetEnumerationIntegerType(lldb::opaque_compiler_type_t type) {
- clang::QualType enum_qual_type(GetCanonicalQualType(type));
- const clang::Type *clang_type = enum_qual_type.getTypePtr();
- if (clang_type) {
- const clang::EnumType *enutype =
- llvm::dyn_cast<clang::EnumType>(clang_type);
- if (enutype) {
- clang::EnumDecl *enum_decl = enutype->getDecl();
- if (enum_decl)
- return GetType(enum_decl->getIntegerType());
- }
- }
- return CompilerType();
-}
-
-CompilerType
-TypeSystemClang::CreateMemberPointerType(const CompilerType &type,
- const CompilerType &pointee_type) {
- if (type && pointee_type.IsValid() &&
- type.GetTypeSystem() == pointee_type.GetTypeSystem()) {
- TypeSystemClang *ast =
- llvm::dyn_cast<TypeSystemClang>(type.GetTypeSystem());
- if (!ast)
- return CompilerType();
- return ast->GetType(ast->getASTContext().getMemberPointerType(
- ClangUtil::GetQualType(pointee_type),
- ClangUtil::GetQualType(type).getTypePtr()));
- }
- return CompilerType();
-}
-
-// Dumping types
-#define DEPTH_INCREMENT 2
-
-#ifndef NDEBUG
-LLVM_DUMP_METHOD void
-TypeSystemClang::dump(lldb::opaque_compiler_type_t type) const {
- if (!type)
- return;
- clang::QualType qual_type(GetQualType(type));
- qual_type.dump();
-}
-#endif
-
-void TypeSystemClang::Dump(Stream &s) {
- Decl *tu = Decl::castFromDeclContext(GetTranslationUnitDecl());
- tu->dump(s.AsRawOstream());
-}
-
-void TypeSystemClang::DumpFromSymbolFile(Stream &s,
- llvm::StringRef symbol_name) {
- SymbolFile *symfile = GetSymbolFile();
-
- if (!symfile)
- return;
-
- lldb_private::TypeList type_list;
- symfile->GetTypes(nullptr, eTypeClassAny, type_list);
- size_t ntypes = type_list.GetSize();
-
- for (size_t i = 0; i < ntypes; ++i) {
- TypeSP type = type_list.GetTypeAtIndex(i);
-
- if (!symbol_name.empty())
- if (symbol_name != type->GetName().GetStringRef())
- continue;
-
- s << type->GetName().AsCString() << "\n";
-
- CompilerType full_type = type->GetFullCompilerType();
- if (clang::TagDecl *tag_decl = GetAsTagDecl(full_type)) {
- tag_decl->dump(s.AsRawOstream());
- continue;
- }
- if (clang::TypedefNameDecl *typedef_decl = GetAsTypedefDecl(full_type)) {
- typedef_decl->dump(s.AsRawOstream());
- continue;
- }
- if (auto *objc_obj = llvm::dyn_cast<clang::ObjCObjectType>(
- ClangUtil::GetQualType(full_type).getTypePtr())) {
- if (clang::ObjCInterfaceDecl *interface_decl = objc_obj->getInterface()) {
- interface_decl->dump(s.AsRawOstream());
- continue;
- }
- }
- GetCanonicalQualType(full_type.GetOpaqueQualType()).dump(s.AsRawOstream());
- }
-}
-
-void TypeSystemClang::DumpValue(
- lldb::opaque_compiler_type_t type, ExecutionContext *exe_ctx, Stream *s,
- lldb::Format format, const lldb_private::DataExtractor &data,
- lldb::offset_t data_byte_offset, size_t data_byte_size,
- uint32_t bitfield_bit_size, uint32_t bitfield_bit_offset, bool show_types,
- bool show_summary, bool verbose, uint32_t depth) {
- if (!type)
- return;
-
- clang::QualType qual_type(GetQualType(type));
- switch (qual_type->getTypeClass()) {
- case clang::Type::Record:
- if (GetCompleteType(type)) {
- const clang::RecordType *record_type =
- llvm::cast<clang::RecordType>(qual_type.getTypePtr());
- const clang::RecordDecl *record_decl = record_type->getDecl();
- assert(record_decl);
- uint32_t field_bit_offset = 0;
- uint32_t field_byte_offset = 0;
- const clang::ASTRecordLayout &record_layout =
- getASTContext().getASTRecordLayout(record_decl);
- uint32_t child_idx = 0;
-
- const clang::CXXRecordDecl *cxx_record_decl =
- llvm::dyn_cast<clang::CXXRecordDecl>(record_decl);
- if (cxx_record_decl) {
- // We might have base classes to print out first
- clang::CXXRecordDecl::base_class_const_iterator base_class,
- base_class_end;
- for (base_class = cxx_record_decl->bases_begin(),
- base_class_end = cxx_record_decl->bases_end();
- base_class != base_class_end; ++base_class) {
- const clang::CXXRecordDecl *base_class_decl =
- llvm::cast<clang::CXXRecordDecl>(
- base_class->getType()->getAs<clang::RecordType>()->getDecl());
-
- // Skip empty base classes
- if (!verbose && !TypeSystemClang::RecordHasFields(base_class_decl))
- continue;
-
- if (base_class->isVirtual())
- field_bit_offset =
- record_layout.getVBaseClassOffset(base_class_decl)
- .getQuantity() *
- 8;
- else
- field_bit_offset = record_layout.getBaseClassOffset(base_class_decl)
- .getQuantity() *
- 8;
- field_byte_offset = field_bit_offset / 8;
- assert(field_bit_offset % 8 == 0);
- if (child_idx == 0)
- s->PutChar('{');
- else
- s->PutChar(',');
-
- clang::QualType base_class_qual_type = base_class->getType();
- std::string base_class_type_name(base_class_qual_type.getAsString());
-
- // Indent and print the base class type name
- s->Format("\n{0}{1}", llvm::fmt_repeat(" ", depth + DEPTH_INCREMENT),
- base_class_type_name);
-
- clang::TypeInfo base_class_type_info =
- getASTContext().getTypeInfo(base_class_qual_type);
-
- // Dump the value of the member
- CompilerType base_clang_type = GetType(base_class_qual_type);
- base_clang_type.DumpValue(
- exe_ctx,
- s, // Stream to dump to
- base_clang_type
- .GetFormat(), // The format with which to display the member
- data, // Data buffer containing all bytes for this type
- data_byte_offset + field_byte_offset, // Offset into "data" where
- // to grab value from
- base_class_type_info.Width / 8, // Size of this type in bytes
- 0, // Bitfield bit size
- 0, // Bitfield bit offset
- show_types, // Boolean indicating if we should show the variable
- // types
- show_summary, // Boolean indicating if we should show a summary
- // for the current type
- verbose, // Verbose output?
- depth + DEPTH_INCREMENT); // Scope depth for any types that have
- // children
-
- ++child_idx;
- }
- }
- uint32_t field_idx = 0;
- clang::RecordDecl::field_iterator field, field_end;
- for (field = record_decl->field_begin(),
- field_end = record_decl->field_end();
- field != field_end; ++field, ++field_idx, ++child_idx) {
- // Print the starting squiggly bracket (if this is the first member) or
- // comma (for member 2 and beyond) for the struct/union/class member.
- if (child_idx == 0)
- s->PutChar('{');
- else
- s->PutChar(',');
-
- // Indent
- s->Printf("\n%*s", depth + DEPTH_INCREMENT, "");
-
- clang::QualType field_type = field->getType();
- // Print the member type if requested
- // Figure out the type byte size (field_type_info.first) and alignment
- // (field_type_info.second) from the AST context.
- clang::TypeInfo field_type_info =
- getASTContext().getTypeInfo(field_type);
- assert(field_idx < record_layout.getFieldCount());
- // Figure out the field offset within the current struct/union/class
- // type
- field_bit_offset = record_layout.getFieldOffset(field_idx);
- field_byte_offset = field_bit_offset / 8;
- uint32_t field_bitfield_bit_size = 0;
- uint32_t field_bitfield_bit_offset = 0;
- if (FieldIsBitfield(*field, field_bitfield_bit_size))
- field_bitfield_bit_offset = field_bit_offset % 8;
-
- if (show_types) {
- std::string field_type_name(field_type.getAsString());
- if (field_bitfield_bit_size > 0)
- s->Printf("(%s:%u) ", field_type_name.c_str(),
- field_bitfield_bit_size);
- else
- s->Printf("(%s) ", field_type_name.c_str());
- }
- // Print the member name and equal sign
- s->Printf("%s = ", field->getNameAsString().c_str());
-
- // Dump the value of the member
- CompilerType field_clang_type = GetType(field_type);
- field_clang_type.DumpValue(
- exe_ctx,
- s, // Stream to dump to
- field_clang_type
- .GetFormat(), // The format with which to display the member
- data, // Data buffer containing all bytes for this type
- data_byte_offset + field_byte_offset, // Offset into "data" where to
- // grab value from
- field_type_info.Width / 8, // Size of this type in bytes
- field_bitfield_bit_size, // Bitfield bit size
- field_bitfield_bit_offset, // Bitfield bit offset
- show_types, // Boolean indicating if we should show the variable
- // types
- show_summary, // Boolean indicating if we should show a summary for
- // the current type
- verbose, // Verbose output?
- depth + DEPTH_INCREMENT); // Scope depth for any types that have
- // children
- }
-
- // Indent the trailing squiggly bracket
- if (child_idx > 0)
- s->Printf("\n%*s}", depth, "");
- }
- return;
-
- case clang::Type::Enum:
- if (GetCompleteType(type)) {
- const clang::EnumType *enutype =
- llvm::cast<clang::EnumType>(qual_type.getTypePtr());
- const clang::EnumDecl *enum_decl = enutype->getDecl();
- assert(enum_decl);
- clang::EnumDecl::enumerator_iterator enum_pos, enum_end_pos;
- lldb::offset_t offset = data_byte_offset;
- const int64_t enum_value = data.GetMaxU64Bitfield(
- &offset, data_byte_size, bitfield_bit_size, bitfield_bit_offset);
- for (enum_pos = enum_decl->enumerator_begin(),
- enum_end_pos = enum_decl->enumerator_end();
- enum_pos != enum_end_pos; ++enum_pos) {
- if (enum_pos->getInitVal() == enum_value) {
- s->Printf("%s", enum_pos->getNameAsString().c_str());
- return;
- }
- }
- // If we have gotten here we didn't get find the enumerator in the enum
- // decl, so just print the integer.
- s->Printf("%" PRIi64, enum_value);
- }
- return;
-
- case clang::Type::ConstantArray: {
- const clang::ConstantArrayType *array =
- llvm::cast<clang::ConstantArrayType>(qual_type.getTypePtr());
- bool is_array_of_characters = false;
- clang::QualType element_qual_type = array->getElementType();
-
- const clang::Type *canonical_type =
- element_qual_type->getCanonicalTypeInternal().getTypePtr();
- if (canonical_type)
- is_array_of_characters = canonical_type->isCharType();
-
- const uint64_t element_count = array->getSize().getLimitedValue();
-
- clang::TypeInfo field_type_info =
- getASTContext().getTypeInfo(element_qual_type);
-
- uint32_t element_idx = 0;
- uint32_t element_offset = 0;
- uint64_t element_byte_size = field_type_info.Width / 8;
- uint32_t element_stride = element_byte_size;
-
- if (is_array_of_characters) {
- s->PutChar('"');
- DumpDataExtractor(data, s, data_byte_offset, lldb::eFormatChar,
- element_byte_size, element_count, UINT32_MAX,
- LLDB_INVALID_ADDRESS, 0, 0);
- s->PutChar('"');
- return;
- } else {
- CompilerType element_clang_type = GetType(element_qual_type);
- lldb::Format element_format = element_clang_type.GetFormat();
-
- for (element_idx = 0; element_idx < element_count; ++element_idx) {
- // Print the starting squiggly bracket (if this is the first member) or
- // comman (for member 2 and beyong) for the struct/union/class member.
- if (element_idx == 0)
- s->PutChar('{');
- else
- s->PutChar(',');
-
- // Indent and print the index
- s->Printf("\n%*s[%u] ", depth + DEPTH_INCREMENT, "", element_idx);
-
- // Figure out the field offset within the current struct/union/class
- // type
- element_offset = element_idx * element_stride;
-
- // Dump the value of the member
- element_clang_type.DumpValue(
- exe_ctx,
- s, // Stream to dump to
- element_format, // The format with which to display the element
- data, // Data buffer containing all bytes for this type
- data_byte_offset +
- element_offset, // Offset into "data" where to grab value from
- element_byte_size, // Size of this type in bytes
- 0, // Bitfield bit size
- 0, // Bitfield bit offset
- show_types, // Boolean indicating if we should show the variable
- // types
- show_summary, // Boolean indicating if we should show a summary for
- // the current type
- verbose, // Verbose output?
- depth + DEPTH_INCREMENT); // Scope depth for any types that have
- // children
- }
-
- // Indent the trailing squiggly bracket
- if (element_idx > 0)
- s->Printf("\n%*s}", depth, "");
- }
- }
- return;
-
- case clang::Type::Typedef: {
- clang::QualType typedef_qual_type =
- llvm::cast<clang::TypedefType>(qual_type)
- ->getDecl()
- ->getUnderlyingType();
-
- CompilerType typedef_clang_type = GetType(typedef_qual_type);
- lldb::Format typedef_format = typedef_clang_type.GetFormat();
- clang::TypeInfo typedef_type_info =
- getASTContext().getTypeInfo(typedef_qual_type);
- uint64_t typedef_byte_size = typedef_type_info.Width / 8;
-
- return typedef_clang_type.DumpValue(
- exe_ctx,
- s, // Stream to dump to
- typedef_format, // The format with which to display the element
- data, // Data buffer containing all bytes for this type
- data_byte_offset, // Offset into "data" where to grab value from
- typedef_byte_size, // Size of this type in bytes
- bitfield_bit_size, // Bitfield bit size
- bitfield_bit_offset, // Bitfield bit offset
- show_types, // Boolean indicating if we should show the variable types
- show_summary, // Boolean indicating if we should show a summary for the
- // current type
- verbose, // Verbose output?
- depth); // Scope depth for any types that have children
- } break;
-
- case clang::Type::Auto: {
- clang::QualType elaborated_qual_type =
- llvm::cast<clang::AutoType>(qual_type)->getDeducedType();
- CompilerType elaborated_clang_type = GetType(elaborated_qual_type);
- lldb::Format elaborated_format = elaborated_clang_type.GetFormat();
- clang::TypeInfo elaborated_type_info =
- getASTContext().getTypeInfo(elaborated_qual_type);
- uint64_t elaborated_byte_size = elaborated_type_info.Width / 8;
-
- return elaborated_clang_type.DumpValue(
- exe_ctx,
- s, // Stream to dump to
- elaborated_format, // The format with which to display the element
- data, // Data buffer containing all bytes for this type
- data_byte_offset, // Offset into "data" where to grab value from
- elaborated_byte_size, // Size of this type in bytes
- bitfield_bit_size, // Bitfield bit size
- bitfield_bit_offset, // Bitfield bit offset
- show_types, // Boolean indicating if we should show the variable types
- show_summary, // Boolean indicating if we should show a summary for the
- // current type
- verbose, // Verbose output?
- depth); // Scope depth for any types that have children
- } break;
-
- case clang::Type::Elaborated: {
- clang::QualType elaborated_qual_type =
- llvm::cast<clang::ElaboratedType>(qual_type)->getNamedType();
- CompilerType elaborated_clang_type = GetType(elaborated_qual_type);
- lldb::Format elaborated_format = elaborated_clang_type.GetFormat();
- clang::TypeInfo elaborated_type_info =
- getASTContext().getTypeInfo(elaborated_qual_type);
- uint64_t elaborated_byte_size = elaborated_type_info.Width / 8;
-
- return elaborated_clang_type.DumpValue(
- exe_ctx,
- s, // Stream to dump to
- elaborated_format, // The format with which to display the element
- data, // Data buffer containing all bytes for this type
- data_byte_offset, // Offset into "data" where to grab value from
- elaborated_byte_size, // Size of this type in bytes
- bitfield_bit_size, // Bitfield bit size
- bitfield_bit_offset, // Bitfield bit offset
- show_types, // Boolean indicating if we should show the variable types
- show_summary, // Boolean indicating if we should show a summary for the
- // current type
- verbose, // Verbose output?
- depth); // Scope depth for any types that have children
- } break;
-
- case clang::Type::Paren: {
- clang::QualType desugar_qual_type =
- llvm::cast<clang::ParenType>(qual_type)->desugar();
- CompilerType desugar_clang_type = GetType(desugar_qual_type);
-
- lldb::Format desugar_format = desugar_clang_type.GetFormat();
- clang::TypeInfo desugar_type_info =
- getASTContext().getTypeInfo(desugar_qual_type);
- uint64_t desugar_byte_size = desugar_type_info.Width / 8;
-
- return desugar_clang_type.DumpValue(
- exe_ctx,
- s, // Stream to dump to
- desugar_format, // The format with which to display the element
- data, // Data buffer containing all bytes for this type
- data_byte_offset, // Offset into "data" where to grab value from
- desugar_byte_size, // Size of this type in bytes
- bitfield_bit_size, // Bitfield bit size
- bitfield_bit_offset, // Bitfield bit offset
- show_types, // Boolean indicating if we should show the variable types
- show_summary, // Boolean indicating if we should show a summary for the
- // current type
- verbose, // Verbose output?
- depth); // Scope depth for any types that have children
- } break;
-
- default:
- // We are down to a scalar type that we just need to display.
- DumpDataExtractor(data, s, data_byte_offset, format, data_byte_size, 1,
- UINT32_MAX, LLDB_INVALID_ADDRESS, bitfield_bit_size,
- bitfield_bit_offset);
-
- if (show_summary)
- DumpSummary(type, exe_ctx, s, data, data_byte_offset, data_byte_size);
- break;
- }
-}
-
-static bool DumpEnumValue(const clang::QualType &qual_type, Stream *s,
- const DataExtractor &data, lldb::offset_t byte_offset,
- size_t byte_size, uint32_t bitfield_bit_offset,
- uint32_t bitfield_bit_size) {
- const clang::EnumType *enutype =
- llvm::cast<clang::EnumType>(qual_type.getTypePtr());
- const clang::EnumDecl *enum_decl = enutype->getDecl();
- assert(enum_decl);
- lldb::offset_t offset = byte_offset;
- const uint64_t enum_svalue = data.GetMaxS64Bitfield(
- &offset, byte_size, bitfield_bit_size, bitfield_bit_offset);
- bool can_be_bitfield = true;
- uint64_t covered_bits = 0;
- int num_enumerators = 0;
-
- // Try to find an exact match for the value.
- // At the same time, we're applying a heuristic to determine whether we want
- // to print this enum as a bitfield. We're likely dealing with a bitfield if
- // every enumrator is either a one bit value or a superset of the previous
- // enumerators. Also 0 doesn't make sense when the enumerators are used as
- // flags.
- for (auto enumerator : enum_decl->enumerators()) {
- uint64_t val = enumerator->getInitVal().getSExtValue();
- val = llvm::SignExtend64(val, 8*byte_size);
- if (llvm::countPopulation(val) != 1 && (val & ~covered_bits) != 0)
- can_be_bitfield = false;
- covered_bits |= val;
- ++num_enumerators;
- if (val == enum_svalue) {
- // Found an exact match, that's all we need to do.
- s->PutCString(enumerator->getNameAsString());
- return true;
- }
- }
-
- // Unsigned values make more sense for flags.
- offset = byte_offset;
- const uint64_t enum_uvalue = data.GetMaxU64Bitfield(
- &offset, byte_size, bitfield_bit_size, bitfield_bit_offset);
-
- // No exact match, but we don't think this is a bitfield. Print the value as
- // decimal.
- if (!can_be_bitfield) {
- if (qual_type->isSignedIntegerOrEnumerationType())
- s->Printf("%" PRIi64, enum_svalue);
- else
- s->Printf("%" PRIu64, enum_uvalue);
- return true;
- }
-
- uint64_t remaining_value = enum_uvalue;
- std::vector<std::pair<uint64_t, llvm::StringRef>> values;
- values.reserve(num_enumerators);
- for (auto enumerator : enum_decl->enumerators())
- if (auto val = enumerator->getInitVal().getZExtValue())
- values.emplace_back(val, enumerator->getName());
-
- // Sort in reverse order of the number of the population count, so that in
- // `enum {A, B, ALL = A|B }` we visit ALL first. Use a stable sort so that
- // A | C where A is declared before C is displayed in this order.
- std::stable_sort(values.begin(), values.end(), [](const auto &a, const auto &b) {
- return llvm::countPopulation(a.first) > llvm::countPopulation(b.first);
- });
-
- for (const auto &val : values) {
- if ((remaining_value & val.first) != val.first)
- continue;
- remaining_value &= ~val.first;
- s->PutCString(val.second);
- if (remaining_value)
- s->PutCString(" | ");
- }
-
- // If there is a remainder that is not covered by the value, print it as hex.
- if (remaining_value)
- s->Printf("0x%" PRIx64, remaining_value);
-
- return true;
-}
-
-bool TypeSystemClang::DumpTypeValue(
- lldb::opaque_compiler_type_t type, Stream *s, lldb::Format format,
- const lldb_private::DataExtractor &data, lldb::offset_t byte_offset,
- size_t byte_size, uint32_t bitfield_bit_size, uint32_t bitfield_bit_offset,
- ExecutionContextScope *exe_scope) {
- if (!type)
- return false;
- if (IsAggregateType(type)) {
- return false;
- } else {
- clang::QualType qual_type(GetQualType(type));
-
- const clang::Type::TypeClass type_class = qual_type->getTypeClass();
-
- if (type_class == clang::Type::Elaborated) {
- qual_type = llvm::cast<clang::ElaboratedType>(qual_type)->getNamedType();
- return DumpTypeValue(qual_type.getAsOpaquePtr(), s, format, data, byte_offset, byte_size,
- bitfield_bit_size, bitfield_bit_offset, exe_scope);
- }
-
- switch (type_class) {
- case clang::Type::Typedef: {
- clang::QualType typedef_qual_type =
- llvm::cast<clang::TypedefType>(qual_type)
- ->getDecl()
- ->getUnderlyingType();
- CompilerType typedef_clang_type = GetType(typedef_qual_type);
- if (format == eFormatDefault)
- format = typedef_clang_type.GetFormat();
- clang::TypeInfo typedef_type_info =
- getASTContext().getTypeInfo(typedef_qual_type);
- uint64_t typedef_byte_size = typedef_type_info.Width / 8;
-
- return typedef_clang_type.DumpTypeValue(
- s,
- format, // The format with which to display the element
- data, // Data buffer containing all bytes for this type
- byte_offset, // Offset into "data" where to grab value from
- typedef_byte_size, // Size of this type in bytes
- bitfield_bit_size, // Size in bits of a bitfield value, if zero don't
- // treat as a bitfield
- bitfield_bit_offset, // Offset in bits of a bitfield value if
- // bitfield_bit_size != 0
- exe_scope);
- } break;
-
- case clang::Type::Enum:
- // If our format is enum or default, show the enumeration value as its
- // enumeration string value, else just display it as requested.
- if ((format == eFormatEnum || format == eFormatDefault) &&
- GetCompleteType(type))
- return DumpEnumValue(qual_type, s, data, byte_offset, byte_size,
- bitfield_bit_offset, bitfield_bit_size);
- // format was not enum, just fall through and dump the value as
- // requested....
- LLVM_FALLTHROUGH;
-
- default:
- // We are down to a scalar type that we just need to display.
- {
- uint32_t item_count = 1;
- // A few formats, we might need to modify our size and count for
- // depending
- // on how we are trying to display the value...
- switch (format) {
- default:
- case eFormatBoolean:
- case eFormatBinary:
- case eFormatComplex:
- case eFormatCString: // NULL terminated C strings
- case eFormatDecimal:
- case eFormatEnum:
- case eFormatHex:
- case eFormatHexUppercase:
- case eFormatFloat:
- case eFormatOctal:
- case eFormatOSType:
- case eFormatUnsigned:
- case eFormatPointer:
- case eFormatVectorOfChar:
- case eFormatVectorOfSInt8:
- case eFormatVectorOfUInt8:
- case eFormatVectorOfSInt16:
- case eFormatVectorOfUInt16:
- case eFormatVectorOfSInt32:
- case eFormatVectorOfUInt32:
- case eFormatVectorOfSInt64:
- case eFormatVectorOfUInt64:
- case eFormatVectorOfFloat32:
- case eFormatVectorOfFloat64:
- case eFormatVectorOfUInt128:
- break;
-
- case eFormatChar:
- case eFormatCharPrintable:
- case eFormatCharArray:
- case eFormatBytes:
- case eFormatBytesWithASCII:
- item_count = byte_size;
- byte_size = 1;
- break;
-
- case eFormatUnicode16:
- item_count = byte_size / 2;
- byte_size = 2;
- break;
-
- case eFormatUnicode32:
- item_count = byte_size / 4;
- byte_size = 4;
- break;
- }
- return DumpDataExtractor(data, s, byte_offset, format, byte_size,
- item_count, UINT32_MAX, LLDB_INVALID_ADDRESS,
- bitfield_bit_size, bitfield_bit_offset,
- exe_scope);
- }
- break;
- }
- }
- return false;
-}
-
-void TypeSystemClang::DumpSummary(lldb::opaque_compiler_type_t type,
- ExecutionContext *exe_ctx, Stream *s,
- const lldb_private::DataExtractor &data,
- lldb::offset_t data_byte_offset,
- size_t data_byte_size) {
- uint32_t length = 0;
- if (IsCStringType(type, length)) {
- if (exe_ctx) {
- Process *process = exe_ctx->GetProcessPtr();
- if (process) {
- lldb::offset_t offset = data_byte_offset;
- lldb::addr_t pointer_address = data.GetMaxU64(&offset, data_byte_size);
- std::vector<uint8_t> buf;
- if (length > 0)
- buf.resize(length);
- else
- buf.resize(256);
-
- DataExtractor cstr_data(&buf.front(), buf.size(),
- process->GetByteOrder(), 4);
- buf.back() = '\0';
- size_t bytes_read;
- size_t total_cstr_len = 0;
- Status error;
- while ((bytes_read = process->ReadMemory(pointer_address, &buf.front(),
- buf.size(), error)) > 0) {
- const size_t len = strlen((const char *)&buf.front());
- if (len == 0)
- break;
- if (total_cstr_len == 0)
- s->PutCString(" \"");
- DumpDataExtractor(cstr_data, s, 0, lldb::eFormatChar, 1, len,
- UINT32_MAX, LLDB_INVALID_ADDRESS, 0, 0);
- total_cstr_len += len;
- if (len < buf.size())
- break;
- pointer_address += total_cstr_len;
- }
- if (total_cstr_len > 0)
- s->PutChar('"');
- }
- }
- }
-}
-
-void TypeSystemClang::DumpTypeDescription(lldb::opaque_compiler_type_t type) {
- StreamFile s(stdout, false);
- DumpTypeDescription(type, &s);
-
- CompilerType ct(this, type);
- const clang::Type *clang_type = ClangUtil::GetQualType(ct).getTypePtr();
- ClangASTMetadata *metadata = GetMetadata(clang_type);
- if (metadata) {
- metadata->Dump(&s);
- }
-}
-
-void TypeSystemClang::DumpTypeDescription(lldb::opaque_compiler_type_t type,
- Stream *s) {
- if (type) {
- clang::QualType qual_type =
- RemoveWrappingTypes(GetQualType(type), {clang::Type::Typedef});
-
- llvm::SmallVector<char, 1024> buf;
- llvm::raw_svector_ostream llvm_ostrm(buf);
-
- const clang::Type::TypeClass type_class = qual_type->getTypeClass();
- switch (type_class) {
- case clang::Type::ObjCObject:
- case clang::Type::ObjCInterface: {
- GetCompleteType(type);
-
- const clang::ObjCObjectType *objc_class_type =
- llvm::dyn_cast<clang::ObjCObjectType>(qual_type.getTypePtr());
- assert(objc_class_type);
- if (objc_class_type) {
- clang::ObjCInterfaceDecl *class_interface_decl =
- objc_class_type->getInterface();
- if (class_interface_decl) {
- clang::PrintingPolicy policy = getASTContext().getPrintingPolicy();
- class_interface_decl->print(llvm_ostrm, policy, s->GetIndentLevel());
- }
- }
- } break;
-
- case clang::Type::Typedef: {
- const clang::TypedefType *typedef_type =
- qual_type->getAs<clang::TypedefType>();
- if (typedef_type) {
- const clang::TypedefNameDecl *typedef_decl = typedef_type->getDecl();
- std::string clang_typedef_name(
- typedef_decl->getQualifiedNameAsString());
- if (!clang_typedef_name.empty()) {
- s->PutCString("typedef ");
- s->PutCString(clang_typedef_name);
- }
- }
- } break;
-
- case clang::Type::Record: {
- GetCompleteType(type);
-
- const clang::RecordType *record_type =
- llvm::cast<clang::RecordType>(qual_type.getTypePtr());
- const clang::RecordDecl *record_decl = record_type->getDecl();
- const clang::CXXRecordDecl *cxx_record_decl =
- llvm::dyn_cast<clang::CXXRecordDecl>(record_decl);
-
- if (cxx_record_decl)
- cxx_record_decl->print(llvm_ostrm, getASTContext().getPrintingPolicy(),
- s->GetIndentLevel());
- else
- record_decl->print(llvm_ostrm, getASTContext().getPrintingPolicy(),
- s->GetIndentLevel());
- } break;
-
- default: {
- const clang::TagType *tag_type =
- llvm::dyn_cast<clang::TagType>(qual_type.getTypePtr());
- if (tag_type) {
- clang::TagDecl *tag_decl = tag_type->getDecl();
- if (tag_decl)
- tag_decl->print(llvm_ostrm, 0);
- } else {
- std::string clang_type_name(qual_type.getAsString());
- if (!clang_type_name.empty())
- s->PutCString(clang_type_name);
- }
- }
- }
-
- if (buf.size() > 0) {
- s->Write(buf.data(), buf.size());
- }
- }
-}
-
-void TypeSystemClang::DumpTypeName(const CompilerType &type) {
- if (ClangUtil::IsClangType(type)) {
- clang::QualType qual_type(
- ClangUtil::GetCanonicalQualType(ClangUtil::RemoveFastQualifiers(type)));
-
- const clang::Type::TypeClass type_class = qual_type->getTypeClass();
- switch (type_class) {
- case clang::Type::Record: {
- const clang::CXXRecordDecl *cxx_record_decl =
- qual_type->getAsCXXRecordDecl();
- if (cxx_record_decl)
- printf("class %s", cxx_record_decl->getName().str().c_str());
- } break;
-
- case clang::Type::Enum: {
- clang::EnumDecl *enum_decl =
- llvm::cast<clang::EnumType>(qual_type)->getDecl();
- if (enum_decl) {
- printf("enum %s", enum_decl->getName().str().c_str());
- }
- } break;
-
- case clang::Type::ObjCObject:
- case clang::Type::ObjCInterface: {
- const clang::ObjCObjectType *objc_class_type =
- llvm::dyn_cast<clang::ObjCObjectType>(qual_type);
- if (objc_class_type) {
- clang::ObjCInterfaceDecl *class_interface_decl =
- objc_class_type->getInterface();
- // We currently can't complete objective C types through the newly
- // added ASTContext because it only supports TagDecl objects right
- // now...
- if (class_interface_decl)
- printf("@class %s", class_interface_decl->getName().str().c_str());
- }
- } break;
-
- case clang::Type::Typedef:
- printf("typedef %s", llvm::cast<clang::TypedefType>(qual_type)
- ->getDecl()
- ->getName()
- .str()
- .c_str());
- break;
-
- case clang::Type::Auto:
- printf("auto ");
- return DumpTypeName(CompilerType(type.GetTypeSystem(),
- llvm::cast<clang::AutoType>(qual_type)
- ->getDeducedType()
- .getAsOpaquePtr()));
-
- case clang::Type::Elaborated:
- printf("elaborated ");
- return DumpTypeName(CompilerType(
- type.GetTypeSystem(), llvm::cast<clang::ElaboratedType>(qual_type)
- ->getNamedType()
- .getAsOpaquePtr()));
-
- case clang::Type::Paren:
- printf("paren ");
- return DumpTypeName(CompilerType(
- type.GetTypeSystem(),
- llvm::cast<clang::ParenType>(qual_type)->desugar().getAsOpaquePtr()));
-
- default:
- printf("TypeSystemClang::DumpTypeName() type_class = %u", type_class);
- break;
- }
- }
-}
-
-clang::ClassTemplateDecl *TypeSystemClang::ParseClassTemplateDecl(
- clang::DeclContext *decl_ctx, lldb::AccessType access_type,
- const char *parent_name, int tag_decl_kind,
- const TypeSystemClang::TemplateParameterInfos &template_param_infos) {
- if (template_param_infos.IsValid()) {
- std::string template_basename(parent_name);
- template_basename.erase(template_basename.find('<'));
-
- return CreateClassTemplateDecl(decl_ctx, access_type,
- template_basename.c_str(), tag_decl_kind,
- template_param_infos);
- }
- return nullptr;
-}
-
-void TypeSystemClang::CompleteTagDecl(clang::TagDecl *decl) {
- SymbolFile *sym_file = GetSymbolFile();
- if (sym_file) {
- CompilerType clang_type = GetTypeForDecl(decl);
- if (clang_type)
- sym_file->CompleteType(clang_type);
- }
-}
-
-void TypeSystemClang::CompleteObjCInterfaceDecl(
- clang::ObjCInterfaceDecl *decl) {
- SymbolFile *sym_file = GetSymbolFile();
- if (sym_file) {
- CompilerType clang_type = GetTypeForDecl(decl);
- if (clang_type)
- sym_file->CompleteType(clang_type);
- }
-}
-
-DWARFASTParser *TypeSystemClang::GetDWARFParser() {
- if (!m_dwarf_ast_parser_up)
- m_dwarf_ast_parser_up.reset(new DWARFASTParserClang(*this));
- return m_dwarf_ast_parser_up.get();
-}
-
-PDBASTParser *TypeSystemClang::GetPDBParser() {
- if (!m_pdb_ast_parser_up)
- m_pdb_ast_parser_up.reset(new PDBASTParser(*this));
- return m_pdb_ast_parser_up.get();
-}
-
-bool TypeSystemClang::LayoutRecordType(
- const clang::RecordDecl *record_decl, uint64_t &bit_size,
- uint64_t &alignment,
- llvm::DenseMap<const clang::FieldDecl *, uint64_t> &field_offsets,
- llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits>
- &base_offsets,
- llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits>
- &vbase_offsets) {
- lldb_private::ClangASTImporter *importer = nullptr;
- if (m_dwarf_ast_parser_up)
- importer = &m_dwarf_ast_parser_up->GetClangASTImporter();
- if (!importer && m_pdb_ast_parser_up)
- importer = &m_pdb_ast_parser_up->GetClangASTImporter();
- if (!importer)
- return false;
-
- return importer->LayoutRecordType(record_decl, bit_size, alignment,
- field_offsets, base_offsets, vbase_offsets);
-}
-
-// CompilerDecl override functions
-
-ConstString TypeSystemClang::DeclGetName(void *opaque_decl) {
- if (opaque_decl) {
- clang::NamedDecl *nd =
- llvm::dyn_cast<NamedDecl>((clang::Decl *)opaque_decl);
- if (nd != nullptr)
- return ConstString(nd->getDeclName().getAsString());
- }
- return ConstString();
-}
-
-ConstString TypeSystemClang::DeclGetMangledName(void *opaque_decl) {
- if (opaque_decl) {
- clang::NamedDecl *nd =
- llvm::dyn_cast<clang::NamedDecl>((clang::Decl *)opaque_decl);
- if (nd != nullptr && !llvm::isa<clang::ObjCMethodDecl>(nd)) {
- clang::MangleContext *mc = getMangleContext();
- if (mc && mc->shouldMangleCXXName(nd)) {
- llvm::SmallVector<char, 1024> buf;
- llvm::raw_svector_ostream llvm_ostrm(buf);
- if (llvm::isa<clang::CXXConstructorDecl>(nd)) {
- mc->mangleCXXCtor(llvm::dyn_cast<clang::CXXConstructorDecl>(nd),
- Ctor_Complete, llvm_ostrm);
- } else if (llvm::isa<clang::CXXDestructorDecl>(nd)) {
- mc->mangleCXXDtor(llvm::dyn_cast<clang::CXXDestructorDecl>(nd),
- Dtor_Complete, llvm_ostrm);
- } else {
- mc->mangleName(nd, llvm_ostrm);
- }
- if (buf.size() > 0)
- return ConstString(buf.data(), buf.size());
- }
- }
- }
- return ConstString();
-}
-
-CompilerDeclContext TypeSystemClang::DeclGetDeclContext(void *opaque_decl) {
- if (opaque_decl)
- return CreateDeclContext(((clang::Decl *)opaque_decl)->getDeclContext());
- return CompilerDeclContext();
-}
-
-CompilerType TypeSystemClang::DeclGetFunctionReturnType(void *opaque_decl) {
- if (clang::FunctionDecl *func_decl =
- llvm::dyn_cast<clang::FunctionDecl>((clang::Decl *)opaque_decl))
- return GetType(func_decl->getReturnType());
- if (clang::ObjCMethodDecl *objc_method =
- llvm::dyn_cast<clang::ObjCMethodDecl>((clang::Decl *)opaque_decl))
- return GetType(objc_method->getReturnType());
- else
- return CompilerType();
-}
-
-size_t TypeSystemClang::DeclGetFunctionNumArguments(void *opaque_decl) {
- if (clang::FunctionDecl *func_decl =
- llvm::dyn_cast<clang::FunctionDecl>((clang::Decl *)opaque_decl))
- return func_decl->param_size();
- if (clang::ObjCMethodDecl *objc_method =
- llvm::dyn_cast<clang::ObjCMethodDecl>((clang::Decl *)opaque_decl))
- return objc_method->param_size();
- else
- return 0;
-}
-
-CompilerType TypeSystemClang::DeclGetFunctionArgumentType(void *opaque_decl,
- size_t idx) {
- if (clang::FunctionDecl *func_decl =
- llvm::dyn_cast<clang::FunctionDecl>((clang::Decl *)opaque_decl)) {
- if (idx < func_decl->param_size()) {
- ParmVarDecl *var_decl = func_decl->getParamDecl(idx);
- if (var_decl)
- return GetType(var_decl->getOriginalType());
- }
- } else if (clang::ObjCMethodDecl *objc_method =
- llvm::dyn_cast<clang::ObjCMethodDecl>(
- (clang::Decl *)opaque_decl)) {
- if (idx < objc_method->param_size())
- return GetType(objc_method->parameters()[idx]->getOriginalType());
- }
- return CompilerType();
-}
-
-// CompilerDeclContext functions
-
-std::vector<CompilerDecl> TypeSystemClang::DeclContextFindDeclByName(
- void *opaque_decl_ctx, ConstString name, const bool ignore_using_decls) {
- std::vector<CompilerDecl> found_decls;
- if (opaque_decl_ctx) {
- DeclContext *root_decl_ctx = (DeclContext *)opaque_decl_ctx;
- std::set<DeclContext *> searched;
- std::multimap<DeclContext *, DeclContext *> search_queue;
- SymbolFile *symbol_file = GetSymbolFile();
-
- for (clang::DeclContext *decl_context = root_decl_ctx;
- decl_context != nullptr && found_decls.empty();
- decl_context = decl_context->getParent()) {
- search_queue.insert(std::make_pair(decl_context, decl_context));
-
- for (auto it = search_queue.find(decl_context); it != search_queue.end();
- it++) {
- if (!searched.insert(it->second).second)
- continue;
- symbol_file->ParseDeclsForContext(
- CreateDeclContext(it->second));
-
- for (clang::Decl *child : it->second->decls()) {
- if (clang::UsingDirectiveDecl *ud =
- llvm::dyn_cast<clang::UsingDirectiveDecl>(child)) {
- if (ignore_using_decls)
- continue;
- clang::DeclContext *from = ud->getCommonAncestor();
- if (searched.find(ud->getNominatedNamespace()) == searched.end())
- search_queue.insert(
- std::make_pair(from, ud->getNominatedNamespace()));
- } else if (clang::UsingDecl *ud =
- llvm::dyn_cast<clang::UsingDecl>(child)) {
- if (ignore_using_decls)
- continue;
- for (clang::UsingShadowDecl *usd : ud->shadows()) {
- clang::Decl *target = usd->getTargetDecl();
- if (clang::NamedDecl *nd =
- llvm::dyn_cast<clang::NamedDecl>(target)) {
- IdentifierInfo *ii = nd->getIdentifier();
- if (ii != nullptr &&
- ii->getName().equals(name.AsCString(nullptr)))
- found_decls.push_back(GetCompilerDecl(nd));
- }
- }
- } else if (clang::NamedDecl *nd =
- llvm::dyn_cast<clang::NamedDecl>(child)) {
- IdentifierInfo *ii = nd->getIdentifier();
- if (ii != nullptr && ii->getName().equals(name.AsCString(nullptr)))
- found_decls.push_back(GetCompilerDecl(nd));
- }
- }
- }
- }
- }
- return found_decls;
-}
-
-// Look for child_decl_ctx's lookup scope in frame_decl_ctx and its parents,
-// and return the number of levels it took to find it, or
-// LLDB_INVALID_DECL_LEVEL if not found. If the decl was imported via a using
-// declaration, its name and/or type, if set, will be used to check that the
-// decl found in the scope is a match.
-//
-// The optional name is required by languages (like C++) to handle using
-// declarations like:
-//
-// void poo();
-// namespace ns {
-// void foo();
-// void goo();
-// }
-// void bar() {
-// using ns::foo;
-// // CountDeclLevels returns 0 for 'foo', 1 for 'poo', and
-// // LLDB_INVALID_DECL_LEVEL for 'goo'.
-// }
-//
-// The optional type is useful in the case that there's a specific overload
-// that we're looking for that might otherwise be shadowed, like:
-//
-// void foo(int);
-// namespace ns {
-// void foo();
-// }
-// void bar() {
-// using ns::foo;
-// // CountDeclLevels returns 0 for { 'foo', void() },
-// // 1 for { 'foo', void(int) }, and
-// // LLDB_INVALID_DECL_LEVEL for { 'foo', void(int, int) }.
-// }
-//
-// NOTE: Because file statics are at the TranslationUnit along with globals, a
-// function at file scope will return the same level as a function at global
-// scope. Ideally we'd like to treat the file scope as an additional scope just
-// below the global scope. More work needs to be done to recognise that, if
-// the decl we're trying to look up is static, we should compare its source
-// file with that of the current scope and return a lower number for it.
-uint32_t TypeSystemClang::CountDeclLevels(clang::DeclContext *frame_decl_ctx,
- clang::DeclContext *child_decl_ctx,
- ConstString *child_name,
- CompilerType *child_type) {
- if (frame_decl_ctx) {
- std::set<DeclContext *> searched;
- std::multimap<DeclContext *, DeclContext *> search_queue;
- SymbolFile *symbol_file = GetSymbolFile();
-
- // Get the lookup scope for the decl we're trying to find.
- clang::DeclContext *parent_decl_ctx = child_decl_ctx->getParent();
-
- // Look for it in our scope's decl context and its parents.
- uint32_t level = 0;
- for (clang::DeclContext *decl_ctx = frame_decl_ctx; decl_ctx != nullptr;
- decl_ctx = decl_ctx->getParent()) {
- if (!decl_ctx->isLookupContext())
- continue;
- if (decl_ctx == parent_decl_ctx)
- // Found it!
- return level;
- search_queue.insert(std::make_pair(decl_ctx, decl_ctx));
- for (auto it = search_queue.find(decl_ctx); it != search_queue.end();
- it++) {
- if (searched.find(it->second) != searched.end())
- continue;
-
- // Currently DWARF has one shared translation unit for all Decls at top
- // level, so this would erroneously find using statements anywhere. So
- // don't look at the top-level translation unit.
- // TODO fix this and add a testcase that depends on it.
-
- if (llvm::isa<clang::TranslationUnitDecl>(it->second))
- continue;
-
- searched.insert(it->second);
- symbol_file->ParseDeclsForContext(
- CreateDeclContext(it->second));
-
- for (clang::Decl *child : it->second->decls()) {
- if (clang::UsingDirectiveDecl *ud =
- llvm::dyn_cast<clang::UsingDirectiveDecl>(child)) {
- clang::DeclContext *ns = ud->getNominatedNamespace();
- if (ns == parent_decl_ctx)
- // Found it!
- return level;
- clang::DeclContext *from = ud->getCommonAncestor();
- if (searched.find(ns) == searched.end())
- search_queue.insert(std::make_pair(from, ns));
- } else if (child_name) {
- if (clang::UsingDecl *ud =
- llvm::dyn_cast<clang::UsingDecl>(child)) {
- for (clang::UsingShadowDecl *usd : ud->shadows()) {
- clang::Decl *target = usd->getTargetDecl();
- clang::NamedDecl *nd = llvm::dyn_cast<clang::NamedDecl>(target);
- if (!nd)
- continue;
- // Check names.
- IdentifierInfo *ii = nd->getIdentifier();
- if (ii == nullptr ||
- !ii->getName().equals(child_name->AsCString(nullptr)))
- continue;
- // Check types, if one was provided.
- if (child_type) {
- CompilerType clang_type = GetTypeForDecl(nd);
- if (!AreTypesSame(clang_type, *child_type,
- /*ignore_qualifiers=*/true))
- continue;
- }
- // Found it!
- return level;
- }
- }
- }
- }
- }
- ++level;
- }
- }
- return LLDB_INVALID_DECL_LEVEL;
-}
-
-ConstString TypeSystemClang::DeclContextGetName(void *opaque_decl_ctx) {
- if (opaque_decl_ctx) {
- clang::NamedDecl *named_decl =
- llvm::dyn_cast<clang::NamedDecl>((clang::DeclContext *)opaque_decl_ctx);
- if (named_decl)
- return ConstString(named_decl->getName());
- }
- return ConstString();
-}
-
-ConstString
-TypeSystemClang::DeclContextGetScopeQualifiedName(void *opaque_decl_ctx) {
- if (opaque_decl_ctx) {
- clang::NamedDecl *named_decl =
- llvm::dyn_cast<clang::NamedDecl>((clang::DeclContext *)opaque_decl_ctx);
- if (named_decl)
- return ConstString(
- llvm::StringRef(named_decl->getQualifiedNameAsString()));
- }
- return ConstString();
-}
-
-bool TypeSystemClang::DeclContextIsClassMethod(
- void *opaque_decl_ctx, lldb::LanguageType *language_ptr,
- bool *is_instance_method_ptr, ConstString *language_object_name_ptr) {
- if (opaque_decl_ctx) {
- clang::DeclContext *decl_ctx = (clang::DeclContext *)opaque_decl_ctx;
- if (ObjCMethodDecl *objc_method =
- llvm::dyn_cast<clang::ObjCMethodDecl>(decl_ctx)) {
- if (is_instance_method_ptr)
- *is_instance_method_ptr = objc_method->isInstanceMethod();
- if (language_ptr)
- *language_ptr = eLanguageTypeObjC;
- if (language_object_name_ptr)
- language_object_name_ptr->SetCString("self");
- return true;
- } else if (CXXMethodDecl *cxx_method =
- llvm::dyn_cast<clang::CXXMethodDecl>(decl_ctx)) {
- if (is_instance_method_ptr)
- *is_instance_method_ptr = cxx_method->isInstance();
- if (language_ptr)
- *language_ptr = eLanguageTypeC_plus_plus;
- if (language_object_name_ptr)
- language_object_name_ptr->SetCString("this");
- return true;
- } else if (clang::FunctionDecl *function_decl =
- llvm::dyn_cast<clang::FunctionDecl>(decl_ctx)) {
- ClangASTMetadata *metadata = GetMetadata(function_decl);
- if (metadata && metadata->HasObjectPtr()) {
- if (is_instance_method_ptr)
- *is_instance_method_ptr = true;
- if (language_ptr)
- *language_ptr = eLanguageTypeObjC;
- if (language_object_name_ptr)
- language_object_name_ptr->SetCString(metadata->GetObjectPtrName());
- return true;
- }
- }
- }
- return false;
-}
-
-bool TypeSystemClang::DeclContextIsContainedInLookup(
- void *opaque_decl_ctx, void *other_opaque_decl_ctx) {
- auto *decl_ctx = (clang::DeclContext *)opaque_decl_ctx;
- auto *other = (clang::DeclContext *)other_opaque_decl_ctx;
-
- do {
- // A decl context always includes its own contents in its lookup.
- if (decl_ctx == other)
- return true;
-
- // If we have an inline namespace, then the lookup of the parent context
- // also includes the inline namespace contents.
- } while (other->isInlineNamespace() && (other = other->getParent()));
-
- return false;
-}
-
-static bool IsClangDeclContext(const CompilerDeclContext &dc) {
- return dc.IsValid() && isa<TypeSystemClang>(dc.GetTypeSystem());
-}
-
-clang::DeclContext *
-TypeSystemClang::DeclContextGetAsDeclContext(const CompilerDeclContext &dc) {
- if (IsClangDeclContext(dc))
- return (clang::DeclContext *)dc.GetOpaqueDeclContext();
- return nullptr;
-}
-
-ObjCMethodDecl *
-TypeSystemClang::DeclContextGetAsObjCMethodDecl(const CompilerDeclContext &dc) {
- if (IsClangDeclContext(dc))
- return llvm::dyn_cast<clang::ObjCMethodDecl>(
- (clang::DeclContext *)dc.GetOpaqueDeclContext());
- return nullptr;
-}
-
-CXXMethodDecl *
-TypeSystemClang::DeclContextGetAsCXXMethodDecl(const CompilerDeclContext &dc) {
- if (IsClangDeclContext(dc))
- return llvm::dyn_cast<clang::CXXMethodDecl>(
- (clang::DeclContext *)dc.GetOpaqueDeclContext());
- return nullptr;
-}
-
-clang::FunctionDecl *
-TypeSystemClang::DeclContextGetAsFunctionDecl(const CompilerDeclContext &dc) {
- if (IsClangDeclContext(dc))
- return llvm::dyn_cast<clang::FunctionDecl>(
- (clang::DeclContext *)dc.GetOpaqueDeclContext());
- return nullptr;
-}
-
-clang::NamespaceDecl *
-TypeSystemClang::DeclContextGetAsNamespaceDecl(const CompilerDeclContext &dc) {
- if (IsClangDeclContext(dc))
- return llvm::dyn_cast<clang::NamespaceDecl>(
- (clang::DeclContext *)dc.GetOpaqueDeclContext());
- return nullptr;
-}
-
-ClangASTMetadata *
-TypeSystemClang::DeclContextGetMetaData(const CompilerDeclContext &dc,
- const Decl *object) {
- TypeSystemClang *ast = llvm::cast<TypeSystemClang>(dc.GetTypeSystem());
- return ast->GetMetadata(object);
-}
-
-clang::ASTContext *
-TypeSystemClang::DeclContextGetTypeSystemClang(const CompilerDeclContext &dc) {
- TypeSystemClang *ast =
- llvm::dyn_cast_or_null<TypeSystemClang>(dc.GetTypeSystem());
- if (ast)
- return &ast->getASTContext();
- return nullptr;
-}
-
-TypeSystemClangForExpressions::TypeSystemClangForExpressions(
- Target &target, llvm::Triple triple)
- : TypeSystemClang("scratch ASTContext", triple),
- m_target_wp(target.shared_from_this()),
- m_persistent_variables(new ClangPersistentVariables) {
- m_scratch_ast_source_up.reset(new ClangASTSource(
- target.shared_from_this(), m_persistent_variables->GetClangASTImporter()));
- m_scratch_ast_source_up->InstallASTContext(*this);
- llvm::IntrusiveRefCntPtr<clang::ExternalASTSource> proxy_ast_source(
- m_scratch_ast_source_up->CreateProxy());
- SetExternalSource(proxy_ast_source);
-}
-
-void TypeSystemClangForExpressions::Finalize() {
- TypeSystemClang::Finalize();
- m_scratch_ast_source_up.reset();
-}
-
-UserExpression *TypeSystemClangForExpressions::GetUserExpression(
- llvm::StringRef expr, llvm::StringRef prefix, lldb::LanguageType language,
- Expression::ResultType desired_type,
- const EvaluateExpressionOptions &options,
- ValueObject *ctx_obj) {
- TargetSP target_sp = m_target_wp.lock();
- if (!target_sp)
- return nullptr;
-
- return new ClangUserExpression(*target_sp.get(), expr, prefix, language,
- desired_type, options, ctx_obj);
-}
-
-FunctionCaller *TypeSystemClangForExpressions::GetFunctionCaller(
- const CompilerType &return_type, const Address &function_address,
- const ValueList &arg_value_list, const char *name) {
- TargetSP target_sp = m_target_wp.lock();
- if (!target_sp)
- return nullptr;
-
- Process *process = target_sp->GetProcessSP().get();
- if (!process)
- return nullptr;
-
- return new ClangFunctionCaller(*process, return_type, function_address,
- arg_value_list, name);
-}
-
-UtilityFunction *
-TypeSystemClangForExpressions::GetUtilityFunction(const char *text,
- const char *name) {
- TargetSP target_sp = m_target_wp.lock();
- if (!target_sp)
- return nullptr;
-
- return new ClangUtilityFunction(*target_sp.get(), text, name);
-}
-
-PersistentExpressionState *
-TypeSystemClangForExpressions::GetPersistentExpressionState() {
- return m_persistent_variables.get();
-}
#include "lldb/Host/Host.h"
#include "lldb/Initialization/SystemInitializerCommon.h"
#include "lldb/Interpreter/CommandInterpreter.h"
-#include "lldb/Symbol/TypeSystemClang.h"
#include "lldb/Utility/Timer.h"
#include "Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.h"
#include "Plugins/SymbolVendor/ELF/SymbolVendorELF.h"
#include "Plugins/SymbolVendor/wasm/SymbolVendorWasm.h"
#include "Plugins/SystemRuntime/MacOSX/SystemRuntimeMacOSX.h"
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
#include "Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.h"
#include "Plugins/UnwindAssembly/x86/UnwindAssembly-x86.h"
#include "SystemInitializerTest.h"
#include "Plugins/SymbolFile/DWARF/SymbolFileDWARF.h"
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
#include "lldb/Breakpoint/BreakpointLocation.h"
#include "lldb/Core/Debugger.h"
#include "lldb/Core/Module.h"
#include "lldb/Initialization/SystemLifetimeManager.h"
#include "lldb/Interpreter/CommandInterpreter.h"
#include "lldb/Interpreter/CommandReturnObject.h"
-#include "lldb/Symbol/TypeSystemClang.h"
#include "lldb/Symbol/CompileUnit.h"
#include "lldb/Symbol/LineTable.h"
#include "lldb/Symbol/SymbolFile.h"
LINK_LIBS
lldbCore
lldbPluginExpressionParserClang
+ lldbPluginTypeSystemClang
lldbUtility
lldbUtilityHelpers
LLVMTestingSupport
//===----------------------------------------------------------------------===//
#include "Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h"
+#include "Plugins/ExpressionParser/Clang/ClangUtil.h"
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
#include "TestingSupport/SubsystemRAII.h"
#include "TestingSupport/Symbol/ClangTestUtils.h"
#include "lldb/Host/FileSystem.h"
#include "lldb/Host/HostInfo.h"
-#include "lldb/Symbol/TypeSystemClang.h"
-#include "lldb/Symbol/ClangUtil.h"
#include "lldb/lldb-defines.h"
#include "gtest/gtest.h"
lldbPluginObjectFileMachO
lldbPluginSymbolFileDWARF
lldbPluginSymbolFileSymtab
+ lldbPluginTypeSystemClang
LLVMTestingSupport
)
#include "gtest/gtest.h"
+#include "Plugins/ExpressionParser/Clang/ClangASTImporter.h"
+#include "Plugins/ExpressionParser/Clang/ClangASTMetadata.h"
+#include "Plugins/ExpressionParser/Clang/ClangUtil.h"
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
#include "TestingSupport/SubsystemRAII.h"
#include "TestingSupport/Symbol/ClangTestUtils.h"
#include "lldb/Host/FileSystem.h"
#include "lldb/Host/HostInfo.h"
-#include "lldb/Symbol/TypeSystemClang.h"
-#include "lldb/Symbol/ClangASTImporter.h"
-#include "lldb/Symbol/ClangASTMetadata.h"
-#include "lldb/Symbol/ClangUtil.h"
#include "lldb/Symbol/Declaration.h"
#include "clang/AST/DeclCXX.h"
#include "Plugins/ObjectFile/Mach-O/ObjectFileMachO.h"
#include "Plugins/SymbolFile/DWARF/DWARFASTParserClang.h"
#include "Plugins/SymbolFile/DWARF/SymbolFileDWARF.h"
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
#include "TestingSupport/SubsystemRAII.h"
#include "TestingSupport/TestUtilities.h"
-#include "lldb/Symbol/TypeSystemClang.h"
#include "lldb/Core/Module.h"
#include "lldb/Host/FileSystem.h"
//
//===----------------------------------------------------------------------===//
+#include "Plugins/ExpressionParser/Clang/ClangUtil.h"
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
#include "TestingSupport/SubsystemRAII.h"
#include "TestingSupport/Symbol/ClangTestUtils.h"
#include "lldb/Host/FileSystem.h"
#include "lldb/Host/HostInfo.h"
-#include "lldb/Symbol/TypeSystemClang.h"
-#include "lldb/Symbol/ClangUtil.h"
#include "lldb/Symbol/Declaration.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/ExprCXX.h"
lldbPluginObjectFilePECOFF
lldbPluginSymbolFileDWARF
lldbPluginSymbolFilePDB
+ lldbPluginTypeSystemClang
lldbUtilityHelpers
LINK_COMPONENTS
Support
#include "Plugins/SymbolFile/DWARF/DWARFDebugAbbrev.h"
#include "Plugins/SymbolFile/DWARF/SymbolFileDWARF.h"
#include "Plugins/SymbolFile/PDB/SymbolFilePDB.h"
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
#include "TestingSupport/SubsystemRAII.h"
#include "TestingSupport/TestUtilities.h"
#include "lldb/Core/Address.h"
#include "lldb/Core/ModuleSpec.h"
#include "lldb/Host/FileSystem.h"
#include "lldb/Host/HostInfo.h"
-#include "lldb/Symbol/TypeSystemClang.h"
#include "lldb/Symbol/CompileUnit.h"
#include "lldb/Symbol/LineTable.h"
#include "lldb/Utility/ArchSpec.h"
#include "lldb/Utility/FileSpec.h"
#include "lldb/Utility/StreamString.h"
-
-
using namespace lldb;
using namespace lldb_private;
lldbPluginObjectFilePECOFF
lldbPluginSymbolFileDWARF
lldbPluginSymbolFilePDB
+ lldbPluginTypeSystemClang
lldbUtilityHelpers
LLVMTestingSupport
LINK_COMPONENTS
#include "Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.h"
#include "Plugins/SymbolFile/DWARF/SymbolFileDWARF.h"
#include "Plugins/SymbolFile/PDB/SymbolFilePDB.h"
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
#include "TestingSupport/TestUtilities.h"
#include "lldb/Core/Address.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/ModuleSpec.h"
#include "lldb/Host/FileSystem.h"
#include "lldb/Host/HostInfo.h"
-#include "lldb/Symbol/TypeSystemClang.h"
#include "lldb/Symbol/CompileUnit.h"
#include "lldb/Symbol/LineTable.h"
#include "lldb/Symbol/TypeMap.h"
#ifndef LLDB_UNITTESTS_TESTINGSUPPORT_SYMBOL_CLANGTESTUTILS_H
#define LLDB_UNITTESTS_TESTINGSUPPORT_SYMBOL_CLANGTESTUTILS_H
+#include "Plugins/ExpressionParser/Clang/ClangUtil.h"
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
#include "lldb/Host/HostInfo.h"
-#include "lldb/Symbol/TypeSystemClang.h"
-#include "lldb/Symbol/ClangUtil.h"
namespace lldb_private {
namespace clang_utils {