text: //===-- ClangASTContext.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_ClangASTContext_h_
  #define liblldb_ClangASTContext_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/ExternalASTMerger.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/Symbol/CompilerType.h"
  #include "lldb/Symbol/TypeSystem.h"
  #include "lldb/Utility/ConstString.h"
  #include "lldb/lldb-enumerations.h"
  
  class DWARFASTParserClang;
  class PDBASTParser;
  
  namespace lldb_private {
  
  class Declaration;
  
  class ClangASTContext : public TypeSystem {
  public:
    typedef void (*CompleteTagDeclCallback)(void *baton, clang::TagDecl *);
    typedef void (*CompleteObjCInterfaceDeclCallback)(void *baton,
                                                      clang::ObjCInterfaceDecl *);
  
    // llvm casting support
    static bool classof(const TypeSystem *ts) {
      return ts->getKind() == TypeSystem::eKindClang;
    }
  
    // Constructors and Destructors
    ClangASTContext(const char *triple = nullptr);
  
    ClangASTContext(clang::ASTContext *ast_ctx);
  
    ~ClangASTContext() 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,
                                             const char *compiler_options);
  
    static LanguageSet GetSupportedLanguagesForTypes();
    static LanguageSet GetSupportedLanguagesForExpressions();
  
    static void Initialize();
  
    static void Terminate();
  
    static ClangASTContext *GetASTContext(clang::ASTContext *ast_ctx);
  
    clang::ASTContext *getASTContext();
  
    void setASTContext(clang::ASTContext *ast_ctx);
  
    clang::Builtin::Context *getBuiltinContext();
  
    clang::IdentifierTable *getIdentifierTable();
  
    clang::LangOptions *getLanguageOptions();
  
    clang::SelectorTable *getSelectorTable();
  
    clang::FileManager *getFileManager();
  
    clang::SourceManager *getSourceManager();
  
    clang::DiagnosticsEngine *getDiagnosticsEngine();
  
    clang::DiagnosticConsumer *getDiagnosticConsumer();
  
    clang::MangleContext *getMangleContext();
  
    std::shared_ptr<clang::TargetOptions> &getTargetOptions();
  
    clang::TargetInfo *getTargetInfo();
  
    void setSema(clang::Sema *s);
    clang::Sema *getSema() { return m_sema; }
  
    void Clear();
  
    const char *GetTargetTriple();
  
    void SetTargetTriple(const char *target_triple);
  
    void SetArchitecture(const ArchSpec &arch);
  
    bool HasExternalSource();
  
    void SetExternalSource(
        llvm::IntrusiveRefCntPtr<clang::ExternalASTSource> &ast_source_up);
  
    void RemoveExternalSource();
  
    bool GetCompleteDecl(clang::Decl *decl) {
      return ClangASTContext::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 void *object, lldb::user_id_t user_id);
  
    void SetMetadata(const void *object, ClangASTMetadata &meta_data) {
      SetMetadata(getASTContext(), object, meta_data);
    }
  
    static void SetMetadata(clang::ASTContext *ast, const void *object,
                            ClangASTMetadata &meta_data);
  
    ClangASTMetadata *GetMetadata(const void *object) {
      return GetMetadata(getASTContext(), object);
    }
  
    static ClangASTMetadata *GetMetadata(clang::ASTContext *ast,
                                         const void *object);
  
    // Basic Types
    CompilerType GetBuiltinTypeForEncodingAndBitSize(lldb::Encoding encoding,
                                                     size_t bit_size) override;
  
    static CompilerType GetBuiltinTypeForEncodingAndBitSize(
        clang::ASTContext *ast, lldb::Encoding encoding, uint32_t bit_size);
  
    CompilerType GetBasicType(lldb::BasicType type);
  
    static CompilerType GetBasicType(clang::ASTContext *ast,
                                     lldb::BasicType type);
  
    static CompilerType GetBasicType(clang::ASTContext *ast,
                                     ConstString name);
  
    static lldb::BasicType GetBasicTypeEnumeration(ConstString name);
  
    CompilerType GetBuiltinTypeForDWARFEncodingAndBitSize(const char *type_name,
                                                          uint32_t dw_ate,
                                                          uint32_t bit_size);
  
    CompilerType GetCStringType(bool is_const);
  
    static CompilerType GetUnknownAnyType(clang::ASTContext *ast);
  
    CompilerType GetUnknownAnyType() {
      return ClangASTContext::GetUnknownAnyType(getASTContext());
    }
  
    static clang::DeclContext *GetDeclContextForType(clang::QualType type);
  
    static clang::DeclContext *GetDeclContextForType(const CompilerType &type);
  
    uint32_t GetPointerByteSize() override;
  
    static clang::DeclContext *GetTranslationUnitDecl(clang::ASTContext *ast);
  
    clang::DeclContext *GetTranslationUnitDecl() {
      return GetTranslationUnitDecl(getASTContext());
    }
  
    // Copy "src" into this ClangASTContext.
    CompilerType CopyType(const CompilerType &src);
  
    static clang::Decl *CopyDecl(clang::ASTContext *dest_context,
                                 clang::ASTContext *source_context,
                                 clang::Decl *source_decl);
  
    static bool AreTypesSame(CompilerType type1, CompilerType type2,
                             bool ignore_qualifiers = false);
  
    static CompilerType GetTypeForDecl(clang::NamedDecl *decl);
  
    static CompilerType GetTypeForDecl(clang::TagDecl *decl);
  
    static 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 (ast) {
          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);
  
    static uint32_t
    GetIndexForRecordBase(const clang::RecordDecl *record_decl,
                          const clang::CXXBaseSpecifier *base_spec,
                          bool omit_empty_base_classes);
  
    CompilerType CreateRecordType(clang::DeclContext *decl_ctx,
                                  lldb::AccessType access_type, const char *name,
                                  int kind, lldb::LanguageType language,
                                  ClangASTMetadata *metadata = nullptr);
  
    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::CXXMethodDecl *cxx_method_decl);
  
    static clang::DeclContext *
    GetAsDeclContext(clang::ObjCMethodDecl *objc_method_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 FieldIsBitfield(clang::ASTContext *ast, clang::FieldDecl *field,
                                uint32_t &bitfield_bit_size);
  
    static bool RecordHasFields(const clang::RecordDecl *record_decl);
  
    CompilerType CreateObjCClass(const char *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 ClangASTContext::eTypeXXX
    // enumerations
  
    // Namespace Declarations
  
    clang::NamespaceDecl *
    GetUniqueNamespaceDeclaration(const char *name, clang::DeclContext *decl_ctx,
                                  bool is_inline = false);
  
    static clang::NamespaceDecl *
    GetUniqueNamespaceDeclaration(clang::ASTContext *ast, 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);
  
    static CompilerType CreateFunctionType(clang::ASTContext *ast,
                                           const CompilerType &result_type,
                                           const CompilerType *args,
                                           unsigned num_args, bool is_variadic,
                                           unsigned type_quals,
                                           clang::CallingConv cc);
  
    static CompilerType CreateFunctionType(clang::ASTContext *ast,
                                           const CompilerType &result_type,
                                           const CompilerType *args,
                                           unsigned num_args, bool is_variadic,
                                           unsigned type_quals) {
      return ClangASTContext::CreateFunctionType(
          ast, result_type, args, num_args, is_variadic, type_quals, clang::CC_C);
    }
  
    CompilerType CreateFunctionType(const CompilerType &result_type,
                                    const CompilerType *args, unsigned num_args,
                                    bool is_variadic, unsigned type_quals) {
      return ClangASTContext::CreateFunctionType(
          getASTContext(), result_type, args, num_args, is_variadic, type_quals);
    }
  
    CompilerType CreateFunctionType(const CompilerType &result_type,
                                    const CompilerType *args, unsigned num_args,
                                    bool is_variadic, unsigned type_quals,
                                    clang::CallingConv cc) {
      return ClangASTContext::CreateFunctionType(getASTContext(), result_type,
                                                 args, num_args, is_variadic,
                                                 type_quals, cc);
    }
  
    clang::ParmVarDecl *CreateParameterDeclaration(clang::DeclContext *decl_ctx,
                                                   const char *name,
                                                   const CompilerType &param_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
  
    static CompilerType GetIntTypeFromBitSize(clang::ASTContext *ast,
                                              size_t bit_size, bool is_signed);
  
    CompilerType GetPointerSizedIntType(bool is_signed) {
      return GetPointerSizedIntType(getASTContext(), is_signed);
    }
  
    static CompilerType GetPointerSizedIntType(clang::ASTContext *ast,
                                               bool is_signed);
  
    // Floating point functions
  
    static CompilerType GetFloatTypeFromBitSize(clang::ASTContext *ast,
                                                size_t bit_size);
  
    // TypeSystem methods
    DWARFASTParser *GetDWARFParser() override;
    PDBASTParser *GetPDBParser() override;
  
    // ClangASTContext callbacks for external source lookups.
    static void CompleteTagDecl(void *baton, clang::TagDecl *);
  
    static void CompleteObjCInterfaceDecl(void *baton,
                                          clang::ObjCInterfaceDecl *);
  
    static bool LayoutRecordType(
        void *baton, 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);
  
    // 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
  
    std::vector<CompilerDecl>
    DeclContextFindDeclByName(void *opaque_decl_ctx, ConstString name,
                              const bool ignore_using_decls) override;
  
    bool DeclContextIsStructUnionOrClass(void *opaque_decl_ctx) 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 void *object);
  
    static clang::ASTContext *
    DeclContextGetClangASTContext(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,
                               bool check_swift) 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 bool GetCXXClassName(const CompilerType &type,
                                std::string &class_name);
  
    static bool GetObjCClassName(const CompilerType &type,
                                 std::string &class_name);
  
    // 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 GetInstanceType(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
    GetLValueReferenceType(lldb::opaque_compiler_type_t type) 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
    GetRValueReferenceType(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;
  
    CompilerType GetUnboundType(lldb::opaque_compiler_type_t type) override;
  
    static CompilerType RemoveFastQualifiers(const CompilerType &type);
  
    // Create related types using the current type's AST
    CompilerType GetBasicTypeFromAST(lldb::BasicType basic_type) override;
  
    // Exploring the type
  
    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;
  
    llvm::Optional<uint64_t>
    GetByteStride(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, const char *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);
  
    static bool SetHasExternalStorage(lldb::opaque_compiler_type_t type,
                                      bool has_extern);
  
    static bool GetHasExternalStorage(const CompilerType &type);
    // 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);
  
    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,
                       bool is_base_class) 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);
  
    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 ClangASTContext::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);
    
    virtual const clang::ExternalASTMerger::OriginMap &GetOriginMap() {
      return m_origins;
    }
  protected:
    const clang::ClassTemplateSpecializationDecl *
    GetAsTemplateSpecialization(lldb::opaque_compiler_type_t type);
  
    // Classes that inherit from ClangASTContext can see and modify these
    // clang-format off
      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<ClangASTSource>                 m_scratch_ast_source_up;
      std::unique_ptr<clang::MangleContext>           m_mangle_ctx_up;
      CompleteTagDeclCallback                         m_callback_tag_decl;
      CompleteObjCInterfaceDeclCallback               m_callback_objc_decl;
      void *                                          m_callback_baton;
      clang::ExternalASTMerger::OriginMap             m_origins;
      uint32_t                                        m_pointer_byte_size;
      bool                                            m_ast_owned;
      /// 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;
    // clang-format on
  private:
    // For ClangASTContext only
    ClangASTContext(const ClangASTContext &);
    const ClangASTContext &operator=(const ClangASTContext &);
  };
  
  class ClangASTContextForExpressions : public ClangASTContext {
  public:
    ClangASTContextForExpressions(Target &target);
  
    ~ClangASTContextForExpressions() override = default;
  
    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;
    
    clang::ExternalASTMerger &GetMergerUnchecked();
    
    const clang::ExternalASTMerger::OriginMap &GetOriginMap() override {
      return GetMergerUnchecked().GetOrigins();
    }
  private:
    lldb::TargetWP m_target_wp;
    lldb::ClangPersistentVariablesUP m_persistent_variables; ///< These are the
                                                             ///persistent
                                                             ///variables
                                                             ///associated with
                                                             ///this process for
                                                             ///the expression
                                                             ///parser.
  };
  
  } // namespace lldb_private
  
  #endif // liblldb_ClangASTContext_h_
  