diff options
Diffstat (limited to 'lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp')
| -rw-r--r-- | lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp | 2255 | 
1 files changed, 2255 insertions, 0 deletions
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp new file mode 100644 index 0000000000000..372c2439ebf0a --- /dev/null +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp @@ -0,0 +1,2255 @@ +//===-- ClangASTSource.cpp ---------------------------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#include "ClangASTSource.h" + +#include "ASTDumper.h" +#include "ClangDeclVendor.h" +#include "ClangModulesDeclVendor.h" + +#include "lldb/Core/Module.h" +#include "lldb/Core/ModuleList.h" +#include "lldb/Symbol/ClangASTContext.h" +#include "lldb/Symbol/ClangUtil.h" +#include "lldb/Symbol/CompilerDeclContext.h" +#include "lldb/Symbol/Function.h" +#include "lldb/Symbol/SymbolFile.h" +#include "lldb/Symbol/TaggedASTType.h" +#include "lldb/Target/Target.h" +#include "lldb/Utility/Log.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/RecordLayout.h" + +#include "Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h" + +#include <memory> +#include <vector> + +using namespace clang; +using namespace lldb_private; + +// Scoped class that will remove an active lexical decl from the set when it +// goes out of scope. +namespace { +class ScopedLexicalDeclEraser { +public: +  ScopedLexicalDeclEraser(std::set<const clang::Decl *> &decls, +                          const clang::Decl *decl) +      : m_active_lexical_decls(decls), m_decl(decl) {} + +  ~ScopedLexicalDeclEraser() { m_active_lexical_decls.erase(m_decl); } + +private: +  std::set<const clang::Decl *> &m_active_lexical_decls; +  const clang::Decl *m_decl; +}; +} + +ClangASTSource::ClangASTSource(const lldb::TargetSP &target) +    : m_import_in_progress(false), m_lookups_enabled(false), m_target(target), +      m_ast_context(nullptr), m_active_lexical_decls(), m_active_lookups() { +  if (!target->GetUseModernTypeLookup()) { +    m_ast_importer_sp = m_target->GetClangASTImporter(); +  } +} + +void ClangASTSource::InstallASTContext(clang::ASTContext &ast_context, +                                       clang::FileManager &file_manager, +                                       bool is_shared_context) { +  m_ast_context = &ast_context; +  m_file_manager = &file_manager; +  if (m_target->GetUseModernTypeLookup()) { +    // Configure the ExternalASTMerger.  The merger needs to be able to import +    // types from any source that we would do lookups in, which includes the +    // persistent AST context as well as the modules and Objective-C runtime +    // AST contexts. + +    lldbassert(!m_merger_up); +    clang::ExternalASTMerger::ImporterTarget target = {ast_context, +                                                       file_manager}; +    std::vector<clang::ExternalASTMerger::ImporterSource> sources; +    for (lldb::ModuleSP module_sp : m_target->GetImages().Modules()) { +      auto type_system_or_err = +          module_sp->GetTypeSystemForLanguage(lldb::eLanguageTypeC); +      if (auto err = type_system_or_err.takeError()) { +        LLDB_LOG_ERROR( +            lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_EXPRESSIONS), +            std::move(err), "Failed to get ClangASTContext"); +      } else if (auto *module_ast_ctx = llvm::cast_or_null<ClangASTContext>( +                     &type_system_or_err.get())) { +        lldbassert(module_ast_ctx->getASTContext()); +        lldbassert(module_ast_ctx->getFileManager()); +        sources.emplace_back(*module_ast_ctx->getASTContext(), +                             *module_ast_ctx->getFileManager(), +                             module_ast_ctx->GetOriginMap()); +      } +    } + +    do { +      lldb::ProcessSP process(m_target->GetProcessSP()); + +      if (!process) +        break; + +      ObjCLanguageRuntime *language_runtime(ObjCLanguageRuntime::Get(*process)); + +      if (!language_runtime) +        break; + +      if (auto *runtime_decl_vendor = llvm::dyn_cast_or_null<ClangDeclVendor>( +              language_runtime->GetDeclVendor())) { +        sources.push_back(runtime_decl_vendor->GetImporterSource()); +      } +    } while (false); + +    do { +      auto *modules_decl_vendor = m_target->GetClangModulesDeclVendor(); + +      if (!modules_decl_vendor) +        break; + +      sources.push_back(modules_decl_vendor->GetImporterSource()); +    } while (false); + +    if (!is_shared_context) { +      // Update the scratch AST context's merger to reflect any new sources we +      // might have come across since the last time an expression was parsed. + +      auto scratch_ast_context = static_cast<ClangASTContextForExpressions*>( +          m_target->GetScratchClangASTContext()); + +      scratch_ast_context->GetMergerUnchecked().AddSources(sources); + +      sources.push_back({*scratch_ast_context->getASTContext(), +                         *scratch_ast_context->getFileManager(), +                         scratch_ast_context->GetOriginMap()}); +    } + +    m_merger_up = +        std::make_unique<clang::ExternalASTMerger>(target, sources); +  } else { +    m_ast_importer_sp->InstallMapCompleter(&ast_context, *this); +  } +} + +ClangASTSource::~ClangASTSource() { +  if (m_ast_importer_sp) +    m_ast_importer_sp->ForgetDestination(m_ast_context); + +  // We are in the process of destruction, don't create clang ast context on +  // demand by passing false to +  // Target::GetScratchClangASTContext(create_on_demand). +  ClangASTContext *scratch_clang_ast_context = +      m_target->GetScratchClangASTContext(false); + +  if (!scratch_clang_ast_context) +    return; + +  clang::ASTContext *scratch_ast_context = +      scratch_clang_ast_context->getASTContext(); + +  if (!scratch_ast_context) +    return; + +  if (m_ast_context != scratch_ast_context && m_ast_importer_sp) +    m_ast_importer_sp->ForgetSource(scratch_ast_context, m_ast_context); +} + +void ClangASTSource::StartTranslationUnit(ASTConsumer *Consumer) { +  if (!m_ast_context) +    return; + +  m_ast_context->getTranslationUnitDecl()->setHasExternalVisibleStorage(); +  m_ast_context->getTranslationUnitDecl()->setHasExternalLexicalStorage(); +} + +// The core lookup interface. +bool ClangASTSource::FindExternalVisibleDeclsByName( +    const DeclContext *decl_ctx, DeclarationName clang_decl_name) { +  if (!m_ast_context) { +    SetNoExternalVisibleDeclsForName(decl_ctx, clang_decl_name); +    return false; +  } + +  if (GetImportInProgress()) { +    SetNoExternalVisibleDeclsForName(decl_ctx, clang_decl_name); +    return false; +  } + +  std::string decl_name(clang_decl_name.getAsString()); + +  //    if (m_decl_map.DoingASTImport ()) +  //      return DeclContext::lookup_result(); +  // +  switch (clang_decl_name.getNameKind()) { +  // Normal identifiers. +  case DeclarationName::Identifier: { +    clang::IdentifierInfo *identifier_info = +        clang_decl_name.getAsIdentifierInfo(); + +    if (!identifier_info || identifier_info->getBuiltinID() != 0) { +      SetNoExternalVisibleDeclsForName(decl_ctx, clang_decl_name); +      return false; +    } +  } break; + +  // Operator names. +  case DeclarationName::CXXOperatorName: +  case DeclarationName::CXXLiteralOperatorName: +    break; + +  // Using directives found in this context. +  // Tell Sema we didn't find any or we'll end up getting asked a *lot*. +  case DeclarationName::CXXUsingDirective: +    SetNoExternalVisibleDeclsForName(decl_ctx, clang_decl_name); +    return false; + +  case DeclarationName::ObjCZeroArgSelector: +  case DeclarationName::ObjCOneArgSelector: +  case DeclarationName::ObjCMultiArgSelector: { +    llvm::SmallVector<NamedDecl *, 1> method_decls; + +    NameSearchContext method_search_context(*this, method_decls, +                                            clang_decl_name, decl_ctx); + +    FindObjCMethodDecls(method_search_context); + +    SetExternalVisibleDeclsForName(decl_ctx, clang_decl_name, method_decls); +    return (method_decls.size() > 0); +  } +  // These aren't possible in the global context. +  case DeclarationName::CXXConstructorName: +  case DeclarationName::CXXDestructorName: +  case DeclarationName::CXXConversionFunctionName: +  case DeclarationName::CXXDeductionGuideName: +    SetNoExternalVisibleDeclsForName(decl_ctx, clang_decl_name); +    return false; +  } + +  if (!GetLookupsEnabled()) { +    // Wait until we see a '$' at the start of a name before we start doing any +    // lookups so we can avoid lookup up all of the builtin types. +    if (!decl_name.empty() && decl_name[0] == '$') { +      SetLookupsEnabled(true); +    } else { +      SetNoExternalVisibleDeclsForName(decl_ctx, clang_decl_name); +      return false; +    } +  } + +  ConstString const_decl_name(decl_name.c_str()); + +  const char *uniqued_const_decl_name = const_decl_name.GetCString(); +  if (m_active_lookups.find(uniqued_const_decl_name) != +      m_active_lookups.end()) { +    // We are currently looking up this name... +    SetNoExternalVisibleDeclsForName(decl_ctx, clang_decl_name); +    return false; +  } +  m_active_lookups.insert(uniqued_const_decl_name); +  //  static uint32_t g_depth = 0; +  //  ++g_depth; +  //  printf("[%5u] FindExternalVisibleDeclsByName() \"%s\"\n", g_depth, +  //  uniqued_const_decl_name); +  llvm::SmallVector<NamedDecl *, 4> name_decls; +  NameSearchContext name_search_context(*this, name_decls, clang_decl_name, +                                        decl_ctx); +  FindExternalVisibleDecls(name_search_context); +  SetExternalVisibleDeclsForName(decl_ctx, clang_decl_name, name_decls); +  //  --g_depth; +  m_active_lookups.erase(uniqued_const_decl_name); +  return (name_decls.size() != 0); +} + +void ClangASTSource::CompleteType(TagDecl *tag_decl) { +  Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); + +  static unsigned int invocation_id = 0; +  unsigned int current_id = invocation_id++; + +  if (log) { +    LLDB_LOGF(log, +              "    CompleteTagDecl[%u] on (ASTContext*)%p Completing " +              "(TagDecl*)%p named %s", +              current_id, static_cast<void *>(m_ast_context), +              static_cast<void *>(tag_decl), tag_decl->getName().str().c_str()); + +    LLDB_LOGF(log, "      CTD[%u] Before:", current_id); +    ASTDumper dumper((Decl *)tag_decl); +    dumper.ToLog(log, "      [CTD] "); +  } + +  auto iter = m_active_lexical_decls.find(tag_decl); +  if (iter != m_active_lexical_decls.end()) +    return; +  m_active_lexical_decls.insert(tag_decl); +  ScopedLexicalDeclEraser eraser(m_active_lexical_decls, tag_decl); + +  if (!m_ast_importer_sp) { +    if (HasMerger()) { +      GetMergerUnchecked().CompleteType(tag_decl); +    } +    return; +  } + +  if (!m_ast_importer_sp->CompleteTagDecl(tag_decl)) { +    // We couldn't complete the type.  Maybe there's a definition somewhere +    // else that can be completed. + +    LLDB_LOGF(log, +              "      CTD[%u] Type could not be completed in the module in " +              "which it was first found.", +              current_id); + +    bool found = false; + +    DeclContext *decl_ctx = tag_decl->getDeclContext(); + +    if (const NamespaceDecl *namespace_context = +            dyn_cast<NamespaceDecl>(decl_ctx)) { +      ClangASTImporter::NamespaceMapSP namespace_map = +          m_ast_importer_sp->GetNamespaceMap(namespace_context); + +      if (log && log->GetVerbose()) +        LLDB_LOGF(log, "      CTD[%u] Inspecting namespace map %p (%d entries)", +                  current_id, static_cast<void *>(namespace_map.get()), +                  static_cast<int>(namespace_map->size())); + +      if (!namespace_map) +        return; + +      for (ClangASTImporter::NamespaceMap::iterator i = namespace_map->begin(), +                                                    e = namespace_map->end(); +           i != e && !found; ++i) { +        LLDB_LOGF(log, "      CTD[%u] Searching namespace %s in module %s", +                  current_id, i->second.GetName().AsCString(), +                  i->first->GetFileSpec().GetFilename().GetCString()); + +        TypeList types; + +        ConstString name(tag_decl->getName().str().c_str()); + +        i->first->FindTypesInNamespace(name, &i->second, UINT32_MAX, types); + +        for (uint32_t ti = 0, te = types.GetSize(); ti != te && !found; ++ti) { +          lldb::TypeSP type = types.GetTypeAtIndex(ti); + +          if (!type) +            continue; + +          CompilerType clang_type(type->GetFullCompilerType()); + +          if (!ClangUtil::IsClangType(clang_type)) +            continue; + +          const TagType *tag_type = +              ClangUtil::GetQualType(clang_type)->getAs<TagType>(); + +          if (!tag_type) +            continue; + +          TagDecl *candidate_tag_decl = +              const_cast<TagDecl *>(tag_type->getDecl()); + +          if (m_ast_importer_sp->CompleteTagDeclWithOrigin(tag_decl, +                                                           candidate_tag_decl)) +            found = true; +        } +      } +    } else { +      TypeList types; + +      ConstString name(tag_decl->getName().str().c_str()); +      CompilerDeclContext namespace_decl; + +      const ModuleList &module_list = m_target->GetImages(); + +      bool exact_match = false; +      llvm::DenseSet<SymbolFile *> searched_symbol_files; +      module_list.FindTypes(nullptr, name, exact_match, UINT32_MAX, +                            searched_symbol_files, types); + +      for (uint32_t ti = 0, te = types.GetSize(); ti != te && !found; ++ti) { +        lldb::TypeSP type = types.GetTypeAtIndex(ti); + +        if (!type) +          continue; + +        CompilerType clang_type(type->GetFullCompilerType()); + +        if (!ClangUtil::IsClangType(clang_type)) +          continue; + +        const TagType *tag_type = +            ClangUtil::GetQualType(clang_type)->getAs<TagType>(); + +        if (!tag_type) +          continue; + +        TagDecl *candidate_tag_decl = +            const_cast<TagDecl *>(tag_type->getDecl()); + +        // We have found a type by basename and we need to make sure the decl +        // contexts are the same before we can try to complete this type with +        // another +        if (!ClangASTContext::DeclsAreEquivalent(tag_decl, candidate_tag_decl)) +          continue; + +        if (m_ast_importer_sp->CompleteTagDeclWithOrigin(tag_decl, +                                                         candidate_tag_decl)) +          found = true; +      } +    } +  } + +  if (log) { +    LLDB_LOGF(log, "      [CTD] After:"); +    ASTDumper dumper((Decl *)tag_decl); +    dumper.ToLog(log, "      [CTD] "); +  } +} + +void ClangASTSource::CompleteType(clang::ObjCInterfaceDecl *interface_decl) { +  Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); + +  if (log) { +    LLDB_LOGF(log, +              "    [CompleteObjCInterfaceDecl] on (ASTContext*)%p Completing " +              "an ObjCInterfaceDecl named %s", +              static_cast<void *>(m_ast_context), +              interface_decl->getName().str().c_str()); +    LLDB_LOGF(log, "      [COID] Before:"); +    ASTDumper dumper((Decl *)interface_decl); +    dumper.ToLog(log, "      [COID] "); +  } + +  if (!m_ast_importer_sp) { +    if (HasMerger()) { +      ObjCInterfaceDecl *complete_iface_decl = +        GetCompleteObjCInterface(interface_decl); + +      if (complete_iface_decl && (complete_iface_decl != interface_decl)) { +        m_merger_up->ForceRecordOrigin(interface_decl, {complete_iface_decl, &complete_iface_decl->getASTContext()}); +      } + +      GetMergerUnchecked().CompleteType(interface_decl); +    } else { +      lldbassert(0 && "No mechanism for completing a type!"); +    } +    return; +  } + +  Decl *original_decl = nullptr; +  ASTContext *original_ctx = nullptr; + +  if (m_ast_importer_sp->ResolveDeclOrigin(interface_decl, &original_decl, +                                           &original_ctx)) { +    if (ObjCInterfaceDecl *original_iface_decl = +            dyn_cast<ObjCInterfaceDecl>(original_decl)) { +      ObjCInterfaceDecl *complete_iface_decl = +          GetCompleteObjCInterface(original_iface_decl); + +      if (complete_iface_decl && (complete_iface_decl != original_iface_decl)) { +        m_ast_importer_sp->SetDeclOrigin(interface_decl, complete_iface_decl); +      } +    } +  } + +  m_ast_importer_sp->CompleteObjCInterfaceDecl(interface_decl); + +  if (interface_decl->getSuperClass() && +      interface_decl->getSuperClass() != interface_decl) +    CompleteType(interface_decl->getSuperClass()); + +  if (log) { +    LLDB_LOGF(log, "      [COID] After:"); +    ASTDumper dumper((Decl *)interface_decl); +    dumper.ToLog(log, "      [COID] "); +  } +} + +clang::ObjCInterfaceDecl *ClangASTSource::GetCompleteObjCInterface( +    const clang::ObjCInterfaceDecl *interface_decl) { +  lldb::ProcessSP process(m_target->GetProcessSP()); + +  if (!process) +    return nullptr; + +  ObjCLanguageRuntime *language_runtime(ObjCLanguageRuntime::Get(*process)); + +  if (!language_runtime) +    return nullptr; + +  ConstString class_name(interface_decl->getNameAsString().c_str()); + +  lldb::TypeSP complete_type_sp( +      language_runtime->LookupInCompleteClassCache(class_name)); + +  if (!complete_type_sp) +    return nullptr; + +  TypeFromUser complete_type = +      TypeFromUser(complete_type_sp->GetFullCompilerType()); +  lldb::opaque_compiler_type_t complete_opaque_type = +      complete_type.GetOpaqueQualType(); + +  if (!complete_opaque_type) +    return nullptr; + +  const clang::Type *complete_clang_type = +      QualType::getFromOpaquePtr(complete_opaque_type).getTypePtr(); +  const ObjCInterfaceType *complete_interface_type = +      dyn_cast<ObjCInterfaceType>(complete_clang_type); + +  if (!complete_interface_type) +    return nullptr; + +  ObjCInterfaceDecl *complete_iface_decl(complete_interface_type->getDecl()); + +  return complete_iface_decl; +} + +void ClangASTSource::FindExternalLexicalDecls( +    const DeclContext *decl_context, +    llvm::function_ref<bool(Decl::Kind)> predicate, +    llvm::SmallVectorImpl<Decl *> &decls) { + +  if (HasMerger()) { +    if (auto *interface_decl = dyn_cast<ObjCInterfaceDecl>(decl_context)) { +      ObjCInterfaceDecl *complete_iface_decl = +         GetCompleteObjCInterface(interface_decl); + +      if (complete_iface_decl && (complete_iface_decl != interface_decl)) { +        m_merger_up->ForceRecordOrigin(interface_decl, {complete_iface_decl, &complete_iface_decl->getASTContext()}); +      } +    } +    return GetMergerUnchecked().FindExternalLexicalDecls(decl_context, +                                                         predicate, +                                                         decls); +  } else if (!m_ast_importer_sp) +    return; + +  ClangASTMetrics::RegisterLexicalQuery(); + +  Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); + +  const Decl *context_decl = dyn_cast<Decl>(decl_context); + +  if (!context_decl) +    return; + +  auto iter = m_active_lexical_decls.find(context_decl); +  if (iter != m_active_lexical_decls.end()) +    return; +  m_active_lexical_decls.insert(context_decl); +  ScopedLexicalDeclEraser eraser(m_active_lexical_decls, context_decl); + +  static unsigned int invocation_id = 0; +  unsigned int current_id = invocation_id++; + +  if (log) { +    if (const NamedDecl *context_named_decl = dyn_cast<NamedDecl>(context_decl)) +      LLDB_LOGF( +          log, +          "FindExternalLexicalDecls[%u] on (ASTContext*)%p in '%s' (%sDecl*)%p", +          current_id, static_cast<void *>(m_ast_context), +          context_named_decl->getNameAsString().c_str(), +          context_decl->getDeclKindName(), +          static_cast<const void *>(context_decl)); +    else if (context_decl) +      LLDB_LOGF( +          log, "FindExternalLexicalDecls[%u] on (ASTContext*)%p in (%sDecl*)%p", +          current_id, static_cast<void *>(m_ast_context), +          context_decl->getDeclKindName(), +          static_cast<const void *>(context_decl)); +    else +      LLDB_LOGF( +          log, +          "FindExternalLexicalDecls[%u] on (ASTContext*)%p in a NULL context", +          current_id, static_cast<const void *>(m_ast_context)); +  } + +  Decl *original_decl = nullptr; +  ASTContext *original_ctx = nullptr; + +  if (!m_ast_importer_sp->ResolveDeclOrigin(context_decl, &original_decl, +                                            &original_ctx)) +    return; + +  if (log) { +    LLDB_LOGF( +        log, "  FELD[%u] Original decl (ASTContext*)%p (Decl*)%p:", current_id, +        static_cast<void *>(original_ctx), static_cast<void *>(original_decl)); +    ASTDumper(original_decl).ToLog(log, "    "); +  } + +  if (ObjCInterfaceDecl *original_iface_decl = +          dyn_cast<ObjCInterfaceDecl>(original_decl)) { +    ObjCInterfaceDecl *complete_iface_decl = +        GetCompleteObjCInterface(original_iface_decl); + +    if (complete_iface_decl && (complete_iface_decl != original_iface_decl)) { +      original_decl = complete_iface_decl; +      original_ctx = &complete_iface_decl->getASTContext(); + +      m_ast_importer_sp->SetDeclOrigin(context_decl, complete_iface_decl); +    } +  } + +  if (TagDecl *original_tag_decl = dyn_cast<TagDecl>(original_decl)) { +    ExternalASTSource *external_source = original_ctx->getExternalSource(); + +    if (external_source) +      external_source->CompleteType(original_tag_decl); +  } + +  const DeclContext *original_decl_context = +      dyn_cast<DeclContext>(original_decl); + +  if (!original_decl_context) +    return; + +  // Indicates whether we skipped any Decls of the original DeclContext. +  bool SkippedDecls = false; +  for (TagDecl::decl_iterator iter = original_decl_context->decls_begin(); +       iter != original_decl_context->decls_end(); ++iter) { +    Decl *decl = *iter; + +    // The predicate function returns true if the passed declaration kind is +    // the one we are looking for. +    // See clang::ExternalASTSource::FindExternalLexicalDecls() +    if (predicate(decl->getKind())) { +      if (log) { +        ASTDumper ast_dumper(decl); +        if (const NamedDecl *context_named_decl = +                dyn_cast<NamedDecl>(context_decl)) +          LLDB_LOGF(log, "  FELD[%d] Adding [to %sDecl %s] lexical %sDecl %s", +                    current_id, context_named_decl->getDeclKindName(), +                    context_named_decl->getNameAsString().c_str(), +                    decl->getDeclKindName(), ast_dumper.GetCString()); +        else +          LLDB_LOGF(log, "  FELD[%d] Adding lexical %sDecl %s", current_id, +                    decl->getDeclKindName(), ast_dumper.GetCString()); +      } + +      Decl *copied_decl = CopyDecl(decl); + +      if (!copied_decl) +        continue; + +      if (FieldDecl *copied_field = dyn_cast<FieldDecl>(copied_decl)) { +        QualType copied_field_type = copied_field->getType(); + +        m_ast_importer_sp->RequireCompleteType(copied_field_type); +      } +      auto decl_context_non_const = const_cast<DeclContext *>(decl_context); + +      // The decl ended up in the wrong DeclContext. Let's fix that so +      // the decl we copied will actually be found. +      // FIXME: This is a horrible hack that shouldn't be necessary. However +      // it seems our current setup sometimes fails to copy decls to the right +      // place. See rdar://55129537. +      if (copied_decl->getDeclContext() != decl_context) { +        assert(copied_decl->getDeclContext()->containsDecl(copied_decl)); +        copied_decl->getDeclContext()->removeDecl(copied_decl); +        copied_decl->setDeclContext(decl_context_non_const); +        assert(!decl_context_non_const->containsDecl(copied_decl)); +        decl_context_non_const->addDeclInternal(copied_decl); +      } +    } else { +      SkippedDecls = true; +    } +  } + +  // CopyDecl may build a lookup table which may set up ExternalLexicalStorage +  // to false.  However, since we skipped some of the external Decls we must +  // set it back! +  if (SkippedDecls) { +    decl_context->setHasExternalLexicalStorage(true); +    // This sets HasLazyExternalLexicalLookups to true.  By setting this bit we +    // ensure that the lookup table is rebuilt, which means the external source +    // is consulted again when a clang::DeclContext::lookup is called. +    const_cast<DeclContext *>(decl_context)->setMustBuildLookupTable(); +  } + +  return; +} + +void ClangASTSource::FindExternalVisibleDecls(NameSearchContext &context) { +  assert(m_ast_context); + +  ClangASTMetrics::RegisterVisibleQuery(); + +  const ConstString name(context.m_decl_name.getAsString().c_str()); + +  Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); + +  static unsigned int invocation_id = 0; +  unsigned int current_id = invocation_id++; + +  if (log) { +    if (!context.m_decl_context) +      LLDB_LOGF(log, +                "ClangASTSource::FindExternalVisibleDecls[%u] on " +                "(ASTContext*)%p for '%s' in a NULL DeclContext", +                current_id, static_cast<void *>(m_ast_context), +                name.GetCString()); +    else if (const NamedDecl *context_named_decl = +                 dyn_cast<NamedDecl>(context.m_decl_context)) +      LLDB_LOGF(log, +                "ClangASTSource::FindExternalVisibleDecls[%u] on " +                "(ASTContext*)%p for '%s' in '%s'", +                current_id, static_cast<void *>(m_ast_context), +                name.GetCString(), +                context_named_decl->getNameAsString().c_str()); +    else +      LLDB_LOGF(log, +                "ClangASTSource::FindExternalVisibleDecls[%u] on " +                "(ASTContext*)%p for '%s' in a '%s'", +                current_id, static_cast<void *>(m_ast_context), +                name.GetCString(), context.m_decl_context->getDeclKindName()); +  } + +  if (HasMerger() && !isa<TranslationUnitDecl>(context.m_decl_context) +      /* possibly handle NamespaceDecls here? */) { +    if (auto *interface_decl = +    dyn_cast<ObjCInterfaceDecl>(context.m_decl_context)) { +      ObjCInterfaceDecl *complete_iface_decl = +      GetCompleteObjCInterface(interface_decl); + +      if (complete_iface_decl && (complete_iface_decl != interface_decl)) { +        GetMergerUnchecked().ForceRecordOrigin( +            interface_decl, +            {complete_iface_decl, &complete_iface_decl->getASTContext()}); +      } +    } + +    GetMergerUnchecked().FindExternalVisibleDeclsByName(context.m_decl_context, +                                                context.m_decl_name); +    return; // otherwise we may need to fall back +  } + +  context.m_namespace_map = std::make_shared<ClangASTImporter::NamespaceMap>(); + +  if (const NamespaceDecl *namespace_context = +          dyn_cast<NamespaceDecl>(context.m_decl_context)) { +    ClangASTImporter::NamespaceMapSP namespace_map =  m_ast_importer_sp ? +        m_ast_importer_sp->GetNamespaceMap(namespace_context) : nullptr; + +    if (log && log->GetVerbose()) +      LLDB_LOGF(log, "  CAS::FEVD[%u] Inspecting namespace map %p (%d entries)", +                current_id, static_cast<void *>(namespace_map.get()), +                static_cast<int>(namespace_map->size())); + +    if (!namespace_map) +      return; + +    for (ClangASTImporter::NamespaceMap::iterator i = namespace_map->begin(), +                                                  e = namespace_map->end(); +         i != e; ++i) { +      LLDB_LOGF(log, "  CAS::FEVD[%u] Searching namespace %s in module %s", +                current_id, i->second.GetName().AsCString(), +                i->first->GetFileSpec().GetFilename().GetCString()); + +      FindExternalVisibleDecls(context, i->first, i->second, current_id); +    } +  } else if (isa<ObjCInterfaceDecl>(context.m_decl_context) && !HasMerger()) { +    FindObjCPropertyAndIvarDecls(context); +  } else if (!isa<TranslationUnitDecl>(context.m_decl_context)) { +    // we shouldn't be getting FindExternalVisibleDecls calls for these +    return; +  } else { +    CompilerDeclContext namespace_decl; + +    LLDB_LOGF(log, "  CAS::FEVD[%u] Searching the root namespace", current_id); + +    FindExternalVisibleDecls(context, lldb::ModuleSP(), namespace_decl, +                             current_id); +  } + +  if (!context.m_namespace_map->empty()) { +    if (log && log->GetVerbose()) +      LLDB_LOGF(log, +                "  CAS::FEVD[%u] Registering namespace map %p (%d entries)", +                current_id, static_cast<void *>(context.m_namespace_map.get()), +                static_cast<int>(context.m_namespace_map->size())); + +    NamespaceDecl *clang_namespace_decl = +        AddNamespace(context, context.m_namespace_map); + +    if (clang_namespace_decl) +      clang_namespace_decl->setHasExternalVisibleStorage(); +  } +} + +clang::Sema *ClangASTSource::getSema() { +  return ClangASTContext::GetASTContext(m_ast_context)->getSema(); +} + +bool ClangASTSource::IgnoreName(const ConstString name, +                                bool ignore_all_dollar_names) { +  static const ConstString id_name("id"); +  static const ConstString Class_name("Class"); + +  if (m_ast_context->getLangOpts().ObjC) +    if (name == id_name || name == Class_name) +      return true; + +  StringRef name_string_ref = name.GetStringRef(); + +  // The ClangASTSource is not responsible for finding $-names. +  return name_string_ref.empty() || +         (ignore_all_dollar_names && name_string_ref.startswith("$")) || +         name_string_ref.startswith("_$"); +} + +void ClangASTSource::FindExternalVisibleDecls( +    NameSearchContext &context, lldb::ModuleSP module_sp, +    CompilerDeclContext &namespace_decl, unsigned int current_id) { +  assert(m_ast_context); + +  Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); + +  SymbolContextList sc_list; + +  const ConstString name(context.m_decl_name.getAsString().c_str()); +  if (IgnoreName(name, true)) +    return; + +  if (module_sp && namespace_decl) { +    CompilerDeclContext found_namespace_decl; + +    if (SymbolFile *symbol_file = module_sp->GetSymbolFile()) { +      found_namespace_decl = symbol_file->FindNamespace(name, &namespace_decl); + +      if (found_namespace_decl) { +        context.m_namespace_map->push_back( +            std::pair<lldb::ModuleSP, CompilerDeclContext>( +                module_sp, found_namespace_decl)); + +        LLDB_LOGF(log, "  CAS::FEVD[%u] Found namespace %s in module %s", +                  current_id, name.GetCString(), +                  module_sp->GetFileSpec().GetFilename().GetCString()); +      } +    } +  } else if (!HasMerger()) { +    const ModuleList &target_images = m_target->GetImages(); +    std::lock_guard<std::recursive_mutex> guard(target_images.GetMutex()); + +    for (size_t i = 0, e = target_images.GetSize(); i < e; ++i) { +      lldb::ModuleSP image = target_images.GetModuleAtIndexUnlocked(i); + +      if (!image) +        continue; + +      CompilerDeclContext found_namespace_decl; + +      SymbolFile *symbol_file = image->GetSymbolFile(); + +      if (!symbol_file) +        continue; + +      found_namespace_decl = symbol_file->FindNamespace(name, &namespace_decl); + +      if (found_namespace_decl) { +        context.m_namespace_map->push_back( +            std::pair<lldb::ModuleSP, CompilerDeclContext>( +                image, found_namespace_decl)); + +        LLDB_LOGF(log, "  CAS::FEVD[%u] Found namespace %s in module %s", +                  current_id, name.GetCString(), +                  image->GetFileSpec().GetFilename().GetCString()); +      } +    } +  } + +  do { +    if (context.m_found.type) +      break; + +    TypeList types; +    const bool exact_match = true; +    llvm::DenseSet<lldb_private::SymbolFile *> searched_symbol_files; +    if (module_sp && namespace_decl) +      module_sp->FindTypesInNamespace(name, &namespace_decl, 1, types); +    else { +      m_target->GetImages().FindTypes(module_sp.get(), name, exact_match, 1, +                                      searched_symbol_files, types); +    } + +    if (size_t num_types = types.GetSize()) { +      for (size_t ti = 0; ti < num_types; ++ti) { +        lldb::TypeSP type_sp = types.GetTypeAtIndex(ti); + +        if (log) { +          const char *name_string = type_sp->GetName().GetCString(); + +          LLDB_LOGF(log, "  CAS::FEVD[%u] Matching type found for \"%s\": %s", +                    current_id, name.GetCString(), +                    (name_string ? name_string : "<anonymous>")); +        } + +        CompilerType full_type = type_sp->GetFullCompilerType(); + +        CompilerType copied_clang_type(GuardedCopyType(full_type)); + +        if (!copied_clang_type) { +          LLDB_LOGF(log, "  CAS::FEVD[%u] - Couldn't export a type", +                    current_id); + +          continue; +        } + +        context.AddTypeDecl(copied_clang_type); + +        context.m_found.type = true; +        break; +      } +    } + +    if (!context.m_found.type) { +      // Try the modules next. + +      do { +        if (ClangModulesDeclVendor *modules_decl_vendor = +                m_target->GetClangModulesDeclVendor()) { +          bool append = false; +          uint32_t max_matches = 1; +          std::vector<clang::NamedDecl *> decls; + +          if (!modules_decl_vendor->FindDecls(name, append, max_matches, decls)) +            break; + +          if (log) { +            LLDB_LOGF(log, +                      "  CAS::FEVD[%u] Matching entity found for \"%s\" in " +                      "the modules", +                      current_id, name.GetCString()); +          } + +          clang::NamedDecl *const decl_from_modules = decls[0]; + +          if (llvm::isa<clang::TypeDecl>(decl_from_modules) || +              llvm::isa<clang::ObjCContainerDecl>(decl_from_modules) || +              llvm::isa<clang::EnumConstantDecl>(decl_from_modules)) { +            clang::Decl *copied_decl = CopyDecl(decl_from_modules); +            clang::NamedDecl *copied_named_decl = +                copied_decl ? dyn_cast<clang::NamedDecl>(copied_decl) : nullptr; + +            if (!copied_named_decl) { +              LLDB_LOGF( +                  log, +                  "  CAS::FEVD[%u] - Couldn't export a type from the modules", +                  current_id); + +              break; +            } + +            context.AddNamedDecl(copied_named_decl); + +            context.m_found.type = true; +          } +        } +      } while (false); +    } + +    if (!context.m_found.type) { +      do { +        // Couldn't find any types elsewhere.  Try the Objective-C runtime if +        // one exists. + +        lldb::ProcessSP process(m_target->GetProcessSP()); + +        if (!process) +          break; + +        ObjCLanguageRuntime *language_runtime( +            ObjCLanguageRuntime::Get(*process)); + +        if (!language_runtime) +          break; + +        DeclVendor *decl_vendor = language_runtime->GetDeclVendor(); + +        if (!decl_vendor) +          break; + +        bool append = false; +        uint32_t max_matches = 1; +        std::vector<clang::NamedDecl *> decls; + +        auto *clang_decl_vendor = llvm::cast<ClangDeclVendor>(decl_vendor); +        if (!clang_decl_vendor->FindDecls(name, append, max_matches, decls)) +          break; + +        if (log) { +          LLDB_LOGF( +              log, +              "  CAS::FEVD[%u] Matching type found for \"%s\" in the runtime", +              current_id, name.GetCString()); +        } + +        clang::Decl *copied_decl = CopyDecl(decls[0]); +        clang::NamedDecl *copied_named_decl = +            copied_decl ? dyn_cast<clang::NamedDecl>(copied_decl) : nullptr; + +        if (!copied_named_decl) { +          LLDB_LOGF(log, +                    "  CAS::FEVD[%u] - Couldn't export a type from the runtime", +                    current_id); + +          break; +        } + +        context.AddNamedDecl(copied_named_decl); +      } while (false); +    } + +  } while (false); +} + +template <class D> class TaggedASTDecl { +public: +  TaggedASTDecl() : decl(nullptr) {} +  TaggedASTDecl(D *_decl) : decl(_decl) {} +  bool IsValid() const { return (decl != nullptr); } +  bool IsInvalid() const { return !IsValid(); } +  D *operator->() const { return decl; } +  D *decl; +}; + +template <class D2, template <class D> class TD, class D1> +TD<D2> DynCast(TD<D1> source) { +  return TD<D2>(dyn_cast<D2>(source.decl)); +} + +template <class D = Decl> class DeclFromParser; +template <class D = Decl> class DeclFromUser; + +template <class D> class DeclFromParser : public TaggedASTDecl<D> { +public: +  DeclFromParser() : TaggedASTDecl<D>() {} +  DeclFromParser(D *_decl) : TaggedASTDecl<D>(_decl) {} + +  DeclFromUser<D> GetOrigin(ClangASTSource &source); +}; + +template <class D> class DeclFromUser : public TaggedASTDecl<D> { +public: +  DeclFromUser() : TaggedASTDecl<D>() {} +  DeclFromUser(D *_decl) : TaggedASTDecl<D>(_decl) {} + +  DeclFromParser<D> Import(ClangASTSource &source); +}; + +template <class D> +DeclFromUser<D> DeclFromParser<D>::GetOrigin(ClangASTSource &source) { +  DeclFromUser<> origin_decl; +  source.ResolveDeclOrigin(this->decl, &origin_decl.decl, nullptr); +  if (origin_decl.IsInvalid()) +    return DeclFromUser<D>(); +  return DeclFromUser<D>(dyn_cast<D>(origin_decl.decl)); +} + +template <class D> +DeclFromParser<D> DeclFromUser<D>::Import(ClangASTSource &source) { +  DeclFromParser<> parser_generic_decl(source.CopyDecl(this->decl)); +  if (parser_generic_decl.IsInvalid()) +    return DeclFromParser<D>(); +  return DeclFromParser<D>(dyn_cast<D>(parser_generic_decl.decl)); +} + +bool ClangASTSource::FindObjCMethodDeclsWithOrigin( +    unsigned int current_id, NameSearchContext &context, +    ObjCInterfaceDecl *original_interface_decl, const char *log_info) { +  const DeclarationName &decl_name(context.m_decl_name); +  clang::ASTContext *original_ctx = &original_interface_decl->getASTContext(); + +  Selector original_selector; + +  if (decl_name.isObjCZeroArgSelector()) { +    IdentifierInfo *ident = &original_ctx->Idents.get(decl_name.getAsString()); +    original_selector = original_ctx->Selectors.getSelector(0, &ident); +  } else if (decl_name.isObjCOneArgSelector()) { +    const std::string &decl_name_string = decl_name.getAsString(); +    std::string decl_name_string_without_colon(decl_name_string.c_str(), +                                               decl_name_string.length() - 1); +    IdentifierInfo *ident = +        &original_ctx->Idents.get(decl_name_string_without_colon); +    original_selector = original_ctx->Selectors.getSelector(1, &ident); +  } else { +    SmallVector<IdentifierInfo *, 4> idents; + +    clang::Selector sel = decl_name.getObjCSelector(); + +    unsigned num_args = sel.getNumArgs(); + +    for (unsigned i = 0; i != num_args; ++i) { +      idents.push_back(&original_ctx->Idents.get(sel.getNameForSlot(i))); +    } + +    original_selector = +        original_ctx->Selectors.getSelector(num_args, idents.data()); +  } + +  DeclarationName original_decl_name(original_selector); + +  llvm::SmallVector<NamedDecl *, 1> methods; + +  ClangASTContext::GetCompleteDecl(original_ctx, original_interface_decl); + +  if (ObjCMethodDecl *instance_method_decl = +          original_interface_decl->lookupInstanceMethod(original_selector)) { +    methods.push_back(instance_method_decl); +  } else if (ObjCMethodDecl *class_method_decl = +                 original_interface_decl->lookupClassMethod( +                     original_selector)) { +    methods.push_back(class_method_decl); +  } + +  if (methods.empty()) { +    return false; +  } + +  for (NamedDecl *named_decl : methods) { +    if (!named_decl) +      continue; + +    ObjCMethodDecl *result_method = dyn_cast<ObjCMethodDecl>(named_decl); + +    if (!result_method) +      continue; + +    Decl *copied_decl = CopyDecl(result_method); + +    if (!copied_decl) +      continue; + +    ObjCMethodDecl *copied_method_decl = dyn_cast<ObjCMethodDecl>(copied_decl); + +    if (!copied_method_decl) +      continue; + +    Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); + +    if (log) { +      ASTDumper dumper((Decl *)copied_method_decl); +      LLDB_LOGF(log, "  CAS::FOMD[%d] found (%s) %s", current_id, log_info, +                dumper.GetCString()); +    } + +    context.AddNamedDecl(copied_method_decl); +  } + +  return true; +} + +void ClangASTSource::FindObjCMethodDecls(NameSearchContext &context) { +  Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); + +  if (HasMerger()) { +    if (auto *interface_decl = dyn_cast<ObjCInterfaceDecl>(context.m_decl_context)) { +      ObjCInterfaceDecl *complete_iface_decl = +          GetCompleteObjCInterface(interface_decl); + +      if (complete_iface_decl && (complete_iface_decl != context.m_decl_context)) { +        m_merger_up->ForceRecordOrigin(interface_decl, {complete_iface_decl, &complete_iface_decl->getASTContext()}); +      } +    } + +    GetMergerUnchecked().FindExternalVisibleDeclsByName(context.m_decl_context, +                                                        context.m_decl_name); +    return; +  } + +  static unsigned int invocation_id = 0; +  unsigned int current_id = invocation_id++; + +  const DeclarationName &decl_name(context.m_decl_name); +  const DeclContext *decl_ctx(context.m_decl_context); + +  const ObjCInterfaceDecl *interface_decl = +      dyn_cast<ObjCInterfaceDecl>(decl_ctx); + +  if (!interface_decl) +    return; + +  do { +    Decl *original_decl = nullptr; +    ASTContext *original_ctx = nullptr; + +    m_ast_importer_sp->ResolveDeclOrigin(interface_decl, &original_decl, +                                         &original_ctx); + +    if (!original_decl) +      break; + +    ObjCInterfaceDecl *original_interface_decl = +        dyn_cast<ObjCInterfaceDecl>(original_decl); + +    if (FindObjCMethodDeclsWithOrigin(current_id, context, +                                      original_interface_decl, "at origin")) +      return; // found it, no need to look any further +  } while (false); + +  StreamString ss; + +  if (decl_name.isObjCZeroArgSelector()) { +    ss.Printf("%s", decl_name.getAsString().c_str()); +  } else if (decl_name.isObjCOneArgSelector()) { +    ss.Printf("%s", decl_name.getAsString().c_str()); +  } else { +    clang::Selector sel = decl_name.getObjCSelector(); + +    for (unsigned i = 0, e = sel.getNumArgs(); i != e; ++i) { +      llvm::StringRef r = sel.getNameForSlot(i); +      ss.Printf("%s:", r.str().c_str()); +    } +  } +  ss.Flush(); + +  if (ss.GetString().contains("$__lldb")) +    return; // we don't need any results + +  ConstString selector_name(ss.GetString()); + +  LLDB_LOGF(log, +            "ClangASTSource::FindObjCMethodDecls[%d] on (ASTContext*)%p " +            "for selector [%s %s]", +            current_id, static_cast<void *>(m_ast_context), +            interface_decl->getNameAsString().c_str(), +            selector_name.AsCString()); +  SymbolContextList sc_list; + +  const bool include_symbols = false; +  const bool include_inlines = false; + +  std::string interface_name = interface_decl->getNameAsString(); + +  do { +    StreamString ms; +    ms.Printf("-[%s %s]", interface_name.c_str(), selector_name.AsCString()); +    ms.Flush(); +    ConstString instance_method_name(ms.GetString()); + +    sc_list.Clear(); +    m_target->GetImages().FindFunctions( +        instance_method_name, lldb::eFunctionNameTypeFull, include_symbols, +        include_inlines, sc_list); + +    if (sc_list.GetSize()) +      break; + +    ms.Clear(); +    ms.Printf("+[%s %s]", interface_name.c_str(), selector_name.AsCString()); +    ms.Flush(); +    ConstString class_method_name(ms.GetString()); + +    sc_list.Clear(); +    m_target->GetImages().FindFunctions( +        class_method_name, lldb::eFunctionNameTypeFull, include_symbols, +        include_inlines, sc_list); + +    if (sc_list.GetSize()) +      break; + +    // Fall back and check for methods in categories.  If we find methods this +    // way, we need to check that they're actually in categories on the desired +    // class. + +    SymbolContextList candidate_sc_list; + +    m_target->GetImages().FindFunctions( +        selector_name, lldb::eFunctionNameTypeSelector, include_symbols, +        include_inlines, candidate_sc_list); + +    for (uint32_t ci = 0, ce = candidate_sc_list.GetSize(); ci != ce; ++ci) { +      SymbolContext candidate_sc; + +      if (!candidate_sc_list.GetContextAtIndex(ci, candidate_sc)) +        continue; + +      if (!candidate_sc.function) +        continue; + +      const char *candidate_name = candidate_sc.function->GetName().AsCString(); + +      const char *cursor = candidate_name; + +      if (*cursor != '+' && *cursor != '-') +        continue; + +      ++cursor; + +      if (*cursor != '[') +        continue; + +      ++cursor; + +      size_t interface_len = interface_name.length(); + +      if (strncmp(cursor, interface_name.c_str(), interface_len)) +        continue; + +      cursor += interface_len; + +      if (*cursor == ' ' || *cursor == '(') +        sc_list.Append(candidate_sc); +    } +  } while (false); + +  if (sc_list.GetSize()) { +    // We found a good function symbol.  Use that. + +    for (uint32_t i = 0, e = sc_list.GetSize(); i != e; ++i) { +      SymbolContext sc; + +      if (!sc_list.GetContextAtIndex(i, sc)) +        continue; + +      if (!sc.function) +        continue; + +      CompilerDeclContext function_decl_ctx = sc.function->GetDeclContext(); +      if (!function_decl_ctx) +        continue; + +      ObjCMethodDecl *method_decl = +          ClangASTContext::DeclContextGetAsObjCMethodDecl(function_decl_ctx); + +      if (!method_decl) +        continue; + +      ObjCInterfaceDecl *found_interface_decl = +          method_decl->getClassInterface(); + +      if (!found_interface_decl) +        continue; + +      if (found_interface_decl->getName() == interface_decl->getName()) { +        Decl *copied_decl = CopyDecl(method_decl); + +        if (!copied_decl) +          continue; + +        ObjCMethodDecl *copied_method_decl = +            dyn_cast<ObjCMethodDecl>(copied_decl); + +        if (!copied_method_decl) +          continue; + +        if (log) { +          ASTDumper dumper((Decl *)copied_method_decl); +          LLDB_LOGF(log, "  CAS::FOMD[%d] found (in symbols) %s", current_id, +                    dumper.GetCString()); +        } + +        context.AddNamedDecl(copied_method_decl); +      } +    } + +    return; +  } + +  // Try the debug information. + +  do { +    ObjCInterfaceDecl *complete_interface_decl = GetCompleteObjCInterface( +        const_cast<ObjCInterfaceDecl *>(interface_decl)); + +    if (!complete_interface_decl) +      break; + +    // We found the complete interface.  The runtime never needs to be queried +    // in this scenario. + +    DeclFromUser<const ObjCInterfaceDecl> complete_iface_decl( +        complete_interface_decl); + +    if (complete_interface_decl == interface_decl) +      break; // already checked this one + +    LLDB_LOGF(log, +              "CAS::FOPD[%d] trying origin " +              "(ObjCInterfaceDecl*)%p/(ASTContext*)%p...", +              current_id, static_cast<void *>(complete_interface_decl), +              static_cast<void *>(&complete_iface_decl->getASTContext())); + +    FindObjCMethodDeclsWithOrigin(current_id, context, complete_interface_decl, +                                  "in debug info"); + +    return; +  } while (false); + +  do { +    // Check the modules only if the debug information didn't have a complete +    // interface. + +    if (ClangModulesDeclVendor *modules_decl_vendor = +            m_target->GetClangModulesDeclVendor()) { +      ConstString interface_name(interface_decl->getNameAsString().c_str()); +      bool append = false; +      uint32_t max_matches = 1; +      std::vector<clang::NamedDecl *> decls; + +      if (!modules_decl_vendor->FindDecls(interface_name, append, max_matches, +                                          decls)) +        break; + +      ObjCInterfaceDecl *interface_decl_from_modules = +          dyn_cast<ObjCInterfaceDecl>(decls[0]); + +      if (!interface_decl_from_modules) +        break; + +      if (FindObjCMethodDeclsWithOrigin( +              current_id, context, interface_decl_from_modules, "in modules")) +        return; +    } +  } while (false); + +  do { +    // Check the runtime only if the debug information didn't have a complete +    // interface and the modules don't get us anywhere. + +    lldb::ProcessSP process(m_target->GetProcessSP()); + +    if (!process) +      break; + +    ObjCLanguageRuntime *language_runtime(ObjCLanguageRuntime::Get(*process)); + +    if (!language_runtime) +      break; + +    DeclVendor *decl_vendor = language_runtime->GetDeclVendor(); + +    if (!decl_vendor) +      break; + +    ConstString interface_name(interface_decl->getNameAsString().c_str()); +    bool append = false; +    uint32_t max_matches = 1; +    std::vector<clang::NamedDecl *> decls; + +    auto *clang_decl_vendor = llvm::cast<ClangDeclVendor>(decl_vendor); +    if (!clang_decl_vendor->FindDecls(interface_name, append, max_matches, +                                      decls)) +      break; + +    ObjCInterfaceDecl *runtime_interface_decl = +        dyn_cast<ObjCInterfaceDecl>(decls[0]); + +    if (!runtime_interface_decl) +      break; + +    FindObjCMethodDeclsWithOrigin(current_id, context, runtime_interface_decl, +                                  "in runtime"); +  } while (false); +} + +static bool FindObjCPropertyAndIvarDeclsWithOrigin( +    unsigned int current_id, NameSearchContext &context, ClangASTSource &source, +    DeclFromUser<const ObjCInterfaceDecl> &origin_iface_decl) { +  Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); + +  if (origin_iface_decl.IsInvalid()) +    return false; + +  std::string name_str = context.m_decl_name.getAsString(); +  StringRef name(name_str); +  IdentifierInfo &name_identifier( +      origin_iface_decl->getASTContext().Idents.get(name)); + +  DeclFromUser<ObjCPropertyDecl> origin_property_decl( +      origin_iface_decl->FindPropertyDeclaration( +          &name_identifier, ObjCPropertyQueryKind::OBJC_PR_query_instance)); + +  bool found = false; + +  if (origin_property_decl.IsValid()) { +    DeclFromParser<ObjCPropertyDecl> parser_property_decl( +        origin_property_decl.Import(source)); +    if (parser_property_decl.IsValid()) { +      if (log) { +        ASTDumper dumper((Decl *)parser_property_decl.decl); +        LLDB_LOGF(log, "  CAS::FOPD[%d] found %s", current_id, +                  dumper.GetCString()); +      } + +      context.AddNamedDecl(parser_property_decl.decl); +      found = true; +    } +  } + +  DeclFromUser<ObjCIvarDecl> origin_ivar_decl( +      origin_iface_decl->getIvarDecl(&name_identifier)); + +  if (origin_ivar_decl.IsValid()) { +    DeclFromParser<ObjCIvarDecl> parser_ivar_decl( +        origin_ivar_decl.Import(source)); +    if (parser_ivar_decl.IsValid()) { +      if (log) { +        ASTDumper dumper((Decl *)parser_ivar_decl.decl); +        LLDB_LOGF(log, "  CAS::FOPD[%d] found %s", current_id, +                  dumper.GetCString()); +      } + +      context.AddNamedDecl(parser_ivar_decl.decl); +      found = true; +    } +  } + +  return found; +} + +void ClangASTSource::FindObjCPropertyAndIvarDecls(NameSearchContext &context) { +  Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); + +  static unsigned int invocation_id = 0; +  unsigned int current_id = invocation_id++; + +  DeclFromParser<const ObjCInterfaceDecl> parser_iface_decl( +      cast<ObjCInterfaceDecl>(context.m_decl_context)); +  DeclFromUser<const ObjCInterfaceDecl> origin_iface_decl( +      parser_iface_decl.GetOrigin(*this)); + +  ConstString class_name(parser_iface_decl->getNameAsString().c_str()); + +  LLDB_LOGF(log, +            "ClangASTSource::FindObjCPropertyAndIvarDecls[%d] on " +            "(ASTContext*)%p for '%s.%s'", +            current_id, static_cast<void *>(m_ast_context), +            parser_iface_decl->getNameAsString().c_str(), +            context.m_decl_name.getAsString().c_str()); + +  if (FindObjCPropertyAndIvarDeclsWithOrigin( +          current_id, context, *this, origin_iface_decl)) +    return; + +  LLDB_LOGF(log, +            "CAS::FOPD[%d] couldn't find the property on origin " +            "(ObjCInterfaceDecl*)%p/(ASTContext*)%p, searching " +            "elsewhere...", +            current_id, static_cast<const void *>(origin_iface_decl.decl), +            static_cast<void *>(&origin_iface_decl->getASTContext())); + +  SymbolContext null_sc; +  TypeList type_list; + +  do { +    ObjCInterfaceDecl *complete_interface_decl = GetCompleteObjCInterface( +        const_cast<ObjCInterfaceDecl *>(parser_iface_decl.decl)); + +    if (!complete_interface_decl) +      break; + +    // We found the complete interface.  The runtime never needs to be queried +    // in this scenario. + +    DeclFromUser<const ObjCInterfaceDecl> complete_iface_decl( +        complete_interface_decl); + +    if (complete_iface_decl.decl == origin_iface_decl.decl) +      break; // already checked this one + +    LLDB_LOGF(log, +              "CAS::FOPD[%d] trying origin " +              "(ObjCInterfaceDecl*)%p/(ASTContext*)%p...", +              current_id, static_cast<const void *>(complete_iface_decl.decl), +              static_cast<void *>(&complete_iface_decl->getASTContext())); + +    FindObjCPropertyAndIvarDeclsWithOrigin(current_id, context, *this, +                                           complete_iface_decl); + +    return; +  } while (false); + +  do { +    // Check the modules only if the debug information didn't have a complete +    // interface. + +    ClangModulesDeclVendor *modules_decl_vendor = +        m_target->GetClangModulesDeclVendor(); + +    if (!modules_decl_vendor) +      break; + +    bool append = false; +    uint32_t max_matches = 1; +    std::vector<clang::NamedDecl *> decls; + +    if (!modules_decl_vendor->FindDecls(class_name, append, max_matches, decls)) +      break; + +    DeclFromUser<const ObjCInterfaceDecl> interface_decl_from_modules( +        dyn_cast<ObjCInterfaceDecl>(decls[0])); + +    if (!interface_decl_from_modules.IsValid()) +      break; + +    LLDB_LOGF( +        log, +        "CAS::FOPD[%d] trying module " +        "(ObjCInterfaceDecl*)%p/(ASTContext*)%p...", +        current_id, static_cast<const void *>(interface_decl_from_modules.decl), +        static_cast<void *>(&interface_decl_from_modules->getASTContext())); + +    if (FindObjCPropertyAndIvarDeclsWithOrigin(current_id, context, *this, +                                               interface_decl_from_modules)) +      return; +  } while (false); + +  do { +    // Check the runtime only if the debug information didn't have a complete +    // interface and nothing was in the modules. + +    lldb::ProcessSP process(m_target->GetProcessSP()); + +    if (!process) +      return; + +    ObjCLanguageRuntime *language_runtime(ObjCLanguageRuntime::Get(*process)); + +    if (!language_runtime) +      return; + +    DeclVendor *decl_vendor = language_runtime->GetDeclVendor(); + +    if (!decl_vendor) +      break; + +    bool append = false; +    uint32_t max_matches = 1; +    std::vector<clang::NamedDecl *> decls; + +    auto *clang_decl_vendor = llvm::cast<ClangDeclVendor>(decl_vendor); +    if (!clang_decl_vendor->FindDecls(class_name, append, max_matches, decls)) +      break; + +    DeclFromUser<const ObjCInterfaceDecl> interface_decl_from_runtime( +        dyn_cast<ObjCInterfaceDecl>(decls[0])); + +    if (!interface_decl_from_runtime.IsValid()) +      break; + +    LLDB_LOGF( +        log, +        "CAS::FOPD[%d] trying runtime " +        "(ObjCInterfaceDecl*)%p/(ASTContext*)%p...", +        current_id, static_cast<const void *>(interface_decl_from_runtime.decl), +        static_cast<void *>(&interface_decl_from_runtime->getASTContext())); + +    if (FindObjCPropertyAndIvarDeclsWithOrigin( +            current_id, context, *this, interface_decl_from_runtime)) +      return; +  } while (false); +} + +typedef llvm::DenseMap<const FieldDecl *, uint64_t> FieldOffsetMap; +typedef llvm::DenseMap<const CXXRecordDecl *, CharUnits> BaseOffsetMap; + +template <class D, class O> +static bool ImportOffsetMap(llvm::DenseMap<const D *, O> &destination_map, +                            llvm::DenseMap<const D *, O> &source_map, +                            ClangASTSource &source) { +  // When importing fields into a new record, clang has a hard requirement that +  // fields be imported in field offset order.  Since they are stored in a +  // DenseMap with a pointer as the key type, this means we cannot simply +  // iterate over the map, as the order will be non-deterministic.  Instead we +  // have to sort by the offset and then insert in sorted order. +  typedef llvm::DenseMap<const D *, O> MapType; +  typedef typename MapType::value_type PairType; +  std::vector<PairType> sorted_items; +  sorted_items.reserve(source_map.size()); +  sorted_items.assign(source_map.begin(), source_map.end()); +  llvm::sort(sorted_items.begin(), sorted_items.end(), +             [](const PairType &lhs, const PairType &rhs) { +               return lhs.second < rhs.second; +             }); + +  for (const auto &item : sorted_items) { +    DeclFromUser<D> user_decl(const_cast<D *>(item.first)); +    DeclFromParser<D> parser_decl(user_decl.Import(source)); +    if (parser_decl.IsInvalid()) +      return false; +    destination_map.insert( +        std::pair<const D *, O>(parser_decl.decl, item.second)); +  } + +  return true; +} + +template <bool IsVirtual> +bool ExtractBaseOffsets(const ASTRecordLayout &record_layout, +                        DeclFromUser<const CXXRecordDecl> &record, +                        BaseOffsetMap &base_offsets) { +  for (CXXRecordDecl::base_class_const_iterator +           bi = (IsVirtual ? record->vbases_begin() : record->bases_begin()), +           be = (IsVirtual ? record->vbases_end() : record->bases_end()); +       bi != be; ++bi) { +    if (!IsVirtual && bi->isVirtual()) +      continue; + +    const clang::Type *origin_base_type = bi->getType().getTypePtr(); +    const clang::RecordType *origin_base_record_type = +        origin_base_type->getAs<RecordType>(); + +    if (!origin_base_record_type) +      return false; + +    DeclFromUser<RecordDecl> origin_base_record( +        origin_base_record_type->getDecl()); + +    if (origin_base_record.IsInvalid()) +      return false; + +    DeclFromUser<CXXRecordDecl> origin_base_cxx_record( +        DynCast<CXXRecordDecl>(origin_base_record)); + +    if (origin_base_cxx_record.IsInvalid()) +      return false; + +    CharUnits base_offset; + +    if (IsVirtual) +      base_offset = +          record_layout.getVBaseClassOffset(origin_base_cxx_record.decl); +    else +      base_offset = +          record_layout.getBaseClassOffset(origin_base_cxx_record.decl); + +    base_offsets.insert(std::pair<const CXXRecordDecl *, CharUnits>( +        origin_base_cxx_record.decl, base_offset)); +  } + +  return true; +} + +bool ClangASTSource::layoutRecordType(const RecordDecl *record, uint64_t &size, +                                      uint64_t &alignment, +                                      FieldOffsetMap &field_offsets, +                                      BaseOffsetMap &base_offsets, +                                      BaseOffsetMap &virtual_base_offsets) { +  ClangASTMetrics::RegisterRecordLayout(); + +  static unsigned int invocation_id = 0; +  unsigned int current_id = invocation_id++; + +  Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); + +  LLDB_LOGF(log, +            "LayoutRecordType[%u] on (ASTContext*)%p for (RecordDecl*)%p " +            "[name = '%s']", +            current_id, static_cast<void *>(m_ast_context), +            static_cast<const void *>(record), +            record->getNameAsString().c_str()); + +  DeclFromParser<const RecordDecl> parser_record(record); +  DeclFromUser<const RecordDecl> origin_record( +      parser_record.GetOrigin(*this)); + +  if (origin_record.IsInvalid()) +    return false; + +  FieldOffsetMap origin_field_offsets; +  BaseOffsetMap origin_base_offsets; +  BaseOffsetMap origin_virtual_base_offsets; + +  ClangASTContext::GetCompleteDecl( +      &origin_record->getASTContext(), +      const_cast<RecordDecl *>(origin_record.decl)); + +  clang::RecordDecl *definition = origin_record.decl->getDefinition(); +  if (!definition || !definition->isCompleteDefinition()) +    return false; + +  const ASTRecordLayout &record_layout( +      origin_record->getASTContext().getASTRecordLayout(origin_record.decl)); + +  int field_idx = 0, field_count = record_layout.getFieldCount(); + +  for (RecordDecl::field_iterator fi = origin_record->field_begin(), +                                  fe = origin_record->field_end(); +       fi != fe; ++fi) { +    if (field_idx >= field_count) +      return false; // Layout didn't go well.  Bail out. + +    uint64_t field_offset = record_layout.getFieldOffset(field_idx); + +    origin_field_offsets.insert( +        std::pair<const FieldDecl *, uint64_t>(*fi, field_offset)); + +    field_idx++; +  } + +  lldbassert(&record->getASTContext() == m_ast_context); + +  DeclFromUser<const CXXRecordDecl> origin_cxx_record( +      DynCast<const CXXRecordDecl>(origin_record)); + +  if (origin_cxx_record.IsValid()) { +    if (!ExtractBaseOffsets<false>(record_layout, origin_cxx_record, +                                   origin_base_offsets) || +        !ExtractBaseOffsets<true>(record_layout, origin_cxx_record, +                                  origin_virtual_base_offsets)) +      return false; +  } + +  if (!ImportOffsetMap(field_offsets, origin_field_offsets, *this) || +      !ImportOffsetMap(base_offsets, origin_base_offsets, *this) || +      !ImportOffsetMap(virtual_base_offsets, origin_virtual_base_offsets, +                       *this)) +    return false; + +  size = record_layout.getSize().getQuantity() * m_ast_context->getCharWidth(); +  alignment = record_layout.getAlignment().getQuantity() * +              m_ast_context->getCharWidth(); + +  if (log) { +    LLDB_LOGF(log, "LRT[%u] returned:", current_id); +    LLDB_LOGF(log, "LRT[%u]   Original = (RecordDecl*)%p", current_id, +              static_cast<const void *>(origin_record.decl)); +    LLDB_LOGF(log, "LRT[%u]   Size = %" PRId64, current_id, size); +    LLDB_LOGF(log, "LRT[%u]   Alignment = %" PRId64, current_id, alignment); +    LLDB_LOGF(log, "LRT[%u]   Fields:", current_id); +    for (RecordDecl::field_iterator fi = record->field_begin(), +                                    fe = record->field_end(); +         fi != fe; ++fi) { +      LLDB_LOGF(log, +                "LRT[%u]     (FieldDecl*)%p, Name = '%s', Offset = %" PRId64 +                " bits", +                current_id, static_cast<void *>(*fi), +                fi->getNameAsString().c_str(), field_offsets[*fi]); +    } +    DeclFromParser<const CXXRecordDecl> parser_cxx_record = +        DynCast<const CXXRecordDecl>(parser_record); +    if (parser_cxx_record.IsValid()) { +      LLDB_LOGF(log, "LRT[%u]   Bases:", current_id); +      for (CXXRecordDecl::base_class_const_iterator +               bi = parser_cxx_record->bases_begin(), +               be = parser_cxx_record->bases_end(); +           bi != be; ++bi) { +        bool is_virtual = bi->isVirtual(); + +        QualType base_type = bi->getType(); +        const RecordType *base_record_type = base_type->getAs<RecordType>(); +        DeclFromParser<RecordDecl> base_record(base_record_type->getDecl()); +        DeclFromParser<CXXRecordDecl> base_cxx_record = +            DynCast<CXXRecordDecl>(base_record); + +        LLDB_LOGF( +            log, +            "LRT[%u]     %s(CXXRecordDecl*)%p, Name = '%s', Offset = %" PRId64 +            " chars", +            current_id, (is_virtual ? "Virtual " : ""), +            static_cast<void *>(base_cxx_record.decl), +            base_cxx_record.decl->getNameAsString().c_str(), +            (is_virtual +                 ? virtual_base_offsets[base_cxx_record.decl].getQuantity() +                 : base_offsets[base_cxx_record.decl].getQuantity())); +      } +    } else { +      LLDB_LOGF(log, "LRD[%u]   Not a CXXRecord, so no bases", current_id); +    } +  } + +  return true; +} + +void ClangASTSource::CompleteNamespaceMap( +    ClangASTImporter::NamespaceMapSP &namespace_map, ConstString name, +    ClangASTImporter::NamespaceMapSP &parent_map) const { +  static unsigned int invocation_id = 0; +  unsigned int current_id = invocation_id++; + +  Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); + +  if (log) { +    if (parent_map && parent_map->size()) +      LLDB_LOGF(log, +                "CompleteNamespaceMap[%u] on (ASTContext*)%p Searching for " +                "namespace %s in namespace %s", +                current_id, static_cast<void *>(m_ast_context), +                name.GetCString(), +                parent_map->begin()->second.GetName().AsCString()); +    else +      LLDB_LOGF(log, +                "CompleteNamespaceMap[%u] on (ASTContext*)%p Searching for " +                "namespace %s", +                current_id, static_cast<void *>(m_ast_context), +                name.GetCString()); +  } + +  if (parent_map) { +    for (ClangASTImporter::NamespaceMap::iterator i = parent_map->begin(), +                                                  e = parent_map->end(); +         i != e; ++i) { +      CompilerDeclContext found_namespace_decl; + +      lldb::ModuleSP module_sp = i->first; +      CompilerDeclContext module_parent_namespace_decl = i->second; + +      SymbolFile *symbol_file = module_sp->GetSymbolFile(); + +      if (!symbol_file) +        continue; + +      found_namespace_decl = +          symbol_file->FindNamespace(name, &module_parent_namespace_decl); + +      if (!found_namespace_decl) +        continue; + +      namespace_map->push_back(std::pair<lldb::ModuleSP, CompilerDeclContext>( +          module_sp, found_namespace_decl)); + +      LLDB_LOGF(log, "  CMN[%u] Found namespace %s in module %s", current_id, +                name.GetCString(), +                module_sp->GetFileSpec().GetFilename().GetCString()); +    } +  } else { +    const ModuleList &target_images = m_target->GetImages(); +    std::lock_guard<std::recursive_mutex> guard(target_images.GetMutex()); + +    CompilerDeclContext null_namespace_decl; + +    for (size_t i = 0, e = target_images.GetSize(); i < e; ++i) { +      lldb::ModuleSP image = target_images.GetModuleAtIndexUnlocked(i); + +      if (!image) +        continue; + +      CompilerDeclContext found_namespace_decl; + +      SymbolFile *symbol_file = image->GetSymbolFile(); + +      if (!symbol_file) +        continue; + +      found_namespace_decl = +          symbol_file->FindNamespace(name, &null_namespace_decl); + +      if (!found_namespace_decl) +        continue; + +      namespace_map->push_back(std::pair<lldb::ModuleSP, CompilerDeclContext>( +          image, found_namespace_decl)); + +      LLDB_LOGF(log, "  CMN[%u] Found namespace %s in module %s", current_id, +                name.GetCString(), +                image->GetFileSpec().GetFilename().GetCString()); +    } +  } +} + +NamespaceDecl *ClangASTSource::AddNamespace( +    NameSearchContext &context, +    ClangASTImporter::NamespaceMapSP &namespace_decls) { +  if (!namespace_decls) +    return nullptr; + +  const CompilerDeclContext &namespace_decl = namespace_decls->begin()->second; + +  clang::ASTContext *src_ast = +      ClangASTContext::DeclContextGetClangASTContext(namespace_decl); +  if (!src_ast) +    return nullptr; +  clang::NamespaceDecl *src_namespace_decl = +      ClangASTContext::DeclContextGetAsNamespaceDecl(namespace_decl); + +  if (!src_namespace_decl) +    return nullptr; + +  Decl *copied_decl = CopyDecl(src_namespace_decl); + +  if (!copied_decl) +    return nullptr; + +  NamespaceDecl *copied_namespace_decl = dyn_cast<NamespaceDecl>(copied_decl); + +  if (!copied_namespace_decl) +    return nullptr; + +  context.m_decls.push_back(copied_namespace_decl); + +  m_ast_importer_sp->RegisterNamespaceMap(copied_namespace_decl, +                                          namespace_decls); + +  return dyn_cast<NamespaceDecl>(copied_decl); +} + +clang::QualType ClangASTSource::CopyTypeWithMerger( +    clang::ASTContext &from_context, +    clang::ExternalASTMerger &merger, +    clang::QualType type) { +  if (!merger.HasImporterForOrigin(from_context)) { +    lldbassert(0 && "Couldn't find the importer for a source context!"); +    return QualType(); +  } + +  if (llvm::Expected<QualType> type_or_error = +          merger.ImporterForOrigin(from_context).Import(type)) { +    return *type_or_error; +  } else { +    Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS); +    LLDB_LOG_ERROR(log, type_or_error.takeError(), "Couldn't import type: {0}"); +    return QualType(); +  } +} + +clang::Decl *ClangASTSource::CopyDecl(Decl *src_decl) { +  clang::ASTContext &from_context = src_decl->getASTContext(); +  if (m_ast_importer_sp) { +    return m_ast_importer_sp->CopyDecl(m_ast_context, &from_context, src_decl); +  } else if (m_merger_up) { +    if (!m_merger_up->HasImporterForOrigin(from_context)) { +      lldbassert(0 && "Couldn't find the importer for a source context!"); +      return nullptr; +    } + +    if (llvm::Expected<Decl *> decl_or_error = +            m_merger_up->ImporterForOrigin(from_context).Import(src_decl)) { +      return *decl_or_error; +    } else { +      Log *log = +          lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS); +      LLDB_LOG_ERROR(log, decl_or_error.takeError(), +                     "Couldn't import decl: {0}"); +      return nullptr; +    } +  } else { +    lldbassert(0 && "No mechanism for copying a decl!"); +    return nullptr; +  } +} + +bool ClangASTSource::ResolveDeclOrigin(const clang::Decl *decl, +                                       clang::Decl **original_decl, +                                       clang::ASTContext **original_ctx) { +  if (m_ast_importer_sp) { +    return m_ast_importer_sp->ResolveDeclOrigin(decl, original_decl, +                                                original_ctx); +  } else if (m_merger_up) { +    return false; // Implement this correctly in ExternalASTMerger +  } else { +    // this can happen early enough that no ExternalASTSource is installed. +    return false; +  } +} + +clang::ExternalASTMerger &ClangASTSource::GetMergerUnchecked() { +  lldbassert(m_merger_up != nullptr); +  return *m_merger_up; +} + +CompilerType ClangASTSource::GuardedCopyType(const CompilerType &src_type) { +  ClangASTContext *src_ast = +      llvm::dyn_cast_or_null<ClangASTContext>(src_type.GetTypeSystem()); +  if (src_ast == nullptr) +    return CompilerType(); + +  ClangASTMetrics::RegisterLLDBImport(); + +  SetImportInProgress(true); + +  QualType copied_qual_type; + +  if (m_ast_importer_sp) { +    copied_qual_type = +        m_ast_importer_sp->CopyType(m_ast_context, src_ast->getASTContext(), +                                    ClangUtil::GetQualType(src_type)); +  } else if (m_merger_up) { +    copied_qual_type = +        CopyTypeWithMerger(*src_ast->getASTContext(), *m_merger_up, +                 ClangUtil::GetQualType(src_type)); +  } else { +    lldbassert(0 && "No mechanism for copying a type!"); +    return CompilerType(); +  } + +  SetImportInProgress(false); + +  if (copied_qual_type.getAsOpaquePtr() && +      copied_qual_type->getCanonicalTypeInternal().isNull()) +    // this shouldn't happen, but we're hardening because the AST importer +    // seems to be generating bad types on occasion. +    return CompilerType(); + +  return CompilerType(ClangASTContext::GetASTContext(m_ast_context), +                      copied_qual_type.getAsOpaquePtr()); +} + +clang::NamedDecl *NameSearchContext::AddVarDecl(const CompilerType &type) { +  assert(type && "Type for variable must be valid!"); + +  if (!type.IsValid()) +    return nullptr; + +  ClangASTContext *lldb_ast = +      llvm::dyn_cast<ClangASTContext>(type.GetTypeSystem()); +  if (!lldb_ast) +    return nullptr; + +  IdentifierInfo *ii = m_decl_name.getAsIdentifierInfo(); + +  clang::ASTContext *ast = lldb_ast->getASTContext(); + +  clang::NamedDecl *Decl = VarDecl::Create( +      *ast, const_cast<DeclContext *>(m_decl_context), SourceLocation(), +      SourceLocation(), ii, ClangUtil::GetQualType(type), nullptr, SC_Static); +  m_decls.push_back(Decl); + +  return Decl; +} + +clang::NamedDecl *NameSearchContext::AddFunDecl(const CompilerType &type, +                                                bool extern_c) { +  assert(type && "Type for variable must be valid!"); + +  if (!type.IsValid()) +    return nullptr; + +  if (m_function_types.count(type)) +    return nullptr; + +  ClangASTContext *lldb_ast = +      llvm::dyn_cast<ClangASTContext>(type.GetTypeSystem()); +  if (!lldb_ast) +    return nullptr; + +  m_function_types.insert(type); + +  QualType qual_type(ClangUtil::GetQualType(type)); + +  clang::ASTContext *ast = lldb_ast->getASTContext(); + +  const bool isInlineSpecified = false; +  const bool hasWrittenPrototype = true; +  const bool isConstexprSpecified = false; + +  clang::DeclContext *context = const_cast<DeclContext *>(m_decl_context); + +  if (extern_c) { +    context = LinkageSpecDecl::Create( +        *ast, context, SourceLocation(), SourceLocation(), +        clang::LinkageSpecDecl::LanguageIDs::lang_c, false); +  } + +  // Pass the identifier info for functions the decl_name is needed for +  // operators +  clang::DeclarationName decl_name = +      m_decl_name.getNameKind() == DeclarationName::Identifier +          ? m_decl_name.getAsIdentifierInfo() +          : m_decl_name; + +  clang::FunctionDecl *func_decl = FunctionDecl::Create( +      *ast, context, SourceLocation(), SourceLocation(), decl_name, qual_type, +      nullptr, SC_Extern, isInlineSpecified, hasWrittenPrototype, +      isConstexprSpecified ? CSK_constexpr : CSK_unspecified); + +  // We have to do more than just synthesize the FunctionDecl.  We have to +  // synthesize ParmVarDecls for all of the FunctionDecl's arguments.  To do +  // this, we raid the function's FunctionProtoType for types. + +  const FunctionProtoType *func_proto_type = +      qual_type.getTypePtr()->getAs<FunctionProtoType>(); + +  if (func_proto_type) { +    unsigned NumArgs = func_proto_type->getNumParams(); +    unsigned ArgIndex; + +    SmallVector<ParmVarDecl *, 5> parm_var_decls; + +    for (ArgIndex = 0; ArgIndex < NumArgs; ++ArgIndex) { +      QualType arg_qual_type(func_proto_type->getParamType(ArgIndex)); + +      parm_var_decls.push_back( +          ParmVarDecl::Create(*ast, const_cast<DeclContext *>(context), +                              SourceLocation(), SourceLocation(), nullptr, +                              arg_qual_type, nullptr, SC_Static, nullptr)); +    } + +    func_decl->setParams(ArrayRef<ParmVarDecl *>(parm_var_decls)); +  } else { +    Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); + +    LLDB_LOGF(log, "Function type wasn't a FunctionProtoType"); +  } + +  // If this is an operator (e.g. operator new or operator==), only insert the +  // declaration we inferred from the symbol if we can provide the correct +  // number of arguments. We shouldn't really inject random decl(s) for +  // functions that are analyzed semantically in a special way, otherwise we +  // will crash in clang. +  clang::OverloadedOperatorKind op_kind = clang::NUM_OVERLOADED_OPERATORS; +  if (func_proto_type && +      ClangASTContext::IsOperator(decl_name.getAsString().c_str(), op_kind)) { +    if (!ClangASTContext::CheckOverloadedOperatorKindParameterCount( +            false, op_kind, func_proto_type->getNumParams())) +      return nullptr; +  } +  m_decls.push_back(func_decl); + +  return func_decl; +} + +clang::NamedDecl *NameSearchContext::AddGenericFunDecl() { +  FunctionProtoType::ExtProtoInfo proto_info; + +  proto_info.Variadic = true; + +  QualType generic_function_type(m_ast_source.m_ast_context->getFunctionType( +      m_ast_source.m_ast_context->UnknownAnyTy, // result +      ArrayRef<QualType>(),                     // argument types +      proto_info)); + +  return AddFunDecl( +      CompilerType(ClangASTContext::GetASTContext(m_ast_source.m_ast_context), +                   generic_function_type.getAsOpaquePtr()), +      true); +} + +clang::NamedDecl * +NameSearchContext::AddTypeDecl(const CompilerType &clang_type) { +  if (ClangUtil::IsClangType(clang_type)) { +    QualType qual_type = ClangUtil::GetQualType(clang_type); + +    if (const TypedefType *typedef_type = +            llvm::dyn_cast<TypedefType>(qual_type)) { +      TypedefNameDecl *typedef_name_decl = typedef_type->getDecl(); + +      m_decls.push_back(typedef_name_decl); + +      return (NamedDecl *)typedef_name_decl; +    } else if (const TagType *tag_type = qual_type->getAs<TagType>()) { +      TagDecl *tag_decl = tag_type->getDecl(); + +      m_decls.push_back(tag_decl); + +      return tag_decl; +    } else if (const ObjCObjectType *objc_object_type = +                   qual_type->getAs<ObjCObjectType>()) { +      ObjCInterfaceDecl *interface_decl = objc_object_type->getInterface(); + +      m_decls.push_back((NamedDecl *)interface_decl); + +      return (NamedDecl *)interface_decl; +    } +  } +  return nullptr; +} + +void NameSearchContext::AddLookupResult(clang::DeclContextLookupResult result) { +  for (clang::NamedDecl *decl : result) +    m_decls.push_back(decl); +} + +void NameSearchContext::AddNamedDecl(clang::NamedDecl *decl) { +  m_decls.push_back(decl); +}  | 
