blob: f3a07397ec440a5273e7ef58fe7d089f5c96f449 [file] [log] [blame]
//===-- 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 LLDB_SOURCE_PLUGINS_TYPESYSTEM_CLANG_TYPESYSTEMCLANG_H
#define LLDB_SOURCE_PLUGINS_TYPESYSTEM_CLANG_TYPESYSTEMCLANG_H
#include <cstdint>
#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 "clang/Basic/TargetInfo.h"
#include "llvm/ADT/APSInt.h"
#include "llvm/ADT/SmallVector.h"
#include "Plugins/ExpressionParser/Clang/ClangPersistentVariables.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/Flags.h"
#include "lldb/Utility/Log.h"
#include "lldb/Utility/Logging.h"
#include "lldb/lldb-enumerations.h"
class DWARFASTParserClang;
class PDBASTParser;
namespace clang {
class FileManager;
class HeaderSearch;
class ModuleMap;
} // namespace clang
namespace lldb_private {
class ClangASTMetadata;
class ClangASTSource;
class Declaration;
/// A Clang module ID.
class OptionalClangModuleID {
unsigned m_id = 0;
public:
OptionalClangModuleID() = default;
explicit OptionalClangModuleID(unsigned id) : m_id(id) {}
bool HasValue() const { return m_id != 0; }
unsigned GetValue() const { return m_id; }
};
/// The implementation of lldb::Type's m_payload field for TypeSystemClang.
class TypePayloadClang {
/// The Layout is as follows:
/// \verbatim
/// bit 0..30 ... Owning Module ID.
/// bit 31 ...... IsCompleteObjCClass.
/// \endverbatim
Type::Payload m_payload = 0;
public:
TypePayloadClang() = default;
explicit TypePayloadClang(OptionalClangModuleID owning_module,
bool is_complete_objc_class = false);
explicit TypePayloadClang(uint32_t opaque_payload) : m_payload(opaque_payload) {}
operator Type::Payload() { return m_payload; }
static constexpr unsigned ObjCClassBit = 1 << 31;
bool IsCompleteObjCClass() { return Flags(m_payload).Test(ObjCClassBit); }
void SetIsCompleteObjCClass(bool is_complete_objc_class) {
m_payload = is_complete_objc_class ? Flags(m_payload).Set(ObjCClassBit)
: Flags(m_payload).Clear(ObjCClassBit);
}
OptionalClangModuleID GetOwningModule() {
return OptionalClangModuleID(Flags(m_payload).Clear(ObjCClassBit));
}
void SetOwningModule(OptionalClangModuleID id);
/// \}
};
/// A TypeSystem implementation based on Clang.
///
/// This class uses a single clang::ASTContext as the backend for storing
/// its types and declarations. Every clang::ASTContext should also just have
/// a single associated TypeSystemClang instance that manages it.
///
/// The clang::ASTContext instance can either be created by TypeSystemClang
/// itself or it can adopt an existing clang::ASTContext (for example, when
/// it is necessary to provide a TypeSystem interface for an existing
/// clang::ASTContext that was created by clang::CompilerInstance).
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
llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); }
static llvm::StringRef GetPluginNameStatic() { return "clang"; }
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);
/// 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; }
/// Returns the clang::ASTContext instance managed by this TypeSystemClang.
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.begin();
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);
/// Synthesize a clang::Module and return its ID or a default-constructed ID.
OptionalClangModuleID GetOrCreateClangModule(llvm::StringRef name,
OptionalClangModuleID parent,
bool is_framework = false,
bool is_explicit = false);
CompilerType CreateRecordType(clang::DeclContext *decl_ctx,
OptionalClangModuleID owning_module,
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 {
// Having a pack name but no packed args doesn't make sense, so mark
// these template parameters as invalid.
if (pack_name && !packed_args)
return false;
return args.size() == names.size() &&
(!packed_args || !packed_args->packed_args);
}
bool hasParameterPack() const { return static_cast<bool>(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, OptionalClangModuleID owning_module,
clang::FunctionDecl *func_decl, const TemplateParameterInfos &infos);
void CreateFunctionTemplateSpecializationInfo(
clang::FunctionDecl *func_decl, clang::FunctionTemplateDecl *Template,
const TemplateParameterInfos &infos);
clang::ClassTemplateDecl *CreateClassTemplateDecl(
clang::DeclContext *decl_ctx, OptionalClangModuleID owning_module,
lldb::AccessType access_type, llvm::StringRef class_name, int kind,
const TemplateParameterInfos &infos);
clang::TemplateTemplateParmDecl *
CreateTemplateTemplateParmDecl(const char *template_name);
clang::ClassTemplateSpecializationDecl *CreateClassTemplateSpecializationDecl(
clang::DeclContext *decl_ctx, OptionalClangModuleID owning_module,
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,
OptionalClangModuleID owning_module,
bool isForwardDecl, bool isInternal,
ClangASTMetadata *metadata = nullptr);
// Returns a mask containing bits from the TypeSystemClang::eTypeXXX
// enumerations
// Namespace Declarations
clang::NamespaceDecl *
GetUniqueNamespaceDeclaration(const char *name, clang::DeclContext *decl_ctx,
OptionalClangModuleID owning_module,
bool is_inline = false);
// Function Types
clang::FunctionDecl *CreateFunctionDeclaration(
clang::DeclContext *decl_ctx, OptionalClangModuleID owning_module,
llvm::StringRef name, const CompilerType &function_Type,
clang::StorageClass 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 = clang::CC_C);
clang::ParmVarDecl *
CreateParameterDeclaration(clang::DeclContext *decl_ctx,
OptionalClangModuleID owning_module,
const char *name, const CompilerType &param_type,
int storage, bool add_decl = false);
void SetFunctionParameters(clang::FunctionDecl *function_decl,
llvm::ArrayRef<clang::ParmVarDecl *> 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(llvm::StringRef name,
clang::DeclContext *decl_ctx,
OptionalClangModuleID owning_module,
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);
/// Set the owning module for \p decl.
static void SetOwningModule(clang::Decl *decl,
OptionalClangModuleID owning_module);
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
#ifndef NDEBUG
bool Verify(lldb::opaque_compiler_type_t type) override;
#endif
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) 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;
bool IsScopedEnumerationType(lldb::opaque_compiler_type_t type) 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;
ConstString GetDisplayTypeName(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
CompilerType GetArrayElementType(lldb::opaque_compiler_type_t type,
ExecutionContextScope *exe_scope) 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;
CompilerType
GetEnumerationIntegerType(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;
/// Using the current type, create a new typedef to that type using
/// "typedef_name" as the name and "decl_ctx" as the decl context.
/// \param opaque_payload is an opaque TypePayloadClang.
CompilerType CreateTypedef(lldb::opaque_compiler_type_t type,
const char *name,
const CompilerDeclContext &decl_ctx,
uint32_t opaque_payload) 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);
/// Initializes a variable with an integer value.
/// \param var The variable to initialize. Must not already have an
/// initializer and must have an integer or enum type.
/// \param init_value The integer value that the variable should be
/// initialized to. Has to match the bit width of the
/// variable type.
static void SetIntegerInitializerForVariable(clang::VarDecl *var,
const llvm::APInt &init_value);
/// Initializes a variable with a floating point value.
/// \param var The variable to initialize. Must not already have an
/// initializer and must have a floating point type.
/// \param init_value The float value that the variable should be
/// initialized to.
static void
SetFloatingInitializerForVariable(clang::VarDecl *var,
const llvm::APFloat &init_value);
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);
/// Returns the underlying integer type for an enum type. If the given type
/// is invalid or not an enum-type, the function returns an invalid
/// CompilerType.
CompilerType GetEnumerationIntegerType(CompilerType 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
/// \see lldb_private::TypeSystem::Dump
void Dump(llvm::raw_ostream &output) override;
/// 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,
lldb::DescriptionLevel level = lldb::eDescriptionLevelFull) override;
void DumpTypeDescription(
lldb::opaque_compiler_type_t type, Stream *s,
lldb::DescriptionLevel level = lldb::eDescriptionLevelFull) 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, OptionalClangModuleID owning_module,
lldb::AccessType access_type, const char *parent_name, int tag_decl_kind,
const TypeSystemClang::TemplateParameterInfos &template_param_infos);
clang::BlockDecl *CreateBlockDeclaration(clang::DeclContext *ctx,
OptionalClangModuleID owning_module);
clang::UsingDirectiveDecl *
CreateUsingDirectiveDeclaration(clang::DeclContext *decl_ctx,
OptionalClangModuleID owning_module,
clang::NamespaceDecl *ns_decl);
clang::UsingDecl *CreateUsingDeclaration(clang::DeclContext *current_decl_ctx,
OptionalClangModuleID owning_module,
clang::NamedDecl *target);
clang::VarDecl *CreateVariableDeclaration(clang::DeclContext *decl_context,
OptionalClangModuleID owning_module,
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(llvm::StringRef name,
const CompilerType &function_clang_type);
clang::LangOptions *GetLangOpts() const {
return m_language_options_up.get();
}
clang::SourceManager *GetSourceMgr() const {
return m_source_manager_up.get();
}
private:
/// Returns the PrintingPolicy used when generating the internal type names.
/// These type names are mostly used for the formatter selection.
clang::PrintingPolicy GetTypePrintingPolicy();
/// Returns the internal type name for the given NamedDecl using the
/// type printing policy.
std::string GetTypeNameForDecl(const clang::NamedDecl *named_decl);
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<clang::HeaderSearch> m_header_search_up;
std::unique_ptr<clang::ModuleMap> m_module_map_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);
};
/// The TypeSystemClang instance used for the scratch ASTContext in a
/// lldb::Target.
class ScratchTypeSystemClang : public TypeSystemClang {
/// LLVM RTTI support
static char ID;
public:
ScratchTypeSystemClang(Target &target, llvm::Triple triple);
~ScratchTypeSystemClang() override = default;
void Finalize() override;
/// The different kinds of isolated ASTs within the scratch TypeSystem.
///
/// These ASTs are isolated from the main scratch AST and are each
/// dedicated to a special language option/feature that makes the contained
/// AST nodes incompatible with other AST nodes.
enum IsolatedASTKind {
/// The isolated AST for declarations/types from expressions that imported
/// type information from a C++ module. The templates from a C++ module
/// often conflict with the templates we generate from debug information,
/// so we put these types in their own AST.
CppModules
};
/// Alias for requesting the default scratch TypeSystemClang in GetForTarget.
// This isn't constexpr as gtest/llvm::Optional comparison logic is trying
// to get the address of this for pretty-printing.
static const llvm::NoneType DefaultAST;
/// Infers the appropriate sub-AST from Clang's LangOptions.
static llvm::Optional<IsolatedASTKind>
InferIsolatedASTKindFromLangOpts(const clang::LangOptions &l) {
// If modules are activated we want the dedicated C++ module AST.
// See IsolatedASTKind::CppModules for more info.
if (l.Modules)
return IsolatedASTKind::CppModules;
return DefaultAST;
}
/// Returns the scratch TypeSystemClang for the given target.
/// \param target The Target which scratch TypeSystemClang should be returned.
/// \param ast_kind Allows requesting a specific sub-AST instead of the
/// default scratch AST. See also `IsolatedASTKind`.
/// \param create_on_demand If the scratch TypeSystemClang instance can be
/// created by this call if it doesn't exist yet. If it doesn't exist yet and
/// this parameter is false, this function returns a nullptr.
/// \return The scratch type system of the target or a nullptr in case an
/// error occurred.
static TypeSystemClang *
GetForTarget(Target &target,
llvm::Optional<IsolatedASTKind> ast_kind = DefaultAST,
bool create_on_demand = true);
/// Returns the scratch TypeSystemClang for the given target. The returned
/// TypeSystemClang will be the scratch AST or a sub-AST, depending on which
/// fits best to the passed LangOptions.
/// \param target The Target which scratch TypeSystemClang should be returned.
/// \param lang_opts The LangOptions of a clang ASTContext that the caller
/// wants to export type information from. This is used to
/// find the best matching sub-AST that will be returned.
static TypeSystemClang *GetForTarget(Target &target,
const clang::LangOptions &lang_opts) {
return GetForTarget(target, InferIsolatedASTKindFromLangOpts(lang_opts));
}
/// \see lldb_private::TypeSystem::Dump
void Dump(llvm::raw_ostream &output) 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;
std::unique_ptr<UtilityFunction>
CreateUtilityFunction(std::string text, std::string name) override;
PersistentExpressionState *GetPersistentExpressionState() override;
/// Unregisters the given ASTContext as a source from the scratch AST (and
/// all sub-ASTs).
/// \see ClangASTImporter::ForgetSource
void ForgetSource(clang::ASTContext *src_ctx, ClangASTImporter &importer);
// llvm casting support
bool isA(const void *ClassID) const override {
return ClassID == &ID || TypeSystemClang::isA(ClassID);
}
static bool classof(const TypeSystem *ts) { return ts->isA(&ID); }
private:
std::unique_ptr<ClangASTSource> CreateASTSource();
/// Returns the requested sub-AST.
/// Will lazily create the sub-AST if it hasn't been created before.
TypeSystemClang &GetIsolatedAST(IsolatedASTKind feature);
/// The target triple.
/// This was potentially adjusted and might not be identical to the triple
/// of `m_target_wp`.
llvm::Triple m_triple;
lldb::TargetWP m_target_wp;
/// The persistent variables associated with this process for the expression
/// parser.
std::unique_ptr<ClangPersistentVariables> m_persistent_variables;
/// The ExternalASTSource that performs lookups and completes minimally
/// imported types.
std::unique_ptr<ClangASTSource> m_scratch_ast_source_up;
// FIXME: GCC 5.x doesn't support enum as map keys.
typedef int IsolatedASTKey;
/// Map from IsolatedASTKind to their actual TypeSystemClang instance.
/// This map is lazily filled with sub-ASTs and should be accessed via
/// `GetSubAST` (which lazily fills this map).
std::unordered_map<IsolatedASTKey, std::unique_ptr<TypeSystemClang>>
m_isolated_asts;
};
} // namespace lldb_private
#endif // LLDB_SOURCE_PLUGINS_TYPESYSTEM_CLANG_TYPESYSTEMCLANG_H