[lldb] Move clang-based files out of Symbol

Summary:
This change represents the move of ClangASTImporter, ClangASTMetadata,
ClangExternalASTSourceCallbacks, ClangUtil, CxxModuleHandler, and
TypeSystemClang from lldbSource to lldbPluginExpressionParserClang.h

This explicitly removes knowledge of clang internals from lldbSymbol,
moving towards a more generic core implementation of lldb.

Reviewers: JDevlieghere, davide, aprantl, teemperor, clayborg, labath, jingham, shafik

Subscribers: emaste, mgorny, arphaman, jfb, usaxena95, lldb-commits

Tags: #lldb

Differential Revision: https://reviews.llvm.org/D73661
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.cpp
index 7b2acb4..f0e1b5d 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.cpp
@@ -8,10 +8,10 @@
 
 #include "ASTResultSynthesizer.h"
 
+#include "ClangASTImporter.h"
 #include "ClangPersistentVariables.h"
 
-#include "lldb/Symbol/TypeSystemClang.h"
-#include "lldb/Symbol/ClangASTImporter.h"
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
 #include "lldb/Target/Target.h"
 #include "lldb/Utility/LLDBAssert.h"
 #include "lldb/Utility/Log.h"
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/CMakeLists.txt b/lldb/source/Plugins/ExpressionParser/Clang/CMakeLists.txt
index e92d089..3bb120a 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/CMakeLists.txt
+++ b/lldb/source/Plugins/ExpressionParser/Clang/CMakeLists.txt
@@ -6,19 +6,24 @@
   ASTResultSynthesizer.cpp
   ASTStructExtractor.cpp
   ASTUtils.cpp
+  ClangASTImporter.cpp
+  ClangASTMetadata.cpp
   ClangASTSource.cpp
   ClangDeclVendor.cpp
   ClangExpressionDeclMap.cpp
   ClangExpressionParser.cpp
   ClangExpressionSourceCode.cpp
   ClangExpressionVariable.cpp
+  ClangExternalASTSourceCallbacks.cpp
   ClangFunctionCaller.cpp
   ClangHost.cpp
   ClangModulesDeclVendor.cpp
   ClangPersistentVariables.cpp
   ClangUserExpression.cpp
+  ClangUtil.cpp
   ClangUtilityFunction.cpp
   CppModuleConfiguration.cpp
+  CxxModuleHandler.cpp
   IRForTarget.cpp
   IRDynamicChecks.cpp
 
@@ -35,6 +40,8 @@
     lldbUtility
     lldbPluginCPlusPlusLanguage
     lldbPluginCPPRuntime
+    lldbPluginObjCRuntime
+    lldbPluginTypeSystemClang
   CLANG_LIBS
     clangAST
     clangCodeGen
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp
new file mode 100644
index 0000000..479cb64
--- /dev/null
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp
@@ -0,0 +1,1152 @@
+//===-- ClangASTImporter.cpp ----------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Core/Module.h"
+#include "lldb/Utility/LLDBAssert.h"
+#include "lldb/Utility/Log.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/Sema/Lookup.h"
+#include "clang/Sema/Sema.h"
+#include "llvm/Support/raw_ostream.h"
+
+#include "Plugins/ExpressionParser/Clang/ClangASTImporter.h"
+#include "Plugins/ExpressionParser/Clang/ClangASTMetadata.h"
+#include "Plugins/ExpressionParser/Clang/ClangUtil.h"
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
+
+#include <memory>
+
+using namespace lldb_private;
+using namespace clang;
+
+CompilerType ClangASTImporter::CopyType(TypeSystemClang &dst_ast,
+                                        const CompilerType &src_type) {
+  clang::ASTContext &dst_clang_ast = dst_ast.getASTContext();
+
+  TypeSystemClang *src_ast =
+      llvm::dyn_cast_or_null<TypeSystemClang>(src_type.GetTypeSystem());
+  if (!src_ast)
+    return CompilerType();
+
+  clang::ASTContext &src_clang_ast = src_ast->getASTContext();
+
+  clang::QualType src_qual_type = ClangUtil::GetQualType(src_type);
+
+  ImporterDelegateSP delegate_sp(GetDelegate(&dst_clang_ast, &src_clang_ast));
+  if (!delegate_sp)
+    return CompilerType();
+
+  ASTImporterDelegate::CxxModuleScope std_scope(*delegate_sp, &dst_clang_ast);
+
+  llvm::Expected<QualType> ret_or_error = delegate_sp->Import(src_qual_type);
+  if (!ret_or_error) {
+    Log *log =
+      lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS);
+    LLDB_LOG_ERROR(log, ret_or_error.takeError(),
+        "Couldn't import type: {0}");
+    return CompilerType();
+  }
+
+  lldb::opaque_compiler_type_t dst_clang_type = ret_or_error->getAsOpaquePtr();
+
+  if (dst_clang_type)
+    return CompilerType(&dst_ast, dst_clang_type);
+  return CompilerType();
+}
+
+clang::Decl *ClangASTImporter::CopyDecl(clang::ASTContext *dst_ast,
+                                        clang::Decl *decl) {
+  ImporterDelegateSP delegate_sp;
+
+  clang::ASTContext *src_ast = &decl->getASTContext();
+  delegate_sp = GetDelegate(dst_ast, src_ast);
+
+  ASTImporterDelegate::CxxModuleScope std_scope(*delegate_sp, dst_ast);
+
+  if (!delegate_sp)
+    return nullptr;
+
+  llvm::Expected<clang::Decl *> result = delegate_sp->Import(decl);
+  if (!result) {
+    Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
+    LLDB_LOG_ERROR(log, result.takeError(), "Couldn't import decl: {0}");
+    if (log) {
+      lldb::user_id_t user_id = LLDB_INVALID_UID;
+      ClangASTMetadata *metadata = GetDeclMetadata(decl);
+      if (metadata)
+        user_id = metadata->GetUserID();
+
+      if (NamedDecl *named_decl = dyn_cast<NamedDecl>(decl))
+        LLDB_LOG(log,
+                 "  [ClangASTImporter] WARNING: Failed to import a {0} "
+                 "'{1}', metadata {2}",
+                 decl->getDeclKindName(), named_decl->getNameAsString(),
+                 user_id);
+      else
+        LLDB_LOG(log,
+                 "  [ClangASTImporter] WARNING: Failed to import a {0}, "
+                 "metadata {1}",
+                 decl->getDeclKindName(), user_id);
+    }
+    return nullptr;
+  }
+
+  return *result;
+}
+
+class DeclContextOverride {
+private:
+  struct Backup {
+    clang::DeclContext *decl_context;
+    clang::DeclContext *lexical_decl_context;
+  };
+
+  llvm::DenseMap<clang::Decl *, Backup> m_backups;
+
+  void OverrideOne(clang::Decl *decl) {
+    if (m_backups.find(decl) != m_backups.end()) {
+      return;
+    }
+
+    m_backups[decl] = {decl->getDeclContext(), decl->getLexicalDeclContext()};
+
+    decl->setDeclContext(decl->getASTContext().getTranslationUnitDecl());
+    decl->setLexicalDeclContext(decl->getASTContext().getTranslationUnitDecl());
+  }
+
+  bool ChainPassesThrough(
+      clang::Decl *decl, clang::DeclContext *base,
+      clang::DeclContext *(clang::Decl::*contextFromDecl)(),
+      clang::DeclContext *(clang::DeclContext::*contextFromContext)()) {
+    for (DeclContext *decl_ctx = (decl->*contextFromDecl)(); decl_ctx;
+         decl_ctx = (decl_ctx->*contextFromContext)()) {
+      if (decl_ctx == base) {
+        return true;
+      }
+    }
+
+    return false;
+  }
+
+  clang::Decl *GetEscapedChild(clang::Decl *decl,
+                               clang::DeclContext *base = nullptr) {
+    if (base) {
+      // decl's DeclContext chains must pass through base.
+
+      if (!ChainPassesThrough(decl, base, &clang::Decl::getDeclContext,
+                              &clang::DeclContext::getParent) ||
+          !ChainPassesThrough(decl, base, &clang::Decl::getLexicalDeclContext,
+                              &clang::DeclContext::getLexicalParent)) {
+        return decl;
+      }
+    } else {
+      base = clang::dyn_cast<clang::DeclContext>(decl);
+
+      if (!base) {
+        return nullptr;
+      }
+    }
+
+    if (clang::DeclContext *context =
+            clang::dyn_cast<clang::DeclContext>(decl)) {
+      for (clang::Decl *decl : context->decls()) {
+        if (clang::Decl *escaped_child = GetEscapedChild(decl)) {
+          return escaped_child;
+        }
+      }
+    }
+
+    return nullptr;
+  }
+
+  void Override(clang::Decl *decl) {
+    if (clang::Decl *escaped_child = GetEscapedChild(decl)) {
+      Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
+
+      LLDB_LOG(log,
+               "    [ClangASTImporter] DeclContextOverride couldn't "
+               "override ({0}Decl*){1} - its child ({2}Decl*){3} escapes",
+               decl->getDeclKindName(), decl, escaped_child->getDeclKindName(),
+               escaped_child);
+      lldbassert(0 && "Couldn't override!");
+    }
+
+    OverrideOne(decl);
+  }
+
+public:
+  DeclContextOverride() {}
+
+  void OverrideAllDeclsFromContainingFunction(clang::Decl *decl) {
+    for (DeclContext *decl_context = decl->getLexicalDeclContext();
+         decl_context; decl_context = decl_context->getLexicalParent()) {
+      DeclContext *redecl_context = decl_context->getRedeclContext();
+
+      if (llvm::isa<FunctionDecl>(redecl_context) &&
+          llvm::isa<TranslationUnitDecl>(redecl_context->getLexicalParent())) {
+        for (clang::Decl *child_decl : decl_context->decls()) {
+          Override(child_decl);
+        }
+      }
+    }
+  }
+
+  ~DeclContextOverride() {
+    for (const std::pair<clang::Decl *, Backup> &backup : m_backups) {
+      backup.first->setDeclContext(backup.second.decl_context);
+      backup.first->setLexicalDeclContext(backup.second.lexical_decl_context);
+    }
+  }
+};
+
+namespace {
+/// Completes all imported TagDecls at the end of the scope.
+///
+/// While in a CompleteTagDeclsScope, every decl that could be completed will
+/// be completed at the end of the scope (including all Decls that are
+/// imported while completing the original Decls).
+class CompleteTagDeclsScope : public ClangASTImporter::NewDeclListener {
+  ClangASTImporter::ImporterDelegateSP m_delegate;
+  llvm::SmallVector<NamedDecl *, 32> m_decls_to_complete;
+  llvm::SmallPtrSet<NamedDecl *, 32> m_decls_already_completed;
+  clang::ASTContext *m_dst_ctx;
+  clang::ASTContext *m_src_ctx;
+  ClangASTImporter &importer;
+
+public:
+  /// Constructs a CompleteTagDeclsScope.
+  /// \param importer The ClangASTImporter that we should observe.
+  /// \param dst_ctx The ASTContext to which Decls are imported.
+  /// \param src_ctx The ASTContext from which Decls are imported.
+  explicit CompleteTagDeclsScope(ClangASTImporter &importer,
+                            clang::ASTContext *dst_ctx,
+                            clang::ASTContext *src_ctx)
+      : m_delegate(importer.GetDelegate(dst_ctx, src_ctx)), m_dst_ctx(dst_ctx),
+        m_src_ctx(src_ctx), importer(importer) {
+    m_delegate->SetImportListener(this);
+  }
+
+  virtual ~CompleteTagDeclsScope() {
+    ClangASTImporter::ASTContextMetadataSP to_context_md =
+        importer.GetContextMetadata(m_dst_ctx);
+
+    // Complete all decls we collected until now.
+    while (!m_decls_to_complete.empty()) {
+      NamedDecl *decl = m_decls_to_complete.pop_back_val();
+      m_decls_already_completed.insert(decl);
+
+      // We should only complete decls coming from the source context.
+      assert(to_context_md->m_origins[decl].ctx == m_src_ctx);
+
+      Decl *original_decl = to_context_md->m_origins[decl].decl;
+
+      // Complete the decl now.
+      TypeSystemClang::GetCompleteDecl(m_src_ctx, original_decl);
+      if (auto *tag_decl = dyn_cast<TagDecl>(decl)) {
+        if (auto *original_tag_decl = dyn_cast<TagDecl>(original_decl)) {
+          if (original_tag_decl->isCompleteDefinition()) {
+            m_delegate->ImportDefinitionTo(tag_decl, original_tag_decl);
+            tag_decl->setCompleteDefinition(true);
+          }
+        }
+
+        tag_decl->setHasExternalLexicalStorage(false);
+        tag_decl->setHasExternalVisibleStorage(false);
+      } else if (auto *container_decl = dyn_cast<ObjCContainerDecl>(decl)) {
+        container_decl->setHasExternalLexicalStorage(false);
+        container_decl->setHasExternalVisibleStorage(false);
+      }
+
+      to_context_md->m_origins.erase(decl);
+    }
+
+    // Stop listening to imported decls. We do this after clearing the
+    // Decls we needed to import to catch all Decls they might have pulled in.
+    m_delegate->RemoveImportListener();
+  }
+
+  void NewDeclImported(clang::Decl *from, clang::Decl *to) override {
+    // Filter out decls that we can't complete later.
+    if (!isa<TagDecl>(to) && !isa<ObjCInterfaceDecl>(to))
+      return;
+    RecordDecl *from_record_decl = dyn_cast<RecordDecl>(from);
+    // We don't need to complete injected class name decls.
+    if (from_record_decl && from_record_decl->isInjectedClassName())
+      return;
+
+    NamedDecl *to_named_decl = dyn_cast<NamedDecl>(to);
+    // Check if we already completed this type.
+    if (m_decls_already_completed.count(to_named_decl) != 0)
+      return;
+    m_decls_to_complete.push_back(to_named_decl);
+  }
+};
+} // namespace
+
+CompilerType ClangASTImporter::DeportType(TypeSystemClang &dst,
+                                          const CompilerType &src_type) {
+  Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
+
+  TypeSystemClang *src_ctxt =
+      llvm::cast<TypeSystemClang>(src_type.GetTypeSystem());
+
+  LLDB_LOG(log,
+           "    [ClangASTImporter] DeportType called on ({0}Type*){1} "
+           "from (ASTContext*){2} to (ASTContext*){3}",
+           src_type.GetTypeName(), src_type.GetOpaqueQualType(),
+           &src_ctxt->getASTContext(), &dst.getASTContext());
+
+  DeclContextOverride decl_context_override;
+
+  if (auto *t = ClangUtil::GetQualType(src_type)->getAs<TagType>())
+    decl_context_override.OverrideAllDeclsFromContainingFunction(t->getDecl());
+
+  CompleteTagDeclsScope complete_scope(*this, &dst.getASTContext(),
+                                       &src_ctxt->getASTContext());
+  return CopyType(dst, src_type);
+}
+
+clang::Decl *ClangASTImporter::DeportDecl(clang::ASTContext *dst_ctx,
+                                          clang::Decl *decl) {
+  Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
+
+  clang::ASTContext *src_ctx = &decl->getASTContext();
+  LLDB_LOG(log,
+           "    [ClangASTImporter] DeportDecl called on ({0}Decl*){1} from "
+           "(ASTContext*){2} to (ASTContext*){3}",
+           decl->getDeclKindName(), decl, src_ctx, dst_ctx);
+
+  DeclContextOverride decl_context_override;
+
+  decl_context_override.OverrideAllDeclsFromContainingFunction(decl);
+
+  clang::Decl *result;
+  {
+    CompleteTagDeclsScope complete_scope(*this, dst_ctx, src_ctx);
+    result = CopyDecl(dst_ctx, decl);
+  }
+
+  if (!result)
+    return nullptr;
+
+  LLDB_LOG(log,
+           "    [ClangASTImporter] DeportDecl deported ({0}Decl*){1} to "
+           "({2}Decl*){3}",
+           decl->getDeclKindName(), decl, result->getDeclKindName(), result);
+
+  return result;
+}
+
+bool ClangASTImporter::CanImport(const CompilerType &type) {
+  if (!ClangUtil::IsClangType(type))
+    return false;
+
+  // TODO: remove external completion BOOL
+  // CompleteAndFetchChildren should get the Decl out and check for the
+
+  clang::QualType qual_type(
+      ClangUtil::GetCanonicalQualType(ClangUtil::RemoveFastQualifiers(type)));
+
+  const clang::Type::TypeClass type_class = qual_type->getTypeClass();
+  switch (type_class) {
+  case clang::Type::Record: {
+    const clang::CXXRecordDecl *cxx_record_decl =
+        qual_type->getAsCXXRecordDecl();
+    if (cxx_record_decl) {
+      if (GetDeclOrigin(cxx_record_decl).Valid())
+        return true;
+    }
+  } break;
+
+  case clang::Type::Enum: {
+    clang::EnumDecl *enum_decl =
+        llvm::cast<clang::EnumType>(qual_type)->getDecl();
+    if (enum_decl) {
+      if (GetDeclOrigin(enum_decl).Valid())
+        return true;
+    }
+  } break;
+
+  case clang::Type::ObjCObject:
+  case clang::Type::ObjCInterface: {
+    const clang::ObjCObjectType *objc_class_type =
+        llvm::dyn_cast<clang::ObjCObjectType>(qual_type);
+    if (objc_class_type) {
+      clang::ObjCInterfaceDecl *class_interface_decl =
+          objc_class_type->getInterface();
+      // We currently can't complete objective C types through the newly added
+      // ASTContext because it only supports TagDecl objects right now...
+      if (class_interface_decl) {
+        if (GetDeclOrigin(class_interface_decl).Valid())
+          return true;
+      }
+    }
+  } break;
+
+  case clang::Type::Typedef:
+    return CanImport(CompilerType(type.GetTypeSystem(),
+                                  llvm::cast<clang::TypedefType>(qual_type)
+                                      ->getDecl()
+                                      ->getUnderlyingType()
+                                      .getAsOpaquePtr()));
+
+  case clang::Type::Auto:
+    return CanImport(CompilerType(type.GetTypeSystem(),
+                                  llvm::cast<clang::AutoType>(qual_type)
+                                      ->getDeducedType()
+                                      .getAsOpaquePtr()));
+
+  case clang::Type::Elaborated:
+    return CanImport(CompilerType(type.GetTypeSystem(),
+                                  llvm::cast<clang::ElaboratedType>(qual_type)
+                                      ->getNamedType()
+                                      .getAsOpaquePtr()));
+
+  case clang::Type::Paren:
+    return CanImport(CompilerType(
+        type.GetTypeSystem(),
+        llvm::cast<clang::ParenType>(qual_type)->desugar().getAsOpaquePtr()));
+
+  default:
+    break;
+  }
+
+  return false;
+}
+
+bool ClangASTImporter::Import(const CompilerType &type) {
+  if (!ClangUtil::IsClangType(type))
+    return false;
+  // TODO: remove external completion BOOL
+  // CompleteAndFetchChildren should get the Decl out and check for the
+
+  clang::QualType qual_type(
+      ClangUtil::GetCanonicalQualType(ClangUtil::RemoveFastQualifiers(type)));
+
+  const clang::Type::TypeClass type_class = qual_type->getTypeClass();
+  switch (type_class) {
+  case clang::Type::Record: {
+    const clang::CXXRecordDecl *cxx_record_decl =
+        qual_type->getAsCXXRecordDecl();
+    if (cxx_record_decl) {
+      if (GetDeclOrigin(cxx_record_decl).Valid())
+        return CompleteAndFetchChildren(qual_type);
+    }
+  } break;
+
+  case clang::Type::Enum: {
+    clang::EnumDecl *enum_decl =
+        llvm::cast<clang::EnumType>(qual_type)->getDecl();
+    if (enum_decl) {
+      if (GetDeclOrigin(enum_decl).Valid())
+        return CompleteAndFetchChildren(qual_type);
+    }
+  } break;
+
+  case clang::Type::ObjCObject:
+  case clang::Type::ObjCInterface: {
+    const clang::ObjCObjectType *objc_class_type =
+        llvm::dyn_cast<clang::ObjCObjectType>(qual_type);
+    if (objc_class_type) {
+      clang::ObjCInterfaceDecl *class_interface_decl =
+          objc_class_type->getInterface();
+      // We currently can't complete objective C types through the newly added
+      // ASTContext because it only supports TagDecl objects right now...
+      if (class_interface_decl) {
+        if (GetDeclOrigin(class_interface_decl).Valid())
+          return CompleteAndFetchChildren(qual_type);
+      }
+    }
+  } break;
+
+  case clang::Type::Typedef:
+    return Import(CompilerType(type.GetTypeSystem(),
+                               llvm::cast<clang::TypedefType>(qual_type)
+                                   ->getDecl()
+                                   ->getUnderlyingType()
+                                   .getAsOpaquePtr()));
+
+  case clang::Type::Auto:
+    return Import(CompilerType(type.GetTypeSystem(),
+                               llvm::cast<clang::AutoType>(qual_type)
+                                   ->getDeducedType()
+                                   .getAsOpaquePtr()));
+
+  case clang::Type::Elaborated:
+    return Import(CompilerType(type.GetTypeSystem(),
+                               llvm::cast<clang::ElaboratedType>(qual_type)
+                                   ->getNamedType()
+                                   .getAsOpaquePtr()));
+
+  case clang::Type::Paren:
+    return Import(CompilerType(
+        type.GetTypeSystem(),
+        llvm::cast<clang::ParenType>(qual_type)->desugar().getAsOpaquePtr()));
+
+  default:
+    break;
+  }
+  return false;
+}
+
+bool ClangASTImporter::CompleteType(const CompilerType &compiler_type) {
+  if (!CanImport(compiler_type))
+    return false;
+
+  if (Import(compiler_type)) {
+    TypeSystemClang::CompleteTagDeclarationDefinition(compiler_type);
+    return true;
+  }
+
+  TypeSystemClang::SetHasExternalStorage(compiler_type.GetOpaqueQualType(),
+                                         false);
+  return false;
+}
+
+bool ClangASTImporter::LayoutRecordType(
+    const clang::RecordDecl *record_decl, uint64_t &bit_size,
+    uint64_t &alignment,
+    llvm::DenseMap<const clang::FieldDecl *, uint64_t> &field_offsets,
+    llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits>
+        &base_offsets,
+    llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits>
+        &vbase_offsets) {
+  RecordDeclToLayoutMap::iterator pos =
+      m_record_decl_to_layout_map.find(record_decl);
+  bool success = false;
+  base_offsets.clear();
+  vbase_offsets.clear();
+  if (pos != m_record_decl_to_layout_map.end()) {
+    bit_size = pos->second.bit_size;
+    alignment = pos->second.alignment;
+    field_offsets.swap(pos->second.field_offsets);
+    base_offsets.swap(pos->second.base_offsets);
+    vbase_offsets.swap(pos->second.vbase_offsets);
+    m_record_decl_to_layout_map.erase(pos);
+    success = true;
+  } else {
+    bit_size = 0;
+    alignment = 0;
+    field_offsets.clear();
+  }
+  return success;
+}
+
+void ClangASTImporter::SetRecordLayout(clang::RecordDecl *decl,
+                                        const LayoutInfo &layout) {
+  m_record_decl_to_layout_map.insert(std::make_pair(decl, layout));
+}
+
+bool ClangASTImporter::CompleteTagDecl(clang::TagDecl *decl) {
+  DeclOrigin decl_origin = GetDeclOrigin(decl);
+
+  if (!decl_origin.Valid())
+    return false;
+
+  if (!TypeSystemClang::GetCompleteDecl(decl_origin.ctx, decl_origin.decl))
+    return false;
+
+  ImporterDelegateSP delegate_sp(
+      GetDelegate(&decl->getASTContext(), decl_origin.ctx));
+
+  ASTImporterDelegate::CxxModuleScope std_scope(*delegate_sp,
+                                                &decl->getASTContext());
+  if (delegate_sp)
+    delegate_sp->ImportDefinitionTo(decl, decl_origin.decl);
+
+  return true;
+}
+
+bool ClangASTImporter::CompleteTagDeclWithOrigin(clang::TagDecl *decl,
+                                                 clang::TagDecl *origin_decl) {
+  clang::ASTContext *origin_ast_ctx = &origin_decl->getASTContext();
+
+  if (!TypeSystemClang::GetCompleteDecl(origin_ast_ctx, origin_decl))
+    return false;
+
+  ImporterDelegateSP delegate_sp(
+      GetDelegate(&decl->getASTContext(), origin_ast_ctx));
+
+  if (delegate_sp)
+    delegate_sp->ImportDefinitionTo(decl, origin_decl);
+
+  ASTContextMetadataSP context_md = GetContextMetadata(&decl->getASTContext());
+
+  OriginMap &origins = context_md->m_origins;
+
+  origins[decl] = DeclOrigin(origin_ast_ctx, origin_decl);
+
+  return true;
+}
+
+bool ClangASTImporter::CompleteObjCInterfaceDecl(
+    clang::ObjCInterfaceDecl *interface_decl) {
+  DeclOrigin decl_origin = GetDeclOrigin(interface_decl);
+
+  if (!decl_origin.Valid())
+    return false;
+
+  if (!TypeSystemClang::GetCompleteDecl(decl_origin.ctx, decl_origin.decl))
+    return false;
+
+  ImporterDelegateSP delegate_sp(
+      GetDelegate(&interface_decl->getASTContext(), decl_origin.ctx));
+
+  if (delegate_sp)
+    delegate_sp->ImportDefinitionTo(interface_decl, decl_origin.decl);
+
+  if (ObjCInterfaceDecl *super_class = interface_decl->getSuperClass())
+    RequireCompleteType(clang::QualType(super_class->getTypeForDecl(), 0));
+
+  return true;
+}
+
+bool ClangASTImporter::CompleteAndFetchChildren(clang::QualType type) {
+  if (!RequireCompleteType(type))
+    return false;
+
+  Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS);
+
+  if (const TagType *tag_type = type->getAs<TagType>()) {
+    TagDecl *tag_decl = tag_type->getDecl();
+
+    DeclOrigin decl_origin = GetDeclOrigin(tag_decl);
+
+    if (!decl_origin.Valid())
+      return false;
+
+    ImporterDelegateSP delegate_sp(
+        GetDelegate(&tag_decl->getASTContext(), decl_origin.ctx));
+
+    ASTImporterDelegate::CxxModuleScope std_scope(*delegate_sp,
+                                                  &tag_decl->getASTContext());
+
+    TagDecl *origin_tag_decl = llvm::dyn_cast<TagDecl>(decl_origin.decl);
+
+    for (Decl *origin_child_decl : origin_tag_decl->decls()) {
+      llvm::Expected<Decl *> imported_or_err =
+          delegate_sp->Import(origin_child_decl);
+      if (!imported_or_err) {
+        LLDB_LOG_ERROR(log, imported_or_err.takeError(),
+                       "Couldn't import decl: {0}");
+        return false;
+      }
+    }
+
+    if (RecordDecl *record_decl = dyn_cast<RecordDecl>(origin_tag_decl))
+      record_decl->setHasLoadedFieldsFromExternalStorage(true);
+
+    return true;
+  }
+
+  if (const ObjCObjectType *objc_object_type = type->getAs<ObjCObjectType>()) {
+    if (ObjCInterfaceDecl *objc_interface_decl =
+            objc_object_type->getInterface()) {
+      DeclOrigin decl_origin = GetDeclOrigin(objc_interface_decl);
+
+      if (!decl_origin.Valid())
+        return false;
+
+      ImporterDelegateSP delegate_sp(
+          GetDelegate(&objc_interface_decl->getASTContext(), decl_origin.ctx));
+
+      ObjCInterfaceDecl *origin_interface_decl =
+          llvm::dyn_cast<ObjCInterfaceDecl>(decl_origin.decl);
+
+      for (Decl *origin_child_decl : origin_interface_decl->decls()) {
+        llvm::Expected<Decl *> imported_or_err =
+            delegate_sp->Import(origin_child_decl);
+        if (!imported_or_err) {
+          LLDB_LOG_ERROR(log, imported_or_err.takeError(),
+                         "Couldn't import decl: {0}");
+          return false;
+        }
+      }
+
+      return true;
+    }
+    return false;
+  }
+
+  return true;
+}
+
+bool ClangASTImporter::RequireCompleteType(clang::QualType type) {
+  if (type.isNull())
+    return false;
+
+  if (const TagType *tag_type = type->getAs<TagType>()) {
+    TagDecl *tag_decl = tag_type->getDecl();
+
+    if (tag_decl->getDefinition() || tag_decl->isBeingDefined())
+      return true;
+
+    return CompleteTagDecl(tag_decl);
+  }
+  if (const ObjCObjectType *objc_object_type = type->getAs<ObjCObjectType>()) {
+    if (ObjCInterfaceDecl *objc_interface_decl =
+            objc_object_type->getInterface())
+      return CompleteObjCInterfaceDecl(objc_interface_decl);
+    return false;
+  }
+  if (const ArrayType *array_type = type->getAsArrayTypeUnsafe())
+    return RequireCompleteType(array_type->getElementType());
+  if (const AtomicType *atomic_type = type->getAs<AtomicType>())
+    return RequireCompleteType(atomic_type->getPointeeType());
+
+  return true;
+}
+
+ClangASTMetadata *ClangASTImporter::GetDeclMetadata(const clang::Decl *decl) {
+  DeclOrigin decl_origin = GetDeclOrigin(decl);
+
+  if (decl_origin.Valid()) {
+    TypeSystemClang *ast = TypeSystemClang::GetASTContext(decl_origin.ctx);
+    return ast->GetMetadata(decl_origin.decl);
+  }
+  TypeSystemClang *ast = TypeSystemClang::GetASTContext(&decl->getASTContext());
+  return ast->GetMetadata(decl);
+}
+
+ClangASTImporter::DeclOrigin
+ClangASTImporter::GetDeclOrigin(const clang::Decl *decl) {
+  ASTContextMetadataSP context_md = GetContextMetadata(&decl->getASTContext());
+
+  OriginMap &origins = context_md->m_origins;
+
+  OriginMap::iterator iter = origins.find(decl);
+
+  if (iter != origins.end())
+    return iter->second;
+  return DeclOrigin();
+}
+
+void ClangASTImporter::SetDeclOrigin(const clang::Decl *decl,
+                                     clang::Decl *original_decl) {
+  ASTContextMetadataSP context_md = GetContextMetadata(&decl->getASTContext());
+
+  OriginMap &origins = context_md->m_origins;
+
+  OriginMap::iterator iter = origins.find(decl);
+
+  if (iter != origins.end()) {
+    iter->second.decl = original_decl;
+    iter->second.ctx = &original_decl->getASTContext();
+    return;
+  }
+  origins[decl] = DeclOrigin(&original_decl->getASTContext(), original_decl);
+}
+
+void ClangASTImporter::RegisterNamespaceMap(const clang::NamespaceDecl *decl,
+                                            NamespaceMapSP &namespace_map) {
+  ASTContextMetadataSP context_md = GetContextMetadata(&decl->getASTContext());
+
+  context_md->m_namespace_maps[decl] = namespace_map;
+}
+
+ClangASTImporter::NamespaceMapSP
+ClangASTImporter::GetNamespaceMap(const clang::NamespaceDecl *decl) {
+  ASTContextMetadataSP context_md = GetContextMetadata(&decl->getASTContext());
+
+  NamespaceMetaMap &namespace_maps = context_md->m_namespace_maps;
+
+  NamespaceMetaMap::iterator iter = namespace_maps.find(decl);
+
+  if (iter != namespace_maps.end())
+    return iter->second;
+  return NamespaceMapSP();
+}
+
+void ClangASTImporter::BuildNamespaceMap(const clang::NamespaceDecl *decl) {
+  assert(decl);
+  ASTContextMetadataSP context_md = GetContextMetadata(&decl->getASTContext());
+
+  const DeclContext *parent_context = decl->getDeclContext();
+  const NamespaceDecl *parent_namespace =
+      dyn_cast<NamespaceDecl>(parent_context);
+  NamespaceMapSP parent_map;
+
+  if (parent_namespace)
+    parent_map = GetNamespaceMap(parent_namespace);
+
+  NamespaceMapSP new_map;
+
+  new_map = std::make_shared<NamespaceMap>();
+
+  if (context_md->m_map_completer) {
+    std::string namespace_string = decl->getDeclName().getAsString();
+
+    context_md->m_map_completer->CompleteNamespaceMap(
+        new_map, ConstString(namespace_string.c_str()), parent_map);
+  }
+
+  context_md->m_namespace_maps[decl] = new_map;
+}
+
+void ClangASTImporter::ForgetDestination(clang::ASTContext *dst_ast) {
+  Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
+
+  LLDB_LOG(log,
+           "    [ClangASTImporter] Forgetting destination (ASTContext*){0}",
+           dst_ast);
+
+  m_metadata_map.erase(dst_ast);
+}
+
+void ClangASTImporter::ForgetSource(clang::ASTContext *dst_ast,
+                                    clang::ASTContext *src_ast) {
+  ASTContextMetadataSP md = MaybeGetContextMetadata(dst_ast);
+
+  Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
+
+  LLDB_LOG(log,
+           "    [ClangASTImporter] Forgetting source->dest "
+           "(ASTContext*){0}->(ASTContext*){1}",
+           src_ast, dst_ast);
+
+  if (!md)
+    return;
+
+  md->m_delegates.erase(src_ast);
+
+  for (OriginMap::iterator iter = md->m_origins.begin();
+       iter != md->m_origins.end();) {
+    if (iter->second.ctx == src_ast)
+      md->m_origins.erase(iter++);
+    else
+      ++iter;
+  }
+}
+
+ClangASTImporter::MapCompleter::~MapCompleter() { return; }
+
+llvm::Expected<Decl *>
+ClangASTImporter::ASTImporterDelegate::ImportImpl(Decl *From) {
+  if (m_std_handler) {
+    llvm::Optional<Decl *> D = m_std_handler->Import(From);
+    if (D) {
+      // Make sure we don't use this decl later to map it back to it's original
+      // decl. The decl the CxxModuleHandler created has nothing to do with
+      // the one from debug info, and linking those two would just cause the
+      // ASTImporter to try 'updating' the module decl with the minimal one from
+      // the debug info.
+      m_decls_to_ignore.insert(*D);
+      return *D;
+    }
+  }
+
+  // Check which ASTContext this declaration originally came from.
+  DeclOrigin origin = m_master.GetDeclOrigin(From);
+  // If it originally came from the target ASTContext then we can just
+  // pretend that the original is the one we imported. This can happen for
+  // example when inspecting a persistent declaration from the scratch
+  // ASTContext (which will provide the declaration when parsing the
+  // expression and then we later try to copy the declaration back to the
+  // scratch ASTContext to store the result).
+  // Without this check we would ask the ASTImporter to import a declaration
+  // into the same ASTContext where it came from (which doesn't make a lot of
+  // sense).
+  if (origin.Valid() && origin.ctx == &getToContext()) {
+    RegisterImportedDecl(From, origin.decl);
+    return origin.decl;
+  }
+
+  // This declaration came originally from another ASTContext. Instead of
+  // copying our potentially incomplete 'From' Decl we instead go to the
+  // original ASTContext and copy the original to the target. This is not
+  // only faster than first completing our current decl and then copying it
+  // to the target, but it also prevents that indirectly copying the same
+  // declaration to the same target requires the ASTImporter to merge all
+  // the different decls that appear to come from different ASTContexts (even
+  // though all these different source ASTContexts just got a copy from
+  // one source AST).
+  if (origin.Valid()) {
+    auto R = m_master.CopyDecl(&getToContext(), origin.decl);
+    if (R) {
+      RegisterImportedDecl(From, R);
+      return R;
+    }
+  }
+
+  return ASTImporter::ImportImpl(From);
+}
+
+void ClangASTImporter::ASTImporterDelegate::ImportDefinitionTo(
+    clang::Decl *to, clang::Decl *from) {
+  // We might have a forward declaration from a shared library that we
+  // gave external lexical storage so that Clang asks us about the full
+  // definition when it needs it. In this case the ASTImporter isn't aware
+  // that the forward decl from the shared library is the actual import
+  // target but would create a second declaration that would then be defined.
+  // We want that 'to' is actually complete after this function so let's
+  // tell the ASTImporter that 'to' was imported from 'from'.
+  MapImported(from, to);
+  ASTImporter::Imported(from, to);
+
+  /*
+  if (to_objc_interface)
+      to_objc_interface->startDefinition();
+
+  CXXRecordDecl *to_cxx_record = dyn_cast<CXXRecordDecl>(to);
+
+  if (to_cxx_record)
+      to_cxx_record->startDefinition();
+  */
+
+  Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS);
+
+  if (llvm::Error err = ImportDefinition(from)) {
+    LLDB_LOG_ERROR(log, std::move(err),
+                   "[ClangASTImporter] Error during importing definition: {0}");
+    return;
+  }
+
+  if (clang::TagDecl *to_tag = dyn_cast<clang::TagDecl>(to)) {
+    if (clang::TagDecl *from_tag = dyn_cast<clang::TagDecl>(from)) {
+      to_tag->setCompleteDefinition(from_tag->isCompleteDefinition());
+
+      if (Log *log_ast =
+              lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_AST)) {
+        std::string name_string;
+        if (NamedDecl *from_named_decl = dyn_cast<clang::NamedDecl>(from)) {
+          llvm::raw_string_ostream name_stream(name_string);
+          from_named_decl->printName(name_stream);
+          name_stream.flush();
+        }
+        LLDB_LOG(log_ast, "==== [ClangASTImporter][TUDecl: {0}] Imported "
+                          "({1}Decl*){2}, named {3} (from "
+                          "(Decl*){4})",
+                 static_cast<void *>(to->getTranslationUnitDecl()),
+                 from->getDeclKindName(), static_cast<void *>(to), name_string,
+                 static_cast<void *>(from));
+
+        // Log the AST of the TU.
+        std::string ast_string;
+        llvm::raw_string_ostream ast_stream(ast_string);
+        to->getTranslationUnitDecl()->dump(ast_stream);
+        LLDB_LOG(log_ast, "{0}", ast_string);
+      }
+    }
+  }
+
+  // If we're dealing with an Objective-C class, ensure that the inheritance
+  // has been set up correctly.  The ASTImporter may not do this correctly if
+  // the class was originally sourced from symbols.
+
+  if (ObjCInterfaceDecl *to_objc_interface = dyn_cast<ObjCInterfaceDecl>(to)) {
+    do {
+      ObjCInterfaceDecl *to_superclass = to_objc_interface->getSuperClass();
+
+      if (to_superclass)
+        break; // we're not going to override it if it's set
+
+      ObjCInterfaceDecl *from_objc_interface =
+          dyn_cast<ObjCInterfaceDecl>(from);
+
+      if (!from_objc_interface)
+        break;
+
+      ObjCInterfaceDecl *from_superclass = from_objc_interface->getSuperClass();
+
+      if (!from_superclass)
+        break;
+
+      llvm::Expected<Decl *> imported_from_superclass_decl =
+          Import(from_superclass);
+
+      if (!imported_from_superclass_decl) {
+        LLDB_LOG_ERROR(log, imported_from_superclass_decl.takeError(),
+                       "Couldn't import decl: {0}");
+        break;
+      }
+
+      ObjCInterfaceDecl *imported_from_superclass =
+          dyn_cast<ObjCInterfaceDecl>(*imported_from_superclass_decl);
+
+      if (!imported_from_superclass)
+        break;
+
+      if (!to_objc_interface->hasDefinition())
+        to_objc_interface->startDefinition();
+
+      to_objc_interface->setSuperClass(m_source_ctx->getTrivialTypeSourceInfo(
+          m_source_ctx->getObjCInterfaceType(imported_from_superclass)));
+    } while (false);
+  }
+}
+
+/// Takes a CXXMethodDecl and completes the return type if necessary. This
+/// is currently only necessary for virtual functions with covariant return
+/// types where Clang's CodeGen expects that the underlying records are already
+/// completed.
+static void MaybeCompleteReturnType(ClangASTImporter &importer,
+                                        CXXMethodDecl *to_method) {
+  if (!to_method->isVirtual())
+    return;
+  QualType return_type = to_method->getReturnType();
+  if (!return_type->isPointerType() && !return_type->isReferenceType())
+    return;
+
+  clang::RecordDecl *rd = return_type->getPointeeType()->getAsRecordDecl();
+  if (!rd)
+    return;
+
+  importer.CompleteTagDecl(rd);
+}
+
+void ClangASTImporter::ASTImporterDelegate::Imported(clang::Decl *from,
+                                                     clang::Decl *to) {
+  Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
+
+  // Some decls shouldn't be tracked here because they were not created by
+  // copying 'from' to 'to'. Just exit early for those.
+  if (m_decls_to_ignore.find(to) != m_decls_to_ignore.end())
+    return clang::ASTImporter::Imported(from, to);
+
+  lldb::user_id_t user_id = LLDB_INVALID_UID;
+  ClangASTMetadata *metadata = m_master.GetDeclMetadata(from);
+  if (metadata)
+    user_id = metadata->GetUserID();
+
+  if (log) {
+    if (NamedDecl *from_named_decl = dyn_cast<clang::NamedDecl>(from)) {
+      std::string name_string;
+      llvm::raw_string_ostream name_stream(name_string);
+      from_named_decl->printName(name_stream);
+      name_stream.flush();
+
+      LLDB_LOG(log,
+               "    [ClangASTImporter] Imported ({0}Decl*){1}, named {2} (from "
+               "(Decl*){3}), metadata {4}",
+               from->getDeclKindName(), to, name_string, from, user_id);
+    } else {
+      LLDB_LOG(log,
+               "    [ClangASTImporter] Imported ({0}Decl*){1} (from "
+               "(Decl*){2}), metadata {3}",
+               from->getDeclKindName(), to, from, user_id);
+    }
+  }
+
+  ASTContextMetadataSP to_context_md =
+      m_master.GetContextMetadata(&to->getASTContext());
+  ASTContextMetadataSP from_context_md =
+      m_master.MaybeGetContextMetadata(m_source_ctx);
+
+  if (from_context_md) {
+    OriginMap &origins = from_context_md->m_origins;
+
+    OriginMap::iterator origin_iter = origins.find(from);
+
+    if (origin_iter != origins.end()) {
+      if (to_context_md->m_origins.find(to) == to_context_md->m_origins.end() ||
+          user_id != LLDB_INVALID_UID) {
+        if (origin_iter->second.ctx != &to->getASTContext())
+          to_context_md->m_origins[to] = origin_iter->second;
+      }
+
+      ImporterDelegateSP direct_completer =
+          m_master.GetDelegate(&to->getASTContext(), origin_iter->second.ctx);
+
+      if (direct_completer.get() != this)
+        direct_completer->ASTImporter::Imported(origin_iter->second.decl, to);
+
+      LLDB_LOG(log,
+               "    [ClangASTImporter] Propagated origin "
+               "(Decl*){0}/(ASTContext*){1} from (ASTContext*){2} to "
+               "(ASTContext*){3}",
+               origin_iter->second.decl, origin_iter->second.ctx,
+               &from->getASTContext(), &to->getASTContext());
+    } else {
+      if (m_new_decl_listener)
+        m_new_decl_listener->NewDeclImported(from, to);
+
+      if (to_context_md->m_origins.find(to) == to_context_md->m_origins.end() ||
+          user_id != LLDB_INVALID_UID) {
+        to_context_md->m_origins[to] = DeclOrigin(m_source_ctx, from);
+      }
+
+      LLDB_LOG(log,
+               "    [ClangASTImporter] Decl has no origin information in "
+               "(ASTContext*){0}",
+               &from->getASTContext());
+    }
+
+    if (auto *to_namespace = dyn_cast<clang::NamespaceDecl>(to)) {
+      auto *from_namespace = cast<clang::NamespaceDecl>(from);
+
+      NamespaceMetaMap &namespace_maps = from_context_md->m_namespace_maps;
+
+      NamespaceMetaMap::iterator namespace_map_iter =
+          namespace_maps.find(from_namespace);
+
+      if (namespace_map_iter != namespace_maps.end())
+        to_context_md->m_namespace_maps[to_namespace] =
+            namespace_map_iter->second;
+    }
+  } else {
+    to_context_md->m_origins[to] = DeclOrigin(m_source_ctx, from);
+
+    LLDB_LOG(log,
+             "    [ClangASTImporter] Sourced origin "
+             "(Decl*){0}/(ASTContext*){1} into (ASTContext*){2}",
+             from, m_source_ctx, &to->getASTContext());
+  }
+
+  if (auto *to_tag_decl = dyn_cast<TagDecl>(to)) {
+    to_tag_decl->setHasExternalLexicalStorage();
+    to_tag_decl->getPrimaryContext()->setMustBuildLookupTable();
+    auto from_tag_decl = cast<TagDecl>(from);
+
+    LLDB_LOG(
+        log,
+        "    [ClangASTImporter] To is a TagDecl - attributes {0}{1} [{2}->{3}]",
+        (to_tag_decl->hasExternalLexicalStorage() ? " Lexical" : ""),
+        (to_tag_decl->hasExternalVisibleStorage() ? " Visible" : ""),
+        (from_tag_decl->isCompleteDefinition() ? "complete" : "incomplete"),
+        (to_tag_decl->isCompleteDefinition() ? "complete" : "incomplete"));
+  }
+
+  if (auto *to_namespace_decl = dyn_cast<NamespaceDecl>(to)) {
+    m_master.BuildNamespaceMap(to_namespace_decl);
+    to_namespace_decl->setHasExternalVisibleStorage();
+  }
+
+  if (auto *to_container_decl = dyn_cast<ObjCContainerDecl>(to)) {
+    to_container_decl->setHasExternalLexicalStorage();
+    to_container_decl->setHasExternalVisibleStorage();
+
+    if (log) {
+      if (ObjCInterfaceDecl *to_interface_decl =
+              llvm::dyn_cast<ObjCInterfaceDecl>(to_container_decl)) {
+        LLDB_LOG(
+            log,
+            "    [ClangASTImporter] To is an ObjCInterfaceDecl - attributes "
+            "{0}{1}{2}",
+            (to_interface_decl->hasExternalLexicalStorage() ? " Lexical" : ""),
+            (to_interface_decl->hasExternalVisibleStorage() ? " Visible" : ""),
+            (to_interface_decl->hasDefinition() ? " HasDefinition" : ""));
+      } else {
+        LLDB_LOG(
+            log, "    [ClangASTImporter] To is an {0}Decl - attributes {1}{2}",
+            ((Decl *)to_container_decl)->getDeclKindName(),
+            (to_container_decl->hasExternalLexicalStorage() ? " Lexical" : ""),
+            (to_container_decl->hasExternalVisibleStorage() ? " Visible" : ""));
+      }
+    }
+  }
+
+  if (clang::CXXMethodDecl *to_method = dyn_cast<CXXMethodDecl>(to))
+    MaybeCompleteReturnType(m_master, to_method);
+}
+
+clang::Decl *
+ClangASTImporter::ASTImporterDelegate::GetOriginalDecl(clang::Decl *To) {
+  return m_master.GetDeclOrigin(To).decl;
+}
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.h b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.h
new file mode 100644
index 0000000..b05a89c
--- /dev/null
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.h
@@ -0,0 +1,327 @@
+//===-- ClangASTImporter.h --------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_ClangASTImporter_h_
+#define liblldb_ClangASTImporter_h_
+
+#include <map>
+#include <memory>
+#include <set>
+#include <vector>
+
+#include "clang/AST/ASTImporter.h"
+#include "clang/AST/CharUnits.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Basic/FileSystemOptions.h"
+
+#include "lldb/Host/FileSystem.h"
+#include "lldb/Symbol/CompilerDeclContext.h"
+#include "lldb/lldb-types.h"
+
+#include "Plugins/ExpressionParser/Clang/CxxModuleHandler.h"
+
+#include "llvm/ADT/DenseMap.h"
+
+namespace lldb_private {
+
+class ClangASTImporter {
+public:
+  struct LayoutInfo {
+    LayoutInfo() = default;
+    typedef llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits>
+        OffsetMap;
+
+    uint64_t bit_size = 0;
+    uint64_t alignment = 0;
+    llvm::DenseMap<const clang::FieldDecl *, uint64_t> field_offsets;
+    OffsetMap base_offsets;
+    OffsetMap vbase_offsets;
+  };
+
+  ClangASTImporter()
+      : m_file_manager(clang::FileSystemOptions(),
+                       FileSystem::Instance().GetVirtualFileSystem()) {}
+
+  CompilerType CopyType(TypeSystemClang &dst, const CompilerType &src_type);
+
+  clang::Decl *CopyDecl(clang::ASTContext *dst_ctx, clang::Decl *decl);
+
+  CompilerType DeportType(TypeSystemClang &dst, const CompilerType &src_type);
+
+  clang::Decl *DeportDecl(clang::ASTContext *dst_ctx, clang::Decl *decl);
+
+  /// Sets the layout for the given RecordDecl. The layout will later be
+  /// used by Clang's during code generation. Not calling this function for
+  /// a RecordDecl will cause that Clang's codegen tries to layout the
+  /// record by itself.
+  ///
+  /// \param decl The RecordDecl to set the layout for.
+  /// \param layout The layout for the record.
+  void SetRecordLayout(clang::RecordDecl *decl, const LayoutInfo &layout);
+
+  bool LayoutRecordType(
+      const clang::RecordDecl *record_decl, uint64_t &bit_size,
+      uint64_t &alignment,
+      llvm::DenseMap<const clang::FieldDecl *, uint64_t> &field_offsets,
+      llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits>
+          &base_offsets,
+      llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits>
+          &vbase_offsets);
+
+  bool CanImport(const CompilerType &type);
+
+  bool Import(const CompilerType &type);
+
+  bool CompleteType(const CompilerType &compiler_type);
+
+  bool CompleteTagDecl(clang::TagDecl *decl);
+
+  bool CompleteTagDeclWithOrigin(clang::TagDecl *decl, clang::TagDecl *origin);
+
+  bool CompleteObjCInterfaceDecl(clang::ObjCInterfaceDecl *interface_decl);
+
+  bool CompleteAndFetchChildren(clang::QualType type);
+
+  bool RequireCompleteType(clang::QualType type);
+
+  void SetDeclOrigin(const clang::Decl *decl, clang::Decl *original_decl);
+
+  ClangASTMetadata *GetDeclMetadata(const clang::Decl *decl);
+
+  //
+  // Namespace maps
+  //
+
+  typedef std::vector<std::pair<lldb::ModuleSP, CompilerDeclContext>>
+      NamespaceMap;
+  typedef std::shared_ptr<NamespaceMap> NamespaceMapSP;
+
+  void RegisterNamespaceMap(const clang::NamespaceDecl *decl,
+                            NamespaceMapSP &namespace_map);
+
+  NamespaceMapSP GetNamespaceMap(const clang::NamespaceDecl *decl);
+
+  void BuildNamespaceMap(const clang::NamespaceDecl *decl);
+
+  //
+  // Completers for maps
+  //
+
+  class MapCompleter {
+  public:
+    virtual ~MapCompleter();
+
+    virtual void CompleteNamespaceMap(NamespaceMapSP &namespace_map,
+                                      ConstString name,
+                                      NamespaceMapSP &parent_map) const = 0;
+  };
+
+  void InstallMapCompleter(clang::ASTContext *dst_ctx,
+                           MapCompleter &completer) {
+    ASTContextMetadataSP context_md;
+    ContextMetadataMap::iterator context_md_iter = m_metadata_map.find(dst_ctx);
+
+    if (context_md_iter == m_metadata_map.end()) {
+      context_md = ASTContextMetadataSP(new ASTContextMetadata(dst_ctx));
+      m_metadata_map[dst_ctx] = context_md;
+    } else {
+      context_md = context_md_iter->second;
+    }
+
+    context_md->m_map_completer = &completer;
+  }
+
+  void ForgetDestination(clang::ASTContext *dst_ctx);
+  void ForgetSource(clang::ASTContext *dst_ctx, clang::ASTContext *src_ctx);
+
+public:
+  struct DeclOrigin {
+    DeclOrigin() : ctx(nullptr), decl(nullptr) {}
+
+    DeclOrigin(clang::ASTContext *_ctx, clang::Decl *_decl)
+        : ctx(_ctx), decl(_decl) {}
+
+    DeclOrigin(const DeclOrigin &rhs) {
+      ctx = rhs.ctx;
+      decl = rhs.decl;
+    }
+
+    void operator=(const DeclOrigin &rhs) {
+      ctx = rhs.ctx;
+      decl = rhs.decl;
+    }
+
+    bool Valid() { return (ctx != nullptr || decl != nullptr); }
+
+    clang::ASTContext *ctx;
+    clang::Decl *decl;
+  };
+
+  typedef llvm::DenseMap<const clang::Decl *, DeclOrigin> OriginMap;
+
+  /// Listener interface used by the ASTImporterDelegate to inform other code
+  /// about decls that have been imported the first time.
+  struct NewDeclListener {
+    virtual ~NewDeclListener() = default;
+    /// A decl has been imported for the first time.
+    virtual void NewDeclImported(clang::Decl *from, clang::Decl *to) = 0;
+  };
+
+  /// ASTImporter that intercepts and records the import process of the
+  /// underlying ASTImporter.
+  ///
+  /// This class updates the map from declarations to their original
+  /// declarations and can record declarations that have been imported in a
+  /// certain interval.
+  ///
+  /// When intercepting a declaration import, the ASTImporterDelegate uses the
+  /// CxxModuleHandler to replace any missing or malformed declarations with
+  /// their counterpart from a C++ module.
+  struct ASTImporterDelegate : public clang::ASTImporter {
+    ASTImporterDelegate(ClangASTImporter &master, clang::ASTContext *target_ctx,
+                        clang::ASTContext *source_ctx)
+        : clang::ASTImporter(*target_ctx, master.m_file_manager, *source_ctx,
+                             master.m_file_manager, true /*minimal*/),
+          m_master(master), m_source_ctx(source_ctx) {
+      setODRHandling(clang::ASTImporter::ODRHandlingType::Liberal);
+    }
+
+    /// Scope guard that attaches a CxxModuleHandler to an ASTImporterDelegate
+    /// and deattaches it at the end of the scope. Supports being used multiple
+    /// times on the same ASTImporterDelegate instance in nested scopes.
+    class CxxModuleScope {
+      /// The handler we attach to the ASTImporterDelegate.
+      CxxModuleHandler m_handler;
+      /// The ASTImporterDelegate we are supposed to attach the handler to.
+      ASTImporterDelegate &m_delegate;
+      /// True iff we attached the handler to the ASTImporterDelegate.
+      bool m_valid = false;
+
+    public:
+      CxxModuleScope(ASTImporterDelegate &delegate, clang::ASTContext *dst_ctx)
+          : m_delegate(delegate) {
+        // If the delegate doesn't have a CxxModuleHandler yet, create one
+        // and attach it.
+        if (!delegate.m_std_handler) {
+          m_handler = CxxModuleHandler(delegate, dst_ctx);
+          m_valid = true;
+          delegate.m_std_handler = &m_handler;
+        }
+      }
+      ~CxxModuleScope() {
+        if (m_valid) {
+          // Make sure no one messed with the handler we placed.
+          assert(m_delegate.m_std_handler == &m_handler);
+          m_delegate.m_std_handler = nullptr;
+        }
+      }
+    };
+
+    void ImportDefinitionTo(clang::Decl *to, clang::Decl *from);
+
+    void Imported(clang::Decl *from, clang::Decl *to) override;
+
+    clang::Decl *GetOriginalDecl(clang::Decl *To) override;
+
+    void SetImportListener(NewDeclListener *listener) {
+      assert(m_new_decl_listener == nullptr && "Already attached a listener?");
+      m_new_decl_listener = listener;
+    }
+    void RemoveImportListener() { m_new_decl_listener = nullptr; }
+
+  protected:
+    llvm::Expected<clang::Decl *> ImportImpl(clang::Decl *From) override;
+
+  private:
+    /// Decls we should ignore when mapping decls back to their original
+    /// ASTContext. Used by the CxxModuleHandler to mark declarations that
+    /// were created from the 'std' C++ module to prevent that the Importer
+    /// tries to sync them with the broken equivalent in the debug info AST.
+    llvm::SmallPtrSet<clang::Decl *, 16> m_decls_to_ignore;
+    ClangASTImporter &m_master;
+    clang::ASTContext *m_source_ctx;
+    CxxModuleHandler *m_std_handler = nullptr;
+    /// The currently attached listener.
+    NewDeclListener *m_new_decl_listener = nullptr;
+  };
+
+  typedef std::shared_ptr<ASTImporterDelegate> ImporterDelegateSP;
+  typedef llvm::DenseMap<clang::ASTContext *, ImporterDelegateSP> DelegateMap;
+  typedef llvm::DenseMap<const clang::NamespaceDecl *, NamespaceMapSP>
+      NamespaceMetaMap;
+
+  struct ASTContextMetadata {
+    ASTContextMetadata(clang::ASTContext *dst_ctx)
+        : m_dst_ctx(dst_ctx), m_delegates(), m_origins(), m_namespace_maps(),
+          m_map_completer(nullptr) {}
+
+    clang::ASTContext *m_dst_ctx;
+    DelegateMap m_delegates;
+    OriginMap m_origins;
+
+    NamespaceMetaMap m_namespace_maps;
+    MapCompleter *m_map_completer;
+  };
+
+  typedef std::shared_ptr<ASTContextMetadata> ASTContextMetadataSP;
+  typedef llvm::DenseMap<const clang::ASTContext *, ASTContextMetadataSP>
+      ContextMetadataMap;
+
+  ContextMetadataMap m_metadata_map;
+
+  ASTContextMetadataSP GetContextMetadata(clang::ASTContext *dst_ctx) {
+    ContextMetadataMap::iterator context_md_iter = m_metadata_map.find(dst_ctx);
+
+    if (context_md_iter == m_metadata_map.end()) {
+      ASTContextMetadataSP context_md =
+          ASTContextMetadataSP(new ASTContextMetadata(dst_ctx));
+      m_metadata_map[dst_ctx] = context_md;
+      return context_md;
+    }
+    return context_md_iter->second;
+  }
+
+  ASTContextMetadataSP MaybeGetContextMetadata(clang::ASTContext *dst_ctx) {
+    ContextMetadataMap::iterator context_md_iter = m_metadata_map.find(dst_ctx);
+
+    if (context_md_iter != m_metadata_map.end())
+      return context_md_iter->second;
+    return ASTContextMetadataSP();
+  }
+
+  ImporterDelegateSP GetDelegate(clang::ASTContext *dst_ctx,
+                                 clang::ASTContext *src_ctx) {
+    ASTContextMetadataSP context_md = GetContextMetadata(dst_ctx);
+
+    DelegateMap &delegates = context_md->m_delegates;
+    DelegateMap::iterator delegate_iter = delegates.find(src_ctx);
+
+    if (delegate_iter == delegates.end()) {
+      ImporterDelegateSP delegate =
+          ImporterDelegateSP(new ASTImporterDelegate(*this, dst_ctx, src_ctx));
+      delegates[src_ctx] = delegate;
+      return delegate;
+    }
+    return delegate_iter->second;
+  }
+
+public:
+  DeclOrigin GetDeclOrigin(const clang::Decl *decl);
+
+  clang::FileManager m_file_manager;
+  typedef llvm::DenseMap<const clang::RecordDecl *, LayoutInfo>
+      RecordDeclToLayoutMap;
+
+  RecordDeclToLayoutMap m_record_decl_to_layout_map;
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_ClangASTImporter_h_
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTMetadata.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTMetadata.cpp
new file mode 100644
index 0000000..42933c7
--- /dev/null
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTMetadata.cpp
@@ -0,0 +1,35 @@
+//===-- ClangASTMetadata.cpp ----------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "Plugins/ExpressionParser/Clang/ClangASTMetadata.h"
+#include "lldb/Utility/Stream.h"
+
+using namespace lldb_private;
+
+void ClangASTMetadata::Dump(Stream *s) {
+  lldb::user_id_t uid = GetUserID();
+
+  if (uid != LLDB_INVALID_UID) {
+    s->Printf("uid=0x%" PRIx64, uid);
+  }
+
+  uint64_t isa_ptr = GetISAPtr();
+  if (isa_ptr != 0) {
+    s->Printf("isa_ptr=0x%" PRIx64, isa_ptr);
+  }
+
+  const char *obj_ptr_name = GetObjectPtrName();
+  if (obj_ptr_name) {
+    s->Printf("obj_ptr_name=\"%s\" ", obj_ptr_name);
+  }
+
+  if (m_is_dynamic_cxx) {
+    s->Printf("is_dynamic_cxx=%i ", m_is_dynamic_cxx);
+  }
+  s->EOL();
+}
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTMetadata.h b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTMetadata.h
new file mode 100644
index 0000000..fdf4388
--- /dev/null
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTMetadata.h
@@ -0,0 +1,100 @@
+//===-- ClangASTMetadata.h --------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_ClangASTMetadata_h
+#define liblldb_ClangASTMetadata_h
+
+#include "lldb/Core/dwarf.h"
+#include "lldb/lldb-defines.h"
+#include "lldb/lldb-enumerations.h"
+
+namespace lldb_private {
+
+class ClangASTMetadata {
+public:
+  ClangASTMetadata()
+      : m_user_id(0), m_union_is_user_id(false), m_union_is_isa_ptr(false),
+        m_has_object_ptr(false), m_is_self(false), m_is_dynamic_cxx(true) {}
+
+  bool GetIsDynamicCXXType() const { return m_is_dynamic_cxx; }
+
+  void SetIsDynamicCXXType(bool b) { m_is_dynamic_cxx = b; }
+
+  void SetUserID(lldb::user_id_t user_id) {
+    m_user_id = user_id;
+    m_union_is_user_id = true;
+    m_union_is_isa_ptr = false;
+  }
+
+  lldb::user_id_t GetUserID() const {
+    if (m_union_is_user_id)
+      return m_user_id;
+    else
+      return LLDB_INVALID_UID;
+  }
+
+  void SetISAPtr(uint64_t isa_ptr) {
+    m_isa_ptr = isa_ptr;
+    m_union_is_user_id = false;
+    m_union_is_isa_ptr = true;
+  }
+
+  uint64_t GetISAPtr() const {
+    if (m_union_is_isa_ptr)
+      return m_isa_ptr;
+    else
+      return 0;
+  }
+
+  void SetObjectPtrName(const char *name) {
+    m_has_object_ptr = true;
+    if (strcmp(name, "self") == 0)
+      m_is_self = true;
+    else if (strcmp(name, "this") == 0)
+      m_is_self = false;
+    else
+      m_has_object_ptr = false;
+  }
+
+  lldb::LanguageType GetObjectPtrLanguage() const {
+    if (m_has_object_ptr) {
+      if (m_is_self)
+        return lldb::eLanguageTypeObjC;
+      else
+        return lldb::eLanguageTypeC_plus_plus;
+    }
+    return lldb::eLanguageTypeUnknown;
+  }
+
+  const char *GetObjectPtrName() const {
+    if (m_has_object_ptr) {
+      if (m_is_self)
+        return "self";
+      else
+        return "this";
+    } else
+      return nullptr;
+  }
+
+  bool HasObjectPtr() const { return m_has_object_ptr; }
+
+  void Dump(Stream *s);
+
+private:
+  union {
+    lldb::user_id_t m_user_id;
+    uint64_t m_isa_ptr;
+  };
+
+  bool m_union_is_user_id : 1, m_union_is_isa_ptr : 1, m_has_object_ptr : 1,
+      m_is_self : 1, m_is_dynamic_cxx : 1;
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_ClangASTMetadata_h
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp
index 8fb0f40..7362a00 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp
@@ -13,8 +13,6 @@
 
 #include "lldb/Core/Module.h"
 #include "lldb/Core/ModuleList.h"
-#include "lldb/Symbol/TypeSystemClang.h"
-#include "lldb/Symbol/ClangUtil.h"
 #include "lldb/Symbol/CompilerDeclContext.h"
 #include "lldb/Symbol/Function.h"
 #include "lldb/Symbol/SymbolFile.h"
@@ -24,7 +22,9 @@
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/RecordLayout.h"
 
+#include "Plugins/ExpressionParser/Clang/ClangUtil.h"
 #include "Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h"
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
 
 #include <memory>
 #include <vector>
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.h b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.h
index 2b711db..aeb06b3 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.h
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.h
@@ -11,7 +11,7 @@
 
 #include <set>
 
-#include "lldb/Symbol/ClangASTImporter.h"
+#include "Plugins/ExpressionParser/Clang/ClangASTImporter.h"
 #include "lldb/Symbol/CompilerType.h"
 #include "lldb/Target/Target.h"
 #include "clang/AST/ExternalASTSource.h"
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangDeclVendor.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangDeclVendor.cpp
index f5b0c21..867d4ff 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangDeclVendor.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangDeclVendor.cpp
@@ -7,9 +7,9 @@
 //===----------------------------------------------------------------------===//
 
 #include "Plugins/ExpressionParser/Clang/ClangDeclVendor.h"
+#include "Plugins/ExpressionParser/Clang/ClangUtil.h"
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
 
-#include "lldb/Symbol/ClangUtil.h"
-#include "lldb/Symbol/TypeSystemClang.h"
 #include "lldb/Utility/ConstString.h"
 
 using namespace lldb_private;
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp
index 8f4c92e..58094e0 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp
@@ -11,15 +11,15 @@
 #include "ClangASTSource.h"
 #include "ClangModulesDeclVendor.h"
 #include "ClangPersistentVariables.h"
+#include "ClangUtil.h"
 
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
 #include "lldb/Core/Address.h"
 #include "lldb/Core/Module.h"
 #include "lldb/Core/ModuleSpec.h"
 #include "lldb/Core/ValueObjectConstResult.h"
 #include "lldb/Core/ValueObjectVariable.h"
 #include "lldb/Expression/Materializer.h"
-#include "lldb/Symbol/TypeSystemClang.h"
-#include "lldb/Symbol/ClangUtil.h"
 #include "lldb/Symbol/CompileUnit.h"
 #include "lldb/Symbol/CompilerDecl.h"
 #include "lldb/Symbol/CompilerDeclContext.h"
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
index eeab419..1516d5b 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
@@ -67,6 +67,7 @@
 #include "IRForTarget.h"
 #include "ModuleDependencyCollector.h"
 
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
 #include "lldb/Core/Debugger.h"
 #include "lldb/Core/Disassembler.h"
 #include "lldb/Core/Module.h"
@@ -75,7 +76,6 @@
 #include "lldb/Expression/IRInterpreter.h"
 #include "lldb/Host/File.h"
 #include "lldb/Host/HostInfo.h"
-#include "lldb/Symbol/TypeSystemClang.h"
 #include "lldb/Symbol/SymbolVendor.h"
 #include "lldb/Target/ExecutionContext.h"
 #include "lldb/Target/Language.h"
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExternalASTSourceCallbacks.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangExternalASTSourceCallbacks.cpp
new file mode 100644
index 0000000..26dc4d6
--- /dev/null
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExternalASTSourceCallbacks.cpp
@@ -0,0 +1,45 @@
+//===-- ClangExternalASTSourceCallbacks.cpp -------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "Plugins/ExpressionParser/Clang/ClangExternalASTSourceCallbacks.h"
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
+
+#include "clang/AST/Decl.h"
+
+using namespace lldb_private;
+
+void ClangExternalASTSourceCallbacks::CompleteType(clang::TagDecl *tag_decl) {
+  m_ast.CompleteTagDecl(tag_decl);
+}
+
+void ClangExternalASTSourceCallbacks::CompleteType(
+    clang::ObjCInterfaceDecl *objc_decl) {
+  m_ast.CompleteObjCInterfaceDecl(objc_decl);
+}
+
+bool ClangExternalASTSourceCallbacks::layoutRecordType(
+    const clang::RecordDecl *Record, uint64_t &Size, uint64_t &Alignment,
+    llvm::DenseMap<const clang::FieldDecl *, uint64_t> &FieldOffsets,
+    llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits> &BaseOffsets,
+    llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits>
+        &VirtualBaseOffsets) {
+  return m_ast.LayoutRecordType(Record, Size, Alignment, FieldOffsets,
+                                BaseOffsets, VirtualBaseOffsets);
+}
+
+void ClangExternalASTSourceCallbacks::FindExternalLexicalDecls(
+    const clang::DeclContext *decl_ctx,
+    llvm::function_ref<bool(clang::Decl::Kind)> IsKindWeWant,
+    llvm::SmallVectorImpl<clang::Decl *> &decls) {
+  if (decl_ctx) {
+    clang::TagDecl *tag_decl = llvm::dyn_cast<clang::TagDecl>(
+        const_cast<clang::DeclContext *>(decl_ctx));
+    if (tag_decl)
+      CompleteType(tag_decl);
+  }
+}
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExternalASTSourceCallbacks.h b/lldb/source/Plugins/ExpressionParser/Clang/ClangExternalASTSourceCallbacks.h
new file mode 100644
index 0000000..98e9f5a
--- /dev/null
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExternalASTSourceCallbacks.h
@@ -0,0 +1,46 @@
+//===-- ClangExternalASTSourceCallbacks.h -----------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_ClangExternalASTSourceCallbacks_h_
+#define liblldb_ClangExternalASTSourceCallbacks_h_
+
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
+#include "clang/AST/ExternalASTSource.h"
+
+namespace lldb_private {
+
+class TypeSystemClang;
+
+class ClangExternalASTSourceCallbacks : public clang::ExternalASTSource {
+public:
+  ClangExternalASTSourceCallbacks(TypeSystemClang &ast) : m_ast(ast) {}
+
+  void FindExternalLexicalDecls(
+      const clang::DeclContext *DC,
+      llvm::function_ref<bool(clang::Decl::Kind)> IsKindWeWant,
+      llvm::SmallVectorImpl<clang::Decl *> &Result) override;
+
+  void CompleteType(clang::TagDecl *tag_decl) override;
+
+  void CompleteType(clang::ObjCInterfaceDecl *objc_decl) override;
+
+  bool layoutRecordType(
+      const clang::RecordDecl *Record, uint64_t &Size, uint64_t &Alignment,
+      llvm::DenseMap<const clang::FieldDecl *, uint64_t> &FieldOffsets,
+      llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits>
+          &BaseOffsets,
+      llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits>
+          &VirtualBaseOffsets) override;
+
+private:
+  TypeSystemClang &m_ast;
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_ClangExternalASTSourceCallbacks_h_
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.cpp
index d2a379e..ea56e42 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.cpp
@@ -21,12 +21,12 @@
 #include "llvm/ExecutionEngine/ExecutionEngine.h"
 #include "llvm/IR/Module.h"
 
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
 #include "lldb/Core/Module.h"
 #include "lldb/Core/ValueObject.h"
 #include "lldb/Core/ValueObjectList.h"
 #include "lldb/Expression/IRExecutionUnit.h"
 #include "lldb/Interpreter/CommandReturnObject.h"
-#include "lldb/Symbol/TypeSystemClang.h"
 #include "lldb/Symbol/Function.h"
 #include "lldb/Symbol/Type.h"
 #include "lldb/Target/ExecutionContext.h"
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp
index cc3b4ed..4b0521a 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp
@@ -24,10 +24,10 @@
 #include "ClangModulesDeclVendor.h"
 #include "ModuleDependencyCollector.h"
 
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
 #include "lldb/Core/ModuleList.h"
 #include "lldb/Host/Host.h"
 #include "lldb/Host/HostInfo.h"
-#include "lldb/Symbol/TypeSystemClang.h"
 #include "lldb/Symbol/CompileUnit.h"
 #include "lldb/Symbol/SourceModule.h"
 #include "lldb/Target/Target.h"
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.cpp
index f847dc9..da26c6a 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.cpp
@@ -7,10 +7,10 @@
 //===----------------------------------------------------------------------===//
 
 #include "ClangPersistentVariables.h"
+#include "ClangASTImporter.h"
 
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
 #include "lldb/Core/Value.h"
-#include "lldb/Symbol/ClangASTImporter.h"
-#include "lldb/Symbol/TypeSystemClang.h"
 #include "lldb/Target/Target.h"
 #include "lldb/Utility/DataExtractor.h"
 #include "lldb/Utility/Log.h"
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp
index 2fca504..492ab15 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp
@@ -20,6 +20,7 @@
 #include "ClangUserExpression.h"
 
 #include "ASTResultSynthesizer.h"
+#include "ClangASTMetadata.h"
 #include "ClangDiagnostic.h"
 #include "ClangExpressionDeclMap.h"
 #include "ClangExpressionParser.h"
@@ -27,6 +28,7 @@
 #include "ClangPersistentVariables.h"
 #include "CppModuleConfiguration.h"
 
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
 #include "lldb/Core/Debugger.h"
 #include "lldb/Core/Module.h"
 #include "lldb/Core/StreamFile.h"
@@ -37,8 +39,6 @@
 #include "lldb/Expression/Materializer.h"
 #include "lldb/Host/HostInfo.h"
 #include "lldb/Symbol/Block.h"
-#include "lldb/Symbol/TypeSystemClang.h"
-#include "lldb/Symbol/ClangASTMetadata.h"
 #include "lldb/Symbol/CompileUnit.h"
 #include "lldb/Symbol/Function.h"
 #include "lldb/Symbol/ObjectFile.h"
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangUtil.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangUtil.cpp
new file mode 100644
index 0000000..a7f5dce
--- /dev/null
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangUtil.cpp
@@ -0,0 +1,87 @@
+//===-- ClangUtil.cpp -----------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+// A collection of helper methods and data structures for manipulating clang
+// types and decls.
+//===----------------------------------------------------------------------===//
+
+#include "Plugins/ExpressionParser/Clang/ClangUtil.h"
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
+
+using namespace clang;
+using namespace lldb_private;
+
+bool ClangUtil::IsClangType(const CompilerType &ct) {
+  // Invalid types are never Clang types.
+  if (!ct)
+    return false;
+
+  if (llvm::dyn_cast_or_null<TypeSystemClang>(ct.GetTypeSystem()) == nullptr)
+    return false;
+
+  if (!ct.GetOpaqueQualType())
+    return false;
+
+  return true;
+}
+
+clang::Decl *ClangUtil::GetDecl(const CompilerDecl &decl) {
+  assert(llvm::isa<TypeSystemClang>(decl.GetTypeSystem()));
+  return static_cast<clang::Decl *>(decl.GetOpaqueDecl());
+}
+
+QualType ClangUtil::GetQualType(const CompilerType &ct) {
+  // Make sure we have a clang type before making a clang::QualType
+  if (!IsClangType(ct))
+    return QualType();
+
+  return QualType::getFromOpaquePtr(ct.GetOpaqueQualType());
+}
+
+QualType ClangUtil::GetCanonicalQualType(const CompilerType &ct) {
+  if (!IsClangType(ct))
+    return QualType();
+
+  return GetQualType(ct).getCanonicalType();
+}
+
+CompilerType ClangUtil::RemoveFastQualifiers(const CompilerType &ct) {
+  if (!IsClangType(ct))
+    return ct;
+
+  QualType qual_type(GetQualType(ct));
+  qual_type.removeLocalFastQualifiers();
+  return CompilerType(ct.GetTypeSystem(), qual_type.getAsOpaquePtr());
+}
+
+clang::TagDecl *ClangUtil::GetAsTagDecl(const CompilerType &type) {
+  clang::QualType qual_type = ClangUtil::GetCanonicalQualType(type);
+  if (qual_type.isNull())
+    return nullptr;
+
+  return qual_type->getAsTagDecl();
+}
+
+std::string ClangUtil::DumpDecl(const clang::Decl *d) {
+  if (!d)
+    return "nullptr";
+
+  std::string result;
+  llvm::raw_string_ostream stream(result);
+  bool deserialize = false;
+  d->dump(stream, deserialize);
+
+  stream.flush();
+  return result;
+}
+
+std::string ClangUtil::ToString(const clang::Type *t) {
+  return clang::QualType(t, 0).getAsString();
+}
+
+std::string ClangUtil::ToString(const CompilerType &c) {
+  return ClangUtil::GetQualType(c).getAsString();
+}
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangUtil.h b/lldb/source/Plugins/ExpressionParser/Clang/ClangUtil.h
new file mode 100644
index 0000000..31e86ca
--- /dev/null
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangUtil.h
@@ -0,0 +1,50 @@
+//===-- ClangUtil.h ---------------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+// A collection of helper methods and data structures for manipulating clang
+// types and decls.
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SYMBOL_CLANGUTIL_H
+#define LLDB_SYMBOL_CLANGUTIL_H
+
+#include "clang/AST/DeclBase.h"
+#include "clang/AST/Type.h"
+
+#include "lldb/Symbol/CompilerType.h"
+
+namespace clang {
+class TagDecl;
+}
+
+namespace lldb_private {
+struct ClangUtil {
+  static bool IsClangType(const CompilerType &ct);
+
+  /// Returns the clang::Decl of the given CompilerDecl.
+  /// CompilerDecl has to be valid and represent a clang::Decl.
+  static clang::Decl *GetDecl(const CompilerDecl &decl);
+
+  static clang::QualType GetQualType(const CompilerType &ct);
+
+  static clang::QualType GetCanonicalQualType(const CompilerType &ct);
+
+  static CompilerType RemoveFastQualifiers(const CompilerType &ct);
+
+  static clang::TagDecl *GetAsTagDecl(const CompilerType &type);
+
+  /// Returns a textual representation of the given Decl's AST. Does not
+  /// deserialize any child nodes.
+  static std::string DumpDecl(const clang::Decl *d);
+  /// Returns a textual representation of the given type.
+  static std::string ToString(const clang::Type *t);
+  /// Returns a textual representation of the given CompilerType (assuming
+  /// its underlying type is a Clang type).
+  static std::string ToString(const CompilerType &c);
+};
+}
+
+#endif
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/CxxModuleHandler.cpp b/lldb/source/Plugins/ExpressionParser/Clang/CxxModuleHandler.cpp
new file mode 100644
index 0000000..ae2f074
--- /dev/null
+++ b/lldb/source/Plugins/ExpressionParser/Clang/CxxModuleHandler.cpp
@@ -0,0 +1,289 @@
+//===-- CxxModuleHandler.cpp ----------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "Plugins/ExpressionParser/Clang/CxxModuleHandler.h"
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
+
+#include "lldb/Utility/Log.h"
+#include "clang/Sema/Lookup.h"
+#include "llvm/Support/Error.h"
+
+using namespace lldb_private;
+using namespace clang;
+
+CxxModuleHandler::CxxModuleHandler(ASTImporter &importer, ASTContext *target)
+    : m_importer(&importer),
+      m_sema(TypeSystemClang::GetASTContext(target)->getSema()) {
+
+  std::initializer_list<const char *> supported_names = {
+      // containers
+      "deque",
+      "forward_list",
+      "list",
+      "queue",
+      "stack",
+      "vector",
+      // pointers
+      "shared_ptr",
+      "unique_ptr",
+      "weak_ptr",
+      // utility
+      "allocator",
+  };
+  m_supported_templates.insert(supported_names.begin(), supported_names.end());
+}
+
+/// Builds a list of scopes that point into the given context.
+///
+/// \param sema The sema that will be using the scopes.
+/// \param ctxt The context that the scope should look into.
+/// \param result A list of scopes. The scopes need to be freed by the caller
+///               (except the TUScope which is owned by the sema).
+static void makeScopes(Sema &sema, DeclContext *ctxt,
+                       std::vector<Scope *> &result) {
+  // FIXME: The result should be a list of unique_ptrs, but the TUScope makes
+  // this currently impossible as it's owned by the Sema.
+
+  if (auto parent = ctxt->getParent()) {
+    makeScopes(sema, parent, result);
+
+    Scope *scope =
+        new Scope(result.back(), Scope::DeclScope, sema.getDiagnostics());
+    scope->setEntity(ctxt);
+    result.push_back(scope);
+  } else
+    result.push_back(sema.TUScope);
+}
+
+/// Uses the Sema to look up the given name in the given DeclContext.
+static std::unique_ptr<LookupResult>
+emulateLookupInCtxt(Sema &sema, llvm::StringRef name, DeclContext *ctxt) {
+  IdentifierInfo &ident = sema.getASTContext().Idents.get(name);
+
+  std::unique_ptr<LookupResult> lookup_result;
+  lookup_result.reset(new LookupResult(sema, DeclarationName(&ident),
+                                       SourceLocation(),
+                                       Sema::LookupOrdinaryName));
+
+  // Usually during parsing we already encountered the scopes we would use. But
+  // here don't have these scopes so we have to emulate the behavior of the
+  // Sema during parsing.
+  std::vector<Scope *> scopes;
+  makeScopes(sema, ctxt, scopes);
+
+  // Now actually perform the lookup with the sema.
+  sema.LookupName(*lookup_result, scopes.back());
+
+  // Delete all the allocated scopes beside the translation unit scope (which
+  // has depth 0).
+  for (Scope *s : scopes)
+    if (s->getDepth() != 0)
+      delete s;
+
+  return lookup_result;
+}
+
+/// Error class for handling problems when finding a certain DeclContext.
+struct MissingDeclContext : public llvm::ErrorInfo<MissingDeclContext> {
+
+  static char ID;
+
+  MissingDeclContext(DeclContext *context, std::string error)
+      : m_context(context), m_error(error) {}
+
+  DeclContext *m_context;
+  std::string m_error;
+
+  void log(llvm::raw_ostream &OS) const override {
+    OS << llvm::formatv("error when reconstructing context of kind {0}:{1}",
+                        m_context->getDeclKindName(), m_error);
+  }
+
+  std::error_code convertToErrorCode() const override {
+    return llvm::inconvertibleErrorCode();
+  }
+};
+
+char MissingDeclContext::ID = 0;
+
+/// Given a foreign decl context, this function finds the equivalent local
+/// decl context in the ASTContext of the given Sema. Potentially deserializes
+/// decls from the 'std' module if necessary.
+static llvm::Expected<DeclContext *>
+getEqualLocalDeclContext(Sema &sema, DeclContext *foreign_ctxt) {
+
+  // Inline namespaces don't matter for lookups, so let's skip them.
+  while (foreign_ctxt && foreign_ctxt->isInlineNamespace())
+    foreign_ctxt = foreign_ctxt->getParent();
+
+  // If the foreign context is the TU, we just return the local TU.
+  if (foreign_ctxt->isTranslationUnit())
+    return sema.getASTContext().getTranslationUnitDecl();
+
+  // Recursively find/build the parent DeclContext.
+  llvm::Expected<DeclContext *> parent =
+      getEqualLocalDeclContext(sema, foreign_ctxt->getParent());
+  if (!parent)
+    return parent;
+
+  // We currently only support building namespaces.
+  if (foreign_ctxt->isNamespace()) {
+    NamedDecl *ns = llvm::dyn_cast<NamedDecl>(foreign_ctxt);
+    llvm::StringRef ns_name = ns->getName();
+
+    auto lookup_result = emulateLookupInCtxt(sema, ns_name, *parent);
+    for (NamedDecl *named_decl : *lookup_result) {
+      if (DeclContext *DC = llvm::dyn_cast<DeclContext>(named_decl))
+        return DC->getPrimaryContext();
+    }
+    return llvm::make_error<MissingDeclContext>(
+        foreign_ctxt,
+        "Couldn't find namespace " + ns->getQualifiedNameAsString());
+  }
+
+  return llvm::make_error<MissingDeclContext>(foreign_ctxt, "Unknown context ");
+}
+
+/// Returns true iff tryInstantiateStdTemplate supports instantiating a template
+/// with the given template arguments.
+static bool templateArgsAreSupported(ArrayRef<TemplateArgument> a) {
+  for (const TemplateArgument &arg : a) {
+    switch (arg.getKind()) {
+    case TemplateArgument::Type:
+    case TemplateArgument::Integral:
+      break;
+    default:
+      // TemplateArgument kind hasn't been handled yet.
+      return false;
+    }
+  }
+  return true;
+}
+
+/// Constructor function for Clang declarations. Ensures that the created
+/// declaration is registered with the ASTImporter.
+template <typename T, typename... Args>
+T *createDecl(ASTImporter &importer, Decl *from_d, Args &&... args) {
+  T *to_d = T::Create(std::forward<Args>(args)...);
+  importer.RegisterImportedDecl(from_d, to_d);
+  return to_d;
+}
+
+llvm::Optional<Decl *> CxxModuleHandler::tryInstantiateStdTemplate(Decl *d) {
+  Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS);
+
+  // If we don't have a template to instiantiate, then there is nothing to do.
+  auto td = dyn_cast<ClassTemplateSpecializationDecl>(d);
+  if (!td)
+    return {};
+
+  // We only care about templates in the std namespace.
+  if (!td->getDeclContext()->isStdNamespace())
+    return {};
+
+  // We have a whitelist of supported template names.
+  if (m_supported_templates.find(td->getName()) == m_supported_templates.end())
+    return {};
+
+  // Early check if we even support instantiating this template. We do this
+  // before we import anything into the target AST.
+  auto &foreign_args = td->getTemplateInstantiationArgs();
+  if (!templateArgsAreSupported(foreign_args.asArray()))
+    return {};
+
+  // Find the local DeclContext that corresponds to the DeclContext of our
+  // decl we want to import.
+  llvm::Expected<DeclContext *> to_context =
+      getEqualLocalDeclContext(*m_sema, td->getDeclContext());
+  if (!to_context) {
+    LLDB_LOG_ERROR(log, to_context.takeError(),
+                   "Got error while searching equal local DeclContext for decl "
+                   "'{1}':\n{0}",
+                   td->getName());
+    return {};
+  }
+
+  // Look up the template in our local context.
+  std::unique_ptr<LookupResult> lookup =
+      emulateLookupInCtxt(*m_sema, td->getName(), *to_context);
+
+  ClassTemplateDecl *new_class_template = nullptr;
+  for (auto LD : *lookup) {
+    if ((new_class_template = dyn_cast<ClassTemplateDecl>(LD)))
+      break;
+  }
+  if (!new_class_template)
+    return {};
+
+  // Import the foreign template arguments.
+  llvm::SmallVector<TemplateArgument, 4> imported_args;
+
+  // If this logic is changed, also update templateArgsAreSupported.
+  for (const TemplateArgument &arg : foreign_args.asArray()) {
+    switch (arg.getKind()) {
+    case TemplateArgument::Type: {
+      llvm::Expected<QualType> type = m_importer->Import(arg.getAsType());
+      if (!type) {
+        LLDB_LOG_ERROR(log, type.takeError(), "Couldn't import type: {0}");
+        return {};
+      }
+      imported_args.push_back(TemplateArgument(*type));
+      break;
+    }
+    case TemplateArgument::Integral: {
+      llvm::APSInt integral = arg.getAsIntegral();
+      llvm::Expected<QualType> type =
+          m_importer->Import(arg.getIntegralType());
+      if (!type) {
+        LLDB_LOG_ERROR(log, type.takeError(), "Couldn't import type: {0}");
+        return {};
+      }
+      imported_args.push_back(
+          TemplateArgument(d->getASTContext(), integral, *type));
+      break;
+    }
+    default:
+      assert(false && "templateArgsAreSupported not updated?");
+    }
+  }
+
+  // Find the class template specialization declaration that
+  // corresponds to these arguments.
+  void *InsertPos = nullptr;
+  ClassTemplateSpecializationDecl *result =
+      new_class_template->findSpecialization(imported_args, InsertPos);
+
+  if (result) {
+    // We found an existing specialization in the module that fits our arguments
+    // so we can treat it as the result and register it with the ASTImporter.
+    m_importer->RegisterImportedDecl(d, result);
+    return result;
+  }
+
+  // Instantiate the template.
+  result = createDecl<ClassTemplateSpecializationDecl>(
+      *m_importer, d, m_sema->getASTContext(),
+      new_class_template->getTemplatedDecl()->getTagKind(),
+      new_class_template->getDeclContext(),
+      new_class_template->getTemplatedDecl()->getLocation(),
+      new_class_template->getLocation(), new_class_template, imported_args,
+      nullptr);
+
+  new_class_template->AddSpecialization(result, InsertPos);
+  if (new_class_template->isOutOfLine())
+    result->setLexicalDeclContext(
+        new_class_template->getLexicalDeclContext());
+  return result;
+}
+
+llvm::Optional<Decl *> CxxModuleHandler::Import(Decl *d) {
+  if (!isValid())
+    return {};
+
+  return tryInstantiateStdTemplate(d);
+}
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/CxxModuleHandler.h b/lldb/source/Plugins/ExpressionParser/Clang/CxxModuleHandler.h
new file mode 100644
index 0000000..f4aef36
--- /dev/null
+++ b/lldb/source/Plugins/ExpressionParser/Clang/CxxModuleHandler.h
@@ -0,0 +1,65 @@
+//===-- CxxModuleHandler.h --------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_CxxModuleHandler_h_
+#define liblldb_CxxModuleHandler_h_
+
+#include "clang/AST/ASTImporter.h"
+#include "clang/Sema/Sema.h"
+#include "llvm/ADT/StringSet.h"
+
+namespace lldb_private {
+
+/// Handles importing decls into an ASTContext with an attached C++ module.
+///
+/// This class searches a C++ module (which must be attached to the target
+/// ASTContext) for an equivalent decl to the one that should be imported.
+/// If the decl that is found in the module is a suitable replacement
+/// for the decl that should be imported, the module decl will be treated as
+/// the result of the import process.
+///
+/// If the Decl that should be imported is a template specialization
+/// that doesn't exist yet in the target ASTContext (e.g. `std::vector<int>`),
+/// then this class tries to create the template specialization in the target
+/// ASTContext. This is only possible if the CxxModuleHandler can determine
+/// that instantiating this template is safe to do, e.g. because the target
+/// decl is a container class from the STL.
+class CxxModuleHandler {
+  /// The ASTImporter that should be used to import any Decls which aren't
+  /// directly handled by this class itself.
+  clang::ASTImporter *m_importer = nullptr;
+
+  /// The Sema instance of the target ASTContext.
+  clang::Sema *m_sema = nullptr;
+
+  /// List of template names this class currently supports. These are the
+  /// template names inside the 'std' namespace such as 'vector' or 'list'.
+  llvm::StringSet<> m_supported_templates;
+
+  /// Tries to manually instantiate the given foreign template in the target
+  /// context (designated by m_sema).
+  llvm::Optional<clang::Decl *> tryInstantiateStdTemplate(clang::Decl *d);
+
+public:
+  CxxModuleHandler() = default;
+  CxxModuleHandler(clang::ASTImporter &importer, clang::ASTContext *target);
+
+  /// Attempts to import the given decl into the target ASTContext by
+  /// deserializing it from the 'std' module. This function returns a Decl if a
+  /// Decl has been deserialized from the 'std' module. Otherwise this function
+  /// returns nothing.
+  llvm::Optional<clang::Decl *> Import(clang::Decl *d);
+
+  /// Returns true iff this instance is capable of importing any declarations
+  /// in the target ASTContext.
+  bool isValid() const { return m_sema != nullptr; }
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_CxxModuleHandler_h_
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/IRForTarget.cpp b/lldb/source/Plugins/ExpressionParser/Clang/IRForTarget.cpp
index bcf13e5..e70ab1c 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/IRForTarget.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/IRForTarget.cpp
@@ -9,7 +9,9 @@
 #include "IRForTarget.h"
 
 #include "ClangExpressionDeclMap.h"
+#include "ClangUtil.h"
 
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
 #include "llvm/IR/Constants.h"
 #include "llvm/IR/DataLayout.h"
 #include "llvm/IR/InstrTypes.h"
@@ -27,8 +29,6 @@
 #include "lldb/Core/dwarf.h"
 #include "lldb/Expression/IRExecutionUnit.h"
 #include "lldb/Expression/IRInterpreter.h"
-#include "lldb/Symbol/TypeSystemClang.h"
-#include "lldb/Symbol/ClangUtil.h"
 #include "lldb/Symbol/CompilerType.h"
 #include "lldb/Utility/ConstString.h"
 #include "lldb/Utility/DataBufferHeap.h"