@@ -4087,6 +4087,13 @@ SwiftASTContext::GetTypeFromMangledTypename(const char *mangled_typename,
                      .getPointer();
 
     if (found_type) {
+      // If we have an inout type at the top level, turn it into an lvalue type.
+      // Function parameters that are inout are treated the same as mutable vars
+      // here.
+      if (auto *inout_type = found_type->getAs<swift::InOutType>()) {
+        found_type = swift::LValueType::get(inout_type->getObjectType());
+      }
+
       CacheDemangledType(mangled_name.GetCString(), found_type);
       CompilerType result_type(ast_ctx, found_type);
       if (log)
//===-- SwiftASTContext.cpp -------------------------------------*- C++ -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

#include "lldb/Symbol/SwiftASTContext.h"

// C++ Includes
#include <mutex> // std::once
#include <queue>
#include <set>
#include <sstream>

#include "swift/AST/ASTContext.h"
#include "swift/AST/DebuggerClient.h"
#include "swift/AST/Decl.h"
#include "swift/AST/DiagnosticEngine.h"
#include "swift/AST/ExistentialLayout.h"
#include "swift/AST/IRGenOptions.h"
#include "swift/AST/ASTMangler.h"
#include "swift/AST/GenericSignature.h"
#include "swift/AST/NameLookup.h"
#include "swift/AST/SearchPathOptions.h"
#include "swift/AST/Type.h"
#include "swift/AST/Types.h"
#include "swift/ASTSectionImporter/ASTSectionImporter.h"
#include "swift/Demangling/Demangle.h"
#include "swift/Basic/Dwarf.h"
#include "swift/Basic/LangOptions.h"
#include "swift/Basic/Platform.h"
#include "swift/Basic/SourceManager.h"
#include "swift/ClangImporter/ClangImporter.h"
#include "swift/ClangImporter/ClangImporterOptions.h"
#include "swift/Driver/Util.h"
#include "swift/Frontend/Frontend.h"
#include "swift/Frontend/PrintingDiagnosticConsumer.h"
#include "swift/IDE/Utils.h"
#include "swift/IRGen/Linking.h"
#include "swift/SIL/SILModule.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclObjC.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Basic/TargetOptions.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Process.h"
#include "llvm/Support/TargetRegistry.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetOptions.h"
#include "llvm/Target/TargetSubtargetInfo.h"

#include "swift/../../lib/IRGen/FixedTypeInfo.h"
#include "swift/../../lib/IRGen/GenEnum.h"
#include "swift/../../lib/IRGen/GenHeap.h"
#include "swift/../../lib/IRGen/IRGenMangler.h"
#include "swift/../../lib/IRGen/IRGenModule.h"
#include "swift/../../lib/IRGen/TypeInfo.h"
#include "swift/../../lib/IRGen/IRGenMangler.h"

#include "swift/Serialization/SerializedModuleLoader.h"
#include "swift/Strings.h"

#include "Plugins/ExpressionParser/Swift/SwiftDiagnostic.h"
#include "Plugins/ExpressionParser/Swift/SwiftUserExpression.h"
#include "lldb/Core/ArchSpec.h"
#include "lldb/Core/Debugger.h"
#include "lldb/Core/DumpDataExtractor.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/ModuleSpec.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Core/Section.h"
#include "lldb/Core/StreamFile.h"
#include "lldb/Core/ThreadSafeDenseMap.h"
#include "lldb/Expression/DiagnosticManager.h"
#include "lldb/Host/Host.h"
#include "lldb/Host/HostInfo.h"
#include "lldb/Host/StringConvert.h"
#include "lldb/Symbol/ClangASTContext.h"
#include "lldb/Symbol/CompileUnit.h"
#include "lldb/Symbol/ObjectFile.h"
#include "lldb/Symbol/SymbolFile.h"
#include "lldb/Symbol/SymbolVendor.h"
#include "lldb/Target/Platform.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/SwiftLanguageRuntime.h"
#include "lldb/Target/Target.h"
#include "lldb/Utility/CleanUp.h"
#include "lldb/Utility/Status.h"
#include "lldb/Utility/FileSpec.h"
#include "lldb/Utility/LLDBAssert.h"
#include "lldb/Utility/Log.h"

#include "Plugins/Platform/MacOSX/PlatformDarwin.h"
#include "Plugins/SymbolFile/DWARF/DWARFASTParserSwift.h"

#ifdef LLDB_CONFIGURATION_DEBUG
#define VALID_OR_RETURN(value)                                                 \
  do {                                                                         \
    lldbassert(!HasFatalErrors());                                             \
    if (HasFatalErrors()) {                                                    \
      return (value);                                                          \
    }                                                                          \
  } while (0)
#define VALID_OR_RETURN_VOID()                                                 \
  do {                                                                         \
    lldbassert(!HasFatalErrors());                                             \
    if (HasFatalErrors()) {                                                    \
      return;                                                                  \
    }                                                                          \
  } while (0)
#else
#define VALID_OR_RETURN(value)                                                 \
  do {                                                                         \
    if (HasFatalErrors()) {                                                    \
      return (value);                                                          \
    }                                                                          \
  } while (0)
#define VALID_OR_RETURN_VOID()                                                 \
  do {                                                                         \
    if (HasFatalErrors()) {                                                    \
      return;                                                                  \
    }                                                                          \
  } while (0)
#endif

using namespace lldb;
using namespace lldb_private;

typedef lldb_private::ThreadSafeDenseMap<swift::ASTContext *, SwiftASTContext *>
    ThreadSafeSwiftASTMap;

static ThreadSafeSwiftASTMap &GetASTMap() {
  // The global destructor list will tear down all of the modules when the LLDB
  // shared library is being unloaded and this needs to live beyond all of those
  // and not be destructed before they have all gone away. So we will leak this
  // list intentionally so we can avoid global destructor problems.
  static ThreadSafeSwiftASTMap *g_map_ptr = NULL;
  static std::once_flag g_once_flag;
  std::call_once(g_once_flag, []() {
    g_map_ptr = new ThreadSafeSwiftASTMap(); // NOTE: Intentional leak
  });
  return *g_map_ptr;
}

static inline swift::Type GetSwiftType(void *opaque_ptr) {
  return swift::Type((swift::TypeBase *)opaque_ptr);
}

static inline swift::CanType GetCanonicalSwiftType(void *opaque_ptr) {
  return ((swift::TypeBase *)opaque_ptr)->getCanonicalType();
}

static inline swift::Type GetSwiftType(CompilerType type) {
  return swift::Type((swift::TypeBase *)type.GetOpaqueQualType());
}

static inline swift::CanType GetCanonicalSwiftType(CompilerType type) {
  return ((swift::TypeBase *)type.GetOpaqueQualType())->getCanonicalType();
}

enum class MemberType : uint32_t { Invalid, BaseClass, Field };

static const char *MemberTypeToCString(MemberType member_type) {
  switch (member_type) {
  case MemberType::Invalid:
    return "invalid";
  case MemberType::BaseClass:
    return "base class";
  case MemberType::Field:
    return "field";
  }
  return "???";
}

struct MemberInfo {
  CompilerType clang_type;
  lldb_private::ConstString name;
  uint64_t byte_size;
  uint32_t byte_offset;
  MemberType member_type;
  bool is_fragile;

  MemberInfo(MemberType member_type)
      : clang_type(), name(), byte_size(0), byte_offset(0),
        member_type(member_type), is_fragile(false) {}

  void Dump(uint32_t idx) {
    printf("[%i] %12s +%u (%s) %s <%" PRIu64 "> %s\n", idx,
           MemberTypeToCString(member_type), byte_offset,
           clang_type.GetTypeName().AsCString("<no type name>"),
           name.AsCString("<NULL>"), byte_size, is_fragile ? "[fragile]" : "");
  }
};

struct CachedMemberInfo {
  std::vector<MemberInfo> member_infos;
};

struct EnumElementInfo {
  CompilerType clang_type;
  lldb_private::ConstString name;
  uint64_t byte_size;
  uint32_t value;       // The value for this enumeration element
  uint32_t extra_value; // If not UINT32_MAX, then this value is an extra value
  // that appears at offset 0 to tell one or more empty
  // enums apart. This value will only be filled in if there
  // are one ore more enum elements that have a non-zero byte size

  EnumElementInfo()
      : clang_type(), name(), byte_size(0), extra_value(UINT32_MAX) {}

  void Dump(Stream &strm) const {
    strm.Printf("<%2" PRIu64 "> %4u", byte_size, value);
    if (extra_value != UINT32_MAX)
      strm.Printf("%4u: ", extra_value);
    else
      strm.Printf("    : ");
    strm.Printf("case %s", name.GetCString());
    if (clang_type)
      strm.Printf("%s", clang_type.GetTypeName().AsCString("<no type name>"));
    strm.EOL();
  }
};

class SwiftEnumDescriptor;

typedef std::shared_ptr<CachedMemberInfo> CachedMemberInfoSP;
typedef std::shared_ptr<SwiftEnumDescriptor> SwiftEnumDescriptorSP;
typedef llvm::DenseMap<lldb::opaque_compiler_type_t, CachedMemberInfoSP>
    MemberInfoCache;
typedef llvm::DenseMap<lldb::opaque_compiler_type_t, SwiftEnumDescriptorSP>
    EnumInfoCache;
typedef std::shared_ptr<MemberInfoCache> MemberInfoCacheSP;
typedef std::shared_ptr<EnumInfoCache> EnumInfoCacheSP;
typedef llvm::DenseMap<const swift::ASTContext *, MemberInfoCacheSP>
    ASTMemberInfoCacheMap;
typedef llvm::DenseMap<const swift::ASTContext *, EnumInfoCacheSP>
    ASTEnumInfoCacheMap;

static MemberInfoCache *GetMemberInfoCache(const swift::ASTContext *a) {
  static ASTMemberInfoCacheMap g_cache;
  static std::mutex g_mutex;
  std::lock_guard<std::mutex> locker(g_mutex);
  ASTMemberInfoCacheMap::iterator pos = g_cache.find(a);
  if (pos == g_cache.end()) {
    g_cache.insert(std::make_pair(
        a, std::shared_ptr<MemberInfoCache>(new MemberInfoCache())));
    return g_cache.find(a)->second.get();
  }
  return pos->second.get();
}

static EnumInfoCache *GetEnumInfoCache(const swift::ASTContext *a) {
  static ASTEnumInfoCacheMap g_cache;
  static std::mutex g_mutex;
  std::lock_guard<std::mutex> locker(g_mutex);
  ASTEnumInfoCacheMap::iterator pos = g_cache.find(a);
  if (pos == g_cache.end()) {
    g_cache.insert(
        std::make_pair(a, std::shared_ptr<EnumInfoCache>(new EnumInfoCache())));
    return g_cache.find(a)->second.get();
  }
  return pos->second.get();
}

namespace {
  bool IsDirectory(const FileSpec &spec) {
    return llvm::sys::fs::is_directory(spec.GetPath());
  }
  bool IsRegularFile(const FileSpec &spec) {
    return llvm::sys::fs::is_regular_file(spec.GetPath());
  }
}

llvm::LLVMContext &SwiftASTContext::GetGlobalLLVMContext() {
  // TODO check with Sean.  Do we really want this to be static across
  // an LLDB managing multiple Swift processes?
  static llvm::LLVMContext s_global_context;
  return s_global_context;
}

CachedMemberInfo *SwiftASTContext::GetCachedMemberInfo(void *type) {
  VALID_OR_RETURN(nullptr);

  if (type) {
    // printf("CompilerType::GetCachedMemberInfo () for %s...",
    // GetTypeName().c_str());
    bool is_class = false;
    bool is_protocol = false;
    MemberInfoCache *member_info_cache = GetMemberInfoCache(GetASTContext());
    MemberInfoCache::const_iterator pos = member_info_cache->find(type);
    if (pos != member_info_cache->end()) {
      // printf("cached: %p\n", pos->second.get());
      return pos->second.get();
    }

    CachedMemberInfoSP member_infos_sp(new CachedMemberInfo());
    // printf("creating in %p\n", member_infos_sp.get());

    swift::CanType swift_can_type(GetCanonicalSwiftType(type));

    std::vector<const swift::irgen::TypeInfo *> field_type_infos;
    swift::irgen::LayoutStrategy layout_strategy =
        swift::irgen::LayoutStrategy::Optimal;

    const swift::TypeKind type_kind = swift_can_type->getKind();
    switch (type_kind) {
    case swift::TypeKind::Error:
    case swift::TypeKind::BuiltinInteger:
    case swift::TypeKind::BuiltinFloat:
    case swift::TypeKind::BuiltinRawPointer:
    case swift::TypeKind::BuiltinBridgeObject:
    case swift::TypeKind::BuiltinNativeObject:
    case swift::TypeKind::BuiltinUnsafeValueBuffer:
    case swift::TypeKind::BuiltinUnknownObject:
    case swift::TypeKind::BuiltinVector:
    case swift::TypeKind::UnownedStorage:
    case swift::TypeKind::WeakStorage:
    case swift::TypeKind::UnmanagedStorage:
    case swift::TypeKind::GenericTypeParam:
    case swift::TypeKind::DependentMember:
    case swift::TypeKind::Metatype:
    case swift::TypeKind::Module:
    case swift::TypeKind::Function:
    case swift::TypeKind::GenericFunction:
    case swift::TypeKind::LValue:
    case swift::TypeKind::UnboundGeneric:
    case swift::TypeKind::Enum:
    case swift::TypeKind::BoundGenericEnum:
    case swift::TypeKind::ExistentialMetatype:
    case swift::TypeKind::DynamicSelf:
    case swift::TypeKind::SILBox:
    case swift::TypeKind::SILFunction:
    case swift::TypeKind::SILBlockStorage:
    case swift::TypeKind::InOut:
    case swift::TypeKind::Unresolved:
      assert(false &&
             "Caller must only call this function with valid type_kind");
      break;

    case swift::TypeKind::Tuple: {
      layout_strategy = swift::irgen::LayoutStrategy::Universal;

      swift::TupleType *tuple_type = swift_can_type->castTo<swift::TupleType>();
      for (auto tuple_field : tuple_type->getElements()) {
        MemberInfo member_info(MemberType::Field);
        member_info.clang_type =
            CompilerType(GetASTContext(), tuple_field.getType().getPointer());
        member_info.byte_size = member_info.clang_type.GetByteSize(nullptr);

        const char *tuple_name = tuple_field.getName().get();
        if (tuple_name) {
          member_info.name.SetCString(tuple_name);
        } else {
          StreamString tuple_name_strm;
          tuple_name_strm.Printf(
              "%u", (uint32_t)member_infos_sp->member_infos.size());
          member_info.name.SetCString(tuple_name_strm.GetString().data());
        }

        field_type_infos.push_back(
            GetSwiftTypeInfo(member_info.clang_type.GetOpaqueQualType()));
        assert(field_type_infos.back() != nullptr);
        member_infos_sp->member_infos.push_back(member_info);
      }
    } break;

    case swift::TypeKind::Protocol:
    case swift::TypeKind::ProtocolComposition: {
      ProtocolInfo protocol_info;
      if (!GetProtocolTypeInfo(
              CompilerType(GetASTContext(), GetSwiftType(type)), protocol_info))
        break;
      is_protocol = true;
      uint32_t num_children = protocol_info.m_num_storage_words;

      for (uint32_t idx = 0; idx < num_children; idx++) {
        MemberInfo member_info(MemberType::Field);
        member_info.clang_type = CompilerType(
            GetASTContext(), GetASTContext()->TheRawPointerType.getPointer());
        member_info.byte_size = member_info.clang_type.GetByteSize(nullptr);
        member_info.byte_offset = idx * member_info.byte_size;
        member_info.is_fragile = false;
        StreamString child_name_stream;

        // Opaque existentials have m_num_payload_words != 0.
        if (idx < protocol_info.m_num_payload_words)
          child_name_stream.Printf("payload_data_%u", idx);
        else {
          // After the payload, the first word is either the instance itself
          // (for class or error existentials) or a metadata pointer
          // (for opaque existentials).
          //
          // Class and opaque existentials have zero or more witness tables.
          // Error existentials always store their witness table inline.
          int l_idx = idx - protocol_info.m_num_payload_words;
          if (l_idx == 0)
            child_name_stream.Printf("instance_type");
          else
            child_name_stream.Printf("protocol_witness_%u", l_idx - 1);
        }
        member_info.name = ConstString(child_name_stream.GetData());
        member_infos_sp->member_infos.push_back(member_info);
      }
    } break;

    case swift::TypeKind::Struct:
    case swift::TypeKind::Class:
    case swift::TypeKind::BoundGenericStruct:
    case swift::TypeKind::BoundGenericClass: {
      auto t_decl = swift_can_type.getAnyNominal();
      auto class_decl = swift::dyn_cast<swift::ClassDecl>(t_decl);
      if (class_decl) {
        is_class = true;
        swift::Type superclass_type(swift_can_type->getSuperclass());
        if (superclass_type) {
          MemberInfo member_info(MemberType::BaseClass);
          member_info.clang_type =
              CompilerType(GetASTContext(), superclass_type.getPointer());
          member_info.byte_size =
              member_info.clang_type.GetByteSize(nullptr);
          // Showing somemodule.sometype<A> is confusing to the user because
          // it will show the *unboud* archetype name even though the type
          // is actually properly bound (or it should!) and since one cannot
          // overload a class on the number of generic arguments,
          // somemodule.sometype is just as unique.
          member_info.name.SetCString(
              member_info.clang_type.GetUnboundType()
                  .GetTypeName()
                  .AsCString("<no type name>"));
          field_type_infos.push_back(
              GetSwiftTypeInfo(member_info.clang_type.GetOpaqueQualType()));
          assert(field_type_infos.back() != nullptr);
          member_infos_sp->member_infos.push_back(member_info);
        }
      }

      for (auto decl : t_decl->getMembers()) {
        // Find ivars that aren't properties
        if (swift::isa<swift::VarDecl>(decl)) {
          swift::VarDecl *var_decl = swift::cast<swift::VarDecl>(decl);
          if (var_decl->hasStorage() && !var_decl->isStatic()) {
            MemberInfo member_info(MemberType::Field);
            swift::Type member_type = swift_can_type->getTypeOfMember(
                t_decl->getModuleContext(), var_decl, nullptr);
            member_info.clang_type =
                CompilerType(GetASTContext(), member_type.getPointer());
            member_info.byte_size =
                member_info.clang_type.GetByteSize(nullptr);
            member_info.is_fragile =
                is_class; // Class fields are all fragile...
            const char *child_name_cstr = var_decl->getName().get();
            if (child_name_cstr)
              member_info.name.SetCString(child_name_cstr);
            field_type_infos.push_back(GetSwiftTypeInfo(
                member_info.clang_type.GetOpaqueQualType()));
            assert(field_type_infos.back() != nullptr);
            member_infos_sp->member_infos.push_back(member_info);
          }
        }
      }
    } break;

    case swift::TypeKind::TypeVariable:
    case swift::TypeKind::Archetype:
      break;

    case swift::TypeKind::Optional:
    case swift::TypeKind::ImplicitlyUnwrappedOptional:
    case swift::TypeKind::NameAlias:
    case swift::TypeKind::Paren:
    case swift::TypeKind::Dictionary:
    case swift::TypeKind::ArraySlice:
      assert(false && "Not a canonical type");
      break;
    }
    if (!member_infos_sp->member_infos.empty()) {
      if (is_class) {
        // If we have a class, then all offsets are fragile so we don't need to
        // do layout since we will need to lookup the ivar offset symbol, or
        // munge the runtime data to find the offsets.
      } else if (!is_protocol) {
        // Only do struct layout if we don't have a union since the only thing
        // we need layout for currently is for the byte offset and the byte
        // offset of everything in a union is zero.
        // As for protocols, their fields are artificially generated from what a
        // protocol_container contains in the Swift runtime itself, and it's
        // just pointers, so no need to get fancy.
        swift::irgen::StructLayout layout(
            GetIRGenModule(), swift_can_type,
            swift::irgen::LayoutKind::NonHeapObject, layout_strategy,
            field_type_infos);

        const size_t num_elements = layout.getElements().size();
        assert(num_elements == member_infos_sp->member_infos.size());
        for (int ii = 0; ii < num_elements; ++ii) {
          auto element = layout.getElements()[ii];
          // check or crash
          if (element.getKind() == swift::irgen::ElementLayout::Kind::Fixed)
            member_infos_sp->member_infos[ii].byte_offset =
                element.getByteOffset().getValue();
          else
            member_infos_sp->member_infos[ii].byte_offset =
                0; // TODO: dynamic layout
                   // member_infos_sp->member_infos[ii].Dump(ii);
        }
      }
      member_info_cache->insert(std::make_pair(type, member_infos_sp));
      return member_infos_sp.get();
    }
  }
  return nullptr;
}

class SwiftEnumDescriptor {
public:
  enum class Kind {
    Empty,      // no cases in this enum
    CStyle,     // no cases have payloads
    AllPayload, // all cases have payloads
    Mixed       // some cases have payloads
  };

  struct ElementInfo {
    lldb_private::ConstString name;
    CompilerType payload_type;
    bool has_payload : 1;
    bool is_indirect : 1;
  };

  Kind GetKind() const { return m_kind; }

  ConstString GetTypeName() { return m_type_name; }

  virtual ElementInfo *
  GetElementFromData(const lldb_private::DataExtractor &data) = 0;

  virtual size_t GetNumElements() {
    return GetNumElementsWithPayload() + GetNumCStyleElements();
  }

  virtual size_t GetNumElementsWithPayload() = 0;

  virtual size_t GetNumCStyleElements() = 0;

  virtual ElementInfo *GetElementWithPayloadAtIndex(size_t idx) = 0;

  virtual ElementInfo *GetElementWithNoPayloadAtIndex(size_t idx) = 0;

  virtual ~SwiftEnumDescriptor() = default;

  static SwiftEnumDescriptor *CreateDescriptor(swift::ASTContext *ast,
                                               swift::CanType swift_can_type,
                                               swift::EnumDecl *enum_decl);

protected:
  SwiftEnumDescriptor(swift::ASTContext *ast, swift::CanType swift_can_type,
                      swift::EnumDecl *enum_decl, SwiftEnumDescriptor::Kind k)
      : m_kind(k), m_type_name() {
    if (swift_can_type.getPointer()) {
      if (auto nominal = swift_can_type->getAnyNominal()) {
        swift::Identifier name(nominal->getName());
        if (name.get())
          m_type_name.SetCString(name.get());
      }
    }
  }

private:
  Kind m_kind;
  ConstString m_type_name;
};

class SwiftEmptyEnumDescriptor : public SwiftEnumDescriptor {
public:
  SwiftEmptyEnumDescriptor(swift::ASTContext *ast,
                           swift::CanType swift_can_type,
                           swift::EnumDecl *enum_decl)
      : SwiftEnumDescriptor(ast, swift_can_type, enum_decl,
                            SwiftEnumDescriptor::Kind::Empty) {}

  virtual ElementInfo *
  GetElementFromData(const lldb_private::DataExtractor &data) {
    return nullptr;
  }

  virtual size_t GetNumElementsWithPayload() { return 0; }

  virtual size_t GetNumCStyleElements() { return 0; }

  virtual ElementInfo *GetElementWithPayloadAtIndex(size_t idx) {
    return nullptr;
  }

  virtual ElementInfo *GetElementWithNoPayloadAtIndex(size_t idx) {
    return nullptr;
  }

  static bool classof(const SwiftEnumDescriptor *S) {
    return S->GetKind() == SwiftEnumDescriptor::Kind::Empty;
  }

  virtual ~SwiftEmptyEnumDescriptor() = default;
};

namespace std {
template <> struct less<swift::ClusteredBitVector> {
  bool operator()(const swift::ClusteredBitVector &lhs,
                  const swift::ClusteredBitVector &rhs) const {
    int iL = lhs.size() - 1;
    int iR = rhs.size() - 1;
    for (; iL >= 0 && iR >= 0; --iL, --iR) {
      bool bL = lhs[iL];
      bool bR = rhs[iR];
      if (bL and not bR)
        return false;
      if (bR and not bL)
        return true;
    }
    return false;
  }
};
}

static std::string Dump(const swift::ClusteredBitVector &bit_vector) {
  std::string buffer;
  llvm::raw_string_ostream ostream(buffer);
  for (size_t i = 0; i < bit_vector.size(); i++) {
    if (bit_vector[i])
      ostream << '1';
    else
      ostream << '0';
    if ((i % 4) == 3)
      ostream << ' ';
  }
  ostream.flush();
  return buffer;
}

class SwiftCStyleEnumDescriptor : public SwiftEnumDescriptor {
public:
  SwiftCStyleEnumDescriptor(swift::ASTContext *ast,
                            swift::CanType swift_can_type,
                            swift::EnumDecl *enum_decl)
      : SwiftEnumDescriptor(ast, swift_can_type, enum_decl,
                            SwiftEnumDescriptor::Kind::CStyle),
        m_nopayload_elems_bitmask(), m_elements(), m_element_indexes() {
    Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_TYPES));

    if (log)
      log->Printf("doing C-style enum layout for %s",
                  GetTypeName().AsCString());

    SwiftASTContext *swift_ast_ctx = SwiftASTContext::GetSwiftASTContext(ast);
    swift::irgen::IRGenModule &irgen_module = swift_ast_ctx->GetIRGenModule();
    const swift::irgen::EnumImplStrategy &enum_impl_strategy =
        swift::irgen::getEnumImplStrategy(irgen_module, swift_can_type);
    llvm::ArrayRef<swift::irgen::EnumImplStrategy::Element>
        elements_with_no_payload =
            enum_impl_strategy.getElementsWithNoPayload();
    const bool has_payload = false;
    const bool is_indirect = false;
    uint64_t case_counter = 0;
    m_nopayload_elems_bitmask =
        enum_impl_strategy.getBitMaskForNoPayloadElements();

    if (log)
      log->Printf("m_nopayload_elems_bitmask = %s",
                  Dump(m_nopayload_elems_bitmask).c_str());

    for (auto enum_case : elements_with_no_payload) {
      ConstString case_name(enum_case.decl->getName().str().data());
      swift::ClusteredBitVector case_value =
          enum_impl_strategy.getBitPatternForNoPayloadElement(enum_case.decl);

      if (log)
        log->Printf("case_name = %s, unmasked value = %s",
                    case_name.AsCString(), Dump(case_value).c_str());

      case_value &= m_nopayload_elems_bitmask;

      if (log)
        log->Printf("case_name = %s, masked value = %s", case_name.AsCString(),
                    Dump(case_value).c_str());

      std::unique_ptr<ElementInfo> elem_info(
          new ElementInfo{case_name, CompilerType(), has_payload, is_indirect});
      m_element_indexes.emplace(case_counter, elem_info.get());
      case_counter++;
      m_elements.emplace(case_value, std::move(elem_info));
    }
  }

  virtual ElementInfo *
  GetElementFromData(const lldb_private::DataExtractor &data) {
    Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_TYPES));

    if (log)
      log->Printf(
          "C-style enum - inspecting data to find enum case for type %s",
          GetTypeName().AsCString());

    swift::ClusteredBitVector current_payload;
    lldb::offset_t offset = 0;
    for (size_t idx = 0; idx < data.GetByteSize(); idx++) {
      uint64_t byte = data.GetU8(&offset);
      current_payload.add(8, byte);
    }

    if (log) {
      log->Printf("m_nopayload_elems_bitmask        = %s",
                  Dump(m_nopayload_elems_bitmask).c_str());
      log->Printf("current_payload                  = %s",
                  Dump(current_payload).c_str());
    }

    if (current_payload.size() != m_nopayload_elems_bitmask.size()) {
      if (log)
        log->Printf("sizes don't match; getting out with an error");
      return nullptr;
    }

    current_payload &= m_nopayload_elems_bitmask;

    if (log)
      log->Printf("masked current_payload           = %s",
                  Dump(current_payload).c_str());

    auto iter = m_elements.find(current_payload), end = m_elements.end();
    if (iter == end) {
      if (log)
        log->Printf("bitmask search failed");
      return nullptr;
    }
    if (log)
      log->Printf("bitmask search success - found case %s",
                  iter->second.get()->name.AsCString());
    return iter->second.get();
  }

  virtual size_t GetNumElementsWithPayload() { return 0; }

  virtual size_t GetNumCStyleElements() { return m_elements.size(); }

  virtual ElementInfo *GetElementWithPayloadAtIndex(size_t idx) {
    return nullptr;
  }

  virtual ElementInfo *GetElementWithNoPayloadAtIndex(size_t idx) {
    if (idx >= m_element_indexes.size())
      return nullptr;
    return m_element_indexes[idx];
  }

  static bool classof(const SwiftEnumDescriptor *S) {
    return S->GetKind() == SwiftEnumDescriptor::Kind::CStyle;
  }

  virtual ~SwiftCStyleEnumDescriptor() = default;

private:
  swift::ClusteredBitVector m_nopayload_elems_bitmask;
  std::map<swift::ClusteredBitVector, std::unique_ptr<ElementInfo>> m_elements;
  std::map<uint64_t, ElementInfo *> m_element_indexes;
};

static CompilerType
GetFunctionArgumentTuple(const CompilerType &compiler_type) {
  if (compiler_type.IsValid() &&
      llvm::dyn_cast_or_null<SwiftASTContext>(compiler_type.GetTypeSystem())) {
    swift::CanType swift_can_type(
        GetCanonicalSwiftType(compiler_type.GetOpaqueQualType()));
    auto func =
        swift::dyn_cast_or_null<swift::AnyFunctionType>(
            swift_can_type);
    if (func) {
      auto input = func.getInput();
      // See comment in swift::AnyFunctionType for rationale here:
      // A function can take either a tuple or a parentype, but if a parentype
      // (i.e. (Foo)), then it will be reduced down to just Foo, so if the input
      // is not a tuple, that must mean there is only 1 input.
      auto tuple = swift::dyn_cast<swift::TupleType>(input);
      if (tuple)
        return CompilerType(compiler_type.GetTypeSystem(), tuple);
      else
        return CompilerType(compiler_type.GetTypeSystem(), input.getPointer());
    }
  }
  return CompilerType();
}

class SwiftAllPayloadEnumDescriptor : public SwiftEnumDescriptor {
public:
  SwiftAllPayloadEnumDescriptor(swift::ASTContext *ast,
                                swift::CanType swift_can_type,
                                swift::EnumDecl *enum_decl)
      : SwiftEnumDescriptor(ast, swift_can_type, enum_decl,
                            SwiftEnumDescriptor::Kind::AllPayload),
        m_tag_bits(), m_elements() {
    Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_TYPES));

    if (log)
      log->Printf("doing ADT-style enum layout for %s",
                  GetTypeName().AsCString());

    SwiftASTContext *swift_ast_ctx = SwiftASTContext::GetSwiftASTContext(ast);
    swift::irgen::IRGenModule &irgen_module = swift_ast_ctx->GetIRGenModule();
    const swift::irgen::EnumImplStrategy &enum_impl_strategy =
        swift::irgen::getEnumImplStrategy(irgen_module, swift_can_type);
    llvm::ArrayRef<swift::irgen::EnumImplStrategy::Element>
        elements_with_payload = enum_impl_strategy.getElementsWithPayload();
    m_tag_bits = enum_impl_strategy.getTagBitsForPayloads();

    if (log)
      log->Printf("tag_bits = %s", Dump(m_tag_bits).c_str());

    auto module_ctx = enum_decl->getModuleContext();
    const bool has_payload = true;
    for (auto enum_case : elements_with_payload) {
      ConstString case_name(enum_case.decl->getName().str().data());

      swift::EnumElementDecl *case_decl = enum_case.decl;
      assert(case_decl);
      CompilerType case_type(
          ast, swift_can_type->getTypeOfMember(module_ctx, case_decl, nullptr)
                   .getPointer());
      case_type = GetFunctionArgumentTuple(case_type.GetFunctionReturnType());

      const bool is_indirect = case_decl->isIndirect() 
          || case_decl->getParentEnum()->isIndirect();

      if (log)
        log->Printf("case_name = %s, type = %s, is_indirect = %s",
                    case_name.AsCString(), case_type.GetTypeName().AsCString(),
                    is_indirect ? "yes" : "no");

      std::unique_ptr<ElementInfo> elem_info(
          new ElementInfo{case_name, case_type, has_payload, is_indirect});
      m_elements.push_back(std::move(elem_info));
    }
  }

  virtual ElementInfo *
  GetElementFromData(const lldb_private::DataExtractor &data) {
    Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_TYPES));

    if (log)
      log->Printf(
          "ADT-style enum - inspecting data to find enum case for type %s",
          GetTypeName().AsCString());

    if (m_elements.size() == 0) // no elements, just fail
    {
      if (log)
        log->Printf("enum with no cases. getting out");
      return nullptr;
    }
    if (m_elements.size() == 1) // one element, so it's gotta be it
    {
      if (log)
        log->Printf("enum with one case. getting out easy with %s",
                    m_elements.front().get()->name.AsCString());

      return m_elements.front().get();
    }

    swift::ClusteredBitVector current_payload;
    lldb::offset_t offset = 0;
    for (size_t idx = 0; idx < data.GetByteSize(); idx++) {
      uint64_t byte = data.GetU8(&offset);
      current_payload.add(8, byte);
    }
    if (log) {
      log->Printf("tag_bits        = %s", Dump(m_tag_bits).c_str());
      log->Printf("current_payload = %s", Dump(current_payload).c_str());
    }

    if (current_payload.size() != m_tag_bits.size()) {
      if (log)
        log->Printf("sizes don't match; getting out with an error");
      return nullptr;
    }

    size_t discriminator = 0;
    size_t power_of_2 = 1;
    auto enumerator = m_tag_bits.enumerateSetBits();
    for (llvm::Optional<size_t> next = enumerator.findNext(); next.hasValue();
         next = enumerator.findNext()) {
      discriminator =
          discriminator + (current_payload[next.getValue()] ? power_of_2 : 0);
      power_of_2 <<= 1;
    }

    if (discriminator >= m_elements.size()) // discriminator too large, get out
    {
      if (log)
        log->Printf("discriminator value of %" PRIu64 " too large, getting out",
                    (uint64_t)discriminator);
      return nullptr;
    } else {
      auto ptr = m_elements[discriminator].get();
      if (log) {
        if (!ptr)
          log->Printf("discriminator value of %" PRIu64
                      " acceptable, but null case matched - that's bad",
                      (uint64_t)discriminator);
        else
          log->Printf("discriminator value of %" PRIu64
                      " acceptable, case %s matched",
                      (uint64_t)discriminator, ptr->name.AsCString());
      }
      return ptr;
    }
  }

  virtual size_t GetNumElementsWithPayload() { return m_elements.size(); }

  virtual size_t GetNumCStyleElements() { return 0; }

  virtual ElementInfo *GetElementWithPayloadAtIndex(size_t idx) {
    if (idx >= m_elements.size())
      return nullptr;
    return m_elements[idx].get();
  }

  virtual ElementInfo *GetElementWithNoPayloadAtIndex(size_t idx) {
    return nullptr;
  }

  static bool classof(const SwiftEnumDescriptor *S) {
    return S->GetKind() == SwiftEnumDescriptor::Kind::AllPayload;
  }

  virtual ~SwiftAllPayloadEnumDescriptor() = default;

private:
  swift::ClusteredBitVector m_tag_bits;
  std::vector<std::unique_ptr<ElementInfo>> m_elements;
};

class SwiftMixedEnumDescriptor : public SwiftEnumDescriptor {
public:
  SwiftMixedEnumDescriptor(swift::ASTContext *ast,
                           swift::CanType swift_can_type,
                           swift::EnumDecl *enum_decl)
      : SwiftEnumDescriptor(ast, swift_can_type, enum_decl,
                            SwiftEnumDescriptor::Kind::Mixed),
        m_non_payload_cases(ast, swift_can_type, enum_decl),
        m_payload_cases(ast, swift_can_type, enum_decl) {}

  virtual ElementInfo *
  GetElementFromData(const lldb_private::DataExtractor &data) {
    ElementInfo *elem_info = m_non_payload_cases.GetElementFromData(data);
    return elem_info ? elem_info : m_payload_cases.GetElementFromData(data);
  }

  static bool classof(const SwiftEnumDescriptor *S) {
    return S->GetKind() == SwiftEnumDescriptor::Kind::Mixed;
  }

  virtual size_t GetNumElementsWithPayload() {
    return m_payload_cases.GetNumElementsWithPayload();
  }

  virtual size_t GetNumCStyleElements() {
    return m_non_payload_cases.GetNumCStyleElements();
  }

  virtual ElementInfo *GetElementWithPayloadAtIndex(size_t idx) {
    return m_payload_cases.GetElementWithPayloadAtIndex(idx);
  }

  virtual ElementInfo *GetElementWithNoPayloadAtIndex(size_t idx) {
    return m_non_payload_cases.GetElementWithNoPayloadAtIndex(idx);
  }

  virtual ~SwiftMixedEnumDescriptor() = default;

private:
  SwiftCStyleEnumDescriptor m_non_payload_cases;
  SwiftAllPayloadEnumDescriptor m_payload_cases;
};

SwiftEnumDescriptor *
SwiftEnumDescriptor::CreateDescriptor(swift::ASTContext *ast,
                                      swift::CanType swift_can_type,
                                      swift::EnumDecl *enum_decl) {
  assert(ast);
  assert(enum_decl);
  assert(swift_can_type.getPointer());
  SwiftASTContext *swift_ast_ctx = SwiftASTContext::GetSwiftASTContext(ast);
  assert(swift_ast_ctx);
  if (enum_decl == ast->getImplicitlyUnwrappedOptionalDecl()) {
    swift::EnumDecl *optional_decl = ast->getOptionalDecl();
    swift::CanType bound_optional_can_type =
        swift::BoundGenericType::get(
            optional_decl,
            swift::Type(),
            swift::cast<swift::BoundGenericType>(swift_can_type)
                ->getGenericArgs())->getCanonicalType();
    return CreateDescriptor(ast, bound_optional_can_type, optional_decl);
  }
  swift::irgen::IRGenModule &irgen_module = swift_ast_ctx->GetIRGenModule();
  const swift::irgen::EnumImplStrategy &enum_impl_strategy =
      swift::irgen::getEnumImplStrategy(irgen_module, swift_can_type);
  llvm::ArrayRef<swift::irgen::EnumImplStrategy::Element>
      elements_with_payload = enum_impl_strategy.getElementsWithPayload();
  llvm::ArrayRef<swift::irgen::EnumImplStrategy::Element>
      elements_with_no_payload = enum_impl_strategy.getElementsWithNoPayload();
  if (elements_with_no_payload.size() == 0) {
    // nothing with no payload.. empty or all payloads?
    if (elements_with_payload.size() == 0)
      return new SwiftEmptyEnumDescriptor(ast, swift_can_type, enum_decl);
    else
      return new SwiftAllPayloadEnumDescriptor(ast, swift_can_type, enum_decl);
  } else {
    // something with no payload.. mixed or C-style?
    if (elements_with_payload.size() == 0)
      return new SwiftCStyleEnumDescriptor(ast, swift_can_type, enum_decl);
    else
      return new SwiftMixedEnumDescriptor(ast, swift_can_type, enum_decl);
  }
}

static SwiftEnumDescriptor *
GetEnumInfoFromEnumDecl(swift::ASTContext *ast, swift::CanType swift_can_type,
                        swift::EnumDecl *enum_decl) {
  return SwiftEnumDescriptor::CreateDescriptor(ast, swift_can_type, enum_decl);
}

SwiftEnumDescriptor *SwiftASTContext::GetCachedEnumInfo(void *type) {
  VALID_OR_RETURN(nullptr);

  if (type) {
    EnumInfoCache *enum_info_cache = GetEnumInfoCache(GetASTContext());
    EnumInfoCache::const_iterator pos = enum_info_cache->find(type);
    if (pos != enum_info_cache->end())
      return pos->second.get();

    swift::CanType swift_can_type(GetCanonicalSwiftType(type));
    if (!SwiftASTContext::IsFullyRealized(
            CompilerType(GetASTContext(), swift_can_type)))
      return nullptr;

    SwiftEnumDescriptorSP enum_info_sp;

    if (auto *enum_type = swift_can_type->getAs<swift::EnumType>()) {
      enum_info_sp.reset(GetEnumInfoFromEnumDecl(
          GetASTContext(), swift_can_type, enum_type->getDecl()));
    } else if (auto *bound_enum_type =
          swift_can_type->getAs<swift::BoundGenericEnumType>()) {
      enum_info_sp.reset(GetEnumInfoFromEnumDecl(
          GetASTContext(), swift_can_type, bound_enum_type->getDecl()));
    }

    if (enum_info_sp.get())
      enum_info_cache->insert(std::make_pair(type, enum_info_sp));
    return enum_info_sp.get();
  }
  return nullptr;
}

namespace {
static inline bool
SwiftASTContextSupportsLanguage(lldb::LanguageType language) {
  return language == eLanguageTypeSwift;
}

static bool IsDeviceSupport(const char *path) {
  // The old-style check, which we preserve for safety.
  if (path && strstr(path, "iOS DeviceSupport"))
    return true;

  // The new-style check, which should cover more devices.
  if (path)
    if (const char *Developer_Xcode = strstr(path, "Developer"))
      if (const char *DeviceSupport = strstr(Developer_Xcode, "DeviceSupport"))
        if (strstr(DeviceSupport, "Symbols"))
          return true;

  // Don't look in the simulator runtime frameworks either.  They either 
  // duplicate what the SDK has, or for older simulators conflict with them.
  if (path && strstr(path, ".simruntime/Contents/Resources/"))
    return true;

  return false;
}
}

SwiftASTContext::SwiftASTContext(const char *triple, Target *target)
    : TypeSystem(TypeSystem::eKindSwift), m_source_manager_ap(),
      m_diagnostic_engine_ap(), m_ast_context_ap(), m_ir_gen_module_ap(),
      m_compiler_invocation_ap(new swift::CompilerInvocation()),
      m_dwarf_ast_parser_ap(), m_scratch_module(NULL), m_sil_module_ap(),
      m_serialized_module_loader(NULL), m_clang_importer(NULL),
      m_swift_module_cache(), m_mangled_name_to_type_map(),
      m_type_to_mangled_name_map(), m_pointer_byte_size(0),
      m_pointer_bit_align(0), m_void_function_type(), m_target_wp(),
      m_process(NULL), m_platform_sdk_path(), m_resource_dir(),
      m_ast_file_data_map(), m_initialized_language_options(false),
      m_initialized_search_path_options(false),
      m_initialized_clang_importer_options(false),
      m_reported_fatal_error(false), m_fatal_errors(), m_negative_type_cache(),
      m_extra_type_info_cache(), m_swift_type_map() {
  // Set the module-cache path if it has been specified:
  if (target) {
    FileSpec &module_cache = target->GetModuleCachePath();
    if (module_cache && module_cache.Exists()) {

      std::string module_cache_path = module_cache.GetPath();
      llvm::StringRef module_cache_ref(module_cache_path);
      m_compiler_invocation_ap->setClangModuleCachePath(module_cache_ref);
    }
    m_target_wp = target->shared_from_this();
  }

  if (triple)
    SetTriple(triple);
  swift::IRGenOptions &ir_gen_opts =
      m_compiler_invocation_ap->getIRGenOptions();
  ir_gen_opts.OutputKind = swift::IRGenOutputKind::Module;
  ir_gen_opts.UseJIT = true;
  ir_gen_opts.DWARFVersion = swift::DWARFVersion;
}

SwiftASTContext::SwiftASTContext(const SwiftASTContext &rhs)
    : TypeSystem(rhs.getKind()), m_source_manager_ap(),
      m_diagnostic_engine_ap(), m_ast_context_ap(), m_ir_gen_module_ap(),
      m_compiler_invocation_ap(new swift::CompilerInvocation()),
      m_dwarf_ast_parser_ap(), m_scratch_module(NULL), m_sil_module_ap(),
      m_serialized_module_loader(NULL), m_clang_importer(NULL),
      m_swift_module_cache(), m_mangled_name_to_type_map(),
      m_type_to_mangled_name_map(), m_pointer_byte_size(0),
      m_pointer_bit_align(0), m_void_function_type(), m_target_wp(),
      m_process(NULL), m_platform_sdk_path(), m_resource_dir(),
      m_ast_file_data_map(), m_initialized_language_options(false),
      m_initialized_search_path_options(false),
      m_initialized_clang_importer_options(false),
      m_reported_fatal_error(false), m_fatal_errors(), m_negative_type_cache(),
      m_extra_type_info_cache(), m_swift_type_map() {
  if (rhs.m_compiler_invocation_ap) {
    std::string rhs_triple = rhs.GetTriple();
    if (!rhs_triple.empty()) {
      SetTriple(rhs_triple.c_str());
    }
    llvm::StringRef module_cache_path =
        rhs.m_compiler_invocation_ap->getClangModuleCachePath();
    if (!module_cache_path.empty())
      m_compiler_invocation_ap->setClangModuleCachePath(module_cache_path);
  }

  swift::IRGenOptions &ir_gen_opts =
      m_compiler_invocation_ap->getIRGenOptions();
  ir_gen_opts.OutputKind = swift::IRGenOutputKind::Module;
  ir_gen_opts.UseJIT = true;

  TargetSP target_sp = rhs.m_target_wp.lock();
  if (target_sp)
    m_target_wp = target_sp;

  m_platform_sdk_path = rhs.m_platform_sdk_path;
  m_resource_dir = rhs.m_resource_dir;

  swift::ASTContext *lhs_ast = GetASTContext();
  swift::ASTContext *rhs_ast =
      const_cast<SwiftASTContext &>(rhs).GetASTContext();

  if (lhs_ast && rhs_ast) {
    lhs_ast->SearchPathOpts = rhs_ast->SearchPathOpts;
  }
  GetClangImporter();
}

SwiftASTContext::~SwiftASTContext() {
  if (m_ast_context_ap.get()) {
    GetASTMap().Erase(m_ast_context_ap.get());
  }
}

ConstString SwiftASTContext::GetPluginNameStatic() {
  return ConstString("swift");
}

ConstString SwiftASTContext::GetPluginName() {
  return ClangASTContext::GetPluginNameStatic();
}

uint32_t SwiftASTContext::GetPluginVersion() { return 1; }

static std::string &GetDefaultResourceDir() {
  static std::string s_resource_dir;
  return s_resource_dir;
}

lldb::TypeSystemSP SwiftASTContext::CreateInstance(lldb::LanguageType language,
                                                   Module *module,
                                                   Target *target,
                                                   const char *extra_options) {
  if (SwiftASTContextSupportsLanguage(language)) {
    ArchSpec arch;
    if (module) {
      arch = module->GetArchitecture();

      ObjectFile *objfile = module->GetObjectFile();
      ArchSpec object_arch;

      if (!objfile || !objfile->GetArchitecture(object_arch))
        return TypeSystemSP();

      lldb::CompUnitSP main_compile_unit_sp = module->GetCompileUnitAtIndex(0);

      Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_TYPES));

      if (main_compile_unit_sp && !main_compile_unit_sp->Exists()) {
        if (log) {
          StreamString ss;
          module->GetDescription(&ss);

          log->Printf("Corresponding source not found for %s, loading module "
                      "%s is unlikely to succeed",
                      main_compile_unit_sp->GetCString(), ss.GetData());
        }
      }

      std::shared_ptr<SwiftASTContext> swift_ast_sp(new SwiftASTContext());

      swift_ast_sp->GetLanguageOptions().DebuggerSupport = true;
      swift_ast_sp->GetLanguageOptions().EnableAccessControl = false;

      if (!arch.IsValid())
        return TypeSystemSP();

      llvm::Triple triple = arch.GetTriple();

      if (triple.getOS() == llvm::Triple::UnknownOS) {
// cl_kernels are the only binaries that don't have an LC_MIN_VERSION_xxx load
// command.
// This avoids a Swift assertion.

#if defined(__APPLE__)
        switch (triple.getArch()) {
        default:
          triple.setOS(llvm::Triple::MacOSX);
          break;
        case llvm::Triple::arm:
        case llvm::Triple::armeb:
        case llvm::Triple::aarch64:
        case llvm::Triple::aarch64_be:
          triple.setOS(llvm::Triple::IOS);
          break;
        }

#else
        // Not an elegant hack on OS X, not an elegant hack elsewhere.
        // But we shouldn't be claiming things are Mac binaries when they are
        // not.
        triple.setOS(HostInfo::GetArchitecture().GetTriple().getOS());
#endif
      }

      swift_ast_sp->SetTriple(triple.getTriple().c_str(), module);

      bool set_triple = false;

      SymbolVendor *sym_vendor = module->GetSymbolVendor();

      std::string resource_dir;
      std::string target_triple;

      if (sym_vendor) {
        // Use the new loadFromSerializedAST if possible:

        auto ast_file_datas = sym_vendor->GetASTData(eLanguageTypeSwift);

        bool got_serialized_options = false;
        DataBufferSP ast_file_data_sp;
        if (!ast_file_datas.empty() &&
            ((ast_file_data_sp = ast_file_datas.front()) != nullptr)) {
          if (log)
            log->Printf("Found %d AST file data entries for library: %s.",
                        (int)ast_file_datas.size(),
                        module->GetSpecificationDescription().c_str());

          // Retrieve the first serialized AST data blob and initialize
          // the compiler invocation with it.
          llvm::StringRef section_data_ref(
              (const char *)ast_file_data_sp->GetBytes(),
              ast_file_data_sp->GetByteSize());
          auto result =
              swift_ast_sp->GetCompilerInvocation().loadFromSerializedAST(
                  section_data_ref);

          switch (result) {
          case swift::serialization::Status::Valid:
            got_serialized_options = true;
            break;

          case swift::serialization::Status::FormatTooOld:
            swift_ast_sp->m_fatal_errors.SetErrorString(
                "the swift module file format is too old to be used by the "
                "version of the swift compiler in LLDB");
            return swift_ast_sp;

          case swift::serialization::Status::FormatTooNew:
            swift_ast_sp->m_fatal_errors.SetErrorString(
                "the swift module file format is too new to be used by this "
                "version of the swift compiler in LLDB");
            return swift_ast_sp;

          case swift::serialization::Status::MissingDependency:
            swift_ast_sp->m_fatal_errors.SetErrorString(
                "the swift module file depends on another module that can't be "
                "loaded");
            return swift_ast_sp;

          case swift::serialization::Status::MissingShadowedModule:
            swift_ast_sp->m_fatal_errors.SetErrorString(
                "the swift module file is an overlay for a clang module, which "
                "can't be found");
            return swift_ast_sp;

          case swift::serialization::Status::FailedToLoadBridgingHeader:
            swift_ast_sp->m_fatal_errors.SetErrorString(
                "the swift module file depends on a bridging header that can't "
                "be loaded");
            return swift_ast_sp;

          case swift::serialization::Status::Malformed:
            swift_ast_sp->m_fatal_errors.SetErrorString(
                "the swift module file is malformed");
            return swift_ast_sp;

          case swift::serialization::Status::MalformedDocumentation:
            swift_ast_sp->m_fatal_errors.SetErrorString(
                "the swift module documentation file is malformed in some way");
            return swift_ast_sp;

          case swift::serialization::Status::NameMismatch:
            swift_ast_sp->m_fatal_errors.SetErrorString(
                "the swift module file's name does not match the module it is "
                "being loaded into");
            return swift_ast_sp;

          case swift::serialization::Status::TargetIncompatible:
            swift_ast_sp->m_fatal_errors.SetErrorString(
                "the swift module file was built for a different target "
                "platform");
            return swift_ast_sp;

          case swift::serialization::Status::TargetTooNew:
            swift_ast_sp->m_fatal_errors.SetErrorString(
                "the swift module file was built for a target newer than the "
                "current target");
            return swift_ast_sp;
          }
        }

        // TODO: make sure we only get options for Swift files.
        // We really should be passing down a language enumeration into
        // sym_vendor->GetCompileOption() so we don't get compiler options
        // for a C/C++ file...

        if (got_serialized_options) {
          // Some of the bits in the compiler options we keep separately, so we
          // need to populate them from the serialized options:
          llvm::StringRef serialized_triple =
              swift_ast_sp->GetCompilerInvocation().getTargetTriple();
          if (serialized_triple.empty()) {
            if (log)
              log->Printf("\tSerialized triple for %s was empty.",
                          module->GetSpecificationDescription().c_str());
          } else {
            if (log)
              log->Printf("\tFound serialized triple for %s: %s.",
                          module->GetSpecificationDescription().c_str(),
                          serialized_triple.data());
            swift_ast_sp->SetTriple(serialized_triple.data(), module);
            set_triple = true;
          }

          llvm::StringRef serialized_sdk_path =
              swift_ast_sp->GetCompilerInvocation().getSDKPath();
          if (serialized_sdk_path.empty()) {
            if (log)
              log->Printf("\tNo serialized SDK path.");
          } else {
            if (log)
              log->Printf("\tGot serialized SDK path %s.",
                          serialized_sdk_path.data());
            FileSpec sdk_spec(serialized_sdk_path.data(), false);
            if (sdk_spec.Exists()) {
              swift_ast_sp->SetPlatformSDKPath(serialized_sdk_path.data());
            }
          }
        }

        if (!got_serialized_options || !swift_ast_sp->GetPlatformSDKPath()) {
          std::string platform_sdk_path;
          if (sym_vendor->GetCompileOption("-sdk", platform_sdk_path)) {
            FileSpec sdk_spec(platform_sdk_path.c_str(), false);
            if (sdk_spec.Exists()) {
              swift_ast_sp->SetPlatformSDKPath(platform_sdk_path.c_str());
            }

            if (sym_vendor->GetCompileOption("-target", target_triple)) {
              llvm::StringRef parsed_triple(target_triple);

              swift_ast_sp->SetTriple(target_triple.c_str(), module);
              set_triple = true;
            }
          }
        }

        if (sym_vendor->GetCompileOption("-resource-dir", resource_dir)) {
          swift_ast_sp->SetResourceDir(resource_dir.c_str());
        } else if (!GetDefaultResourceDir().empty()) {
          // Use the first resource dir we found when setting up a target.
          swift_ast_sp->SetResourceDir(GetDefaultResourceDir().c_str());
        } else {
          if (log)
            log->Printf(
                "No resource dir available for module's SwiftASTContext.");
        }

        if (!got_serialized_options) {

          std::vector<std::string> framework_search_paths;

          if (sym_vendor->GetCompileOptions("-F", framework_search_paths)) {
            for (std::string &search_path : framework_search_paths) {
              swift_ast_sp->AddFrameworkSearchPath(search_path.c_str());
            }
          }

          std::vector<std::string> include_paths;

          if (sym_vendor->GetCompileOptions("-I", include_paths)) {
            for (std::string &search_path : include_paths) {
              const FileSpec path_spec(search_path.c_str(), false);

              if (path_spec.Exists()) {
                static const ConstString s_hmap_extension("hmap");

                if (IsDirectory(path_spec)) {
                  swift_ast_sp->AddModuleSearchPath(search_path.c_str());
                } else if (IsRegularFile(path_spec) &&
                           path_spec.GetFileNameExtension() ==
                               s_hmap_extension) {
                  std::string argument("-I");
                  argument.append(search_path);
                  swift_ast_sp->AddClangArgument(argument.c_str());
                }
              }
            }
          }

          std::vector<std::string> cc_options;

          if (sym_vendor->GetCompileOptions("-Xcc", cc_options)) {
            for (int i = 0; i < cc_options.size(); ++i) {
              if (!cc_options[i].compare("-iquote") &&
                  i + 1 < cc_options.size()) {
                swift_ast_sp->AddClangArgumentPair("-iquote",
                                                   cc_options[i + 1].c_str());
              }
            }
          }
        }

        FileSpecList loaded_modules;

        sym_vendor->GetLoadedModules(lldb::eLanguageTypeSwift, loaded_modules);

        for (size_t mi = 0, me = loaded_modules.GetSize(); mi != me; ++mi) {
          const FileSpec &loaded_module = loaded_modules.GetFileSpecAtIndex(mi);

          if (loaded_module.Exists())
            swift_ast_sp->AddModuleSearchPath(
                loaded_module.GetDirectory().GetCString());
        }
      }

      if (!set_triple) {
        llvm::Triple llvm_triple(swift_ast_sp->GetTriple());

        // LLVM wants this to be set to iOS or MacOSX; if we're working on
        // a bare-boards type image, change the triple for LLVM's benefit.
        if (llvm_triple.getVendor() == llvm::Triple::Apple &&
            llvm_triple.getOS() == llvm::Triple::UnknownOS) {
          if (llvm_triple.getArch() == llvm::Triple::arm ||
              llvm_triple.getArch() == llvm::Triple::thumb) {
            llvm_triple.setOS(llvm::Triple::IOS);
          } else {
            llvm_triple.setOS(llvm::Triple::MacOSX);
          }
          swift_ast_sp->SetTriple(llvm_triple.str().c_str(), module);
        }
      }

      if (!swift_ast_sp->GetClangImporter()) {
        if (log) {
          log->Printf("((Module*)%p) [%s]->GetSwiftASTContext() returning NULL "
                      "- couldn't create a ClangImporter",
                      module, module->GetFileSpec().GetFilename().AsCString(
                                  "<anonymous>"));
        }

        return TypeSystemSP();
      }

      std::vector<std::string> module_names;
      swift_ast_sp->RegisterSectionModules(*module, module_names);
      swift_ast_sp->ValidateSectionModules(*module, module_names);

      if (log) {
        log->Printf(
            "((Module*)%p) [%s]->GetSwiftASTContext() = %p", module,
            module->GetFileSpec().GetFilename().AsCString("<anonymous>"),
            swift_ast_sp.get());
        swift_ast_sp->DumpConfiguration(log);
      }
      return swift_ast_sp;
    } else if (target) {
      arch = target->GetArchitecture();

      // Make an AST but don't set the triple yet. We need to try and detect
      // if we have a iOS simulator...
      std::shared_ptr<SwiftASTContextForExpressions> swift_ast_sp(
          new SwiftASTContextForExpressions(*target));

      if (!arch.IsValid())
        return TypeSystemSP();

      bool handled_sdk_path = false;
      bool handled_resource_dir = false;
      const size_t num_images = target->GetImages().GetSize();
      // Set the SDK path and resource dir prior to doing search paths.
      // Otherwise when we create search path options we put in the wrong SDK
      // path.

      FileSpec &target_sdk_spec = target->GetSDKPath();
      if (target_sdk_spec && target_sdk_spec.Exists()) {
        std::string platform_sdk_path(target_sdk_spec.GetPath());
        swift_ast_sp->SetPlatformSDKPath(std::move(platform_sdk_path));
        handled_sdk_path = true;
      }

      Status module_error;
      for (size_t mi = 0; mi != num_images; ++mi) {
        ModuleSP module_sp = target->GetImages().GetModuleAtIndex(mi);

        SwiftASTContext *module_swift_ast =
            llvm::dyn_cast_or_null<SwiftASTContext>(
                module_sp->GetTypeSystemForLanguage(lldb::eLanguageTypeSwift));

        if (!module_swift_ast || module_swift_ast->HasFatalErrors() ||
            !module_swift_ast->GetClangImporter()) {
          // Make sure we warn about this module load failure, the one that
          // comes from loading types often gets swallowed up and not seen,
          // this is the only reliable point where we can show this.
          // But only do it once per UUID so we don't overwhelm the user with
          // warnings...
          std::unordered_set<std::string> m_swift_warnings_issued;

          UUID module_uuid(module_sp->GetUUID());
          std::pair<std::unordered_set<std::string>::iterator, bool> result(
              m_swift_warnings_issued.insert(module_uuid.GetAsString()));
          if (result.second) {
            StreamString ss;
            module_sp->GetDescription(&ss, eDescriptionLevelBrief);
            target->GetDebugger().GetErrorFile()->Printf(
                "warning: Swift error in module %s" /*": \n    %s\n"*/
                ".\nDebug info from this module will be unavailable in the "
                "debugger.\n\n",
                ss.GetData());
          }

          continue;
        }

        if (!handled_sdk_path) {
          const char *platform_sdk_path =
              module_swift_ast->GetPlatformSDKPath();

          if (platform_sdk_path) {
            handled_sdk_path = true;
            swift_ast_sp->SetPlatformSDKPath(platform_sdk_path);
          }
        }

        if (!handled_resource_dir) {
          const char *resource_dir = module_swift_ast->GetResourceDir();
          if (resource_dir) {
            handled_resource_dir = true;
            swift_ast_sp->SetResourceDir(resource_dir);
            if (GetDefaultResourceDir().empty()) {
              // Tuck this away as a reasonable default resource dir
              // for contexts that don't have one. The Swift parser
              // will assert without one.
              GetDefaultResourceDir() = resource_dir;
            }
          }
        }

        if (handled_sdk_path && handled_resource_dir)
          break;
      }

      // First, prime the compiler with the options from the main executable:
      bool read_options_from_ast = false;
      ModuleSP exe_module_sp(target->GetExecutableModule());

      // If we're debugging a testsuite, then treat the main test bundle as the
      // executable.
      if (exe_module_sp &&
          PlatformDarwin::IsUnitTestExecutable(*exe_module_sp)) {
        ModuleSP unit_test_module =
            PlatformDarwin::GetUnitTestModule(target->GetImages());

        if (unit_test_module) {
          exe_module_sp = unit_test_module;
        }
      }

      if (exe_module_sp) {
        SymbolVendor *sym_vendor = exe_module_sp->GetSymbolVendor();
        if (sym_vendor) {
          // Retrieve the Swift ASTs from the symbol vendor.
          auto ast_datas = sym_vendor->GetASTData(eLanguageTypeSwift);
          if (!ast_datas.empty()) {
            // We only initialize the compiler invocation with the first
            // AST since it initializes some data that must remain static,
            // like the SDK path and the triple for the produced output.
            auto ast_data_sp = ast_datas.front();
            llvm::StringRef section_data_ref(
                (const char *)ast_data_sp->GetBytes(),
                ast_data_sp->GetByteSize());
            swift::serialization::Status result =
                swift_ast_sp->GetCompilerInvocation().loadFromSerializedAST(
                    section_data_ref);
            if (result == swift::serialization::Status::Valid) {
              read_options_from_ast = true;
            } else {
              Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_TYPES));
              if (log)
                log->Printf("Attempt to load compiler options from Serialized "
                            "AST failed: %d (%zu AST data blobs total).",
                            result, ast_datas.size());
            }
          }
        }
      }

      // Now if the user fully specified the triple, let that override the one
      // we got from executable's options:

      if (target->GetArchitecture().IsFullySpecifiedTriple()) {
        swift_ast_sp->SetTriple(
            target->GetArchitecture().GetTriple().str().c_str());
      } else {
        // Always run using the Host OS triple...
        bool set_triple = false;
        PlatformSP platform_sp(target->GetPlatform());
        uint32_t major, minor, update;
        if (platform_sp &&
            platform_sp->GetOSVersion(major, minor, update,
                                      target->GetProcessSP().get())) {
          StreamString full_triple_name;
          full_triple_name.PutCString(
              target->GetArchitecture().GetTriple().str());
          if (major != UINT32_MAX) {
            full_triple_name.Printf("%u", major);
            if (minor != UINT32_MAX) {
              full_triple_name.Printf(".%u", minor);
              if (update != UINT32_MAX)
                full_triple_name.Printf(".%u", update);
            }
          }
          swift_ast_sp->SetTriple(full_triple_name.GetString().data());
          set_triple = true;
        }

        if (!set_triple) {
          ModuleSP exe_module_sp(target->GetExecutableModule());
          if (exe_module_sp) {
            Status exe_error;
            SwiftASTContext *exe_swift_ctx =
                llvm::dyn_cast_or_null<SwiftASTContext>(
                    exe_module_sp->GetTypeSystemForLanguage(
                        lldb::eLanguageTypeSwift));
            if (exe_swift_ctx) {
              swift_ast_sp->SetTriple(
                  exe_swift_ctx->GetLanguageOptions().Target.str().c_str());
            }
          }
        }
      }

      const bool use_all_compiler_flags =
          !read_options_from_ast || target->GetUseAllCompilerFlags();

      std::function<void(ModuleSP &&)> process_one_module =
          [target, &swift_ast_sp,
           use_all_compiler_flags](ModuleSP &&module_sp) {
            const FileSpec &module_file = module_sp->GetFileSpec();

            std::string module_path = module_file.GetPath();

            // Add the containing framework to the framework search path.  Don't
            // do that if this is the executable module, since it might be
            // buried in some framework that we don't care about.
            if (use_all_compiler_flags &&
                target->GetExecutableModulePointer() != module_sp.get()) {
              size_t framework_offset = module_path.rfind(".framework/");

              if (framework_offset != std::string::npos) {
                // Sometimes the version of the framework that got loaded has been stripped
                // and in that case, adding it to the framework search path will just
                // short-cut a clang search that might otherwise find the needed headers.
                // So don't add these paths.
                std::string framework_path = module_path.substr(0, framework_offset);
                framework_path.append(".framework");
                FileSpec path_spec(framework_path, true);
                FileSpec headers_spec = path_spec.CopyByAppendingPathComponent("Headers");
                bool add_it = false;
                if (headers_spec.Exists())
                  add_it = true;
                if (!add_it) {
                  FileSpec module_spec = path_spec.CopyByAppendingPathComponent("Modules");
                  if (module_spec.Exists())
                    add_it = true;
                }
                
                if (!add_it) {
                  Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_TYPES));
                  if (log)
                    log->Printf("process_one_module rejecting framework path"
                                " \"%s\" as it has no Headers "
                                "or Modules subdirectories.",
                                framework_path.c_str());
                }
                
                if (add_it) {
                  while (framework_offset &&
                         (module_path[framework_offset] != '/'))
                    framework_offset--;

                  if (module_path[framework_offset] == '/') {
                    // framework_offset now points to the '/';

                    std::string parent_path =
                        module_path.substr(0, framework_offset);

                    if (strncmp(parent_path.c_str(), "/System/Library",
                                strlen("/System/Library")) &&
                        !IsDeviceSupport(parent_path.c_str())) {
                      swift_ast_sp->AddFrameworkSearchPath(parent_path.c_str());
                    }
                  }
                }
              }
            }

            SymbolVendor *sym_vendor = module_sp->GetSymbolVendor();

            if (sym_vendor) {
              std::vector<std::string> module_names;

              SymbolFile *sym_file = sym_vendor->GetSymbolFile();
              if (sym_file) {
                Status sym_file_error;
                SwiftASTContext *ast_context =
                    llvm::dyn_cast_or_null<SwiftASTContext>(
                        sym_file->GetTypeSystemForLanguage(
                            lldb::eLanguageTypeSwift));
                if (ast_context) {
                  if (use_all_compiler_flags ||
                      target->GetExecutableModulePointer() == module_sp.get()) {
                    for (size_t msi = 0,
                                mse = ast_context->GetNumModuleSearchPaths();
                         msi < mse; ++msi) {
                      const char *search_path =
                          ast_context->GetModuleSearchPathAtIndex(msi);
                      swift_ast_sp->AddModuleSearchPath(search_path);
                    }

                    for (size_t fsi = 0,
                                fse = ast_context->GetNumFrameworkSearchPaths();
                         fsi < fse; ++fsi) {
                      const char *search_path =
                          ast_context->GetFrameworkSearchPathAtIndex(fsi);
                      swift_ast_sp->AddFrameworkSearchPath(search_path);
                    }

                    for (size_t osi = 0,
                                ose = ast_context->GetNumClangArguments();
                         osi < ose; ++osi) {
                      const char *clang_argument =
                          ast_context->GetClangArgumentAtIndex(osi);
                      swift_ast_sp->AddClangArgument(clang_argument, true);
                    }
                  }

                  swift_ast_sp->RegisterSectionModules(*module_sp,
                                                       module_names);
                }
              }
            }
          };

      for (size_t mi = 0; mi != num_images; ++mi) {
        process_one_module(target->GetImages().GetModuleAtIndex(mi));
      }

      FileSpecList &framework_search_paths =
          target->GetSwiftFrameworkSearchPaths();
      FileSpecList &module_search_paths = target->GetSwiftModuleSearchPaths();

      for (size_t fi = 0, fe = framework_search_paths.GetSize(); fi != fe;
           ++fi) {
        swift_ast_sp->AddFrameworkSearchPath(
            framework_search_paths.GetFileSpecAtIndex(fi).GetPath().c_str());
      }

      for (size_t mi = 0, me = module_search_paths.GetSize(); mi != me; ++mi) {
        swift_ast_sp->AddModuleSearchPath(
            module_search_paths.GetFileSpecAtIndex(mi).GetPath().c_str());
      }

      // Now fold any extra options we were passed. This has to be done BEFORE
      // the ClangImporter is made by calling GetClangImporter or these options
      // will be ignored.

      if (extra_options) {
        swift::CompilerInvocation &compiler_invocation =
            swift_ast_sp->GetCompilerInvocation();
        Args extra_args(extra_options);
        llvm::ArrayRef<const char *> extra_args_ref(
            extra_args.GetArgumentVector(), extra_args.GetArgumentCount());
        compiler_invocation.parseArgs(extra_args_ref,
                                      swift_ast_sp->GetDiagnosticEngine());
      }

      Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_TYPES));

      // This needs to happen once all the import paths are set, or otherwise no
      // modules will be found.
      if (!swift_ast_sp->GetClangImporter()) {
        if (log) {
          log->Printf("((Target*)%p)->GetSwiftASTContext() returning NULL - "
                      "couldn't create a ClangImporter",
                      target);
        }

        return TypeSystemSP();
      }

      if (log) {
        log->Printf("((Target*)%p)->GetSwiftASTContext() = %p", target,
                    swift_ast_sp.get());
        swift_ast_sp->DumpConfiguration(log);
      }

      if (swift_ast_sp->HasFatalErrors()) {
        swift_ast_sp->m_error.SetErrorStringWithFormat(
            "Error creating target Swift AST context: %s",
            swift_ast_sp->GetFatalErrors().AsCString());
        return lldb::TypeSystemSP();
      }

      {
        const bool can_create = true;
        if (!swift_ast_sp->m_ast_context_ap->getStdlibModule(can_create)) {
          // We need to be able to load the standard library!
          return lldb::TypeSystemSP();
        }
      }

      return swift_ast_sp;
    }
  }
  return lldb::TypeSystemSP();
}

void SwiftASTContext::EnumerateSupportedLanguages(
    std::set<lldb::LanguageType> &languages_for_types,
    std::set<lldb::LanguageType> &languages_for_expressions) {
  static std::vector<lldb::LanguageType> s_supported_languages_for_types(
      {lldb::eLanguageTypeSwift});

  static std::vector<lldb::LanguageType> s_supported_languages_for_expressions(
      {lldb::eLanguageTypeSwift});

  languages_for_types.insert(s_supported_languages_for_types.begin(),
                             s_supported_languages_for_types.end());
  languages_for_expressions.insert(
      s_supported_languages_for_expressions.begin(),
      s_supported_languages_for_expressions.end());
}

void SwiftASTContext::Initialize() {
  PluginManager::RegisterPlugin(GetPluginNameStatic(),
                                "swift AST context plug-in", CreateInstance,
                                EnumerateSupportedLanguages);
}

void SwiftASTContext::Terminate() {
  PluginManager::UnregisterPlugin(CreateInstance);
}

bool SwiftASTContext::SupportsLanguage(lldb::LanguageType language) {
  return SwiftASTContextSupportsLanguage(language);
}

Status SwiftASTContext::IsCompatible() { return GetFatalErrors(); }

Status SwiftASTContext::GetFatalErrors() {
  Status error;
  if (HasFatalErrors()) {
    error = m_fatal_errors;
    if (error.Success())
      error.SetErrorString("unknown fatal error in swift AST context");
  }
  return error;
}

swift::IRGenOptions &SwiftASTContext::GetIRGenOptions() {
  return m_compiler_invocation_ap->getIRGenOptions();
}

std::string SwiftASTContext::GetTriple() const {
  return m_compiler_invocation_ap->getTargetTriple();
}

// Conditions a triple string to be safe for use with Swift.
// Right now this just strips the Haswell marker off the CPU name.
// TODO make Swift more robust
static std::string GetSwiftFriendlyTriple(const std::string &triple) {
  static std::string s_x86_64h("x86_64h");
  static std::string::size_type s_x86_64h_size = s_x86_64h.size();

  if (0 == triple.compare(0, s_x86_64h_size, s_x86_64h)) {
    std::string fixed_triple("x86_64");
    fixed_triple.append(
        triple.substr(s_x86_64h_size, triple.size() - s_x86_64h_size));
    return fixed_triple;
  }
  return triple;
}

bool SwiftASTContext::SetTriple(const char *triple_cstr, Module *module) {
  if (triple_cstr && triple_cstr[0]) {
    Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_TYPES));

    // We can change our triple up until we create the swift::irgen::IRGenModule
    if (m_ir_gen_module_ap.get() == NULL) {
      std::string raw_triple(triple_cstr);
      std::string triple = GetSwiftFriendlyTriple(raw_triple);

      llvm::Triple llvm_triple(triple);
      const unsigned unspecified = 0;
      // If the OS version is unspecified, do fancy things
      if (llvm_triple.getOSMajorVersion() == unspecified) {
        // If a triple is "<arch>-apple-darwin" change it to be
        // "<arch>-apple-macosx" otherwise the major and minor OS version we
        // append below would be wrong.
        if (llvm_triple.getVendor() == llvm::Triple::VendorType::Apple &&
            llvm_triple.getOS() == llvm::Triple::OSType::Darwin) {
          llvm_triple.setOS(llvm::Triple::OSType::MacOSX);
          triple = llvm_triple.str();
        }

        // Append the min OS to the triple if we have a target
        ModuleSP module_sp;
        if (module == NULL) {
          TargetSP target_sp(m_target_wp.lock());
          if (target_sp) {
            module_sp = target_sp->GetExecutableModule();
            if (module_sp)
              module = module_sp.get();
          }
        }

        if (module) {
          ObjectFile *objfile = module->GetObjectFile();
          uint32_t versions[3];
          if (objfile) {
            uint32_t num_versions = objfile->GetMinimumOSVersion(versions, 3);
            StreamString strm;
            if (num_versions) {
              for (uint32_t v = 0; v < 3; ++v) {
                if (v < num_versions) {
                  if (versions[v] == UINT32_MAX)
                    versions[v] = 0;
                } else
                  versions[v] = 0;
              }
              strm.Printf("%s%u.%u.%u", llvm_triple.getOSName().str().c_str(),
                          versions[0], versions[1], versions[2]);
              llvm_triple.setOSName(strm.GetString());
              triple = llvm_triple.str();
            }
          }
        }
      }
      if (log)
        log->Printf("%p: SwiftASTContext::SetTriple('%s') setting to '%s'%s",
                    this, triple_cstr, triple.c_str(),
                    m_target_wp.lock() ? " (target)" : "");
      m_compiler_invocation_ap->setTargetTriple(triple);
      return true;
    } else {
      if (log)
        log->Printf("%p: SwiftASTContext::SetTriple('%s') ignoring triple "
                    "since the IRGenModule has already been created",
                    this, triple_cstr);
    }
  }
  return false;
}

static std::string GetXcodeContentsPath() {
  const char substr[] = ".app/Contents/";

  // First, try based on the current shlib's location

  {
    FileSpec fspec;

    if (HostInfo::GetLLDBPath(ePathTypeLLDBShlibDir, fspec)) {
      std::string path_to_shlib = fspec.GetPath();
      size_t pos = path_to_shlib.rfind(substr);
      if (pos != std::string::npos) {
        path_to_shlib.erase(pos + strlen(substr));
        return path_to_shlib;
      }
    }
  }

  // Fall back to using xcrun

  {
    int status = 0;
    int signo = 0;
    std::string output;
    const char *command = "xcrun -sdk macosx --show-sdk-path";
    lldb_private::Status error = Host::RunShellCommand(
        command, // shell command to run
        NULL,    // current working directory
        &status, // Put the exit status of the process in here
        &signo,  // Put the signal that caused the process to exit in here
        &output, // Get the output from the command and place it in this string
        3);      // Timeout in seconds to wait for shell program to finish
    if (status == 0 && !output.empty()) {
      size_t first_non_newline = output.find_last_not_of("\r\n");
      if (first_non_newline != std::string::npos) {
        output.erase(first_non_newline + 1);
      }

      size_t pos = output.rfind(substr);
      if (pos != std::string::npos) {
        output.erase(pos + strlen(substr));
        return output;
      }
    }
  }

  return std::string();
}

static std::string GetCurrentToolchainPath() {
  const char substr[] = ".xctoolchain/";

  {
    FileSpec fspec;

    if (HostInfo::GetLLDBPath(ePathTypeLLDBShlibDir, fspec)) {
      std::string path_to_shlib = fspec.GetPath();
      size_t pos = path_to_shlib.rfind(substr);
      if (pos != std::string::npos) {
        path_to_shlib.erase(pos + strlen(substr));
        return path_to_shlib;
      }
    }
  }

  return std::string();
}

static std::string GetCurrentCLToolsPath() {
  const char substr[] = "/CommandLineTools/";

  {
    FileSpec fspec;

    if (HostInfo::GetLLDBPath(ePathTypeLLDBShlibDir, fspec)) {
      std::string path_to_shlib = fspec.GetPath();
      size_t pos = path_to_shlib.rfind(substr);
      if (pos != std::string::npos) {
        path_to_shlib.erase(pos + strlen(substr));
        return path_to_shlib;
      }
    }
  }

  return std::string();
}

namespace {

enum class SDKType {
  MacOSX = 0,
  iPhoneSimulator,
  iPhoneOS,
  AppleTVSimulator,
  AppleTVOS,
  WatchSimulator,
  watchOS,
  numSDKTypes,
  unknown = -1
};

const char *const sdk_strings[] = {
    "macosx",    "iphonesimulator", "iphoneos", "appletvsimulator",
    "appletvos", "watchsimulator",  "watchos",
};

struct SDKEnumeratorInfo {
  FileSpec found_path;
  SDKType sdk_type;
  uint32_t least_major;
  uint32_t least_minor;
};

static bool SDKSupportsSwift(const FileSpec &sdk_path, SDKType desired_type) {
  ConstString last_path_component = sdk_path.GetLastPathComponent();

  if (last_path_component) {
    const llvm::StringRef sdk_name_raw = last_path_component.GetStringRef();
    std::string sdk_name_lower = sdk_name_raw.lower();
    const llvm::StringRef sdk_name(sdk_name_lower);

    llvm::StringRef version_part;

    SDKType sdk_type = SDKType::unknown;

    if (desired_type == SDKType::unknown) {
      for (int i = (int)SDKType::MacOSX; i < (int)SDKType::numSDKTypes; ++i) {
        if (sdk_name.startswith(sdk_strings[i])) {
          version_part = sdk_name.drop_front(strlen(sdk_strings[i]));
          sdk_type = (SDKType)i;
          break;
        }
      }

      // For non-Darwin SDKs assume Swift is supported
      if (sdk_type == SDKType::unknown)
        return true;
    } else {
      if (sdk_name.startswith(sdk_strings[(int)desired_type])) {
        version_part =
            sdk_name.drop_front(strlen(sdk_strings[(int)desired_type]));
        sdk_type = desired_type;
      } else {
        return false;
      }
    }

    const size_t major_dot_offset = version_part.find('.');
    if (major_dot_offset == llvm::StringRef::npos)
      return false;

    const llvm::StringRef major_version =
        version_part.slice(0, major_dot_offset);
    const llvm::StringRef minor_part =
        version_part.drop_front(major_dot_offset + 1);

    const size_t minor_dot_offset = minor_part.find('.');
    if (minor_dot_offset == llvm::StringRef::npos)
      return false;

    const llvm::StringRef minor_version = minor_part.slice(0, minor_dot_offset);

    unsigned int major = 0;
    unsigned int minor = 0;

    if (major_version.getAsInteger(10, major))
      return false;

    if (minor_version.getAsInteger(10, minor))
      return false;

    switch (sdk_type) {
    case SDKType::MacOSX:
      if (major > 10 || (major == 10 && minor >= 10))
        return true;
      break;
    case SDKType::iPhoneOS:
    case SDKType::iPhoneSimulator:
      if (major >= 8)
        return true;
      break;
    case SDKType::AppleTVSimulator:
    case SDKType::AppleTVOS:
      if (major >= 9)
        return true;
      break;
    case SDKType::WatchSimulator:
    case SDKType::watchOS:
      if (major >= 2)
        return true;
      break;
    default:
      return false;
    }
  }

  return false;
}

FileSpec::EnumerateDirectoryResult
DirectoryEnumerator(void *baton, llvm::sys::fs::file_type file_type,
                    const FileSpec &spec) {
  SDKEnumeratorInfo *enumerator_info = static_cast<SDKEnumeratorInfo *>(baton);

  if (SDKSupportsSwift(spec, enumerator_info->sdk_type)) {
    enumerator_info->found_path = spec;
    return FileSpec::EnumerateDirectoryResult::eEnumerateDirectoryResultNext;
  }

  return FileSpec::EnumerateDirectoryResult::eEnumerateDirectoryResultNext;
};

static ConstString EnumerateSDKsForVersion(FileSpec sdks_spec, SDKType sdk_type,
                                           uint32_t least_major,
                                           uint32_t least_minor) {
  if (!IsDirectory(sdks_spec))
    return ConstString();

  const bool find_directories = true;
  const bool find_files = false;
  const bool find_other = true; // include symlinks

  SDKEnumeratorInfo enumerator_info;

  enumerator_info.sdk_type = sdk_type;
  enumerator_info.least_major = least_major;
  enumerator_info.least_minor = least_minor;

  FileSpec::EnumerateDirectory(sdks_spec.GetPath().c_str(), find_directories,
                               find_files, find_other, DirectoryEnumerator,
                               &enumerator_info);

  if (IsDirectory(enumerator_info.found_path))
    return ConstString(enumerator_info.found_path.GetPath());
  else
    return ConstString();
}

static ConstString GetSDKDirectory(SDKType sdk_type, uint32_t least_major,
                                   uint32_t least_minor) {
  if (sdk_type != SDKType::MacOSX) {
    // Look inside Xcode for the required installed iOS SDK version

    std::string sdks_path = GetXcodeContentsPath();
    sdks_path.append("Developer/Platforms");

    if (sdk_type == SDKType::iPhoneSimulator) {
      sdks_path.append("/iPhoneSimulator.platform/");
    } else if (sdk_type == SDKType::AppleTVSimulator) {
      sdks_path.append("/AppleTVSimulator.platform/");
    } else if (sdk_type == SDKType::AppleTVOS) {
      sdks_path.append("/AppleTVOS.platform/");
    } else if (sdk_type == SDKType::WatchSimulator) {
      sdks_path.append("/WatchSimulator.platform/");
    } else if (sdk_type == SDKType::watchOS) {
      // For now, we need to be prepared to handle either capitalization of this
      // path.

      std::string WatchOS_candidate_path = sdks_path + "/WatchOS.platform/";
      if (IsDirectory(FileSpec(WatchOS_candidate_path.c_str(), false))) {
        sdks_path = WatchOS_candidate_path;
      } else {
        std::string watchOS_candidate_path = sdks_path + "/watchOS.platform/";
        if (IsDirectory(FileSpec(watchOS_candidate_path.c_str(), false))) {
          sdks_path = watchOS_candidate_path;
        } else {
          return ConstString();
        }
      }
    } else {
      sdks_path.append("/iPhoneOS.platform/");
    }

    sdks_path.append("Developer/SDKs/");

    FileSpec sdks_spec(sdks_path.c_str(), false);

    return EnumerateSDKsForVersion(sdks_spec, sdk_type, least_major,
                                   least_major);
  }

  // The SDK type is Mac OS X

  uint32_t major = 0;
  uint32_t minor = 0;
  uint32_t update = 0;

  if (!HostInfo::GetOSVersion(major, minor, update))
    return ConstString();

  // If there are minimum requirements that exceed the current OS, apply those

  if (least_major > major) {
    major = least_major;
    minor = least_minor;
  } else if (least_major == major) {
    if (least_minor > minor)
      minor = least_minor;
  }

  typedef std::map<uint64_t, ConstString> SDKDirectoryCache;
  static std::mutex g_mutex;
  static SDKDirectoryCache g_sdk_cache;
  std::lock_guard<std::mutex> locker(g_mutex);
  const uint64_t major_minor = (uint64_t)major << 32 | (uint64_t)minor;
  SDKDirectoryCache::iterator pos = g_sdk_cache.find(major_minor);
  if (pos != g_sdk_cache.end())
    return pos->second;

  FileSpec fspec;
  std::string xcode_contents_path;

  if (xcode_contents_path.empty())
    xcode_contents_path = GetXcodeContentsPath();

  if (!xcode_contents_path.empty()) {
    StreamString sdk_path;
    sdk_path.Printf(
        "%sDeveloper/Platforms/MacOSX.platform/Developer/SDKs/MacOSX%u.%u.sdk",
        xcode_contents_path.c_str(), major, minor);
    fspec.SetFile(sdk_path.GetString(), false);
    if (fspec.Exists()) {
      ConstString path(sdk_path.GetString());
      // Cache results
      g_sdk_cache[major_minor] = path;
      return path;
    } else if ((least_major != major) || (least_minor != minor)) {
      // Try the required SDK
      sdk_path.Clear();
      sdk_path.Printf("%sDeveloper/Platforms/MacOSX.platform/Developer/SDKs/"
                      "MacOSX%u.%u.sdk",
                      xcode_contents_path.c_str(), least_major, least_minor);
      fspec.SetFile(sdk_path.GetString(), false);
      if (fspec.Exists()) {
        ConstString path(sdk_path.GetString());
        // Cache results
        g_sdk_cache[major_minor] = path;
        return path;
      } else {
        // Okay, we're going to do an exhaustive search for *any* SDK that has
        // an adequate version.

        std::string sdks_path = GetXcodeContentsPath();
        sdks_path.append("Developer/Platforms/MacOSX.platform/Developer/SDKs");

        FileSpec sdks_spec(sdks_path.c_str(), false);

        ConstString sdk_path = EnumerateSDKsForVersion(
            sdks_spec, sdk_type, least_major, least_major);

        if (sdk_path) {
          g_sdk_cache[major_minor] = sdk_path;
          return sdk_path;
        }
      }
    }
  }

  // Cache results
  g_sdk_cache[major_minor] = ConstString();
  return ConstString();
}

static ConstString GetResourceDir() {
  static ConstString g_cached_resource_dir;
  static std::once_flag g_once_flag;
  std::call_once(g_once_flag, []() {
    Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_TYPES));

    // First, check if there's something in our bundle
    {
      FileSpec swift_dir_spec;
      if (HostInfo::GetLLDBPath(ePathTypeSwiftDir, swift_dir_spec)) {
        if (log)
          log->Printf("%s: trying ePathTypeSwiftDir: %s", __FUNCTION__,
                      swift_dir_spec.GetCString());
        // We can't just check for the Swift directory, because that
        // always exists.  We have to look for "clang" inside that.
        FileSpec swift_clang_dir_spec = swift_dir_spec;
        swift_clang_dir_spec.AppendPathComponent("clang");

        if (IsDirectory(swift_clang_dir_spec)) {
          g_cached_resource_dir = ConstString(swift_dir_spec.GetPath());
          if (log)
            log->Printf("%s: found Swift resource dir via "
                        "ePathTypeSwiftDir': %s",
                        __FUNCTION__, g_cached_resource_dir.AsCString());
          return;
        }
      }
    }

    // Nothing in our bundle. Are we in a toolchain that has its own Swift
    // compiler resource dir?

    {
      std::string xcode_toolchain_path = GetCurrentToolchainPath();
      if (log)
        log->Printf("%s: trying toolchain path: %s", __FUNCTION__,
                    xcode_toolchain_path.c_str());

      if (!xcode_toolchain_path.empty()) {
        xcode_toolchain_path.append("usr/lib/swift");
        if (log)
          log->Printf("%s: trying toolchain-based lib path: %s", __FUNCTION__,
                      xcode_toolchain_path.c_str());

        if (IsDirectory(FileSpec(xcode_toolchain_path, false))) {
          g_cached_resource_dir = ConstString(xcode_toolchain_path);
          if (log)
            log->Printf("%s: found Swift resource dir via "
                        "toolchain path + 'usr/lib/swift': %s",
                        __FUNCTION__, g_cached_resource_dir.AsCString());
          return;
        }
      }
    }

    // We're not in a toolchain that has one. Use the Xcode default toolchain.

    {
      std::string xcode_contents_path = GetXcodeContentsPath();
      if (log)
        log->Printf("%s: trying Xcode path: %s", __FUNCTION__,
                    xcode_contents_path.c_str());

      if (!xcode_contents_path.empty()) {
        xcode_contents_path.append("Developer/Toolchains/"
                                   "XcodeDefault.xctoolchain"
                                   "/usr/lib/swift");
        if (log)
          log->Printf("%s: trying Xcode-based lib path: %s", __FUNCTION__,
                      xcode_contents_path.c_str());

        if (IsDirectory(FileSpec(xcode_contents_path, false))) {
          g_cached_resource_dir = ConstString(xcode_contents_path);
          if (log)
            log->Printf("%s: found Swift resource dir via "
                        "Xcode contents path + default toolchain "
                        "relative dir: %s",
                        __FUNCTION__, g_cached_resource_dir.AsCString());
          return;
        }
      }
    }

    // We're not in Xcode. We might be in the command-line tools.

    {
      std::string cl_tools_path = GetCurrentCLToolsPath();
      if (log)
        log->Printf("%s: trying command-line tools path: %s", __FUNCTION__,
                    cl_tools_path.c_str());

      if (!cl_tools_path.empty()) {
        cl_tools_path.append("usr/lib/swift");
        if (log)
          log->Printf("%s: trying command-line tools-based lib "
                      "path: %s",
                      __FUNCTION__, cl_tools_path.c_str());

        if (IsDirectory(FileSpec(cl_tools_path, false))) {
          g_cached_resource_dir = ConstString(cl_tools_path);
          if (log)
            log->Printf("%s: found Swift resource dir via "
                        "command-line tools path + "
                        "usr/lib/swift: %s",
                        __FUNCTION__, g_cached_resource_dir.AsCString());
          return;
        }
      }
    }

    // We might be in the build-dir configuration for a build-script-driven
    // LLDB build, which has the Swift build dir as a sibling directory
    // to the lldb build dir.  This looks much different than the install-
    // dir layout that the previous checks would try.
    {
      FileSpec faux_swift_dir_spec;
      if (HostInfo::GetLLDBPath(ePathTypeSwiftDir, faux_swift_dir_spec)) {
// We can't use a C++11 stdlib regex feature here because it
// doesn't work on Ubuntu 14.04 x86_64.  Once we don't care
// about supporting that anymore, let's pull the code below
// back in since it is a simpler implementation using
// std::regex.
#if 0
                // Let's try to regex this.
                // We're looking for /some/path/lldb-{os}-{arch}, and want to
                // build the following:
                //    /some/path/swift-{os}-{arch}/lib/swift/{os}/{arch}
                // In a match, these are the following assignments for
                // backrefs:
                //   $1 - first part of path before swift build dir
                //   $2 - the host OS path separator character
                //   $3 - all the stuff that should come after changing
                //        lldb to swift for the lib dir.
                auto match_regex =
                    std::regex("^(.+([/\\\\]))lldb-(.+)$");
                const std::string replace_format = "$1swift-$3";
                const std::string faux_swift_dir =
                    faux_swift_dir_spec.GetCString();
                const std::string build_tree_resource_dir =
                    std::regex_replace(faux_swift_dir, match_regex,
                                       replace_format);
#else
                std::string build_tree_resource_dir;
                const std::string faux_swift_dir =
                    faux_swift_dir_spec.GetCString();

                // Find something that matches lldb- (particularly,
                // the last one).
                const std::string lldb_dash("lldb-");
                auto lldb_pos = faux_swift_dir.rfind(lldb_dash);
                if ((lldb_pos != std::string::npos) &&
                    (lldb_pos > 0) &&
                    ((faux_swift_dir[lldb_pos - 1] == '\\') ||
                     (faux_swift_dir[lldb_pos - 1] == '/')))
                {
                    // We found something that matches ^.+[/\\]lldb-.+$
                    std::ostringstream stream;
                    // Take everything before lldb- (the path leading up to
                    // the lldb dir).
                    stream << faux_swift_dir.substr(0, lldb_pos);

                    // replace lldb- with swift-.
                    stream << "swift-";

                    // and now tack on the same components from after
                    // the lldb- part.
                    stream << faux_swift_dir.substr(lldb_pos +
                                                    lldb_dash.length());
                    const std::string build_tree_resource_dir = stream.str();
                    if (log)
                        log->Printf("%s: trying ePathTypeSwiftDir regex-based "
                                    "build dir: %s",
                                    __FUNCTION__,
                                    build_tree_resource_dir.c_str());
                    FileSpec swift_resource_dir_spec(
                        build_tree_resource_dir.c_str(), false);
                    if (IsDirectory(swift_resource_dir_spec))
                    {
                        g_cached_resource_dir =
                            ConstString(swift_resource_dir_spec.GetPath());
                        if (log)
                            log->Printf("%s: found Swift resource dir via "
                                        "ePathTypeSwiftDir + inferred "
                                        "build-tree dir: %s", __FUNCTION__,
                                        g_cached_resource_dir.AsCString());
                        return;
                    }
                }
#endif
      }
    }

    // We failed to find a reasonable Swift resource dir.
    if (log)
      log->Printf("%s: failed to find a Swift resource dir", __FUNCTION__);
  });

  return g_cached_resource_dir;
}

} // anonymous namespace

swift::CompilerInvocation &SwiftASTContext::GetCompilerInvocation() {
  return *m_compiler_invocation_ap;
}

swift::SourceManager &SwiftASTContext::GetSourceManager() {
  if (m_source_manager_ap.get() == NULL)
    m_source_manager_ap.reset(new swift::SourceManager());
  return *m_source_manager_ap;
}

swift::LangOptions &SwiftASTContext::GetLanguageOptions() {
  return GetCompilerInvocation().getLangOptions();
}

swift::DiagnosticEngine &SwiftASTContext::GetDiagnosticEngine() {
  if (m_diagnostic_engine_ap.get() == NULL)
    m_diagnostic_engine_ap.reset(
        new swift::DiagnosticEngine(GetSourceManager()));
  return *m_diagnostic_engine_ap;
}

// This code comes from CompilerInvocation.cpp (setRuntimeResourcePath)

static void ConfigureResourceDirs(swift::CompilerInvocation &invocation,
                                  FileSpec resource_dir, llvm::Triple triple) {
  // Make sure the triple is right:
  invocation.setTargetTriple(triple.str());
  invocation.setRuntimeResourcePath(resource_dir.GetPath().c_str());
}

swift::SILOptions &SwiftASTContext::GetSILOptions() {
  return GetCompilerInvocation().getSILOptions();
}

bool SwiftASTContext::TargetHasNoSDK() {
  llvm::Triple triple(GetTriple());

  switch (triple.getOS()) {
  case llvm::Triple::OSType::MacOSX:
  case llvm::Triple::OSType::Darwin:
  case llvm::Triple::OSType::IOS:
    return false;
  default:
    return true;
  }
}

swift::ClangImporterOptions &SwiftASTContext::GetClangImporterOptions() {
  swift::ClangImporterOptions &clang_importer_options =
      GetCompilerInvocation().getClangImporterOptions();
  if (!m_initialized_clang_importer_options) {
    m_initialized_clang_importer_options = true;
    FileSpec clang_dir_spec;
    if (HostInfo::GetLLDBPath(ePathTypeClangDir, clang_dir_spec))
      clang_importer_options.OverrideResourceDir =
          std::move(clang_dir_spec.GetPath());
  }
  return clang_importer_options;
}

swift::SearchPathOptions &SwiftASTContext::GetSearchPathOptions() {
  swift::SearchPathOptions &search_path_opts =
      GetCompilerInvocation().getSearchPathOptions();

  if (!m_initialized_search_path_options) {
    m_initialized_search_path_options = true;

    bool set_sdk = false;
    bool set_resource_dir = false;

    if (!search_path_opts.SDKPath.empty()) {
      FileSpec provided_sdk_path(search_path_opts.SDKPath, false);
      if (provided_sdk_path.Exists()) {
        // We don't check whether the SDK supports swift because we figure if
        // someone is passing this to us on the command line (e.g., for the
        // REPL), they probably know what they're doing.

        set_sdk = true;
      }
    } else if (!m_platform_sdk_path.empty()) {
      FileSpec platform_sdk(m_platform_sdk_path.c_str(), false);

      if (platform_sdk.Exists() &&
          SDKSupportsSwift(platform_sdk, SDKType::unknown)) {
        search_path_opts.SDKPath = m_platform_sdk_path.c_str();
        set_sdk = true;
      }
    }

    llvm::Triple triple(GetTriple());

    if (!m_resource_dir.empty()) {
      FileSpec resource_dir(m_resource_dir.c_str(), false);

      if (resource_dir.Exists()) {
        ConfigureResourceDirs(GetCompilerInvocation(), resource_dir, triple);
        set_resource_dir = true;
      }
    }

    if (!set_sdk) {
      if (triple.getOS() == llvm::Triple::OSType::MacOSX ||
          triple.getOS() == llvm::Triple::OSType::Darwin) {
        search_path_opts.SDKPath = GetSDKDirectory(SDKType::MacOSX, 10, 10)
                                       .AsCString(""); // we need the 10.10 SDK
      } else if (triple.getOS() == llvm::Triple::OSType::IOS) {
        if (triple.getArchName().startswith("arm")) {
          search_path_opts.SDKPath =
              GetSDKDirectory(SDKType::iPhoneOS, 8, 0).AsCString("");
        } else {
          search_path_opts.SDKPath =
              GetSDKDirectory(SDKType::iPhoneSimulator, 8, 0).AsCString("");
        }
      }
      // explicitly leave the SDKPath blank on other platforms
    }

    if (!set_resource_dir) {
      FileSpec resource_dir(::GetResourceDir().AsCString(""), false);
      if (resource_dir.Exists())
        ConfigureResourceDirs(GetCompilerInvocation(), resource_dir, triple);
    }
  }

  return search_path_opts;
}

namespace lldb_private {

class ANSIColorStringStream : public llvm::raw_string_ostream {
public:
  ANSIColorStringStream(bool colorize)
      : llvm::raw_string_ostream(m_buffer), m_colorize(colorize) {}
  /// Changes the foreground color of text that will be output from this point
  /// forward.
  /// @param Color ANSI color to use, the special SAVEDCOLOR can be used to
  /// change only the bold attribute, and keep colors untouched
  /// @param Bold bold/brighter text, default false
  /// @param BG if true change the background, default: change foreground
  /// @returns itself so it can be used within << invocations
  virtual raw_ostream &changeColor(enum Colors colors, bool bold = false,
                                   bool bg = false) {
    if (llvm::sys::Process::ColorNeedsFlush())
      flush();
    const char *colorcode;
    if (colors == SAVEDCOLOR)
      colorcode = llvm::sys::Process::OutputBold(bg);
    else
      colorcode = llvm::sys::Process::OutputColor(colors, bold, bg);
    if (colorcode) {
      size_t len = strlen(colorcode);
      write(colorcode, len);
    }
    return *this;
  }

  /// Resets the colors to terminal defaults. Call this when you are done
  /// outputting colored text, or before program exit.
  virtual raw_ostream &resetColor() {
    if (llvm::sys::Process::ColorNeedsFlush())
      flush();
    const char *colorcode = llvm::sys::Process::ResetColor();
    if (colorcode) {
      size_t len = strlen(colorcode);
      write(colorcode, len);
    }
    return *this;
  }

  /// Reverses the forground and background colors.
  virtual raw_ostream &reverseColor() {
    if (llvm::sys::Process::ColorNeedsFlush())
      flush();
    const char *colorcode = llvm::sys::Process::OutputReverse();
    if (colorcode) {
      size_t len = strlen(colorcode);
      write(colorcode, len);
    }
    return *this;
  }

  /// This function determines if this stream is connected to a "tty" or
  /// "console" window. That is, the output would be displayed to the user
  /// rather than being put on a pipe or stored in a file.
  virtual bool is_displayed() const { return m_colorize; }

  /// This function determines if this stream is displayed and supports colors.
  virtual bool has_colors() const { return m_colorize; }

protected:
  std::string m_buffer;
  bool m_colorize;
};

class StoringDiagnosticConsumer : public swift::DiagnosticConsumer {
public:
  StoringDiagnosticConsumer(SwiftASTContext &ast_context)
      : m_ast_context(ast_context), m_diagnostics(), m_num_errors(0),
        m_colorize(false) {
    m_ast_context.GetDiagnosticEngine().resetHadAnyError();
    m_ast_context.GetDiagnosticEngine().addConsumer(*this);
  }

  ~StoringDiagnosticConsumer() {
    m_ast_context.GetDiagnosticEngine().takeConsumers();
  }

  virtual void handleDiagnostic(swift::SourceManager &source_mgr,
                                swift::SourceLoc source_loc,
                                swift::DiagnosticKind kind,
                                llvm::StringRef formatString,
                                llvm::ArrayRef<swift::DiagnosticArgument> formatArgs,
                                const swift::DiagnosticInfo &info) {
    llvm::StringRef bufferName = "<anonymous>";
    unsigned bufferID = 0;
    std::pair<unsigned, unsigned> line_col = {0, 0};

    llvm::SmallString<256> text;
    {
      llvm::raw_svector_ostream out(text);
      swift::DiagnosticEngine::formatDiagnosticText(out, 
                                                    formatString, 
                                                    formatArgs);
    }

    if (source_loc.isValid()) {
      bufferID = source_mgr.findBufferContainingLoc(source_loc);
      bufferName = source_mgr.getBufferIdentifierForLoc(source_loc);
      line_col = source_mgr.getLineAndColumn(source_loc);
    }

    if (line_col.first != 0) {
      ANSIColorStringStream os(m_colorize);

      // Determine what kind of diagnostic we're emitting, and whether we want
      // to use its fixits:
      bool use_fixits = false;
      llvm::SourceMgr::DiagKind source_mgr_kind;
      switch (kind) {
      default:
      case swift::DiagnosticKind::Error:
        source_mgr_kind = llvm::SourceMgr::DK_Error;
        use_fixits = true;
        break;
      case swift::DiagnosticKind::Warning:
        source_mgr_kind = llvm::SourceMgr::DK_Warning;
        break;

      case swift::DiagnosticKind::Note:
        source_mgr_kind = llvm::SourceMgr::DK_Note;
        break;
      }

      // Translate ranges.
      llvm::SmallVector<llvm::SMRange, 2> ranges;
      for (auto R : info.Ranges)
        ranges.push_back(getRawRange(source_mgr, R));

      // Translate fix-its.
      llvm::SmallVector<llvm::SMFixIt, 2> fix_its;
      for (swift::DiagnosticInfo::FixIt F : info.FixIts)
        fix_its.push_back(getRawFixIt(source_mgr, F));

      // Display the diagnostic.

      auto message = source_mgr.GetMessage(source_loc, source_mgr_kind, text,
                                           ranges, fix_its);
      source_mgr.getLLVMSourceMgr().PrintMessage(os, message);

      // Use the llvm::raw_string_ostream::str() accessor as it will flush
      // the stream into our "message" and return us a reference to "message".
      std::string &message_ref = os.str();

      if (message_ref.empty())
        m_diagnostics.push_back(RawDiagnostic(
            text.str(), kind, bufferName, bufferID, line_col.first,
            line_col.second,
            use_fixits ? info.FixIts
                       : llvm::ArrayRef<swift::Diagnostic::FixIt>()));
      else
        m_diagnostics.push_back(RawDiagnostic(
            message_ref, kind, bufferName, bufferID, line_col.first,
            line_col.second,
            use_fixits ? info.FixIts
                       : llvm::ArrayRef<swift::Diagnostic::FixIt>()));
    } else {
      m_diagnostics.push_back(RawDiagnostic(
          text.str(), kind, bufferName, bufferID, line_col.first,
          line_col.second, llvm::ArrayRef<swift::Diagnostic::FixIt>()));
    }

    if (kind == swift::DiagnosticKind::Error)
      m_num_errors++;
  }

  void Clear() {
    m_ast_context.GetDiagnosticEngine().resetHadAnyError();
    m_diagnostics.clear();
    m_num_errors = 0;
  }

  unsigned NumErrors() {
    if (m_num_errors)
      return m_num_errors;
    else if (m_ast_context.GetASTContext()->hadError())
      return 1;
    else
      return 0;
  }

  static DiagnosticSeverity SeverityForKind(swift::DiagnosticKind kind) {
    switch (kind) {
    case swift::DiagnosticKind::Error:
      return eDiagnosticSeverityError;
    case swift::DiagnosticKind::Warning:
      return eDiagnosticSeverityWarning;
    case swift::DiagnosticKind::Note:
      return eDiagnosticSeverityRemark;
    }

    llvm_unreachable("Unhandled DiagnosticKind in switch.");
  }

  void PrintDiagnostics(DiagnosticManager &diagnostic_manager,
                        uint32_t bufferID = UINT32_MAX, uint32_t first_line = 0,
                        uint32_t last_line = UINT32_MAX,
                        uint32_t line_offset = 0) {
    bool added_one_diagnostic = false;
    for (const RawDiagnostic &diagnostic : m_diagnostics) {
      // We often make expressions and wrap them in some code.
      // When we see errors we want the line numbers to be correct so
      // we correct them below. LLVM stores in SourceLoc objects as character
      // offsets so there is no way to get LLVM to move its error line numbers
      // around by adjusting the source location, we must do it manually. We
      // also want to use the same error formatting as LLVM and Clang, so we
      // must muck with the string.

      const DiagnosticSeverity severity = SeverityForKind(diagnostic.kind);
      const DiagnosticOrigin origin = eDiagnosticOriginSwift;

      if (first_line > 0 && bufferID != UINT32_MAX &&
          diagnostic.bufferID == bufferID && !diagnostic.bufferName.empty()) {
        // Make sure the error line is in range
        if (diagnostic.line >= first_line && diagnostic.line <= last_line) {
          // Need to remap the error/warning to a different line
          StreamString match;
          match.Printf("%s:%u:", diagnostic.bufferName.str().c_str(),
                       diagnostic.line);
          const size_t match_len = match.GetString().size();
          size_t match_pos = diagnostic.description.find(match.GetString());
          if (match_pos != std::string::npos) {
            // We have some <file>:<line>:" instances that need to be updated
            StreamString fixed_description;
            size_t start_pos = 0;
            do {
              if (match_pos > start_pos)
                fixed_description.Printf(
                    "%s", diagnostic.description.substr(start_pos, match_pos)
                              .c_str());
              fixed_description.Printf("%s:%u:",
                                       diagnostic.bufferName.str().c_str(),
                                       diagnostic.line - first_line +
                                           line_offset + 1);
              start_pos = match_pos + match_len;
              match_pos =
                  diagnostic.description.find(match.GetString(), start_pos);
            } while (match_pos != std::string::npos);

            // Append any last remainging text
            if (start_pos < diagnostic.description.size())
              fixed_description.Printf(
                  "%s",
                  diagnostic.description.substr(start_pos,
                                                diagnostic.description.size() -
                                                    start_pos)
                      .c_str());

            SwiftDiagnostic *new_diagnostic =
                new SwiftDiagnostic(fixed_description.GetString().data(),
                                    severity, origin, bufferID);
            for (auto fixit : diagnostic.fixits)
              new_diagnostic->AddFixIt(fixit);

            diagnostic_manager.AddDiagnostic(new_diagnostic);
            added_one_diagnostic = true;

            continue;
          }
        }
      }
    }

    // In general, we don't want to see diagnostics from outside of the source
    // text range of the actual user expression. But if we didn't find any
    // diagnostics in the text range, it's probably because the source range was
    // not specified correctly, and we don't want to lose legit errors because
    // of that. So in that case we'll add them all here:

    if (!added_one_diagnostic) {
      // This will report diagnostic errors from outside the expression's source
      // range. Those are not interesting to users, so we only emit them in
      // debug builds.
      for (const RawDiagnostic &diagnostic : m_diagnostics) {
        const DiagnosticSeverity severity = SeverityForKind(diagnostic.kind);
        const DiagnosticOrigin origin = eDiagnosticOriginSwift;
        diagnostic_manager.AddDiagnostic(diagnostic.description.c_str(),
                                         severity, origin);
      }
    }
  }

  bool GetColorize() const { return m_colorize; }

  bool SetColorize(bool b) {
    const bool old = m_colorize;
    m_colorize = b;
    return old;
  }

private:
  // We don't currently use lldb_private::Diagostic or any of the lldb
  // DiagnosticManager machinery to store diagnostics as they occur. Instead,
  // we store them in raw form using this struct, then transcode them to
  // SwiftDiagnostics in PrintDiagnostic.
  struct RawDiagnostic {
    RawDiagnostic(std::string in_desc, swift::DiagnosticKind in_kind,
                  llvm::StringRef in_bufferName, unsigned in_bufferID,
                  uint32_t in_line, uint32_t in_column,
                  llvm::ArrayRef<swift::Diagnostic::FixIt> in_fixits)
        : description(in_desc), kind(in_kind), bufferName(in_bufferName),
          bufferID(in_bufferID), line(in_line), column(in_column) {
      for (auto fixit : in_fixits) {
        fixits.push_back(fixit);
      }
    }
    std::string description;
    swift::DiagnosticKind kind;
    const llvm::StringRef bufferName;
    unsigned bufferID;
    uint32_t line;
    uint32_t column;
    std::vector<swift::DiagnosticInfo::FixIt> fixits;
  };
  typedef std::vector<RawDiagnostic> RawDiagnosticBuffer;

  SwiftASTContext &m_ast_context;
  RawDiagnosticBuffer m_diagnostics;
  unsigned m_num_errors = 0;
  bool m_colorize;
};
}

swift::ASTContext *SwiftASTContext::GetASTContext() {
  if (m_ast_context_ap.get() == NULL) {
    m_ast_context_ap.reset(
        new swift::ASTContext(GetLanguageOptions(), GetSearchPathOptions(),
                              GetSourceManager(), GetDiagnosticEngine()));
    m_diagnostic_consumer_ap.reset(new StoringDiagnosticConsumer(*this));

    if (getenv("LLDB_SWIFT_DUMP_DIAGS")) {
      // NOTE: leaking a swift::PrintingDiagnosticConsumer() here, but this only
      // gets enabled when the above environment variable is set.
      GetDiagnosticEngine().addConsumer(
          *new swift::PrintingDiagnosticConsumer());
    }
    // Install the serialized module loader

    std::unique_ptr<swift::ModuleLoader> serialized_module_loader_ap(
        swift::SerializedModuleLoader::create(*m_ast_context_ap));

    if (serialized_module_loader_ap) {
      m_serialized_module_loader =
          (swift::SerializedModuleLoader *)serialized_module_loader_ap.get();
      m_ast_context_ap->addModuleLoader(std::move(serialized_module_loader_ap));
    }

    GetASTMap().Insert(m_ast_context_ap.get(), this);

    // Store common useful manglings for quick lookup - this also ensures that
    // types that didn't come out of the visitor (e.g. fallback ObjCPointers)
    // still exist in our tables for later mangled name retrieval
    // (the expression parser needs to do this).
    CacheDemangledType(ConstString(SwiftLanguageRuntime::GetCurrentMangledName("_TtBO").c_str()).GetCString(),
                       m_ast_context_ap->TheUnknownObjectType.getPointer());
    CacheDemangledType(ConstString(SwiftLanguageRuntime::GetCurrentMangledName("_TtBp").c_str()).GetCString(),
                       m_ast_context_ap->TheRawPointerType.getPointer());
    CacheDemangledType(ConstString(SwiftLanguageRuntime::GetCurrentMangledName("_TtBb").c_str()).GetCString(),
                       m_ast_context_ap->TheBridgeObjectType.getPointer());
    CacheDemangledType(ConstString(SwiftLanguageRuntime::GetCurrentMangledName("_TtBo").c_str()).GetCString(),
                       m_ast_context_ap->TheNativeObjectType.getPointer());
    CacheDemangledType(ConstString(SwiftLanguageRuntime::GetCurrentMangledName("_TtT_").c_str()).GetCString(),
                       m_ast_context_ap->TheEmptyTupleType.getPointer());
  }

  VALID_OR_RETURN(nullptr);

  return m_ast_context_ap.get();
}

swift::SerializedModuleLoader *SwiftASTContext::GetSerializeModuleLoader() {
  VALID_OR_RETURN(nullptr);

  GetASTContext();
  return m_serialized_module_loader;
}

swift::ClangImporter *SwiftASTContext::GetClangImporter() {
  VALID_OR_RETURN(nullptr);

  if (m_clang_importer == NULL) {
    swift::ASTContext *ast_ctx = GetASTContext();

    if (!ast_ctx) {
      return nullptr;
    }

    // Install the Clang module loader
    TargetSP target_sp(m_target_wp.lock());
    if (true /*target_sp*/) {
      // PlatformSP platform_sp = target_sp->GetPlatform();
      if (true /*platform_sp*/) {
        if (!ast_ctx->SearchPathOpts.SDKPath.empty() || TargetHasNoSDK()) {
          swift::ClangImporterOptions &clang_importer_options =
              GetClangImporterOptions();
          if (!clang_importer_options.OverrideResourceDir.empty()) {
            std::unique_ptr<swift::ModuleLoader> clang_importer_ap(
                swift::ClangImporter::create(*m_ast_context_ap,
                                             clang_importer_options));

            if (clang_importer_ap) {
              const bool isClang = true;
              m_clang_importer =
                  (swift::ClangImporter *)clang_importer_ap.get();
              m_ast_context_ap->addModuleLoader(std::move(clang_importer_ap),
                                                isClang);
            }
          }
        }
      }
    }
  }
  return m_clang_importer;
}

bool SwiftASTContext::AddModuleSearchPath(const char *path) {
  VALID_OR_RETURN(false);

  if (path && path[0]) {
    swift::ASTContext *ast = GetASTContext();
    std::string path_str(path);
    bool add_search_path = true;
    for (auto path : ast->SearchPathOpts.ImportSearchPaths) {
      if (path == path_str) {
        add_search_path = false;
        break;
      }
    }

    if (add_search_path) {
      ast->SearchPathOpts.ImportSearchPaths.push_back(path);
      return true;
    }
  }
  return false;
}

bool SwiftASTContext::AddFrameworkSearchPath(const char *path) {
  VALID_OR_RETURN(false);

  if (path && path[0]) {
    swift::ASTContext *ast = GetASTContext();
    std::string path_str(path);
    bool add_search_path = true;
    for (const auto &swift_path : ast->SearchPathOpts.FrameworkSearchPaths) {
      if (swift_path.Path == path_str) {
        add_search_path = false;
        break;
      }
    }

    if (add_search_path) {
      ast->SearchPathOpts.FrameworkSearchPaths.push_back({path, /*isSystem=*/false});
      return true;
    }
  }
  return false;
}

bool SwiftASTContext::AddClangArgument(const char *clang_arg, bool force) {
  if (clang_arg && clang_arg[0]) {
    swift::ClangImporterOptions &importer_options = GetClangImporterOptions();

    bool add_hmap = true;

    if (!force) {
      for (std::string &arg : importer_options.ExtraArgs) {
        if (!arg.compare(clang_arg)) {
          add_hmap = false;
          break;
        }
      }
    }

    if (add_hmap) {
      importer_options.ExtraArgs.push_back(clang_arg);
      return true;
    }
  }
  return false;
}

bool SwiftASTContext::AddClangArgumentPair(const char *clang_arg_1,
                                           const char *clang_arg_2) {
  if (clang_arg_1 && clang_arg_2 && clang_arg_1[0] && clang_arg_2[0]) {
    swift::ClangImporterOptions &importer_options = GetClangImporterOptions();

    bool add_hmap = true;

    for (ssize_t ai = 0, ae = importer_options.ExtraArgs.size() -
                              1; // -1 because we look at the next one too
         ai < ae;
         ++ai) {
      if (!importer_options.ExtraArgs[ai].compare(clang_arg_1) &&
          !importer_options.ExtraArgs[ai + 1].compare(clang_arg_2)) {
        add_hmap = false;
        break;
      }
    }

    if (add_hmap) {
      importer_options.ExtraArgs.push_back(clang_arg_1);
      importer_options.ExtraArgs.push_back(clang_arg_2);
      return true;
    }
  }
  return false;
}

size_t SwiftASTContext::GetNumModuleSearchPaths() const {
  VALID_OR_RETURN(0);

  if (m_ast_context_ap.get())
    return m_ast_context_ap->SearchPathOpts.ImportSearchPaths.size();
  return 0;
}

const char *SwiftASTContext::GetModuleSearchPathAtIndex(size_t idx) const {
  VALID_OR_RETURN(nullptr);

  if (m_ast_context_ap.get()) {
    if (idx < m_ast_context_ap->SearchPathOpts.ImportSearchPaths.size())
      return m_ast_context_ap->SearchPathOpts.ImportSearchPaths[idx].c_str();
  }
  return NULL;
}

size_t SwiftASTContext::GetNumFrameworkSearchPaths() const {
  VALID_OR_RETURN(0);

  if (m_ast_context_ap.get())
    return m_ast_context_ap->SearchPathOpts.FrameworkSearchPaths.size();
  return 0;
}

const char *SwiftASTContext::GetFrameworkSearchPathAtIndex(size_t idx) const {
  VALID_OR_RETURN(nullptr);

  if (m_ast_context_ap.get()) {
    if (idx < m_ast_context_ap->SearchPathOpts.FrameworkSearchPaths.size())
      return m_ast_context_ap->SearchPathOpts.FrameworkSearchPaths[idx].Path.c_str();
  }
  return NULL;
}

size_t SwiftASTContext::GetNumClangArguments() {
  swift::ClangImporterOptions &importer_options = GetClangImporterOptions();

  return importer_options.ExtraArgs.size();
}

const char *SwiftASTContext::GetClangArgumentAtIndex(size_t idx) {
  swift::ClangImporterOptions &importer_options = GetClangImporterOptions();

  if (idx < importer_options.ExtraArgs.size())
    return importer_options.ExtraArgs[idx].c_str();

  return NULL;
}

swift::ModuleDecl *
SwiftASTContext::GetCachedModule(const ConstString &module_name) {
  VALID_OR_RETURN(nullptr);

  SwiftModuleMap::const_iterator iter =
      m_swift_module_cache.find(module_name.GetCString());

  if (iter != m_swift_module_cache.end())
    return iter->second;
  return NULL;
}

swift::ModuleDecl *
SwiftASTContext::CreateModule(const ConstString &module_basename,
                              Status &error) {
  VALID_OR_RETURN(nullptr);

  if (module_basename) {
    swift::ModuleDecl *module = GetCachedModule(module_basename);
    if (module) {
      error.SetErrorStringWithFormat("module already exists for '%s'",
                                     module_basename.GetCString());
      return NULL;
    }

    swift::ASTContext *ast = GetASTContext();
    if (ast) {
      swift::Identifier module_id(
          ast->getIdentifier(module_basename.GetCString()));
      module = swift::ModuleDecl::create(module_id, *ast);
      if (module) {
        m_swift_module_cache[module_basename.GetCString()] = module;
        return module;
      } else {
        error.SetErrorStringWithFormat("invalid swift AST (NULL)");
      }
    } else {
      error.SetErrorStringWithFormat("invalid swift AST (NULL)");
    }
  } else {
    error.SetErrorStringWithFormat("invalid module name (empty)");
  }
  return NULL;
}

void SwiftASTContext::CacheModule(swift::ModuleDecl *module) {
  VALID_OR_RETURN_VOID();

  if (!module)
    return;
  auto ID = module->getName().get();
  if (nullptr == ID || 0 == ID[0])
    return;
  if (m_swift_module_cache.find(ID) != m_swift_module_cache.end())
    return;
  m_swift_module_cache.insert({ID, module});
}

swift::ModuleDecl *
SwiftASTContext::GetModule(const ConstString &module_basename, Status &error) {
  VALID_OR_RETURN(nullptr);

  Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_TYPES));
  if (log)
    log->Printf("((SwiftASTContext*)%p)->GetModule('%s')", this,
                module_basename.AsCString("<no name>"));

  if (module_basename) {
    swift::ModuleDecl *module = GetCachedModule(module_basename);
    if (module)
      return module;
    if (swift::ASTContext *ast = GetASTContext()) {
      typedef std::pair<swift::Identifier, swift::SourceLoc> ModuleNameSpec;
      llvm::StringRef module_basename_sref(module_basename.GetCString());
      ModuleNameSpec name_pair(ast->getIdentifier(module_basename_sref),
                               swift::SourceLoc());

      if (HasFatalErrors()) {
        error.SetErrorStringWithFormat("failed to get module '%s' from AST "
                                       "context:\nAST context is in a fatal "
                                       "error state",
                                       module_basename.GetCString());
        printf("error in SwiftASTContext::GetModule(%s): AST context is in a "
               "fatal error stat",
               module_basename.GetCString());
        return nullptr;
      }

      ClearDiagnostics();

      module = ast->getModuleByName(module_basename_sref);

      if (HasErrors()) {
        DiagnosticManager diagnostic_manager;
        PrintDiagnostics(diagnostic_manager);
        error.SetErrorStringWithFormat(
            "failed to get module '%s' from AST context:\n%s",
            module_basename.GetCString(),
            diagnostic_manager.GetString().data());
#ifdef LLDB_CONFIGURATION_DEBUG
        printf("error in SwiftASTContext::GetModule(%s): '%s'",
               module_basename.GetCString(),
               diagnostic_manager.GetString().data());
#endif
        if (log)
          log->Printf("((SwiftASTContext*)%p)->GetModule('%s') -- error: %s",
                      this, module_basename.GetCString(),
                      diagnostic_manager.GetString().data());
      } else if (module) {
        if (log)
          log->Printf("((SwiftASTContext*)%p)->GetModule('%s') -- found %s",
                      this, module_basename.GetCString(),
                      module->getName().str().str().c_str());

        m_swift_module_cache[module_basename.GetCString()] = module;
        return module;
      } else {
        if (log)
          log->Printf(
              "((SwiftASTContext*)%p)->GetModule('%s') -- failed with no error",
              this, module_basename.GetCString());

        error.SetErrorStringWithFormat(
            "failed to get module '%s' from AST context",
            module_basename.GetCString());
      }
    } else {
      if (log)
        log->Printf(
            "((SwiftASTContext*)%p)->GetModule('%s') -- invalid ASTContext",
            this, module_basename.GetCString());

      error.SetErrorString("invalid swift::ASTContext");
    }
  } else {
    if (log)
      log->Printf(
          "((SwiftASTContext*)%p)->GetModule('%s') -- empty module name", this,
          module_basename.GetCString());

    error.SetErrorString("invalid module name (empty)");
  }
  return NULL;
}

swift::ModuleDecl *SwiftASTContext::GetModule(const FileSpec &module_spec,
                                              Status &error) {
  VALID_OR_RETURN(nullptr);

  ConstString module_basename(module_spec.GetFileNameStrippingExtension());

  Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_TYPES));
  if (log)
    log->Printf("((SwiftASTContext*)%p)->GetModule((FileSpec)'%s')", this,
                module_spec.GetPath().c_str());

  if (module_basename) {
    SwiftModuleMap::const_iterator iter =
        m_swift_module_cache.find(module_basename.GetCString());

    if (iter != m_swift_module_cache.end())
      return iter->second;

    if (module_spec.Exists()) {
      swift::ASTContext *ast = GetASTContext();
      if (!GetClangImporter()) {
        if (log)
          log->Printf("((SwiftASTContext*)%p)->GetModule((FileSpec)'%s') -- no "
                      "ClangImporter so giving up",
                      this, module_spec.GetPath().c_str());
        error.SetErrorStringWithFormat("couldn't get a ClangImporter");
        return nullptr;
      }

      std::string module_directory(module_spec.GetDirectory().GetCString());
      bool add_search_path = true;
      for (auto path : ast->SearchPathOpts.ImportSearchPaths) {
        if (path == module_directory) {
          add_search_path = false;
          break;
        }
      }
      // Add the search path if needed so we can find the module by basename
      if (add_search_path)
        ast->SearchPathOpts.ImportSearchPaths.push_back(
            std::move(module_directory));

      typedef std::pair<swift::Identifier, swift::SourceLoc> ModuleNameSpec;
      llvm::StringRef module_basename_sref(module_basename.GetCString());
      ModuleNameSpec name_pair(ast->getIdentifier(module_basename_sref),
                               swift::SourceLoc());
      swift::ModuleDecl *module =
          ast->getModule(llvm::ArrayRef<ModuleNameSpec>(name_pair));
      if (module) {
        if (log)
          log->Printf(
              "((SwiftASTContext*)%p)->GetModule((FileSpec)'%s') -- found %s",
              this, module_spec.GetPath().c_str(),
              module->getName().str().str().c_str());

        m_swift_module_cache[module_basename.GetCString()] = module;
        return module;
      } else {
        if (log)
          log->Printf("((SwiftASTContext*)%p)->GetModule((FileSpec)'%s') -- "
                      "couldn't get from AST context",
                      this, module_spec.GetPath().c_str());

        error.SetErrorStringWithFormat(
            "failed to get module '%s' from AST context",
            module_basename.GetCString());
      }
    } else {
      if (log)
        log->Printf("((SwiftASTContext*)%p)->GetModule((FileSpec)'%s') -- "
                    "doesn't exist",
                    this, module_spec.GetPath().c_str());

      error.SetErrorStringWithFormat("module '%s' doesn't exist",
                                     module_spec.GetPath().c_str());
    }
  } else {
    if (log)
      log->Printf(
          "((SwiftASTContext*)%p)->GetModule((FileSpec)'%s') -- no basename",
          this, module_spec.GetPath().c_str());

    error.SetErrorStringWithFormat("no module basename in '%s'",
                                   module_spec.GetPath().c_str());
  }
  return NULL;
}

swift::ModuleDecl *
SwiftASTContext::FindAndLoadModule(const ConstString &module_basename,
                                   Process &process, Status &error) {
  VALID_OR_RETURN(nullptr);

  swift::ModuleDecl *swift_module = GetModule(module_basename, error);
  if (!swift_module)
    return nullptr;
  LoadModule(swift_module, process, error);
  return swift_module;
}

swift::ModuleDecl *
SwiftASTContext::FindAndLoadModule(const FileSpec &module_spec,
                                   Process &process, Status &error) {
  VALID_OR_RETURN(nullptr);

  swift::ModuleDecl *swift_module = GetModule(module_spec, error);
  if (!swift_module)
    return nullptr;
  LoadModule(swift_module, process, error);
  return swift_module;
}

bool SwiftASTContext::LoadOneImage(Process &process, FileSpec &link_lib_spec,
                                   Status &error) {
  VALID_OR_RETURN(false);

  error.Clear();

  PlatformSP platform_sp = process.GetTarget().GetPlatform();
  if (platform_sp)
    return platform_sp->LoadImage(&process, FileSpec(), link_lib_spec, error) !=
           LLDB_INVALID_IMAGE_TOKEN;
  else
    return false;
}

static void
GetLibrarySearchPaths(std::vector<std::string> &paths,
                      const swift::SearchPathOptions &search_path_opts) {
  paths.clear();
  paths.resize(search_path_opts.LibrarySearchPaths.size() + 1);
  std::copy(search_path_opts.LibrarySearchPaths.begin(),
            search_path_opts.LibrarySearchPaths.end(), paths.begin());
  paths.push_back(search_path_opts.RuntimeLibraryPath);
}

void SwiftASTContext::LoadModule(swift::ModuleDecl *swift_module,
                                 Process &process, Status &error) {
  VALID_OR_RETURN_VOID();

  Status current_error;
  auto addLinkLibrary = [&](swift::LinkLibrary link_lib) {
    Status load_image_error;
    StreamString all_dlopen_errors;
    const char *library_name = link_lib.getName().data();

    if (library_name == NULL || library_name[0] == '\0') {
      error.SetErrorString("Empty library name passed to addLinkLibrary");
      return;
    }

    SwiftLanguageRuntime *runtime = process.GetSwiftLanguageRuntime();

    if (runtime && runtime->IsInLibraryNegativeCache(library_name))
      return;

    swift::LibraryKind library_kind = link_lib.getKind();

    Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_TYPES));
    if (log)
      log->Printf("\nLoading link library \"%s\" of kind: %d.", library_name,
                  library_kind);

    switch (library_kind) {
    case swift::LibraryKind::Framework: {

      // First make sure the library isn't already loaded. Since this is a
      // framework, we make sure the file name and the framework name are the
      // same, and that we are contained in FileName.framework with no other
      // intervening frameworks.  We can get more restrictive if this gives
      // false positives.

      ConstString library_cstr(library_name);

      std::string framework_name(library_name);
      framework_name.append(".framework");

      // Lookup the module by file basename and make sure that basename has
      // "<basename>.framework" in the path.

      ModuleSpec module_spec;
      module_spec.GetFileSpec().GetFilename() = library_cstr;
      lldb_private::ModuleList matching_module_list;
      bool module_already_loaded = false;
      if (process.GetTarget().GetImages().FindModules(module_spec,
                                                      matching_module_list)) {
        matching_module_list.ForEach(
            [&module_already_loaded, &module_spec,
             &framework_name](const ModuleSP &module_sp) -> bool {
              module_already_loaded = module_spec.GetFileSpec().GetPath().find(
                                          framework_name) != std::string::npos;
              return module_already_loaded ==
                     false; // Keep iterating if we didn't find the right module
            });
      }
      // If we already have this library loaded, don't try and load it again.
      if (module_already_loaded) {
        if (log)
          log->Printf("Skipping load of %s as it is already loaded.",
                      framework_name.c_str());
        return;
      }

      for (auto module : process.GetTarget().GetImages().Modules()) {
        FileSpec module_file = module->GetFileSpec();
        if (module_file.GetFilename() == library_cstr) {
          std::string module_path = module_file.GetPath();

          size_t framework_offset = module_path.rfind(framework_name);

          if (framework_offset != std::string::npos) {
            // The Framework is already loaded, so we don't need to try to load
            // it again.
            if (log)
              log->Printf("Skipping load of %s as it is already loaded.",
                          framework_name.c_str());
            return;
          }
        }
      }

      std::string framework_path("@rpath/");
      framework_path.append(library_name);
      framework_path.append(".framework/");
      framework_path.append(library_name);
      FileSpec framework_spec(framework_path.c_str(), false);

      if (LoadOneImage(process, framework_spec, load_image_error)) {
        if (log)
          log->Printf("Found framework at: %s.", framework_path.c_str());

        return;
      } else
        all_dlopen_errors.Printf("Looking for \"%s\", error: %s\n",
                                 framework_path.c_str(),
                                 load_image_error.AsCString());

      // And then in the various framework search paths.
      std::unordered_set<std::string> seen_paths;
      for (const auto &framework_search_dir :
           swift_module->getASTContext().SearchPathOpts.FrameworkSearchPaths) {
        // The framework search dir as it comes from the AST context often has
        // duplicate entries, don't try to load along the same path twice.

        std::pair<std::unordered_set<std::string>::iterator, bool>
            insert_result = seen_paths.insert(framework_search_dir.Path);
        if (!insert_result.second)
          continue;

        framework_path = framework_search_dir.Path;
        framework_path.append("/");
        framework_path.append(library_name);
        framework_path.append(".framework/");
        framework_path.append(library_name);
        framework_spec.SetFile(framework_path.c_str(), false);

        if (LoadOneImage(process, framework_spec, load_image_error)) {
          if (log)
            log->Printf("Found framework at: %s.", framework_path.c_str());

          return;
        } else
          all_dlopen_errors.Printf("Looking for \"%s\"\n,    error: %s\n",
                                   framework_path.c_str(),
                                   load_image_error.AsCString());
      }

      // Maybe we were told to add a link library that exists in the system.  I
      // tried just specifying Foo.framework/Foo and letting the system search
      // figure that out, but if DYLD_FRAMEWORK_FALLBACK_PATH is set
      // (e.g. in Xcode's test scheme) then these aren't found. So for now I
      // dial them in explicitly:

      std::string system_path("/System/Library/Frameworks/");
      system_path.append(library_name);
      system_path.append(".framework/");
      system_path.append(library_name);
      framework_spec.SetFile(system_path.c_str(), true);
      if (LoadOneImage(process, framework_spec, load_image_error))
        return;
      else
        all_dlopen_errors.Printf("Looking for \"%s\"\n,    error: %s\n",
                                 framework_path.c_str(),
                                 load_image_error.AsCString());
    } break;
    case swift::LibraryKind::Library: {
      std::vector<std::string> search_paths;

      GetLibrarySearchPaths(search_paths,
                            swift_module->getASTContext().SearchPathOpts);

      if (LoadLibraryUsingPaths(process, library_name, search_paths, true,
                                all_dlopen_errors))
        return;
    } break;
    }

    // If we get here, we aren't going to find this image, so add it to a
    // negative cache:
    if (runtime)
      runtime->AddToLibraryNegativeCache(library_name);

    current_error.SetErrorStringWithFormat(
        "Failed to load linked library %s of module %s - errors:\n%s\n",
        library_name, swift_module->getName().str().str().c_str(),
        all_dlopen_errors.GetData());
  };

  swift_module->forAllVisibleModules({},
                                     true, // includePrivateTopLevel
                                     [&](swift::ModuleDecl::ImportedModule import) {
                                       import.second->collectLinkLibraries(
                                           addLinkLibrary);
                                     });
  error = current_error;
}

bool SwiftASTContext::LoadLibraryUsingPaths(
    Process &process, llvm::StringRef library_name,
    std::vector<std::string> &search_paths, bool check_rpath,
    StreamString &all_dlopen_errors) {
  VALID_OR_RETURN(false);

  Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_TYPES));

  SwiftLanguageRuntime *runtime = process.GetSwiftLanguageRuntime();
  if (!runtime) {
    all_dlopen_errors.PutCString(
        "Can't load Swift libraries without a language runtime.");
    return false;
  }

  if (ConstString::Equals(runtime->GetStandardLibraryBaseName(),
                          ConstString(library_name))) {
    // Never dlopen the standard library. Some binaries statically link to the
    // Swift standard library and dlopening it here will cause ObjC runtime
    // conflicts.
    // If you want to run Swift expressions you have to arrange to load the
    // Swift standard library by hand before doing so.
    if (log)
      log->Printf("Skipping swift standard library \"%s\" - we don't hand load "
                  "that one.",
                  runtime->GetStandardLibraryBaseName().AsCString());
    return true;
  }

  PlatformSP platform_sp(process.GetTarget().GetPlatform());

  std::string library_fullname;

  if (platform_sp) {
    library_fullname =
        platform_sp->GetFullNameForDylib(ConstString(library_name)).AsCString();
  } else // This is the old way, and we shouldn't use it except on Mac OS
  {
#ifdef __APPLE__
    library_fullname = "lib";
    library_fullname.append(library_name);
    library_fullname.append(".dylib");
#else
    return false;
#endif
  }

  ModuleSpec module_spec;
  module_spec.GetFileSpec().GetFilename().SetCString(library_fullname.c_str());
  lldb_private::ModuleList matching_module_list;

  if (process.GetTarget().GetImages().FindModules(module_spec,
                                                  matching_module_list) > 0) {
    if (log)
      log->Printf("Skipping module %s as it is already loaded.",
                  library_fullname.c_str());
    return true;
  }

  FileSpec library_spec;
  std::string library_path;
  std::unordered_set<std::string> seen_paths;
  Status load_image_error;

  for (const std::string &library_search_dir : search_paths) {
    // The library search dir as it comes from the AST context often has
    // duplicate entries, don't try to load along the same path twice.

    std::pair<std::unordered_set<std::string>::iterator, bool> insert_result =
        seen_paths.insert(library_search_dir);
    if (!insert_result.second)
      continue;

    library_path = library_search_dir;
    library_path.append("/");
    library_path.append(library_fullname);
    library_spec.SetFile(library_path.c_str(), false);
    if (LoadOneImage(process, library_spec, load_image_error)) {
      if (log)
        log->Printf("Found library at: %s.", library_path.c_str());
      return true;
    } else
      all_dlopen_errors.Printf("Looking for \"%s\"\n,    error: %s\n",
                               library_path.c_str(),
                               load_image_error.AsCString());
  }

  if (check_rpath) {
    // Let our RPATH help us out when finding the right library
    library_path = "@rpath/";
    library_path += library_fullname;

    FileSpec link_lib_spec(library_path.c_str(), false);

    if (LoadOneImage(process, link_lib_spec, load_image_error)) {
      if (log)
        log->Printf("Found library at: %s.", library_path.c_str());
      return true;
    } else
      all_dlopen_errors.Printf("Looking for \"%s\", error: %s\n",
                               library_path.c_str(),
                               load_image_error.AsCString());
  }
  return false;
}

void SwiftASTContext::LoadExtraDylibs(Process &process, Status &error) {
  VALID_OR_RETURN_VOID();

  error.Clear();
  swift::IRGenOptions &irgen_options = GetIRGenOptions();
  for (const swift::LinkLibrary &link_lib : irgen_options.LinkLibraries) {
    // We don't have to do frameworks here, they actually record their link
    // libraries properly.
    if (link_lib.getKind() == swift::LibraryKind::Library) {
      const char *library_name = link_lib.getName().data();
      StreamString errors;

      std::vector<std::string> search_paths;

      GetLibrarySearchPaths(search_paths,
                            m_compiler_invocation_ap->getSearchPathOptions());

      bool success = LoadLibraryUsingPaths(process, library_name, search_paths,
                                           false, errors);
      if (!success) {
        error.SetErrorString(errors.GetData());
      }
    }
  }
}

bool SwiftASTContext::RegisterSectionModules(
    Module &module, std::vector<std::string> &module_names) {
  VALID_OR_RETURN(false);

  Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_TYPES));

  swift::SerializedModuleLoader *sml = GetSerializeModuleLoader();
  if (sml) {
    SectionList *section_list = module.GetSectionList();
    if (section_list) {
      SectionSP section_sp(
          section_list->FindSectionByType(eSectionTypeSwiftModules, true));
      if (section_sp) {
        DataExtractor section_data;

        if (section_sp->GetSectionData(section_data)) {
          llvm::StringRef section_data_ref(
              (const char *)section_data.GetDataStart(),
              section_data.GetByteSize());
          llvm::SmallVector<std::string, 4> llvm_modules;
          if (swift::parseASTSection(sml, section_data_ref, llvm_modules)) {
            for (auto module_name : llvm_modules)
              module_names.push_back(module_name);
            return true;
          }
        }
      } else {
        if (m_ast_file_data_map.find(&module) != m_ast_file_data_map.end())
          return true;

        SymbolVendor *sym_vendor = module.GetSymbolVendor();
        if (sym_vendor) {
          // Grab all the AST blobs from the symbol vendor.
          auto ast_file_datas = sym_vendor->GetASTData(eLanguageTypeSwift);
          if (log)
            log->Printf("SwiftASTContext::%s() retrieved %zu AST Data blobs "
                        "from the symbol vendor.",
                        __FUNCTION__, ast_file_datas.size());

          // Add each of the AST blobs to the vector of AST blobs for the
          // module.
          auto &ast_vector = GetASTVectorForModule(&module);
          ast_vector.insert(ast_vector.end(), ast_file_datas.begin(),
                            ast_file_datas.end());

          // Retrieve the module names from the AST blobs retrieved from the
          // symbol vendor.
          size_t parse_fail_count = 0;
          size_t ast_number = 0;
          for (auto ast_file_data_sp : ast_file_datas) {
            // Parse the AST section info from the AST blob.
            ++ast_number;
            llvm::StringRef section_data_ref(
                (const char *)ast_file_data_sp->GetBytes(),
                ast_file_data_sp->GetByteSize());
            llvm::SmallVector<std::string, 4> llvm_modules;
            if (swift::parseASTSection(sml, section_data_ref, llvm_modules)) {
              // Collect the LLVM module names referenced by the AST.
              for (auto module_name : llvm_modules)
                module_names.push_back(module_name);
              if (log)
                log->Printf("SwiftASTContext::%s() - parsed %zu llvm modules "
                            "from Swift AST section %zu of %zu.",
                            __FUNCTION__, llvm_modules.size(), ast_number,
                            ast_file_datas.size());
            } else {
              // Keep track of the fact that we failed to parse the AST
              // section info.
              if (log)
                log->Printf("SwiftASTContext::%s() - failed to parse AST "
                            "section %zu of %zu.",
                            __FUNCTION__, ast_number, ast_file_datas.size());
              ++parse_fail_count;
            }
          }
          if (!ast_file_datas.empty() && (parse_fail_count == 0)) {
            // We found AST data entries and we successfully parsed all of
            // them.
            return true;
          }
        }
      }
    }
  }
  return false;
}

void SwiftASTContext::ValidateSectionModules(
    Module &module, const std::vector<std::string> &module_names) {
  VALID_OR_RETURN_VOID();

  Status error;

  for (const std::string &module_name : module_names)
    if (!GetModule(ConstString(module_name.c_str()), error))
      module.ReportWarning("unable to load swift module '%s' (%s)",
                           module_name.c_str(), error.AsCString());
}

swift::Identifier SwiftASTContext::GetIdentifier(const char *name) {
  VALID_OR_RETURN(swift::Identifier());

  return GetASTContext()->getIdentifier(llvm::StringRef(name));
}

swift::Identifier SwiftASTContext::GetIdentifier(const llvm::StringRef &name) {
  VALID_OR_RETURN(swift::Identifier());

  return GetASTContext()->getIdentifier(name);
}

ConstString SwiftASTContext::GetMangledTypeName(swift::TypeBase *type_base) {
  VALID_OR_RETURN(ConstString());

  auto iter = m_type_to_mangled_name_map.find(type_base),
       end = m_type_to_mangled_name_map.end();
  if (iter != end)
    return ConstString(iter->second);

  swift::Type swift_type(type_base);

  bool has_archetypes = swift_type->hasArchetype();

  if (!has_archetypes) {
    swift::Mangle::ASTMangler mangler(true);
    std::string s = mangler.mangleTypeForDebugger(swift_type, nullptr, nullptr);

    if (!s.empty()) {
      ConstString mangled_cs(s.c_str());
      CacheDemangledType(mangled_cs.AsCString(), type_base);
      return mangled_cs;
    }
  }

  return ConstString();
}

void SwiftASTContext::CacheDemangledType(const char *name,
                                         swift::TypeBase *found_type) {
  VALID_OR_RETURN_VOID();

  m_type_to_mangled_name_map.insert(std::make_pair(found_type, name));
  m_mangled_name_to_type_map.insert(std::make_pair(name, found_type));
}

void SwiftASTContext::CacheDemangledTypeFailure(const char *name) {
  VALID_OR_RETURN_VOID();

  m_negative_type_cache.Insert(name);
}

CompilerType
SwiftASTContext::GetTypeFromMangledTypename(const char *mangled_typename,
                                            Status &error) {
  VALID_OR_RETURN(CompilerType());

  if (mangled_typename 
      && SwiftLanguageRuntime::IsSwiftMangledName(mangled_typename)) {
    Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_TYPES));
    if (log)
      log->Printf("((SwiftASTContext*)%p)->GetTypeFromMangledTypename('%s')",
                  this, mangled_typename);

    swift::ASTContext *ast_ctx = GetASTContext();
    if (!ast_ctx) {
      if (log)
        log->Printf("((SwiftASTContext*)%p)->GetTypeFromMangledTypename('%s') "
                    "-- null Swift AST Context",
                    this, mangled_typename);
      error.SetErrorString("null Swift AST Context");
      return CompilerType();
    }

    error.Clear();

    // If we were to crash doing this, remember what type caused it
    llvm::PrettyStackTraceFormat PST("error finding type for %s",
                                        mangled_typename);
    ConstString mangled_name(mangled_typename);
    swift::TypeBase *found_type =
        m_mangled_name_to_type_map.lookup(mangled_name.GetCString());
    if (found_type) {
      if (log)
        log->Printf("((SwiftASTContext*)%p)->GetTypeFromMangledTypename('%s') "
                    "-- found in the positive cache",
                    this, mangled_typename);
      return CompilerType(ast_ctx, found_type);
    }

    if (m_negative_type_cache.Lookup(mangled_name.GetCString())) {
      if (log)
        log->Printf("((SwiftASTContext*)%p)->GetTypeFromMangledTypename('%s') "
                    "-- found in the negative cache",
                    this, mangled_typename);
      return CompilerType();
    }

    if (log)
      log->Printf("((SwiftASTContext*)%p)->GetTypeFromMangledTypename('%s') -- "
                  "not cached, searching",
                  this, mangled_typename);

    std::string swift_error;
    found_type = swift::ide::getTypeFromMangledSymbolname(
                     *ast_ctx, mangled_typename, swift_error)
                     .getPointer();

    if (found_type) {
      CacheDemangledType(mangled_name.GetCString(), found_type);
      CompilerType result_type(ast_ctx, found_type);
      if (log)
        log->Printf("((SwiftASTContext*)%p)->GetTypeFromMangledTypename('%s') "
                    "-- found %s",
                    this, mangled_typename,
                    result_type.GetTypeName().GetCString());
      return result_type;
    } else {
      if (log)
        log->Printf("((SwiftASTContext*)%p)->GetTypeFromMangledTypename('%s') "
                    "-- error: %s",
                    this, mangled_typename, swift_error.c_str());

      error.SetErrorStringWithFormat("type for typename '%s' was not found",
                                     mangled_typename);
      CacheDemangledTypeFailure(mangled_name.GetCString());
      return CompilerType();
    }
  }
  error.SetErrorStringWithFormat("typename '%s' is not a valid Swift mangled "
                                 "typename, it should begin with _T",
                                 mangled_typename);
  return CompilerType();
}

CompilerType SwiftASTContext::GetVoidFunctionType() {
  VALID_OR_RETURN(CompilerType());

  if (!m_void_function_type) {
    swift::ASTContext *ast = GetASTContext();
    swift::Type empty_tuple_type(swift::TupleType::getEmpty(*ast));
    m_void_function_type = CompilerType(
        ast, swift::FunctionType::get(empty_tuple_type, empty_tuple_type));
  }
  return m_void_function_type;
}

static CompilerType ValueDeclToType(swift::ValueDecl *decl,
                                    swift::ASTContext *ast) {
  if (decl) {
    switch (decl->getKind()) {
    case swift::DeclKind::TypeAlias: {
      swift::TypeAliasDecl *alias_decl = swift::cast<swift::TypeAliasDecl>(decl);
      if (alias_decl->hasInterfaceType()) {
        swift::Type swift_type = alias_decl->getDeclaredInterfaceType();
        return CompilerType(ast, swift_type.getPointer());
      }
      break;
    }

    case swift::DeclKind::Enum:
    case swift::DeclKind::Struct:
    case swift::DeclKind::Protocol:
    case swift::DeclKind::Class: {
      swift::NominalTypeDecl *nominal_decl = swift::cast<swift::NominalTypeDecl>(decl);
      if (nominal_decl->hasInterfaceType()) {
        swift::Type swift_type = nominal_decl->getDeclaredType();
        return CompilerType(ast, swift_type.getPointer());
      }
    } break;

    default:
      break;
    }
  }
  return CompilerType();
}

CompilerType SwiftASTContext::FindQualifiedType(const char *qualified_name) {
  VALID_OR_RETURN(CompilerType());

  if (qualified_name && qualified_name[0]) {
    const char *dot_pos = strchr(qualified_name, '.');
    if (dot_pos) {
      ConstString module_name(qualified_name, dot_pos - qualified_name);
      swift::ModuleDecl *swift_module = GetCachedModule(module_name);
      if (swift_module) {
        swift::ModuleDecl::AccessPathTy access_path;
        llvm::SmallVector<swift::ValueDecl *, 4> decls;
        const char *module_type_name = dot_pos + 1;
        swift_module->lookupValue(access_path, GetIdentifier(module_type_name),
                                  swift::NLKind::UnqualifiedLookup, decls);
        for (auto decl : decls) {
          CompilerType type = ValueDeclToType(decl, GetASTContext());
          if (type)
            return type;
        }
      }
    }
  }
  return CompilerType();
}

static CompilerType DeclToType(swift::Decl *decl, swift::ASTContext *ast) {
  if (swift::ValueDecl *value_decl =
          swift::dyn_cast_or_null<swift::ValueDecl>(decl))
    return ValueDeclToType(value_decl, ast);
  return CompilerType();
}

static SwiftASTContext::TypeOrDecl DeclToTypeOrDecl(swift::ASTContext *ast,
                                                    swift::Decl *decl) {
  if (decl) {
    switch (decl->getKind()) {
    case swift::DeclKind::Import:
    case swift::DeclKind::Extension:
    case swift::DeclKind::PatternBinding:
    case swift::DeclKind::TopLevelCode:
    case swift::DeclKind::GenericTypeParam:
    case swift::DeclKind::AssociatedType:
    case swift::DeclKind::EnumElement:
    case swift::DeclKind::EnumCase:
    case swift::DeclKind::IfConfig:
    case swift::DeclKind::Param:
    case swift::DeclKind::Module:
    case swift::DeclKind::MissingMember:
      break;

    case swift::DeclKind::InfixOperator:
    case swift::DeclKind::PrefixOperator:
    case swift::DeclKind::PostfixOperator:
    case swift::DeclKind::PrecedenceGroup:
      return decl;

    case swift::DeclKind::TypeAlias: {
      swift::TypeAliasDecl *alias_decl =
          swift::cast<swift::TypeAliasDecl>(decl);
      if (alias_decl->hasInterfaceType()) {
        swift::Type swift_type = alias_decl->getDeclaredInterfaceType();
        return CompilerType(ast, swift_type.getPointer());
      }
    } break;
    case swift::DeclKind::Enum:
    case swift::DeclKind::Struct:
    case swift::DeclKind::Class:
    case swift::DeclKind::Protocol: {
      swift::NominalTypeDecl *nominal_decl =
          swift::cast<swift::NominalTypeDecl>(decl);
      if (nominal_decl->hasInterfaceType()) {
        swift::Type swift_type = nominal_decl->getDeclaredType();
        return CompilerType(ast, swift_type.getPointer());
      }
    } break;

    case swift::DeclKind::Func:
    case swift::DeclKind::Var:
      return decl;

    case swift::DeclKind::Subscript:
    case swift::DeclKind::Constructor:
    case swift::DeclKind::Destructor:
      break;
    }
  }
  return CompilerType();
}

size_t SwiftASTContext::FindContainedType(llvm::StringRef name,
                                          CompilerType container_type,
                                          std::set<CompilerType> &results,
                                          bool append) {
  VALID_OR_RETURN(0);

  if (!append)
    results.clear();

  size_t size_before = results.size();

  TypesOrDecls types_or_decl_results;
  FindContainedTypeOrDecl(name, container_type, types_or_decl_results);

  for (const auto &result : types_or_decl_results) {
    CompilerType type = result.Apply<CompilerType>(
        [](CompilerType type) -> CompilerType { return type; },
        [this](swift::Decl *decl) -> CompilerType {
          return DeclToType(decl, GetASTContext());
        });
    results.emplace(type);
  }

  return results.size() - size_before;
}

size_t
SwiftASTContext::FindContainedTypeOrDecl(llvm::StringRef name,
                                         TypeOrDecl container_type_or_decl,
                                         TypesOrDecls &results, bool append) {
  VALID_OR_RETURN(0);

  if (!append)
    results.clear();
  size_t size_before = results.size();

  CompilerType container_type = container_type_or_decl.Apply<CompilerType>(
      [](CompilerType type) -> CompilerType { return type; },
      [this](swift::Decl *decl) -> CompilerType {
        return DeclToType(decl, GetASTContext());
      });

  if (false == name.empty() &&
      llvm::dyn_cast_or_null<SwiftASTContext>(container_type.GetTypeSystem())) {
    swift::Type swift_type(GetSwiftType(container_type));
    if (!swift_type)
      return 0;
    swift::CanType swift_can_type(swift_type->getCanonicalType());
    swift::NominalType *nominal_type =
        swift_can_type->getAs<swift::NominalType>();
    if (!nominal_type)
      return 0;
    swift::NominalTypeDecl *nominal_decl = nominal_type->getDecl();
    llvm::ArrayRef<swift::ValueDecl *> decls =
        nominal_decl->lookupDirect(
            swift::DeclName(m_ast_context_ap->getIdentifier(name)));
    for (auto decl : decls)
      results.emplace(DeclToTypeOrDecl(GetASTContext(), decl));
  }
  return results.size() - size_before;
}

CompilerType SwiftASTContext::FindType(const char *name,
                                       swift::ModuleDecl *swift_module) {
  VALID_OR_RETURN(CompilerType());

  std::set<CompilerType> search_results;

  FindTypes(name, swift_module, search_results, false);

  if (search_results.empty())
    return CompilerType();
  else
    return *search_results.begin();
}

llvm::Optional<SwiftASTContext::TypeOrDecl>
SwiftASTContext::FindTypeOrDecl(const char *name,
                                swift::ModuleDecl *swift_module) {
  VALID_OR_RETURN(llvm::Optional<SwiftASTContext::TypeOrDecl>());

  TypesOrDecls search_results;

  FindTypesOrDecls(name, swift_module, search_results, false);

  if (search_results.empty())
    return llvm::Optional<SwiftASTContext::TypeOrDecl>();
  else
    return *search_results.begin();
}

size_t SwiftASTContext::FindTypes(const char *name,
                                  swift::ModuleDecl *swift_module,
                                  std::set<CompilerType> &results,
                                  bool append) {
  VALID_OR_RETURN(0);

  if (!append)
    results.clear();

  size_t before = results.size();

  TypesOrDecls types_or_decls_results;
  FindTypesOrDecls(name, swift_module, types_or_decls_results);

  for (const auto &result : types_or_decls_results) {
    CompilerType type = result.Apply<CompilerType>(
        [](CompilerType type) -> CompilerType { return type; },
        [this](swift::Decl *decl) -> CompilerType {
          if (swift::ValueDecl *value_decl =
                  swift::dyn_cast_or_null<swift::ValueDecl>(decl)) {
            if (value_decl->hasInterfaceType()) {
              swift::Type swift_type = value_decl->getInterfaceType();
              swift::MetatypeType *meta_type =
                  swift_type->getAs<swift::MetatypeType>();
              swift::ASTContext *ast = GetASTContext();
              if (meta_type)
                return CompilerType(ast,
                                    meta_type->getInstanceType().getPointer());
              else
                return CompilerType(ast, swift_type.getPointer());
            }
          }
          return CompilerType();
        });
    results.emplace(type);
  }

  return results.size() - before;
}

size_t SwiftASTContext::FindTypesOrDecls(const char *name,
                                         swift::ModuleDecl *swift_module,
                                         TypesOrDecls &results, bool append) {
  VALID_OR_RETURN(0);

  if (!append)
    results.clear();

  size_t before = results.size();

  if (name && name[0] && swift_module) {
    swift::ModuleDecl::AccessPathTy access_path;
    llvm::SmallVector<swift::ValueDecl *, 4> value_decls;
    swift::Identifier identifier(GetIdentifier(name));
    if (strchr(name, '.'))
      swift_module->lookupValue(access_path, identifier,
                                swift::NLKind::QualifiedLookup, value_decls);
    else
      swift_module->lookupValue(access_path, identifier,
                                swift::NLKind::UnqualifiedLookup, value_decls);
    if (identifier.isOperator()) {
      swift::OperatorDecl *op_decl =
          swift_module->lookupPrefixOperator(identifier);
      if (op_decl)
        results.emplace(DeclToTypeOrDecl(GetASTContext(), op_decl));
      if ((op_decl = swift_module->lookupInfixOperator(identifier)))
        results.emplace(DeclToTypeOrDecl(GetASTContext(), op_decl));
      if ((op_decl = swift_module->lookupPostfixOperator(identifier)))
        results.emplace(DeclToTypeOrDecl(GetASTContext(), op_decl));
    }
    if (swift::PrecedenceGroupDecl *pg_decl =
            swift_module->lookupPrecedenceGroup(identifier))
      results.emplace(DeclToTypeOrDecl(GetASTContext(), pg_decl));

    for (auto decl : value_decls)
      results.emplace(DeclToTypeOrDecl(GetASTContext(), decl));
  }

  return results.size() - before;
}

size_t SwiftASTContext::FindType(const char *name,
                                 std::set<CompilerType> &results, bool append) {
  VALID_OR_RETURN(0);

  if (!append)
    results.clear();
  auto iter = m_swift_module_cache.begin(), end = m_swift_module_cache.end();

  size_t count = 0;

  std::function<void(swift::ModuleDecl *)> lookup_func =
      [this, name, &results, &count](swift::ModuleDecl *module) -> void {
    CompilerType candidate(this->FindType(name, module));
    if (candidate) {
      ++count;
      results.insert(candidate);
    }
  };

  for (; iter != end; iter++)
    lookup_func(iter->second);

  if (m_scratch_module)
    lookup_func(m_scratch_module);

  return count;
}

CompilerType SwiftASTContext::FindFirstType(const char *name,
                                            const ConstString &module_name) {
  VALID_OR_RETURN(CompilerType());

  if (name && name[0]) {
    if (module_name) {
      return FindType(name, GetCachedModule(module_name));
    } else {
      std::set<CompilerType> types;
      FindType(name, types);
      if (!types.empty())
        return *types.begin();
    }
  }
  return CompilerType();
}

CompilerType SwiftASTContext::ImportType(CompilerType &type, Status &error) {
  VALID_OR_RETURN(CompilerType());

  if (m_ast_context_ap.get() == NULL)
    return CompilerType();

  SwiftASTContext *swift_ast_ctx =
      llvm::dyn_cast_or_null<SwiftASTContext>(type.GetTypeSystem());

  if (swift_ast_ctx == nullptr) {
    error.SetErrorString("Can't import clang type into a Swift ASTContext.");
    return CompilerType();
  } else if (swift_ast_ctx == this) {
    // This is the same AST context, so the type is already imported...
    return type;
  }

  // For now we're going to do this all using mangled names.  If we find that is
  // too slow, we can use the TypeBase * in the CompilerType to match this to
  // the version of the type we got from the mangled name in the original
  // swift::ASTContext.

  ConstString mangled_name(type.GetMangledTypeName());
  if (mangled_name) {
    swift::TypeBase *our_type_base =
        m_mangled_name_to_type_map.lookup(mangled_name.GetCString());
    if (our_type_base)
      return CompilerType(m_ast_context_ap.get(), our_type_base);
    else {
      Status error;

      CompilerType our_type(
          GetTypeFromMangledTypename(mangled_name.GetCString(), error));
      if (error.Success())
        return our_type;
    }
  }
  return CompilerType();
}

swift::IRGenDebugInfoKind SwiftASTContext::GetGenerateDebugInfo() {
  return GetIRGenOptions().DebugInfoKind;
}

swift::PrintOptions SwiftASTContext::GetUserVisibleTypePrintingOptions(
    bool print_help_if_available) {
  swift::PrintOptions print_options;
  print_options.SynthesizeSugarOnTypes = true;
  print_options.VarInitializers = true;
  print_options.TypeDefinitions = true;
  print_options.PrintGetSetOnRWProperties = true;
  print_options.SkipImplicit = false;
  print_options.PreferTypeRepr = true;
  print_options.FunctionDefinitions = true;
  print_options.FullyQualifiedTypesIfAmbiguous = true;
  print_options.FullyQualifiedTypes = true;
  print_options.ExplodePatternBindingDecls = false;
  print_options.PrintDocumentationComments =
      print_options.PrintRegularClangComments = print_help_if_available;
  return print_options;
}

void SwiftASTContext::SetGenerateDebugInfo(swift::IRGenDebugInfoKind b) {
  GetIRGenOptions().DebugInfoKind = b;
}

llvm::TargetOptions *SwiftASTContext::getTargetOptions() {
  if (m_target_options_ap.get() == NULL) {
    m_target_options_ap.reset(new llvm::TargetOptions());
  }
  return m_target_options_ap.get();
}

swift::ModuleDecl *SwiftASTContext::GetScratchModule() {
  VALID_OR_RETURN(nullptr);

  if (m_scratch_module == nullptr)
    m_scratch_module = swift::ModuleDecl::create(
        GetASTContext()->getIdentifier("__lldb_scratch_module"),
        *GetASTContext());
  return m_scratch_module;
}

swift::SILModule *SwiftASTContext::GetSILModule() {
  VALID_OR_RETURN(nullptr);

  if (m_sil_module_ap.get() == NULL)
    m_sil_module_ap = swift::SILModule::createEmptyModule(GetScratchModule(),
                                                          GetSILOptions());
  return m_sil_module_ap.get();
}

swift::irgen::IRGenerator &
SwiftASTContext::GetIRGenerator(swift::IRGenOptions &opts,
                                swift::SILModule &module) {
  if (m_ir_generator_ap.get() == nullptr) {
    m_ir_generator_ap.reset(new swift::irgen::IRGenerator(opts, module));
  }

  return *m_ir_generator_ap.get();
}

swift::irgen::IRGenModule &SwiftASTContext::GetIRGenModule() {
  VALID_OR_RETURN(*m_ir_gen_module_ap);

  if (m_ir_gen_module_ap.get() == NULL) {
    // Make sure we have a good ClangImporter.
    GetClangImporter();

    swift::IRGenOptions &ir_gen_opts = GetIRGenOptions();

    std::string error_str;
    std::string triple = GetTriple();
    const llvm::Target *llvm_target =
        llvm::TargetRegistry::lookupTarget(triple, error_str);

    llvm::CodeGenOpt::Level optimization_level = llvm::CodeGenOpt::Level::None;

    // Create a target machine.
    llvm::TargetMachine *target_machine = llvm_target->createTargetMachine(
        triple,
        "generic", // cpu
        "",        // features
        *getTargetOptions(),
        llvm::Reloc::Static, // TODO verify with Sean, Default went away
        llvm::CodeModel::Default, optimization_level);
    if (target_machine) {
      // Set the module's string representation.
      const llvm::DataLayout data_layout = target_machine->createDataLayout();

      llvm::Triple llvm_triple(triple);
      swift::SILModule *sil_module = GetSILModule();
      if (sil_module != nullptr) {
        swift::irgen::IRGenerator &ir_generator =
            GetIRGenerator(ir_gen_opts, *sil_module);
        m_ir_gen_module_ap.reset(new swift::irgen::IRGenModule(
            ir_generator, ir_generator.createTargetMachine(), nullptr,
            GetGlobalLLVMContext(), ir_gen_opts.ModuleName,
            ir_gen_opts.getSingleOutputFilename()));
        llvm::Module *llvm_module = m_ir_gen_module_ap->getModule();
        llvm_module->setDataLayout(data_layout.getStringRepresentation());
        llvm_module->setTargetTriple(triple);
      }
    }
  }
  return *m_ir_gen_module_ap;
}

CompilerType
SwiftASTContext::CreateTupleType(const std::vector<CompilerType> &elements) {
  VALID_OR_RETURN(CompilerType());

  Status error;
  if (elements.size() == 0)
    return CompilerType(GetASTContext(), GetASTContext()->TheEmptyTupleType);
  else {
    std::vector<swift::TupleTypeElt> tuple_elems;
    for (const CompilerType &type : elements) {
      if (auto swift_type = GetSwiftType(type))
        tuple_elems.push_back(swift::TupleTypeElt(swift_type));
      else
        return CompilerType();
    }
    llvm::ArrayRef<swift::TupleTypeElt> fields(tuple_elems);
    return CompilerType(
        GetASTContext(),
        swift::TupleType::get(fields, *GetASTContext()).getPointer());
  }
}

CompilerType
SwiftASTContext::CreateTupleType(const std::vector<TupleElement> &elements) {
  VALID_OR_RETURN(CompilerType());

  Status error;
  if (elements.size() == 0)
    return CompilerType(GetASTContext(), GetASTContext()->TheEmptyTupleType);
  else {
    std::vector<swift::TupleTypeElt> tuple_elems;
    for (const TupleElement &element : elements) {
      if (auto swift_type = GetSwiftType(element.element_type)) {
        if (element.element_name.IsEmpty())
          tuple_elems.push_back(swift::TupleTypeElt(swift_type));
        else
          tuple_elems.push_back(swift::TupleTypeElt(
              swift_type, m_ast_context_ap->getIdentifier(
                              element.element_name.GetCString())));
      } else
        return CompilerType();
    }
    llvm::ArrayRef<swift::TupleTypeElt> fields(tuple_elems);
    return CompilerType(
        GetASTContext(),
        swift::TupleType::get(fields, *GetASTContext()).getPointer());
  }
}

CompilerType SwiftASTContext::CreateFunctionType(CompilerType arg_type,
                                                 CompilerType ret_type,
                                                 bool throws) {
  VALID_OR_RETURN(CompilerType());

  if (!llvm::dyn_cast_or_null<SwiftASTContext>(arg_type.GetTypeSystem()) ||
      !llvm::dyn_cast_or_null<SwiftASTContext>(ret_type.GetTypeSystem()))
    return CompilerType();
  swift::FunctionType::ExtInfo ext_info;
  if (throws)
    ext_info = ext_info.withThrows();
  return CompilerType(GetASTContext(), swift::FunctionType::get(
                                           GetSwiftType(arg_type),
                                           GetSwiftType(ret_type), ext_info));
}

CompilerType SwiftASTContext::GetErrorType() {
  VALID_OR_RETURN(CompilerType());

  swift::ASTContext *swift_ctx = GetASTContext();
  if (swift_ctx) {
    // Getting the error type requires the Stdlib module be loaded, but doesn't
    // cause it to be loaded.
    // Do that here:
    swift_ctx->getStdlibModule(true);
    swift::NominalTypeDecl *error_type_decl = GetASTContext()->getErrorDecl();
    if (error_type_decl) {
      auto error_type = error_type_decl->getDeclaredType().getPointer();
      return CompilerType(GetASTContext(), error_type);
    }
  }
  return CompilerType();
}

CompilerType SwiftASTContext::GetNSErrorType(Status &error) {
  VALID_OR_RETURN(CompilerType());

  return GetTypeFromMangledTypename(SwiftLanguageRuntime::GetCurrentMangledName("_TtC10Foundation7NSError").c_str(), error);
}

CompilerType SwiftASTContext::CreateMetatypeType(CompilerType instance_type) {
  VALID_OR_RETURN(CompilerType());

  if (llvm::dyn_cast_or_null<SwiftASTContext>(instance_type.GetTypeSystem()))
    return CompilerType(GetASTContext(),
                        swift::MetatypeType::get(GetSwiftType(instance_type),
                                                 *GetASTContext()));
  return CompilerType();
}

SwiftASTContext *SwiftASTContext::GetSwiftASTContext(swift::ASTContext *ast) {
  SwiftASTContext *swift_ast = GetASTMap().Lookup(ast);
  return swift_ast;
}

uint32_t SwiftASTContext::GetPointerByteSize() {
  VALID_OR_RETURN(0);

  if (m_pointer_byte_size == 0) {
    swift::ASTContext *ast = GetASTContext();
    m_pointer_byte_size = CompilerType(ast, ast->TheRawPointerType.getPointer())
                              .GetByteSize(nullptr);
  }
  return m_pointer_byte_size;
}

uint32_t SwiftASTContext::GetPointerBitAlignment() {
  VALID_OR_RETURN(0);

  if (m_pointer_bit_align == 0) {
    swift::ASTContext *ast = GetASTContext();
    m_pointer_bit_align = CompilerType(ast, ast->TheRawPointerType.getPointer())
                              .GetAlignedBitSize();
  }
  return m_pointer_bit_align;
}

bool SwiftASTContext::HasErrors() {
  if (m_diagnostic_consumer_ap.get())
    return (
        static_cast<StoringDiagnosticConsumer *>(m_diagnostic_consumer_ap.get())
            ->NumErrors() != 0);
  else
    return false;
}

bool SwiftASTContext::HasFatalErrors(swift::ASTContext *ast_context) {
  return (ast_context && ast_context->Diags.hasFatalErrorOccurred());
}

void SwiftASTContext::ClearDiagnostics() {
  assert(!HasFatalErrors() && "Never clear a fatal diagnostic!");
  if (m_diagnostic_consumer_ap.get())
    static_cast<StoringDiagnosticConsumer *>(m_diagnostic_consumer_ap.get())
        ->Clear();
}

bool SwiftASTContext::SetColorizeDiagnostics(bool b) {
  if (m_diagnostic_consumer_ap.get())
    return static_cast<StoringDiagnosticConsumer *>(
               m_diagnostic_consumer_ap.get())
        ->SetColorize(b);
  return false;
}

void SwiftASTContext::PrintDiagnostics(DiagnosticManager &diagnostic_manager,
                                       uint32_t bufferID, uint32_t first_line,
                                       uint32_t last_line,
                                       uint32_t line_offset) {
  // If this is a fatal error, copy the error into the AST context's fatal error
  // field, and then put it to the stream, otherwise just dump the diagnostics
  // to the stream.


  // N.B. you cannot use VALID_OR_RETURN_VOID here since that exits if you have
  // fatal errors, which are what we are trying to print here.
  if (!m_ast_context_ap.get()) {
    SymbolFile *sym_file = GetSymbolFile();
    if (sym_file) {
      ConstString name 
              = sym_file->GetObjectFile()->GetModule()->GetObjectName();
      m_fatal_errors.SetErrorStringWithFormat(
                  "Null context for %s.", name.AsCString());
    } else {
      m_fatal_errors.SetErrorString("Unknown fatal error occurred.");
    }
    return;
  }

  if (m_ast_context_ap->Diags.hasFatalErrorOccurred() &&
      !m_reported_fatal_error) {
    DiagnosticManager fatal_diagnostics;

    if (m_diagnostic_consumer_ap.get())
      static_cast<StoringDiagnosticConsumer *>(m_diagnostic_consumer_ap.get())
          ->PrintDiagnostics(fatal_diagnostics, bufferID, first_line, last_line,
                             line_offset);
    if (fatal_diagnostics.Diagnostics().size())
      m_fatal_errors.SetErrorString(fatal_diagnostics.GetString().data());
    else
      m_fatal_errors.SetErrorString("Unknown fatal error occurred.");

    m_reported_fatal_error = true;

    for (const DiagnosticList::value_type &fatal_diagnostic :
         fatal_diagnostics.Diagnostics()) {
      // FIXME: need to add a CopyDiagnostic operation for copying diagnostics
      // from one manager to another.
      diagnostic_manager.AddDiagnostic(
          fatal_diagnostic->GetMessage(), fatal_diagnostic->GetSeverity(),
          fatal_diagnostic->getKind(), fatal_diagnostic->GetCompilerID());
    }
  } else {
    if (m_diagnostic_consumer_ap.get())
      static_cast<StoringDiagnosticConsumer *>(m_diagnostic_consumer_ap.get())
          ->PrintDiagnostics(diagnostic_manager, bufferID, first_line,
                             last_line, line_offset);
  }
}

void SwiftASTContext::ModulesDidLoad(ModuleList &module_list) {
  ClearModuleDependentCaches();
}

void SwiftASTContext::ClearModuleDependentCaches() {
  m_negative_type_cache.Clear();
  m_extra_type_info_cache.Clear();
}

void SwiftASTContext::DumpConfiguration(Log *log) {
  VALID_OR_RETURN_VOID();

  if (!log)
    return;

  log->Printf("(SwiftASTContext*)%p:", this);

  if (!m_ast_context_ap)
    log->Printf("  (no AST context)");

  log->Printf("  Architecture                 : %s",
              m_ast_context_ap->LangOpts.Target.getTriple().c_str());

  log->Printf("  SDK path                     : %s",
              m_ast_context_ap->SearchPathOpts.SDKPath.c_str());
  log->Printf("  Runtime resource path        : %s",
              m_ast_context_ap->SearchPathOpts.RuntimeResourcePath.c_str());
  log->Printf("  Runtime library path         : %s",
              m_ast_context_ap->SearchPathOpts.RuntimeLibraryPath.c_str());
  log->Printf(
      "  Runtime library import path  : %s",
      m_ast_context_ap->SearchPathOpts.RuntimeLibraryImportPath.c_str());

  log->Printf("  Framework search paths       : (%llu items)",
              (unsigned long long)
                  m_ast_context_ap->SearchPathOpts.FrameworkSearchPaths.size());
  for (const auto &framework_search_path :
       m_ast_context_ap->SearchPathOpts.FrameworkSearchPaths) {
    log->Printf("    %s", framework_search_path.Path.c_str());
  }

  log->Printf("  Import search paths          : (%llu items)",
              (unsigned long long)
                  m_ast_context_ap->SearchPathOpts.ImportSearchPaths.size());
  for (std::string &import_search_path :
       m_ast_context_ap->SearchPathOpts.ImportSearchPaths) {
    log->Printf("    %s", import_search_path.c_str());
  }

  swift::ClangImporterOptions &clang_importer_options =
      GetClangImporterOptions();

  log->Printf("  Extra clang arguments        : (%llu items)",
              (unsigned long long)clang_importer_options.ExtraArgs.size());
  for (std::string &extra_arg : clang_importer_options.ExtraArgs) {
    log->Printf("    %s", extra_arg.c_str());
  }
}

bool SwiftASTContext::HasTarget() const {
  lldb::TargetWP empty_wp;

  // If either call to "std::weak_ptr::owner_before(...) value returns true,
  // this indicates that m_section_wp once contained (possibly still does) a
  // reference to a valid shared pointer. This helps us know if we had a valid
  // reference to a target which is now invalid because the target was deleted.
  return empty_wp.owner_before(m_target_wp) ||
         m_target_wp.owner_before(empty_wp);
}

bool SwiftASTContext::CheckProcessChanged() {
  if (HasTarget()) {
    TargetSP target_sp(m_target_wp.lock());
    if (target_sp) {
      Process *process = target_sp->GetProcessSP().get();
      if (m_process == NULL) {
        if (process)
          m_process = process;
      } else {
        if (m_process != process)
          return true;
      }
    }
  }
  return false;
}

void SwiftASTContext::AddDebuggerClient(
    swift::DebuggerClient *debugger_client) {
  m_debugger_clients.push_back(
      std::unique_ptr<swift::DebuggerClient>(debugger_client));
}

SwiftASTContext::ExtraTypeInformation::ExtraTypeInformation()
    : m_flags(false, false) {}

SwiftASTContext::ExtraTypeInformation::ExtraTypeInformation(
    swift::CanType swift_can_type)
    : m_flags(false, false) {
  static ConstString g_rawValue("rawValue");

  swift::ASTContext &ast_ctx = swift_can_type->getASTContext();
  SwiftASTContext *swift_ast = SwiftASTContext::GetSwiftASTContext(&ast_ctx);
  if (swift_ast) {
    swift::ProtocolDecl *option_set =
        ast_ctx.getProtocol(swift::KnownProtocolKind::OptionSet);
    if (option_set) {
      if (auto nominal_decl =
              swift_can_type.getNominalOrBoundGenericNominal()) {
        for (swift::ProtocolDecl *protocol_decl :
             nominal_decl->getAllProtocols()) {
          if (protocol_decl == option_set) {
            for (swift::VarDecl *stored_property :
                 nominal_decl->getStoredProperties()) {
              swift::Identifier name = stored_property->getName();
              if (name.str() == g_rawValue.GetStringRef()) {
                m_flags.m_is_trivial_option_set = true;
                break;
              }
            }
          }
        }
      }
    }
  }

  if (auto metatype_type = swift::dyn_cast_or_null<swift::MetatypeType>(
          swift_can_type)) {
    if (!metatype_type->hasRepresentation() ||
        (swift::MetatypeRepresentation::Thin ==
         metatype_type->getRepresentation()))
      m_flags.m_is_zero_size = true;
  } else if (auto enum_decl = swift_can_type->getEnumOrBoundGenericEnum()) {
    size_t num_nopayload = 0, num_payload = 0;
    for (auto the_case : enum_decl->getAllElements()) {
      if (the_case->getArgumentInterfaceType()) {
        num_payload = 1;
        break;
      } else {
        if (++num_nopayload > 1)
          break;
      }
    }
    if (num_nopayload == 1 && num_payload == 0)
      m_flags.m_is_zero_size = true;
  } else if (auto struct_decl =
                 swift_can_type->getStructOrBoundGenericStruct()) {
    bool has_storage = false;
    auto members = struct_decl->getMembers();
    for (const auto &member : members) {
      if (swift::VarDecl *var_decl =
              swift::dyn_cast<swift::VarDecl>(member)) {
        if (!var_decl->isStatic() && var_decl->hasStorage()) {
          has_storage = true;
          break;
        }
      }
    }
    m_flags.m_is_zero_size = !has_storage;
  } else if (auto tuple_type = swift::dyn_cast_or_null<swift::TupleType>(
                 swift_can_type)) {
    m_flags.m_is_zero_size = (tuple_type->getNumElements() == 0);
  }
}

SwiftASTContext::ExtraTypeInformation
SwiftASTContext::GetExtraTypeInformation(void *type) {
  if (!type)
    return ExtraTypeInformation();

  swift::CanType swift_can_type;
  void *swift_can_type_ptr = nullptr;
  if (auto swift_type = GetSwiftType(type)) {
    swift_can_type = swift_type->getCanonicalType();
    swift_can_type_ptr = swift_can_type.getPointer();
  }
  if (!swift_can_type_ptr)
    return ExtraTypeInformation();

  ExtraTypeInformation eti;
  if (!m_extra_type_info_cache.Lookup(swift_can_type_ptr, eti)) {
    ExtraTypeInformation extra_info(swift_can_type);
    m_extra_type_info_cache.Insert(swift_can_type_ptr, extra_info);
    return extra_info;
  } else {
    return eti;
  }
}

bool SwiftASTContext::DeclContextIsStructUnionOrClass(void *opaque_decl_ctx) {
  return false;
}

ConstString SwiftASTContext::DeclContextGetName(void *opaque_decl_ctx) {
  return ConstString();
}

ConstString
SwiftASTContext::DeclContextGetScopeQualifiedName(void *opaque_decl_ctx) {
  return ConstString();
}

bool SwiftASTContext::DeclContextIsClassMethod(
    void *opaque_decl_ctx, lldb::LanguageType *language_ptr,
    bool *is_instance_method_ptr, ConstString *language_object_name_ptr) {
  return false;
}

///////////
////////////////////
///////////

bool SwiftASTContext::IsArrayType(void *type, CompilerType *element_type_ptr,
                                  uint64_t *size, bool *is_incomplete) {
  VALID_OR_RETURN(false);

  swift::CanType swift_can_type(GetCanonicalSwiftType(type));
  swift::BoundGenericStructType *struct_type =
      swift_can_type->getAs<swift::BoundGenericStructType>();
  if (struct_type) {
    swift::StructDecl *struct_decl = struct_type->getDecl();
    if (strcmp(struct_decl->getName().get(), "Array") != 0)
      return false;
    if (!struct_decl->getModuleContext()->isStdlibModule())
      return false;
    const llvm::ArrayRef<swift::Type> &args = struct_type->getGenericArgs();
    if (args.size() != 1)
      return false;
    if (is_incomplete)
      *is_incomplete = true;
    if (size)
      *size = 0;
    if (element_type_ptr)
      *element_type_ptr =
          CompilerType(GetASTContext(), args[0].getPointer());
    return true;
  }

  return false;
}

bool SwiftASTContext::IsAggregateType(void *type) {
  if (type) {
    swift::CanType swift_can_type(GetCanonicalSwiftType(type));
    auto referent_type = swift_can_type->getReferenceStorageReferent();
    return (referent_type->is<swift::TupleType>() ||
            referent_type->is<swift::BuiltinVectorType>() ||
            referent_type->getAnyNominal());
  }

  return false;
}

bool SwiftASTContext::IsVectorType(void *type, CompilerType *element_type,
                                   uint64_t *size) {
  return false;
}

bool SwiftASTContext::IsRuntimeGeneratedType(void *type) { return false; }

bool SwiftASTContext::IsCharType(void *type) { return false; }

bool SwiftASTContext::IsCompleteType(void *type) { return true; }

bool SwiftASTContext::IsConst(void *type) { return false; }

bool SwiftASTContext::IsCStringType(void *type, uint32_t &length) {
  return false;
}

bool SwiftASTContext::IsFunctionType(void *type, bool *is_variadic_ptr) {
  if (type) {
    swift::CanType swift_can_type(GetCanonicalSwiftType(type));
    const swift::TypeKind type_kind = swift_can_type->getKind();
    switch (type_kind) {
    case swift::TypeKind::Function:
    case swift::TypeKind::GenericFunction:
      return true;
    case swift::TypeKind::SILFunction:
      return false; // TODO: is this correct?
    default:
      return false;
    }
  }
  return false;
}

// Used to detect "Homogeneous Floating-point Aggregates"
uint32_t SwiftASTContext::IsHomogeneousAggregate(void *type,
                                                 CompilerType *base_type_ptr) {
  return 0;
}

size_t SwiftASTContext::GetNumberOfFunctionArguments(void *type) {
  if (type) {
    swift::CanType swift_can_type(GetCanonicalSwiftType(type));
    auto func =
        swift::dyn_cast_or_null<swift::AnyFunctionType>(
            swift_can_type);
    if (func) {
      auto input = func.getInput();
      // See comment in swift::AnyFunctionType for rationale here:
      // A function can take either a tuple or a parentype, but if a parentype
      // (i.e. (Foo)), then it will be reduced down to just Foo, so if the input
      // is not a tuple, that must mean there is only 1 input.
      auto tuple = swift::dyn_cast<swift::TupleType>(input);
      if (tuple)
        return tuple->getNumElements();
      else
        return 1;
    }
  }
  return 0;
}

CompilerType SwiftASTContext::GetFunctionArgumentAtIndex(void *type,
                                                         const size_t index) {
  VALID_OR_RETURN(CompilerType());

  if (type) {
    swift::CanType swift_can_type(GetCanonicalSwiftType(type));
    auto func =
        swift::dyn_cast<swift::AnyFunctionType>(
            swift_can_type);
    if (func) {
      auto input = func.getInput();
      // See comment in swift::AnyFunctionType for rationale here:
      // A function can take either a tuple or a parentype, but if a parentype
      // (i.e. (Foo)), then it will be reduced down to just Foo, so if the input
      // is not a tuple, that must mean there is only 1 input.
      auto tuple = swift::dyn_cast<swift::TupleType>(input);
      if (tuple) {
        if (index < tuple->getNumElements())
          return CompilerType(GetASTContext(),
                              tuple->getElementType(index));
      } else
        return CompilerType(GetASTContext(), input);
    }
  }
  return CompilerType();
}

bool SwiftASTContext::IsFunctionPointerType(void *type) {
  return IsFunctionType(type, nullptr); // FIXME: think about this
}

bool SwiftASTContext::IsBlockPointerType(
    void *type, CompilerType *function_pointer_type_ptr) {
  return false;
}

bool SwiftASTContext::IsIntegerType(void *type, bool &is_signed) {
  return (GetTypeInfo(type, nullptr) & eTypeIsInteger);
}

bool SwiftASTContext::IsPointerType(void *type, CompilerType *pointee_type) {
  VALID_OR_RETURN(false);

  if (type) {
    swift::CanType swift_can_type(GetCanonicalSwiftType(type));
    auto referent_type = swift_can_type->getReferenceStorageReferent();
    return (referent_type->is<swift::BuiltinRawPointerType>() ||
            referent_type->is<swift::BuiltinNativeObjectType>() ||
            referent_type->is<swift::BuiltinUnsafeValueBufferType>() ||
            referent_type->is<swift::BuiltinUnknownObjectType>() ||
            referent_type->is<swift::BuiltinBridgeObjectType>());
  }

  if (pointee_type)
    pointee_type->Clear();
  return false;
}

bool SwiftASTContext::IsPointerOrReferenceType(void *type,
                                               CompilerType *pointee_type) {
  return IsPointerType(type, pointee_type) ||
         IsReferenceType(type, pointee_type, nullptr);
}

bool SwiftASTContext::ShouldTreatScalarValueAsAddress(
    lldb::opaque_compiler_type_t type) {
  return Flags(GetTypeInfo(type, nullptr))
      .AnySet(eTypeInstanceIsPointer | eTypeIsReference);
}

bool SwiftASTContext::IsReferenceType(void *type, CompilerType *pointee_type,
                                      bool *is_rvalue) {
  if (type) {
    swift::CanType swift_can_type(GetCanonicalSwiftType(type));
    const swift::TypeKind type_kind = swift_can_type->getKind();
    switch (type_kind) {
    case swift::TypeKind::InOut:
    case swift::TypeKind::LValue:
      if (pointee_type)
        *pointee_type = GetNonReferenceType(type);
      return true;
    default:
      break;
    }
  }
  if (pointee_type)
    pointee_type->Clear();
  return false;
}

bool SwiftASTContext::IsInoutType(const CompilerType &compiler_type,
                                  CompilerType *original_type) {
  if (compiler_type.IsValid()) {
    if (auto ast = llvm::dyn_cast_or_null<SwiftASTContext>(
            compiler_type.GetTypeSystem())) {
      swift::CanType swift_can_type(GetCanonicalSwiftType(compiler_type));
      swift::LValueType *lvalue = swift_can_type->getAs<swift::LValueType>();
      if (lvalue) {
        if (original_type)
          *original_type =
          CompilerType(ast, lvalue->getObjectType().getPointer());
        return true;
      }
      swift::InOutType *inout = swift_can_type->getAs<swift::InOutType>();
      if (inout) {
        if (original_type)
          *original_type =
          CompilerType(ast, inout->getObjectType().getPointer());
        return true;
      }
    }
  }
  return false;
}

bool SwiftASTContext::IsFloatingPointType(void *type, uint32_t &count,
                                          bool &is_complex) {
  if (type) {
    if (GetTypeInfo(type, nullptr) & eTypeIsFloat) {
      count = 1;
      is_complex = false;
      return true;
    }
  }
  count = 0;
  is_complex = false;
  return false;
}

bool SwiftASTContext::IsDefined(void *type) {
  if (!type)
    return false;

  return true;
}

bool SwiftASTContext::IsPolymorphicClass(void *type) { return false; }

bool SwiftASTContext::IsPossibleDynamicType(void *type,
                                            CompilerType *dynamic_pointee_type,
                                            bool check_cplusplus,
                                            bool check_objc, bool check_swift) {
  VALID_OR_RETURN(false);

  if (type && check_swift) {
    // FIXME: use the dynamic_pointee_type
    Flags type_flags(GetTypeInfo(type, nullptr));

    if (type_flags.AnySet(eTypeIsArchetype | eTypeIsClass | eTypeIsProtocol))
      return true;

    if (type_flags.AnySet(eTypeIsStructUnion | eTypeIsEnumeration |
                          eTypeIsTuple)) {
      CompilerType compiler_type(GetASTContext(), GetCanonicalSwiftType(type));
      return !SwiftASTContext::IsFullyRealized(compiler_type);
    }

    auto can_type = GetCanonicalSwiftType(type).getPointer();
    if (can_type == GetASTContext()->TheRawPointerType.getPointer())
      return true;
    if (can_type == GetASTContext()->TheUnknownObjectType.getPointer())
      return true;
    if (can_type == GetASTContext()->TheNativeObjectType.getPointer())
      return true;
    if (can_type == GetASTContext()->TheBridgeObjectType.getPointer())
      return true;
  }

  if (dynamic_pointee_type)
    dynamic_pointee_type->Clear();
  return false;
}

bool SwiftASTContext::IsScalarType(void *type) {
  if (!type)
    return false;

  return (GetTypeInfo(type, nullptr) & eTypeIsScalar) != 0;
}

bool SwiftASTContext::IsTypedefType(void *type) {
  if (!type)
    return false;
  swift::Type swift_type(GetSwiftType(type));
  return swift::isa<swift::NameAliasType>(swift_type.getPointer());
}

bool SwiftASTContext::IsVoidType(void *type) {
  VALID_OR_RETURN(false);

  if (!type)
    return false;
  return type == GetASTContext()->TheEmptyTupleType.getPointer();
}

bool SwiftASTContext::IsArchetypeType(const CompilerType &compiler_type) {
  if (!compiler_type.IsValid())
    return false;

  if (llvm::dyn_cast_or_null<SwiftASTContext>(compiler_type.GetTypeSystem())) {
    swift::Type swift_type(GetSwiftType(compiler_type));
    return swift_type->is<swift::ArchetypeType>();
  }
  return false;
}

bool SwiftASTContext::IsSelfArchetypeType(const CompilerType &compiler_type) {
  if (!compiler_type.IsValid())
    return false;

  if (llvm::dyn_cast_or_null<SwiftASTContext>(compiler_type.GetTypeSystem())) {
    if (swift::isa<swift::ArchetypeType>(
        (swift::TypeBase *)compiler_type.GetOpaqueQualType())) {
      // Hack: Just assume if we have an archetype as the type of 'self',
      // it's going to be a protocol 'Self' type.
      return true;
    }
  }
  return false;
}

bool SwiftASTContext::IsPossibleZeroSizeType(
    const CompilerType &compiler_type) {
  if (!compiler_type.IsValid())
    return false;

  if (auto ast = llvm::dyn_cast_or_null<SwiftASTContext>(
          compiler_type.GetTypeSystem()))
    return ast
        ->GetExtraTypeInformation(
            GetCanonicalSwiftType(compiler_type).getPointer())
        .m_flags.m_is_zero_size;
  return false;
}

bool SwiftASTContext::IsErrorType(const CompilerType &compiler_type) {
  if (compiler_type.IsValid() &&
      llvm::dyn_cast_or_null<SwiftASTContext>(compiler_type.GetTypeSystem())) {
    ProtocolInfo protocol_info;

    if (GetProtocolTypeInfo(compiler_type, protocol_info))
      return protocol_info.m_is_errortype;
    return false;
  }
  return false;
}

CompilerType
SwiftASTContext::GetReferentType(const CompilerType &compiler_type) {
  VALID_OR_RETURN(CompilerType());

  if (compiler_type.IsValid() &&
      llvm::dyn_cast_or_null<SwiftASTContext>(compiler_type.GetTypeSystem())) {
    swift::CanType swift_can_type(GetCanonicalSwiftType(compiler_type));
    auto ref_type = swift_can_type->getReferenceStorageReferent();
    return CompilerType(GetASTContext(), ref_type);
  }

  return CompilerType();
}

bool SwiftASTContext::IsTrivialOptionSetType(
    const CompilerType &compiler_type) {
  if (compiler_type.IsValid() &&
      llvm::dyn_cast_or_null<SwiftASTContext>(compiler_type.GetTypeSystem()))
    return GetExtraTypeInformation(compiler_type.GetOpaqueQualType())
        .m_flags.m_is_trivial_option_set;
  return false;
}

bool SwiftASTContext::IsFullyRealized(const CompilerType &compiler_type) {
  if (!compiler_type.IsValid())
    return false;

  if (auto ast = llvm::dyn_cast_or_null<SwiftASTContext>(
          compiler_type.GetTypeSystem())) {
    swift::CanType swift_can_type(GetCanonicalSwiftType(compiler_type));
    if (swift::isa<swift::MetatypeType>(swift_can_type))
      return true;
    return !swift_can_type->hasArchetype();
  }

  return false;
}

bool SwiftASTContext::GetProtocolTypeInfo(const CompilerType &type,
                                          ProtocolInfo &protocol_info) {
  if (auto ast =
          llvm::dyn_cast_or_null<SwiftASTContext>(type.GetTypeSystem())) {
    swift::CanType swift_can_type(GetCanonicalSwiftType(type));
    if (!swift_can_type.isExistentialType())
      return false;

    swift::ExistentialLayout layout = swift_can_type.getExistentialLayout();
    protocol_info.m_is_class_only = layout.requiresClass();
    protocol_info.m_num_protocols = layout.getProtocols().size();
    protocol_info.m_is_objc = layout.isObjC();
    protocol_info.m_is_anyobject = layout.isAnyObject();
    protocol_info.m_is_errortype = layout.isErrorExistential();

    unsigned num_witness_tables = 0;
    for (auto protoTy : layout.getProtocols()) {
      if (!protoTy->getDecl()->isObjC() &&
          !protoTy->isAnyObject())
        num_witness_tables++;
    }

    if (layout.isErrorExistential()) {
      // Error existential -- instance pointer only
      protocol_info.m_num_payload_words = 0;
      protocol_info.m_num_storage_words = 1;
    } else if (layout.requiresClass()) {
      // Class-constrained existential -- instance pointer plus witness tables
      protocol_info.m_num_payload_words = 0;
      protocol_info.m_num_storage_words = 1 + num_witness_tables;
    } else {
      // Opaque existential -- three words of inline storage, metadata and
      // witness tables
      protocol_info.m_num_payload_words = 3;
      protocol_info.m_num_storage_words = 3 + 1 + num_witness_tables;
    }

    return true;
  }

  return false;
}

bool SwiftASTContext::IsOptionalChain(CompilerType type,
                                      CompilerType &payload_type,
                                      uint32_t &depth) {
  auto is_optional = [](const CompilerType &type) -> bool {
    if (auto ast =
            llvm::dyn_cast_or_null<SwiftASTContext>(type.GetTypeSystem())) {
      if (auto swift_ast = ast->GetASTContext()) {
        swift::CanType swift_can_type(GetCanonicalSwiftType(type));
        if (swift_can_type.getAnyOptionalObjectType())
          return true;
        return false;
      }
    }
    return false;
  };

  depth = 0;

  while (is_optional(type)) {
    ++depth;
    lldb::TemplateArgumentKind kind;
    type = type.GetTemplateArgument(0, kind);
  }

  if (depth > 0) {
    payload_type = type;
    return true;
  } else
    return false;
}

SwiftASTContext::TypeAllocationStrategy
SwiftASTContext::GetAllocationStrategy(const CompilerType &type) {
  if (auto ast =
          llvm::dyn_cast_or_null<SwiftASTContext>(type.GetTypeSystem())) {
    const swift::irgen::TypeInfo *type_info =
        ast->GetSwiftTypeInfo(type.GetOpaqueQualType());
    if (!type_info)
      return TypeAllocationStrategy::eUnknown;
    switch (type_info->getFixedPacking(ast->GetIRGenModule())) {
    case swift::irgen::FixedPacking::OffsetZero:
      return TypeAllocationStrategy::eInline;
    case swift::irgen::FixedPacking::Allocate:
      return TypeAllocationStrategy::ePointer;
    case swift::irgen::FixedPacking::Dynamic:
      return TypeAllocationStrategy::eDynamic;
    default:
      break;
    }
  }

  return TypeAllocationStrategy::eUnknown;
}

bool SwiftASTContext::IsBeingDefined(void *type) { return false; }

bool SwiftASTContext::IsObjCObjectPointerType(const CompilerType &type,
                                              CompilerType *class_type_ptr) {
  if (!type)
    return false;

  swift::CanType swift_can_type(GetCanonicalSwiftType(type));
  const swift::TypeKind type_kind = swift_can_type->getKind();
  if (type_kind == swift::TypeKind::BuiltinNativeObject ||
      type_kind == swift::TypeKind::BuiltinUnknownObject)
    return true;

  if (class_type_ptr)
    class_type_ptr->Clear();
  return false;
}

//----------------------------------------------------------------------
// Type Completion
//----------------------------------------------------------------------

bool SwiftASTContext::GetCompleteType(void *type) { return true; }

ConstString SwiftASTContext::GetTypeName(void *type) {
  std::string type_name;
  if (type) {
    swift::Type swift_type(GetSwiftType(type));

    swift::Type normalized_type =
        swift_type.transform([](swift::Type type) -> swift::Type {
          if (swift::SyntaxSugarType *syntax_sugar_type =
                  swift::dyn_cast<swift::SyntaxSugarType>(type.getPointer())) {
            return syntax_sugar_type->getSinglyDesugaredType();
          }
          if (swift::DictionaryType *dictionary_type =
                  swift::dyn_cast<swift::DictionaryType>(type.getPointer())) {
            return dictionary_type->getSinglyDesugaredType();
          }
          return type;
        });

    swift::PrintOptions print_options;
    print_options.FullyQualifiedTypes = true;
    print_options.SynthesizeSugarOnTypes = false;
    type_name = normalized_type.getString(print_options);
  }
  return ConstString(type_name);
}

ConstString SwiftASTContext::GetDisplayTypeName(void *type) {
  std::string type_name(GetTypeName(type).AsCString(""));

  if (type) {
    swift::Type swift_type(GetSwiftType(type));

    swift::PrintOptions print_options;
    print_options.FullyQualifiedTypes = false;
    print_options.SynthesizeSugarOnTypes = true;
    print_options.FullyQualifiedTypesIfAmbiguous = true;
    type_name = swift_type.getString(print_options);
  }

  return ConstString(type_name);
}

ConstString SwiftASTContext::GetTypeSymbolName(void *type) {
  swift::Type swift_type(GetSwiftType(type));
  return GetTypeName(swift_type->getWithoutParens().getPointer());
}

ConstString SwiftASTContext::GetMangledTypeName(void *type) {
  return GetMangledTypeName(GetSwiftType(type).getPointer());
}

uint32_t
SwiftASTContext::GetTypeInfo(void *type,
                             CompilerType *pointee_or_element_clang_type) {
  VALID_OR_RETURN(0);

  if (!type)
    return 0;

  if (pointee_or_element_clang_type)
    pointee_or_element_clang_type->Clear();

  swift::CanType swift_can_type(GetCanonicalSwiftType(type));
  const swift::TypeKind type_kind = swift_can_type->getKind();
  uint32_t swift_flags = eTypeIsSwift;
  switch (type_kind) {
  case swift::TypeKind::DependentMember:
  case swift::TypeKind::Error:
  case swift::TypeKind::GenericTypeParam:
  case swift::TypeKind::Module:
  case swift::TypeKind::TypeVariable:
    break;
  case swift::TypeKind::UnboundGeneric:
    swift_flags |= eTypeIsGeneric;
    break;

  case swift::TypeKind::GenericFunction:
    swift_flags |= eTypeIsGeneric;
  case swift::TypeKind::Function:
    swift_flags |=
        eTypeIsBuiltIn | eTypeHasValue | eTypeIsScalar | eTypeInstanceIsPointer;
    break;
  case swift::TypeKind::BuiltinInteger:
    swift_flags |=
        eTypeIsBuiltIn | eTypeHasValue | eTypeIsScalar | eTypeIsInteger;
    break;
  case swift::TypeKind::BuiltinFloat:
    swift_flags |=
        eTypeIsBuiltIn | eTypeHasValue | eTypeIsScalar | eTypeIsFloat;
    break;
  case swift::TypeKind::BuiltinRawPointer:
    swift_flags |= eTypeIsBuiltIn | eTypeHasChildren | eTypeIsPointer |
                   eTypeIsScalar | eTypeHasValue;
    break;
  case swift::TypeKind::BuiltinNativeObject:
    swift_flags |= eTypeIsBuiltIn | eTypeHasChildren | eTypeIsPointer |
                   eTypeIsScalar | eTypeHasValue;
    break;
  case swift::TypeKind::BuiltinUnknownObject:
    swift_flags |= eTypeIsBuiltIn | eTypeHasChildren | eTypeIsPointer |
                   eTypeIsScalar | eTypeHasValue | eTypeIsObjC;
    break;
  case swift::TypeKind::BuiltinBridgeObject:
    swift_flags |= eTypeIsBuiltIn | eTypeHasChildren | eTypeIsPointer |
                   eTypeIsScalar | eTypeHasValue | eTypeIsObjC;
    break;
  case swift::TypeKind::BuiltinUnsafeValueBuffer:
    swift_flags |=
        eTypeIsBuiltIn | eTypeIsPointer | eTypeIsScalar | eTypeHasValue;
    break;
  case swift::TypeKind::BuiltinVector:
    // TODO: OR in eTypeIsFloat or eTypeIsInteger as needed
    return eTypeIsBuiltIn | eTypeHasChildren | eTypeIsVector;
    break;

  case swift::TypeKind::Tuple:
    swift_flags |= eTypeHasChildren | eTypeIsTuple;
    break;
  case swift::TypeKind::UnmanagedStorage:
  case swift::TypeKind::UnownedStorage:
  case swift::TypeKind::WeakStorage:
    swift_flags |=
        CompilerType(GetASTContext(),
                     swift_can_type->getReferenceStorageReferent())
            .GetTypeInfo(pointee_or_element_clang_type);
    break;
  case swift::TypeKind::BoundGenericEnum:
    swift_flags |= eTypeIsGeneric | eTypeIsBound;
  case swift::TypeKind::Enum: {
    SwiftEnumDescriptor *cached_enum_info = GetCachedEnumInfo(type);
    if (cached_enum_info) {
      if (cached_enum_info->GetNumElementsWithPayload() == 0)
        swift_flags |= eTypeHasValue | eTypeIsEnumeration;
      else
        swift_flags |= eTypeHasValue | eTypeIsEnumeration | eTypeHasChildren;
    } else
      swift_flags |= eTypeIsEnumeration;
  } break;

  case swift::TypeKind::BoundGenericStruct:
    swift_flags |= eTypeIsGeneric | eTypeIsBound;
  case swift::TypeKind::Struct:
    swift_flags |= eTypeHasChildren | eTypeIsStructUnion;
    break;

  case swift::TypeKind::BoundGenericClass:
    swift_flags |= eTypeIsGeneric | eTypeIsBound;
  case swift::TypeKind::Class:
    swift_flags |= eTypeHasChildren | eTypeIsClass | eTypeHasValue |
                   eTypeInstanceIsPointer;
    break;

  case swift::TypeKind::Protocol:
  case swift::TypeKind::ProtocolComposition:
    swift_flags |= eTypeHasChildren | eTypeIsStructUnion | eTypeIsProtocol;
    break;
  case swift::TypeKind::ExistentialMetatype:
  case swift::TypeKind::Metatype:
    swift_flags |= eTypeIsMetatype | eTypeHasValue;
    break;

  case swift::TypeKind::Archetype:
    swift_flags |=
        eTypeHasValue | eTypeIsScalar | eTypeIsPointer | eTypeIsArchetype;
    break;

  case swift::TypeKind::InOut:
  case swift::TypeKind::LValue:
    if (pointee_or_element_clang_type)
      *pointee_or_element_clang_type = GetNonReferenceType(type);
    swift_flags |= eTypeHasChildren | eTypeIsReference | eTypeHasValue;
    break;
  case swift::TypeKind::DynamicSelf:
  case swift::TypeKind::SILBox:
  case swift::TypeKind::SILFunction:
  case swift::TypeKind::SILBlockStorage:
  case swift::TypeKind::Unresolved:
    break;

  case swift::TypeKind::Optional:
  case swift::TypeKind::ImplicitlyUnwrappedOptional:
  case swift::TypeKind::NameAlias:
  case swift::TypeKind::Paren:
  case swift::TypeKind::Dictionary:
  case swift::TypeKind::ArraySlice:
    assert(false && "Not a canonical type");
    break;
  }
  return swift_flags;
}

lldb::LanguageType SwiftASTContext::GetMinimumLanguage(void *type) {
  if (!type)
    return lldb::eLanguageTypeC;

  return lldb::eLanguageTypeSwift;
}

lldb::TypeClass SwiftASTContext::GetTypeClass(void *type) {
  VALID_OR_RETURN(lldb::eTypeClassInvalid);

  if (!type)
    return lldb::eTypeClassInvalid;

  swift::CanType swift_can_type(GetCanonicalSwiftType(type));
  const swift::TypeKind type_kind = swift_can_type->getKind();
  switch (type_kind) {
  case swift::TypeKind::Error:
    return lldb::eTypeClassOther;
  case swift::TypeKind::BuiltinInteger:
    return lldb::eTypeClassBuiltin;
  case swift::TypeKind::BuiltinFloat:
    return lldb::eTypeClassBuiltin;
  case swift::TypeKind::BuiltinRawPointer:
    return lldb::eTypeClassBuiltin;
  case swift::TypeKind::BuiltinNativeObject:
    return lldb::eTypeClassBuiltin;
  case swift::TypeKind::BuiltinUnsafeValueBuffer:
    return lldb::eTypeClassBuiltin;
  case swift::TypeKind::BuiltinUnknownObject:
    return lldb::eTypeClassBuiltin;
  case swift::TypeKind::BuiltinBridgeObject:
    return lldb::eTypeClassBuiltin;
  case swift::TypeKind::BuiltinVector:
    return lldb::eTypeClassVector;
  case swift::TypeKind::Tuple:
    return lldb::eTypeClassArray;
  case swift::TypeKind::UnmanagedStorage:
  case swift::TypeKind::UnownedStorage:
  case swift::TypeKind::WeakStorage:
    return CompilerType(GetASTContext(),
                        swift_can_type->getReferenceStorageReferent())
        .GetTypeClass();
  case swift::TypeKind::GenericTypeParam:
    return lldb::eTypeClassOther;
  case swift::TypeKind::DependentMember:
    return lldb::eTypeClassOther;
  case swift::TypeKind::Enum:
    return lldb::eTypeClassUnion;
  case swift::TypeKind::Struct:
    return lldb::eTypeClassStruct;
  case swift::TypeKind::Class:
    return lldb::eTypeClassClass;
  case swift::TypeKind::Protocol:
    return lldb::eTypeClassOther;
  case swift::TypeKind::Metatype:
    return lldb::eTypeClassOther;
  case swift::TypeKind::Module:
    return lldb::eTypeClassOther;
  case swift::TypeKind::Archetype:
    return lldb::eTypeClassOther;
  case swift::TypeKind::Function:
    return lldb::eTypeClassFunction;
  case swift::TypeKind::GenericFunction:
    return lldb::eTypeClassFunction;
  case swift::TypeKind::ProtocolComposition:
    return lldb::eTypeClassOther;
  case swift::TypeKind::LValue:
    return lldb::eTypeClassReference;
  case swift::TypeKind::UnboundGeneric:
    return lldb::eTypeClassOther;
  case swift::TypeKind::BoundGenericClass:
    return lldb::eTypeClassClass;
  case swift::TypeKind::BoundGenericEnum:
    return lldb::eTypeClassUnion;
  case swift::TypeKind::BoundGenericStruct:
    return lldb::eTypeClassStruct;
  case swift::TypeKind::TypeVariable:
    return lldb::eTypeClassOther;
  case swift::TypeKind::ExistentialMetatype:
    return lldb::eTypeClassOther;
  case swift::TypeKind::DynamicSelf:
    return lldb::eTypeClassOther;
  case swift::TypeKind::SILBox:
    return lldb::eTypeClassOther;
  case swift::TypeKind::SILFunction:
    return lldb::eTypeClassFunction;
  case swift::TypeKind::SILBlockStorage:
    return lldb::eTypeClassOther;
  case swift::TypeKind::InOut:
    return lldb::eTypeClassOther;
  case swift::TypeKind::Unresolved:
    return lldb::eTypeClassOther;

  case swift::TypeKind::Optional:
  case swift::TypeKind::ImplicitlyUnwrappedOptional:
  case swift::TypeKind::NameAlias:
  case swift::TypeKind::Paren:
  case swift::TypeKind::Dictionary:
  case swift::TypeKind::ArraySlice:
    assert(false && "Not a canonical type");
    break;
  }

  return lldb::eTypeClassOther;
}

unsigned SwiftASTContext::GetTypeQualifiers(void *type) { return 0; }

//----------------------------------------------------------------------
// Creating related types
//----------------------------------------------------------------------

CompilerType SwiftASTContext::GetArrayElementType(void *type,
                                                  uint64_t *stride) {
  VALID_OR_RETURN(CompilerType());

  CompilerType element_type;
  if (type) {
    swift::CanType swift_type(GetCanonicalSwiftType(type));
    // There are a couple of structs that mean "Array" in Swift:
    // Array<T>
    // NativeArray<T>
    // Slice<T>
    // Treat them as arrays for convenience sake.
    swift::BoundGenericStructType *boundGenericStructType(
        swift_type->getAs<swift::BoundGenericStructType>());
    if (boundGenericStructType) {
      auto args = boundGenericStructType->getGenericArgs();
      swift::StructDecl *decl = boundGenericStructType->getDecl();
      if (args.size() == 1 &&
          decl->getModuleContext()->isStdlibModule()) {
        const char *declname = decl->getName().get();
        if (0 == strcmp(declname, "NativeArray") ||
            0 == strcmp(declname, "Array") || 0 == strcmp(declname, "ArraySlice"))
          element_type = CompilerType(GetASTContext(), args[0].getPointer());
      }
    }
  }
  return element_type;
}

CompilerType SwiftASTContext::GetCanonicalType(void *type) {
  VALID_OR_RETURN(CompilerType());

  if (type)
    return CompilerType(GetASTContext(),
                        GetCanonicalSwiftType(type).getPointer());
  return CompilerType();
}

CompilerType SwiftASTContext::GetInstanceType(void *type) {
  VALID_OR_RETURN(CompilerType());

  if (!type)
    return CompilerType();

  swift::CanType swift_can_type(GetCanonicalSwiftType(type));
  switch (swift_can_type->getKind()) {
  case swift::TypeKind::ExistentialMetatype:
  case swift::TypeKind::Metatype: {
    auto metatype_type =
        swift::dyn_cast<swift::AnyMetatypeType>(swift_can_type);
    if (metatype_type)
      return CompilerType(GetASTContext(),
                          metatype_type.getInstanceType().getPointer());
    return CompilerType();
  }
  default:
    break;
  }

  return CompilerType(GetASTContext(), GetSwiftType(type));
}

CompilerType SwiftASTContext::GetFullyUnqualifiedType(void *type) {
  VALID_OR_RETURN(CompilerType());

  return CompilerType(GetASTContext(), GetSwiftType(type));
}

int SwiftASTContext::GetFunctionArgumentCount(void *type) {
  return GetNumberOfFunctionArguments(type);
}

CompilerType SwiftASTContext::GetFunctionArgumentTypeAtIndex(void *type,
                                                             size_t idx) {
  return GetFunctionArgumentAtIndex(type, idx);
}

CompilerType SwiftASTContext::GetFunctionReturnType(void *type) {
  VALID_OR_RETURN(CompilerType());

  if (type) {
    auto func = swift::dyn_cast<swift::AnyFunctionType>(
        GetCanonicalSwiftType(type));
    if (func)
      return CompilerType(GetASTContext(), func.getResult().getPointer());
  }
  return CompilerType();
}

size_t SwiftASTContext::GetNumMemberFunctions(void *type) {
  size_t num_functions = 0;
  if (type) {
    swift::CanType swift_can_type(GetCanonicalSwiftType(type));

    auto nominal_decl = swift_can_type.getAnyNominal();
    if (nominal_decl) {
      auto iter = nominal_decl->getMembers().begin();
      auto end = nominal_decl->getMembers().end();
      for (; iter != end; iter++) {
        switch (iter->getKind()) {
        case swift::DeclKind::Constructor:
        case swift::DeclKind::Destructor:
        case swift::DeclKind::Func:
          num_functions += 1;
          break;
        default:
          break;
        }
      }
    }
  }
  return num_functions;
}

TypeMemberFunctionImpl SwiftASTContext::GetMemberFunctionAtIndex(void *type,
                                                                 size_t idx) {
  VALID_OR_RETURN(TypeMemberFunctionImpl());

  std::string name("");
  CompilerType result_type;
  MemberFunctionKind kind(MemberFunctionKind::eMemberFunctionKindUnknown);
  swift::AbstractFunctionDecl *the_decl_we_care_about = nullptr;
  if (type) {
    swift::CanType swift_can_type(GetCanonicalSwiftType(type));

    auto nominal_decl = swift_can_type.getAnyNominal();
    if (nominal_decl) {
      auto iter = nominal_decl->getMembers().begin();
      auto end = nominal_decl->getMembers().end();
      for (; iter != end; iter++) {
        auto decl_kind = iter->getKind();
        switch (decl_kind) {
        case swift::DeclKind::Constructor:
        case swift::DeclKind::Destructor:
        case swift::DeclKind::Func: {
          if (idx == 0) {
            swift::AbstractFunctionDecl *abstract_func_decl =
                llvm::dyn_cast_or_null<swift::AbstractFunctionDecl>(*iter);
            if (abstract_func_decl) {
              switch (decl_kind) {
              case swift::DeclKind::Constructor:
                name.clear();
                kind = lldb::eMemberFunctionKindConstructor;
                the_decl_we_care_about = abstract_func_decl;
                break;
              case swift::DeclKind::Destructor:
                name.clear();
                kind = lldb::eMemberFunctionKindDestructor;
                the_decl_we_care_about = abstract_func_decl;
                break;
              case swift::DeclKind::Func:
              default: // I know that this can only be one of three kinds
                       // since I am here..
              {
                swift::FuncDecl *func_decl =
                    llvm::dyn_cast<swift::FuncDecl>(*iter);
                if (func_decl) {
                  if (func_decl->getName().empty())
                    name.clear();
                  else
                    name.assign(func_decl->getName().get());
                  if (func_decl->isStatic())
                    kind = lldb::eMemberFunctionKindStaticMethod;
                  else
                    kind = lldb::eMemberFunctionKindInstanceMethod;
                  the_decl_we_care_about = func_decl;
                }
              }
              }
              result_type =
                  CompilerType(GetASTContext(),
                               abstract_func_decl->getInterfaceType().getPointer());
            }
          } else
            --idx;
        } break;
        default:
          break;
        }
      }
    }
  }

  if (type && the_decl_we_care_about && (kind != eMemberFunctionKindUnknown))
    return TypeMemberFunctionImpl(
        result_type, CompilerDecl(this, the_decl_we_care_about), name, kind);

  return TypeMemberFunctionImpl();
}

CompilerType SwiftASTContext::GetLValueReferenceType(void *type) {
  VALID_OR_RETURN(CompilerType());

  if (type)
    return CompilerType(GetASTContext(),
                        swift::LValueType::get(GetSwiftType(type)));
  return CompilerType();
}

CompilerType SwiftASTContext::GetRValueReferenceType(void *type) {
  return CompilerType();
}

CompilerType SwiftASTContext::GetNonReferenceType(void *type) {
  VALID_OR_RETURN(CompilerType());

  if (type) {
    swift::CanType swift_can_type(GetCanonicalSwiftType(type));

    swift::LValueType *lvalue = swift_can_type->getAs<swift::LValueType>();
    if (lvalue)
      return CompilerType(GetASTContext(),
                          lvalue->getObjectType().getPointer());
    swift::InOutType *inout = swift_can_type->getAs<swift::InOutType>();
    if (inout)
        return CompilerType(GetASTContext(),
                            inout->getObjectType().getPointer());
  }
  return CompilerType();
}

CompilerType SwiftASTContext::GetPointeeType(void *type) {
  return CompilerType();
}

CompilerType SwiftASTContext::GetPointerType(void *type) {
  VALID_OR_RETURN(CompilerType());

  if (type) {
    swift::Type swift_type(::GetSwiftType(type));
    const swift::TypeKind type_kind = swift_type->getKind();
    if (type_kind == swift::TypeKind::BuiltinRawPointer)
      return CompilerType(GetASTContext(), swift_type);
    else if (type_kind == swift::TypeKind::Struct)
      return CompilerType(GetASTContext(), swift::InOutType::get(swift_type));
  }
  return CompilerType();
}

CompilerType SwiftASTContext::GetTypedefedType(void *type) {
  VALID_OR_RETURN(CompilerType());

  if (type) {
    swift::Type swift_type(::GetSwiftType(type));
    swift::NameAliasType *name_alias_type =
        swift::dyn_cast<swift::NameAliasType>(swift_type.getPointer());
    if (name_alias_type) {
      return CompilerType(GetASTContext(),
                          name_alias_type->getSinglyDesugaredType());
    }
  }

  return CompilerType();
}

CompilerType
SwiftASTContext::GetUnboundType(lldb::opaque_compiler_type_t type) {
  VALID_OR_RETURN(CompilerType());

  if (type) {
    swift::CanType swift_can_type(GetCanonicalSwiftType(type));
    swift::BoundGenericType *bound_generic_type =
        swift_can_type->getAs<swift::BoundGenericType>();
    if (bound_generic_type) {
      swift::NominalTypeDecl *nominal_type_decl = bound_generic_type->getDecl();
      if (nominal_type_decl)
        return CompilerType(GetASTContext(),
                            nominal_type_decl->getDeclaredType());
    }
  }

  return CompilerType(GetASTContext(), GetSwiftType(type));
}

//----------------------------------------------------------------------
// Create related types using the current type's AST
//----------------------------------------------------------------------

CompilerType SwiftASTContext::GetBasicTypeFromAST(lldb::BasicType basic_type) {
  return CompilerType();
}

CompilerType SwiftASTContext::GetIntTypeFromBitSize(size_t bit_size,
                                                    bool is_signed) {
  return CompilerType();
}

CompilerType SwiftASTContext::GetFloatTypeFromBitSize(size_t bit_size) {
  return CompilerType();
}

//----------------------------------------------------------------------
// Exploring the type
//----------------------------------------------------------------------

const swift::irgen::TypeInfo *
SwiftASTContext::GetSwiftTypeInfo(swift::Type container_type,
                                  swift::VarDecl *item_decl) {
  VALID_OR_RETURN(nullptr);

  if (container_type && item_decl) {
    auto &irgen_module = GetIRGenModule();
    swift::CanType container_can_type(
        GetCanonicalSwiftType(container_type.getPointer()));
    swift::SILType lowered_container_type =
        irgen_module.getLoweredType(container_can_type);
    swift::SILType lowered_field_type =
        lowered_container_type.getFieldType(item_decl, *GetSILModule());
    return &irgen_module.getTypeInfo(lowered_field_type);
  }

  return nullptr;
}

const swift::irgen::TypeInfo *SwiftASTContext::GetSwiftTypeInfo(void *type) {
  VALID_OR_RETURN(nullptr);

  if (type) {
    auto &irgen_module = GetIRGenModule();
    swift::CanType swift_can_type(GetCanonicalSwiftType(type));
    swift::SILType swift_sil_type = irgen_module.getLoweredType(
        swift_can_type);
    return &irgen_module.getTypeInfo(swift_sil_type);
  }
  return nullptr;
}

const swift::irgen::FixedTypeInfo *
SwiftASTContext::GetSwiftFixedTypeInfo(void *type) {
  VALID_OR_RETURN(nullptr);

  const swift::irgen::TypeInfo *type_info = GetSwiftTypeInfo(type);
  if (type_info) {
    if (type_info->isFixedSize())
      return swift::cast<const swift::irgen::FixedTypeInfo>(type_info);
  }
  return nullptr;
}

uint64_t SwiftASTContext::GetBitSize(lldb::opaque_compiler_type_t type,
                                     ExecutionContextScope *exe_scope) {
  if (type) {
    swift::CanType swift_can_type(GetCanonicalSwiftType(type));
    const swift::TypeKind type_kind = swift_can_type->getKind();
    switch (type_kind) {
    case swift::TypeKind::Archetype:
    case swift::TypeKind::LValue:
    case swift::TypeKind::UnboundGeneric:
    case swift::TypeKind::GenericFunction:
    case swift::TypeKind::Function:
      return GetPointerByteSize() * 8;
    default:
      break;
    }
    const swift::irgen::FixedTypeInfo *fixed_type_info =
        GetSwiftFixedTypeInfo(type);
    if (fixed_type_info)
      return fixed_type_info->getFixedSize().getValue() * 8;
  }
  return 0;
}

uint64_t SwiftASTContext::GetByteStride(lldb::opaque_compiler_type_t type) {
  if (type) {
    const swift::irgen::FixedTypeInfo *fixed_type_info =
        GetSwiftFixedTypeInfo(type);
    if (fixed_type_info)
      return fixed_type_info->getFixedStride().getValue();
  }
  return 0;
}

size_t SwiftASTContext::GetTypeBitAlign(void *type) {
  if (type) {
    const swift::irgen::FixedTypeInfo *fixed_type_info =
        GetSwiftFixedTypeInfo(type);
    if (fixed_type_info)
      return fixed_type_info->getFixedAlignment().getValue();
  }
  return 0;
}

lldb::Encoding SwiftASTContext::GetEncoding(void *type, uint64_t &count) {
  VALID_OR_RETURN(lldb::eEncodingInvalid);

  if (!type)
    return lldb::eEncodingInvalid;

  count = 1;
  swift::CanType swift_can_type(GetCanonicalSwiftType(type));

  const swift::TypeKind type_kind = swift_can_type->getKind();
  switch (type_kind) {
  case swift::TypeKind::Error:
    break;
  case swift::TypeKind::BuiltinInteger:
    return lldb::eEncodingSint; // TODO: detect if an integer is unsigned
  case swift::TypeKind::BuiltinFloat:
    return lldb::eEncodingIEEE754; // TODO: detect if an integer is unsigned

  case swift::TypeKind::Archetype:
  case swift::TypeKind::BuiltinRawPointer:
  case swift::TypeKind::BuiltinNativeObject:
  case swift::TypeKind::BuiltinUnsafeValueBuffer:
  case swift::TypeKind::BuiltinUnknownObject:
  case swift::TypeKind::BuiltinBridgeObject:
  case swift::TypeKind::Class: // Classes are pointers in swift...
  case swift::TypeKind::BoundGenericClass:
    return lldb::eEncodingUint;

  case swift::TypeKind::BuiltinVector:
    break;
  case swift::TypeKind::Tuple:
    break;
  case swift::TypeKind::UnmanagedStorage:
  case swift::TypeKind::UnownedStorage:
  case swift::TypeKind::WeakStorage:
    return CompilerType(GetASTContext(),
                        swift_can_type->getReferenceStorageReferent())
        .GetEncoding(count);
  case swift::TypeKind::GenericTypeParam:
  case swift::TypeKind::DependentMember:
    break;

  case swift::TypeKind::ExistentialMetatype:
  case swift::TypeKind::Metatype:
    return lldb::eEncodingUint;

  case swift::TypeKind::GenericFunction:
  case swift::TypeKind::Function:
    return lldb::eEncodingUint;

  case swift::TypeKind::Enum:
  case swift::TypeKind::BoundGenericEnum:
    break;

  case swift::TypeKind::Struct:
  case swift::TypeKind::Protocol:
  case swift::TypeKind::Module:
  case swift::TypeKind::ProtocolComposition:
    break;
  case swift::TypeKind::LValue:
    return lldb::eEncodingUint;
  case swift::TypeKind::UnboundGeneric:
  case swift::TypeKind::BoundGenericStruct:
  case swift::TypeKind::TypeVariable:
  case swift::TypeKind::DynamicSelf:
  case swift::TypeKind::SILBox:
  case swift::TypeKind::SILFunction:
  case swift::TypeKind::SILBlockStorage:
  case swift::TypeKind::InOut:
  case swift::TypeKind::Unresolved:
    break;

  case swift::TypeKind::Optional:
  case swift::TypeKind::ImplicitlyUnwrappedOptional:
  case swift::TypeKind::NameAlias:
  case swift::TypeKind::Paren:
  case swift::TypeKind::Dictionary:
  case swift::TypeKind::ArraySlice:
    assert(false && "Not a canonical type");
    break;
  }
  count = 0;
  return lldb::eEncodingInvalid;
}

lldb::Format SwiftASTContext::GetFormat(void *type) {
  VALID_OR_RETURN(lldb::eFormatInvalid);

  if (!type)
    return lldb::eFormatDefault;

  swift::CanType swift_can_type(GetCanonicalSwiftType(type));

  const swift::TypeKind type_kind = swift_can_type->getKind();
  switch (type_kind) {
  case swift::TypeKind::Error:
    break;
  case swift::TypeKind::BuiltinInteger:
    return eFormatDecimal; // TODO: detect if an integer is unsigned
  case swift::TypeKind::BuiltinFloat:
    return eFormatFloat; // TODO: detect if an integer is unsigned

  case swift::TypeKind::BuiltinRawPointer:
  case swift::TypeKind::BuiltinNativeObject:
  case swift::TypeKind::BuiltinUnknownObject:
  case swift::TypeKind::BuiltinUnsafeValueBuffer:
  case swift::TypeKind::BuiltinBridgeObject:
  case swift::TypeKind::Archetype:
    return eFormatAddressInfo;

  // Classes are always pointers in swift...
  case swift::TypeKind::Class:
  case swift::TypeKind::BoundGenericClass:
    return eFormatHex;

  case swift::TypeKind::BuiltinVector:
    break;
  case swift::TypeKind::Tuple:
    break;
  case swift::TypeKind::UnmanagedStorage:
  case swift::TypeKind::UnownedStorage:
  case swift::TypeKind::WeakStorage:
    return CompilerType(GetASTContext(),
                        swift_can_type->getReferenceStorageReferent())
        .GetFormat();
  case swift::TypeKind::GenericTypeParam:
  case swift::TypeKind::DependentMember:
    break;

  case swift::TypeKind::Enum:
  case swift::TypeKind::BoundGenericEnum:
    return eFormatUnsigned;

  case swift::TypeKind::GenericFunction:
  case swift::TypeKind::Function:
    return lldb::eFormatAddressInfo;

  case swift::TypeKind::Struct:
  case swift::TypeKind::Protocol:
  case swift::TypeKind::Metatype:
  case swift::TypeKind::Module:
  case swift::TypeKind::ProtocolComposition:
    break;
  case swift::TypeKind::LValue:
    return lldb::eFormatHex;
  case swift::TypeKind::UnboundGeneric:
  case swift::TypeKind::BoundGenericStruct:
  case swift::TypeKind::TypeVariable:
  case swift::TypeKind::ExistentialMetatype:
  case swift::TypeKind::DynamicSelf:
  case swift::TypeKind::SILBox:
  case swift::TypeKind::SILFunction:
  case swift::TypeKind::SILBlockStorage:
  case swift::TypeKind::InOut:
  case swift::TypeKind::Unresolved:
    break;

  case swift::TypeKind::Optional:
  case swift::TypeKind::ImplicitlyUnwrappedOptional:
  case swift::TypeKind::NameAlias:
  case swift::TypeKind::Paren:
  case swift::TypeKind::Dictionary:
  case swift::TypeKind::ArraySlice:
    assert(false && "Not a canonical type");
    break;
  }
  // We don't know hot to display this type...
  return lldb::eFormatBytes;
}

uint32_t SwiftASTContext::GetNumChildren(void *type,
                                         bool omit_empty_base_classes) {
  VALID_OR_RETURN(0);

  if (!type)
    return 0;

  uint32_t num_children = 0;

  swift::CanType swift_can_type(GetCanonicalSwiftType(type));

  const swift::TypeKind type_kind = swift_can_type->getKind();
  switch (type_kind) {
  case swift::TypeKind::Error:
  case swift::TypeKind::BuiltinInteger:
  case swift::TypeKind::BuiltinFloat:
  case swift::TypeKind::BuiltinRawPointer:
  case swift::TypeKind::BuiltinNativeObject:
  case swift::TypeKind::BuiltinUnknownObject:
  case swift::TypeKind::BuiltinUnsafeValueBuffer:
  case swift::TypeKind::BuiltinBridgeObject:
  case swift::TypeKind::BuiltinVector:
  case swift::TypeKind::Module:
  case swift::TypeKind::Function:
  case swift::TypeKind::GenericFunction:
  case swift::TypeKind::DynamicSelf:
  case swift::TypeKind::SILBox:
  case swift::TypeKind::SILFunction:
  case swift::TypeKind::InOut:
    break;
  case swift::TypeKind::UnmanagedStorage:
  case swift::TypeKind::UnownedStorage:
  case swift::TypeKind::WeakStorage:
    return CompilerType(GetASTContext(),
                        swift_can_type->getReferenceStorageReferent())
        .GetNumChildren(omit_empty_base_classes);
  case swift::TypeKind::GenericTypeParam:
  case swift::TypeKind::DependentMember:
    break;

  case swift::TypeKind::Enum:
  case swift::TypeKind::BoundGenericEnum: {
    SwiftEnumDescriptor *cached_enum_info = GetCachedEnumInfo(type);
    if (cached_enum_info)
      return cached_enum_info->GetNumElementsWithPayload();
  } break;

  case swift::TypeKind::Tuple:
  case swift::TypeKind::Struct:
  case swift::TypeKind::Class:
  case swift::TypeKind::BoundGenericClass:
  case swift::TypeKind::BoundGenericStruct:
  case swift::TypeKind::Protocol:
  case swift::TypeKind::ProtocolComposition:
  case swift::TypeKind::Archetype: {
    CachedMemberInfo *cached_member_info = GetCachedMemberInfo(type);
    if (cached_member_info)
      return cached_member_info->member_infos.size();
  } break;

  case swift::TypeKind::ExistentialMetatype:
  case swift::TypeKind::Metatype:
    return 0;

  case swift::TypeKind::LValue: {
    swift::LValueType *lvalue_type = swift_can_type->castTo<swift::LValueType>();
    swift::TypeBase *deref_type = lvalue_type->getObjectType().getPointer();

    uint32_t num_pointee_children =
        CompilerType(GetASTContext(), deref_type)
            .GetNumChildren(omit_empty_base_classes);
    // If this type points to a simple type (or to a class), then it has 1 child
    if (num_pointee_children == 0 || deref_type->getClassOrBoundGenericClass())
      num_children = 1;
    else
      num_children = num_pointee_children;
  } break;

  case swift::TypeKind::UnboundGeneric:
    break;
  case swift::TypeKind::TypeVariable:
    break;

  case swift::TypeKind::SILBlockStorage:
  case swift::TypeKind::Unresolved:
    break;

  case swift::TypeKind::Optional:
  case swift::TypeKind::ImplicitlyUnwrappedOptional:
  case swift::TypeKind::NameAlias:
  case swift::TypeKind::Paren:
  case swift::TypeKind::Dictionary:
  case swift::TypeKind::ArraySlice:
    assert(false && "Not a canonical type");
    break;
  }

  return num_children;
}

lldb::BasicType SwiftASTContext::GetBasicTypeEnumeration(void *type) {
  return eBasicTypeInvalid;
}

#pragma mark Aggregate Types

uint32_t SwiftASTContext::GetNumDirectBaseClasses(void *opaque_type) {
  if (!opaque_type)
    return 0;

  swift::CanType swift_can_type(GetCanonicalSwiftType(opaque_type));
  swift::ClassDecl *class_decl = swift_can_type->getClassOrBoundGenericClass();
  if (class_decl) {
    if (class_decl->hasSuperclass())
      return 1;
  }

  return 0;
}

uint32_t SwiftASTContext::GetNumVirtualBaseClasses(void *opaque_type) {
  return 0;
}

uint32_t SwiftASTContext::GetNumFields(void *type) {
  VALID_OR_RETURN(0);

  if (!type)
    return 0;

  uint32_t count = 0;

  swift::CanType swift_can_type(GetCanonicalSwiftType(type));

  const swift::TypeKind type_kind = swift_can_type->getKind();
  switch (type_kind) {
  case swift::TypeKind::Error:
  case swift::TypeKind::BuiltinInteger:
  case swift::TypeKind::BuiltinFloat:
  case swift::TypeKind::BuiltinRawPointer:
  case swift::TypeKind::BuiltinNativeObject:
  case swift::TypeKind::BuiltinUnknownObject:
  case swift::TypeKind::BuiltinUnsafeValueBuffer:
  case swift::TypeKind::BuiltinBridgeObject:
  case swift::TypeKind::BuiltinVector:
    break;
  case swift::TypeKind::UnmanagedStorage:
  case swift::TypeKind::UnownedStorage:
  case swift::TypeKind::WeakStorage:
    return CompilerType(GetASTContext(),
                        swift_can_type->getReferenceStorageReferent())
        .GetNumFields();
  case swift::TypeKind::GenericTypeParam:
  case swift::TypeKind::DependentMember:
    break;

  case swift::TypeKind::Enum:
  case swift::TypeKind::BoundGenericEnum: {
    SwiftEnumDescriptor *cached_enum_info = GetCachedEnumInfo(type);
    if (cached_enum_info)
      return cached_enum_info->GetNumElementsWithPayload();
  } break;

  case swift::TypeKind::Tuple:
  case swift::TypeKind::Struct:
  case swift::TypeKind::Class:
  case swift::TypeKind::Protocol:
  case swift::TypeKind::ProtocolComposition:
  case swift::TypeKind::BoundGenericClass:
  case swift::TypeKind::BoundGenericStruct: {
    CachedMemberInfo *cached_member_info = GetCachedMemberInfo(type);
    if (cached_member_info) {
      const size_t num_members = cached_member_info->member_infos.size();
      if (num_members > 0 &&
          cached_member_info->member_infos.front().member_type ==
              MemberType::BaseClass)
        return num_members - 1;
      else
        return num_members;
    }
  } break;

  case swift::TypeKind::ExistentialMetatype:
  case swift::TypeKind::Metatype:
    return 0;

  case swift::TypeKind::Module:
  case swift::TypeKind::Archetype:
  case swift::TypeKind::Function:
  case swift::TypeKind::GenericFunction:
  case swift::TypeKind::LValue:
  case swift::TypeKind::UnboundGeneric:
  case swift::TypeKind::TypeVariable:
  case swift::TypeKind::DynamicSelf:
  case swift::TypeKind::SILBox:
  case swift::TypeKind::SILFunction:
  case swift::TypeKind::SILBlockStorage:
  case swift::TypeKind::InOut:
  case swift::TypeKind::Unresolved:
    break;

  case swift::TypeKind::Optional:
  case swift::TypeKind::ImplicitlyUnwrappedOptional:
  case swift::TypeKind::NameAlias:
  case swift::TypeKind::Paren:
  case swift::TypeKind::Dictionary:
  case swift::TypeKind::ArraySlice:
    assert(false && "Not a canonical type");
    break;
  }

  return count;
}

CompilerType
SwiftASTContext::GetDirectBaseClassAtIndex(void *opaque_type, size_t idx,
                                           uint32_t *bit_offset_ptr) {
  VALID_OR_RETURN(CompilerType());

  if (opaque_type) {
    swift::CanType swift_can_type(GetCanonicalSwiftType(opaque_type));
    swift::ClassDecl *class_decl =
        swift_can_type->getClassOrBoundGenericClass();
    if (class_decl) {
      swift::Type base_class_type = class_decl->getSuperclass();
      if (base_class_type)
        return CompilerType(GetASTContext(), base_class_type.getPointer());
    }
  }
  return CompilerType();
}

CompilerType
SwiftASTContext::GetVirtualBaseClassAtIndex(void *opaque_type, size_t idx,
                                            uint32_t *bit_offset_ptr) {
  return CompilerType();
}

CompilerType SwiftASTContext::GetFieldAtIndex(void *type, size_t idx,
                                              std::string &name,
                                              uint64_t *bit_offset_ptr,
                                              uint32_t *bitfield_bit_size_ptr,
                                              bool *is_bitfield_ptr) {
  VALID_OR_RETURN(CompilerType());

  if (!type)
    return CompilerType();

  swift::CanType swift_can_type(GetCanonicalSwiftType(type));

  const swift::TypeKind type_kind = swift_can_type->getKind();
  switch (type_kind) {
  case swift::TypeKind::Error:
  case swift::TypeKind::BuiltinInteger:
  case swift::TypeKind::BuiltinFloat:
  case swift::TypeKind::BuiltinRawPointer:
  case swift::TypeKind::BuiltinNativeObject:
  case swift::TypeKind::BuiltinUnsafeValueBuffer:
  case swift::TypeKind::BuiltinUnknownObject:
  case swift::TypeKind::BuiltinBridgeObject:
  case swift::TypeKind::BuiltinVector:
    break;
  case swift::TypeKind::UnmanagedStorage:
  case swift::TypeKind::UnownedStorage:
  case swift::TypeKind::WeakStorage:
    return CompilerType(GetASTContext(),
                        swift_can_type->getReferenceStorageReferent())
        .GetFieldAtIndex(idx, name, bit_offset_ptr, bitfield_bit_size_ptr,
                         is_bitfield_ptr);
  case swift::TypeKind::GenericTypeParam:
  case swift::TypeKind::DependentMember:
    break;

  case swift::TypeKind::Enum:
  case swift::TypeKind::BoundGenericEnum: {
    SwiftEnumDescriptor *cached_enum_info = GetCachedEnumInfo(type);
    if (cached_enum_info &&
        idx < cached_enum_info->GetNumElementsWithPayload()) {
      const SwiftEnumDescriptor::ElementInfo *enum_element_info =
          cached_enum_info->GetElementWithPayloadAtIndex(idx);
      name.assign(enum_element_info->name.GetCString());
      if (bit_offset_ptr)
        *bit_offset_ptr = 0;
      if (bitfield_bit_size_ptr)
        *bitfield_bit_size_ptr = 0;
      if (is_bitfield_ptr)
        *is_bitfield_ptr = false;
      return enum_element_info->payload_type;
    }
  } break;

  case swift::TypeKind::Tuple:
  case swift::TypeKind::Struct:
  case swift::TypeKind::Class:
  case swift::TypeKind::Protocol:
  case swift::TypeKind::ProtocolComposition:
  case swift::TypeKind::BoundGenericClass:
  case swift::TypeKind::BoundGenericStruct: {
    CachedMemberInfo *cached_member_info = GetCachedMemberInfo(type);
    if (cached_member_info) {
      const size_t num_members = cached_member_info->member_infos.size();
      uint32_t actual_idx = idx;
      if (num_members > 0 &&
          cached_member_info->member_infos.front().member_type ==
              MemberType::BaseClass)
        ++actual_idx; // Skip base class since we are looking for fields only
      if (actual_idx < num_members) {
        if (cached_member_info->member_infos[actual_idx].name)
          name = cached_member_info->member_infos[actual_idx].name.GetCString();
        if (bit_offset_ptr)
          *bit_offset_ptr =
              cached_member_info->member_infos[actual_idx].byte_offset * 8;
        if (bitfield_bit_size_ptr)
          *bitfield_bit_size_ptr = 0;
        if (is_bitfield_ptr)
          *is_bitfield_ptr = false;
        return cached_member_info->member_infos[actual_idx].clang_type;
      }
    }
  } break;

  case swift::TypeKind::ExistentialMetatype:
  case swift::TypeKind::Metatype:
    break;

  case swift::TypeKind::Module:
  case swift::TypeKind::Archetype:
  case swift::TypeKind::Function:
  case swift::TypeKind::GenericFunction:
  case swift::TypeKind::LValue:
  case swift::TypeKind::UnboundGeneric:
  case swift::TypeKind::TypeVariable:
  case swift::TypeKind::DynamicSelf:
  case swift::TypeKind::SILBox:
  case swift::TypeKind::SILFunction:
  case swift::TypeKind::SILBlockStorage:
  case swift::TypeKind::InOut:
  case swift::TypeKind::Unresolved:
    break;

  case swift::TypeKind::Optional:
  case swift::TypeKind::ImplicitlyUnwrappedOptional:
  case swift::TypeKind::NameAlias:
  case swift::TypeKind::Paren:
  case swift::TypeKind::Dictionary:
  case swift::TypeKind::ArraySlice:
    assert(false && "Not a canonical type");
    break;
  }

  return CompilerType();
}

// If a pointer to a pointee type (the clang_type arg) says that it has no
// children, then we either need to trust it, or override it and return a
// different result. For example, an "int *" has one child that is an integer,
// but a function pointer doesn't have any children. Likewise if a Record type
// claims it has no children, then there really is nothing to show.
uint32_t SwiftASTContext::GetNumPointeeChildren(void *type) {
  if (!type)
    return 0;

  swift::CanType swift_can_type(GetCanonicalSwiftType(type));

  const swift::TypeKind type_kind = swift_can_type->getKind();
  switch (type_kind) {
  case swift::TypeKind::Error:
    return 0;
  case swift::TypeKind::BuiltinInteger:
    return 1;
  case swift::TypeKind::BuiltinFloat:
    return 1;
  case swift::TypeKind::BuiltinRawPointer:
    return 1;
  case swift::TypeKind::BuiltinUnsafeValueBuffer:
    return 1;
  case swift::TypeKind::BuiltinNativeObject:
    return 1;
  case swift::TypeKind::BuiltinUnknownObject:
    return 1;
  case swift::TypeKind::BuiltinBridgeObject:
    return 1;
  case swift::TypeKind::BuiltinVector:
    return 0;
  case swift::TypeKind::UnmanagedStorage:
  case swift::TypeKind::UnownedStorage:
  case swift::TypeKind::WeakStorage:
    return GetNumPointeeChildren(
        swift::cast<swift::ReferenceStorageType>(swift_can_type)
            .getPointer());
  case swift::TypeKind::Tuple:
    return 0;
  case swift::TypeKind::GenericTypeParam:
    return 0;
  case swift::TypeKind::DependentMember:
    return 0;
  case swift::TypeKind::Enum:
    return 0;
  case swift::TypeKind::Struct:
    return 0;
  case swift::TypeKind::Class:
    return 0;
  case swift::TypeKind::Protocol:
    return 0;
  case swift::TypeKind::Metatype:
    return 0;
  case swift::TypeKind::Module:
    return 0;
  case swift::TypeKind::Archetype:
    return 0;
  case swift::TypeKind::Function:
    return 0;
  case swift::TypeKind::GenericFunction:
    return 0;
  case swift::TypeKind::ProtocolComposition:
    return 0;
  case swift::TypeKind::LValue:
    return 1;
  case swift::TypeKind::UnboundGeneric:
    return 0;
  case swift::TypeKind::BoundGenericClass:
    return 0;
  case swift::TypeKind::BoundGenericEnum:
    return 0;
  case swift::TypeKind::BoundGenericStruct:
    return 0;
  case swift::TypeKind::TypeVariable:
    return 0;
  case swift::TypeKind::ExistentialMetatype:
    return 0;
  case swift::TypeKind::DynamicSelf:
    return 0;
  case swift::TypeKind::SILBox:
    return 0;
  case swift::TypeKind::SILFunction:
    return 0;
  case swift::TypeKind::SILBlockStorage:
    return 0;
  case swift::TypeKind::InOut:
    return 0;
  case swift::TypeKind::Unresolved:
    return 0;

  case swift::TypeKind::Optional:
  case swift::TypeKind::ImplicitlyUnwrappedOptional:
  case swift::TypeKind::NameAlias:
  case swift::TypeKind::Paren:
  case swift::TypeKind::Dictionary:
  case swift::TypeKind::ArraySlice:
    assert(false && "Not a canonical type");
    break;
  }

  return 0;
}

static int64_t GetInstanceVariableOffset_Symbol(ExecutionContext *exe_ctx,
                                                const CompilerType &type,
                                                const char *ivar_name,
                                                const CompilerType &ivar_type) {
  Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_TYPES));

  ConstString class_name(type.GetTypeSymbolName());
  Target *target = exe_ctx->GetTargetPtr();

  if (log)
    log->Printf("[GetInstanceVariableOffset_Symbol] ivar_name = %s, type = %s "
                "class_name = %s",
                ivar_name, type.GetTypeName().AsCString(),
                class_name.AsCString());

  if (target && class_name && ivar_type.IsValid() && ivar_name) {
    swift::NominalTypeDecl *nominal_decl =
        GetSwiftType(type)->getNominalOrBoundGenericNominal();

    if (nominal_decl) {
      swift::ValueDecl *the_value_decl = nullptr;
      SwiftASTContext *swift_ast_ctx =
          llvm::dyn_cast_or_null<SwiftASTContext>(type.GetTypeSystem());

      auto decls = nominal_decl->lookupDirect(swift::DeclName(
          swift_ast_ctx->GetASTContext()->getIdentifier(ivar_name)));
      for (auto &decl : decls) {
        swift::VarDecl *var_decl = llvm::dyn_cast_or_null<swift::VarDecl>(decl);
        if (var_decl && var_decl->hasStorage()) {
          the_value_decl = var_decl;
          break;
        }
      }

      if (the_value_decl) {
        swift::irgen::IRGenMangler mangler;
        std::string buffer = mangler.mangleFieldOffsetFull(the_value_decl, false);

        StreamString symbol_name;
        symbol_name.Printf("%s", buffer.c_str());
        ConstString ivar_const_str(symbol_name.GetString());

        lldb::addr_t ivar_offset_ptr =
            target->FindLoadAddrForNameInSymbolsAndPersistentVariables(
                ivar_const_str, eSymbolTypeIVarOffset);

        if (log)
          log->Printf("[GetInstanceVariableOffset_Symbol] symbol_name = %s "
                      "ivar_offset_ptr = 0x%" PRIx64,
                      ivar_const_str.AsCString(), ivar_offset_ptr);

        if (ivar_offset_ptr != LLDB_INVALID_ADDRESS) {
          Status error;
          return target->ReadUnsignedIntegerFromMemory(
              ivar_offset_ptr,
              false,                     // prefer_file_cache
              type.GetPointerByteSize(), // byte size of integer to read
              LLDB_INVALID_IVAR_OFFSET, error);
        }
      } else if (log)
        log->Printf("[GetInstanceVariableOffset_Symbol] no the_value_decl");
    } else if (log)
      log->Printf("[GetInstanceVariableOffset_Symbol] no nominal_decl");
  }
  return LLDB_INVALID_IVAR_OFFSET;
}

static int64_t GetInstanceVariableOffset_Metadata(
    ValueObject *valobj, ExecutionContext *exe_ctx, const CompilerType &type,
    ConstString ivar_name, const CompilerType &ivar_type) {
  Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_TYPES));
  if (log)
    log->Printf(
        "[GetInstanceVariableOffset_Metadata] ivar_name = %s, type = %s",
        ivar_name.AsCString(), type.GetTypeName().AsCString());

  Process *process = exe_ctx->GetProcessPtr();
  if (process) {
    SwiftLanguageRuntime *runtime = process->GetSwiftLanguageRuntime();
    if (runtime) {
      if (auto resolver_sp = runtime->GetMemberVariableOffsetResolver(type)) {
        Status error;
        if (auto result = resolver_sp->ResolveOffset(valobj, ivar_name, &error))
          return result.getValue();
        else if (log)
          log->Printf(
              "[GetInstanceVariableOffset_Metadata] resolver failure: %s",
              error.AsCString());
      } else if (log)
        log->Printf("[GetInstanceVariableOffset_Metadata] no offset resolver");
    } else if (log)
      log->Printf("[GetInstanceVariableOffset_Metadata] no runtime");
  } else if (log)
    log->Printf("[GetInstanceVariableOffset_Metadata] no process");
  return LLDB_INVALID_IVAR_OFFSET;
}

static int64_t GetInstanceVariableOffset(ValueObject *valobj,
                                         ExecutionContext *exe_ctx,
                                         const CompilerType &class_type,
                                         const char *ivar_name,
                                         const CompilerType &ivar_type) {
  int64_t offset = LLDB_INVALID_IVAR_OFFSET;

  if (ivar_name && ivar_name[0]) {
    if (exe_ctx) {
      Target *target = exe_ctx->GetTargetPtr();
      if (target) {
        // Given a type there are three cases:
        //   non generic type - field offset symbols are emitted
        //   generic type:
        //     iVar offsets depend on the type arguments - no field offsets
        //     emitted
        //     iVar offsets do not depend on the type arguments - field offsets
        //     emitted for the *unbound* type

        bool is_generic = (class_type.GetTypeInfo() & eTypeIsGeneric);

        bool try_symbol = false;
        bool try_metadata = true;

        if (!is_generic)
          try_symbol = true;

        if (try_symbol) {
          offset = GetInstanceVariableOffset_Symbol(exe_ctx, class_type,
                                                    ivar_name, ivar_type);
          if (offset != LLDB_INVALID_IVAR_OFFSET)
            return offset;
        }

        if (try_metadata) {
          offset = GetInstanceVariableOffset_Symbol(exe_ctx, class_type,
                                                    ivar_name, ivar_type);
          if (offset == LLDB_INVALID_IVAR_OFFSET)
            offset = GetInstanceVariableOffset_Metadata(
                valobj, exe_ctx, class_type, ConstString(ivar_name), ivar_type);
        }
      }
    }
  }
  return offset;
}

bool SwiftASTContext::IsNonTriviallyManagedReferenceType(
    const CompilerType &type, NonTriviallyManagedReferenceStrategy &strategy,
    CompilerType *underlying_type) {
  if (auto ast =
          llvm::dyn_cast_or_null<SwiftASTContext>(type.GetTypeSystem())) {
    swift::CanType swift_can_type(GetCanonicalSwiftType(type));

    const swift::TypeKind type_kind = swift_can_type->getKind();
    switch (type_kind) {
    default:
      break;
    case swift::TypeKind::UnmanagedStorage: {
      strategy = NonTriviallyManagedReferenceStrategy::eUnmanaged;
      if (underlying_type)
        *underlying_type = CompilerType(
            ast, swift_can_type->getReferenceStorageReferent()
              .getPointer());
    }
      return true;
    case swift::TypeKind::UnownedStorage: {
      strategy = NonTriviallyManagedReferenceStrategy::eUnowned;
      if (underlying_type)
        *underlying_type = CompilerType(
            ast, swift_can_type->getReferenceStorageReferent()
              .getPointer());
    }
      return true;
    case swift::TypeKind::WeakStorage: {
      strategy = NonTriviallyManagedReferenceStrategy::eWeak;
      if (underlying_type)
        *underlying_type = CompilerType(
            ast, swift_can_type->getReferenceStorageReferent()
              .getPointer());
    }
      return true;
    }
  }
  return false;
}

CompilerType SwiftASTContext::GetChildCompilerTypeAtIndex(
    void *type, ExecutionContext *exe_ctx, size_t idx,
    bool transparent_pointers, bool omit_empty_base_classes,
    bool ignore_array_bounds, std::string &child_name,
    uint32_t &child_byte_size, int32_t &child_byte_offset,
    uint32_t &child_bitfield_bit_size, uint32_t &child_bitfield_bit_offset,
    bool &child_is_base_class, bool &child_is_deref_of_parent,
    ValueObject *valobj, uint64_t &language_flags) {
  VALID_OR_RETURN(CompilerType());

  if (!type)
    return CompilerType();

  language_flags = 0;

  swift::CanType swift_can_type(GetCanonicalSwiftType(type));

  const swift::TypeKind type_kind = swift_can_type->getKind();
  switch (type_kind) {
  case swift::TypeKind::Error:
  case swift::TypeKind::BuiltinInteger:
  case swift::TypeKind::BuiltinFloat:
  case swift::TypeKind::BuiltinRawPointer:
  case swift::TypeKind::BuiltinNativeObject:
  case swift::TypeKind::BuiltinUnknownObject:
  case swift::TypeKind::BuiltinUnsafeValueBuffer:
  case swift::TypeKind::BuiltinBridgeObject:
  case swift::TypeKind::BuiltinVector:

  //            case swift::TypeKind::Tuple:
  //                {
  //                    swift::TupleType *tuple_type =
  //                    swift_can_type->getAs<swift::TupleType>();
  //                    if (tuple_type && idx < tuple_type->getNumElements())
  //                    {
  //                        child_byte_offset = 0; // TODO: figure out how to
  //                        get byte offset of tuple field...
  //                        child_bitfield_bit_size = 0;
  //                        child_bitfield_bit_offset = 0;
  //                        child_is_base_class = false;
  //                        child_is_deref_of_parent = false;
  //
  //                        uint32_t tuple_idx = 0;
  //                        for (auto tuple_field : tuple_type->getFields())
  //                        {
  //                            CompilerType tuple_field_type(m_swift_ast,
  //                            tuple_field.getType().getPointer());
  //                            auto tuple_field_byte_size =
  //                            tuple_field_type.GetByteSize();
  //
  //                            if (tuple_idx == idx)
  //                            {
  //                                child_byte_size = tuple_field_byte_size;
  //                                const char *tuple_name =
  //                                tuple_field.getName().get();
  //                                if (tuple_name)
  //                                {
  //                                    child_name = tuple_name;
  //                                }
  //                                else
  //                                {
  //                                    StreamString tuple_name_strm;
  //                                    tuple_name_strm.Printf("%u",
  //                                    (uint32_t)idx);
  //                                    child_name =
  //                                    std::move(tuple_name_strm.GetString());
  //                                }
  //                                return tuple_field_type;
  //                            }
  //                            else
  //                            {
  //                                const uint64_t tuple_field_bit_size =
  //                                tuple_field_byte_size * 8;
  //                                const uint64_t tuple_aligned_bit_size =
  //                                tuple_field_type.GetAlignedBitSize();
  //                                child_byte_offset +=
  //                                llvm::RoundUpToAlignment(tuple_field_bit_size,
  //                                tuple_aligned_bit_size) / 8;
  //                                ++tuple_idx;
  //                            }
  //                        }
  //                    }
  //                }
  //                break;
  case swift::TypeKind::UnmanagedStorage:
  case swift::TypeKind::UnownedStorage:
  case swift::TypeKind::WeakStorage:
    return CompilerType(GetASTContext(),
                        swift_can_type->getReferenceStorageReferent())
        .GetChildCompilerTypeAtIndex(
            exe_ctx, idx, transparent_pointers, omit_empty_base_classes,
            ignore_array_bounds, child_name, child_byte_size, child_byte_offset,
            child_bitfield_bit_size, child_bitfield_bit_offset,
            child_is_base_class, child_is_deref_of_parent, valobj,
            language_flags);
  case swift::TypeKind::GenericTypeParam:
  case swift::TypeKind::DependentMember:
    break;

  case swift::TypeKind::Enum:
  case swift::TypeKind::BoundGenericEnum: {
    SwiftEnumDescriptor *cached_enum_info = GetCachedEnumInfo(type);
    if (cached_enum_info &&
        idx < cached_enum_info->GetNumElementsWithPayload()) {
      const SwiftEnumDescriptor::ElementInfo *element_info =
          cached_enum_info->GetElementWithPayloadAtIndex(idx);
      child_name.assign(element_info->name.GetCString());
      child_byte_size = element_info->payload_type.GetByteSize(
          exe_ctx ? exe_ctx->GetBestExecutionContextScope() : NULL);
      child_byte_offset = 0;
      child_bitfield_bit_size = 0;
      child_bitfield_bit_offset = 0;
      child_is_base_class = false;
      child_is_deref_of_parent = false;
      if (element_info->is_indirect) {
        language_flags |= LanguageFlags::eIsIndirectEnumCase;
        return CompilerType(GetASTContext(),
                            GetASTContext()->TheRawPointerType.getPointer());
      } else
        return element_info->payload_type;
    }
  } break;

  case swift::TypeKind::Tuple:
  case swift::TypeKind::Struct:
  case swift::TypeKind::Class:
  case swift::TypeKind::BoundGenericClass:
  case swift::TypeKind::BoundGenericStruct:
  case swift::TypeKind::Protocol:
  case swift::TypeKind::ProtocolComposition: {
    CachedMemberInfo *cached_member_info = GetCachedMemberInfo(type);
    if (cached_member_info) {
      const size_t num_members = cached_member_info->member_infos.size();
      if (idx < num_members) {
        if (cached_member_info->member_infos[idx].name)
          child_name = cached_member_info->member_infos[idx].name.GetCString();
        else
          child_name.clear();
        child_byte_size = cached_member_info->member_infos[idx].byte_size;
        // Check for fragile ivar offsets and look them up and cache them.
        if (cached_member_info->member_infos[idx].is_fragile &&
            cached_member_info->member_infos[idx].byte_offset == 0) {
          CompilerType compiler_type(GetASTContext(), GetSwiftType(type));
          const int64_t fragile_ivar_offset = GetInstanceVariableOffset(
              valobj, exe_ctx, compiler_type, child_name.c_str(),
              cached_member_info->member_infos[idx].clang_type);
          if (fragile_ivar_offset != LLDB_INVALID_IVAR_OFFSET)
            cached_member_info->member_infos[idx].byte_offset =
                fragile_ivar_offset;
        }
        child_byte_offset = cached_member_info->member_infos[idx].byte_offset;
        child_bitfield_bit_size = 0;
        child_bitfield_bit_offset = 0;
        if ((child_is_base_class =
                 cached_member_info->member_infos[idx].member_type ==
                 MemberType::BaseClass)) {
          language_flags |= LanguageFlags::eIgnoreInstancePointerness;
        }
        child_is_deref_of_parent = false;
        return cached_member_info->member_infos[idx].clang_type;
      }
    }
  } break;

  case swift::TypeKind::ExistentialMetatype:
  case swift::TypeKind::Metatype:
    break;

  case swift::TypeKind::Module:
  case swift::TypeKind::Archetype:
  case swift::TypeKind::Function:
  case swift::TypeKind::GenericFunction:
    break;

  case swift::TypeKind::LValue:
    if (idx < GetNumChildren(type, omit_empty_base_classes)) {
      CompilerType pointee_clang_type(GetNonReferenceType(type));
      Flags pointee_clang_type_flags(pointee_clang_type.GetTypeInfo());
      const char *parent_name = valobj ? valobj->GetName().GetCString() : NULL;
      if (parent_name) {
        child_name.assign(1, '&');
        child_name += parent_name;
      }

      // We have a pointer to a simple type
      if (idx == 0) {
        child_byte_size = pointee_clang_type.GetByteSize(
            exe_ctx ? exe_ctx->GetBestExecutionContextScope() : NULL);
        child_byte_offset = 0;
        return pointee_clang_type;
      }
    }
    break;
  case swift::TypeKind::UnboundGeneric:
    break;
  case swift::TypeKind::TypeVariable:
    break;

  case swift::TypeKind::DynamicSelf:
  case swift::TypeKind::SILBox:
  case swift::TypeKind::SILFunction:
  case swift::TypeKind::SILBlockStorage:
  case swift::TypeKind::InOut:
  case swift::TypeKind::Unresolved:
    break;

  case swift::TypeKind::Optional:
  case swift::TypeKind::ImplicitlyUnwrappedOptional:
  case swift::TypeKind::NameAlias:
  case swift::TypeKind::Paren:
  case swift::TypeKind::Dictionary:
  case swift::TypeKind::ArraySlice:
    assert(false && "Not a canonical type");
    break;
  }
  return CompilerType();
}

// Look for a child member (doesn't include base classes, but it does include
// their members) in the type hierarchy. Returns an index path into "clang_type"
// on how to reach the appropriate member.
//
//    class A
//    {
//    public:
//        int m_a;
//        int m_b;
//    };
//
//    class B
//    {
//    };
//
//    class C :
//        public B,
//        public A
//    {
//    };
//
// If we have a clang type that describes "class C", and we wanted to look for
// "m_b" in it:
//
// With omit_empty_base_classes == false we would get an integer array back
// with:
// { 1,  1 }
// The first index 1 is the child index for "class A" within class C.
// The second index 1 is the child index for "m_b" within class A.
//
// With omit_empty_base_classes == true we would get an integer array back with:
// { 0,  1 }
// The first index 0 is the child index for "class A" within class C (since
// class B doesn't have any members it doesn't count).
// The second index 1 is the child index for "m_b" within class A.

size_t SwiftASTContext::GetIndexOfChildMemberWithName(
    void *type, const char *name, bool omit_empty_base_classes,
    std::vector<uint32_t> &child_indexes) {
  VALID_OR_RETURN(0);

  if (type && name && name[0]) {
    swift::CanType swift_can_type(GetCanonicalSwiftType(type));

    const swift::TypeKind type_kind = swift_can_type->getKind();
    switch (type_kind) {
    case swift::TypeKind::Error:
    case swift::TypeKind::BuiltinInteger:
    case swift::TypeKind::BuiltinFloat:
    case swift::TypeKind::BuiltinRawPointer:
    case swift::TypeKind::BuiltinNativeObject:
    case swift::TypeKind::BuiltinUnknownObject:
    case swift::TypeKind::BuiltinUnsafeValueBuffer:
    case swift::TypeKind::BuiltinBridgeObject:
    case swift::TypeKind::BuiltinVector:
      break;

    case swift::TypeKind::UnmanagedStorage:
    case swift::TypeKind::UnownedStorage:
    case swift::TypeKind::WeakStorage:
      return CompilerType(GetASTContext(),
                          swift_can_type->getReferenceStorageReferent())
          .GetIndexOfChildMemberWithName(name, omit_empty_base_classes,
                                         child_indexes);
    case swift::TypeKind::GenericTypeParam:
    case swift::TypeKind::DependentMember:
      break;

    case swift::TypeKind::Enum:
    case swift::TypeKind::BoundGenericEnum: {
      SwiftEnumDescriptor *cached_enum_info = GetCachedEnumInfo(type);
      if (cached_enum_info) {
        ConstString const_name(name);
        const size_t num_sized_elements =
            cached_enum_info->GetNumElementsWithPayload();
        for (size_t i = 0; i < num_sized_elements; ++i) {
          if (cached_enum_info->GetElementWithPayloadAtIndex(i)->name ==
              const_name) {
            child_indexes.push_back(i);
            return child_indexes.size();
          }
        }
      }
    } break;

    case swift::TypeKind::Tuple: {
      // For tuples only always look for the member by number first as a tuple
      // element can be named, yet still be accessed by the number...
      swift::TupleType *tuple_type = swift_can_type->castTo<swift::TupleType>();
      uint32_t tuple_idx = StringConvert::ToUInt32(name, UINT32_MAX);
      if (tuple_idx != UINT32_MAX) {
        if (tuple_idx < tuple_type->getNumElements()) {
          child_indexes.push_back(tuple_idx);
          return child_indexes.size();
        } else
          return 0;
      }
    }
    // Fall through to class/union/struct case...
    case swift::TypeKind::Struct:
    case swift::TypeKind::Class:
    case swift::TypeKind::Protocol:
    case swift::TypeKind::ProtocolComposition:
    case swift::TypeKind::BoundGenericClass:
    case swift::TypeKind::BoundGenericStruct: {
      CachedMemberInfo *cached_member_info = GetCachedMemberInfo(type);
      if (cached_member_info) {
        ConstString const_name(name);
        const size_t num_members = cached_member_info->member_infos.size();
        if (num_members > 0) {
          for (size_t i = 0; i < num_members; ++i) {
            const MemberInfo &member_info = cached_member_info->member_infos[i];
            if (member_info.name &&
                member_info.member_type != MemberType::BaseClass) {
              if (const_name == member_info.name) {
                child_indexes.push_back(i);
                return child_indexes.size();
              }
            }
          }
          // Check the base class if we have one...
          if (cached_member_info->member_infos[0].member_type ==
              MemberType::BaseClass) {
            // Push index zero for the base class
            child_indexes.push_back(0);

            if (cached_member_info->member_infos[0]
                    .clang_type.GetIndexOfChildMemberWithName(
                        name, omit_empty_base_classes, child_indexes)) {
              // We did find an ivar in a superclass so just
              // return the results!
              return child_indexes.size();
            }
            // We didn't find an ivar matching "name" in our
            // superclass, pop the superclass zero index that
            // we pushed on above.
            child_indexes.pop_back();
          }
        }
      }
    } break;

    case swift::TypeKind::ExistentialMetatype:
    case swift::TypeKind::Metatype:
      break;

    case swift::TypeKind::Module:
    case swift::TypeKind::Archetype:
    case swift::TypeKind::Function:
    case swift::TypeKind::GenericFunction:
      break;
    case swift::TypeKind::InOut:
    case swift::TypeKind::LValue: {
      CompilerType pointee_clang_type(GetNonReferenceType(type));

      if (pointee_clang_type.IsAggregateType()) {
        return pointee_clang_type.GetIndexOfChildMemberWithName(
            name, omit_empty_base_classes, child_indexes);
      }
    } break;
    case swift::TypeKind::UnboundGeneric:
      break;
    case swift::TypeKind::TypeVariable:
      break;

    case swift::TypeKind::DynamicSelf:
    case swift::TypeKind::SILBox:
    case swift::TypeKind::SILFunction:
    case swift::TypeKind::SILBlockStorage:
    case swift::TypeKind::Unresolved:
      break;

    case swift::TypeKind::Optional:
    case swift::TypeKind::ImplicitlyUnwrappedOptional:
    case swift::TypeKind::NameAlias:
    case swift::TypeKind::Paren:
    case swift::TypeKind::Dictionary:
    case swift::TypeKind::ArraySlice:
      assert(false && "Not a canonical type");
      break;

    }
  }
  return 0;
}

// Get the index of the child of "clang_type" whose name matches. This function
// doesn't descend into the children, but only looks one level deep and name
// matches can include base class names.

uint32_t
SwiftASTContext::GetIndexOfChildWithName(void *type, const char *name,
                                         bool omit_empty_base_classes) {
  VALID_OR_RETURN(UINT32_MAX);

  if (type && name && name[0]) {
    swift::CanType swift_can_type(GetCanonicalSwiftType(type));

    const swift::TypeKind type_kind = swift_can_type->getKind();
    switch (type_kind) {
    case swift::TypeKind::Error:
    case swift::TypeKind::BuiltinInteger:
    case swift::TypeKind::BuiltinFloat:
    case swift::TypeKind::BuiltinRawPointer:
    case swift::TypeKind::BuiltinNativeObject:
    case swift::TypeKind::BuiltinUnsafeValueBuffer:
    case swift::TypeKind::BuiltinUnknownObject:
    case swift::TypeKind::BuiltinBridgeObject:
    case swift::TypeKind::BuiltinVector:
      break;
    case swift::TypeKind::UnmanagedStorage:
    case swift::TypeKind::UnownedStorage:
    case swift::TypeKind::WeakStorage:
      return CompilerType(GetASTContext(),
                          swift_can_type->getReferenceStorageReferent())
          .GetIndexOfChildWithName(name, omit_empty_base_classes);
    case swift::TypeKind::GenericTypeParam:
    case swift::TypeKind::DependentMember:
      break;

    case swift::TypeKind::Enum:
    case swift::TypeKind::BoundGenericEnum: {
      SwiftEnumDescriptor *cached_enum_info = GetCachedEnumInfo(type);
      if (cached_enum_info) {
        ConstString const_name(name);
        const size_t num_sized_elements =
            cached_enum_info->GetNumElementsWithPayload();
        for (size_t i = 0; i < num_sized_elements; ++i) {
          if (cached_enum_info->GetElementWithPayloadAtIndex(i)->name ==
              const_name)
            return i;
        }
      }
    } break;

    case swift::TypeKind::Tuple: {
      swift::TupleType *tuple_type = swift_can_type->castTo<swift::TupleType>();
      uint32_t tuple_idx = StringConvert::ToUInt32(name, UINT32_MAX);
      if (tuple_idx != UINT32_MAX) {
        if (tuple_idx < tuple_type->getNumElements())
          return tuple_idx;
      }
    }
    // Fall through to struct/union/class case...
    case swift::TypeKind::Struct:
    case swift::TypeKind::Class:
    case swift::TypeKind::Protocol:
    case swift::TypeKind::ProtocolComposition:
    case swift::TypeKind::BoundGenericClass:
    case swift::TypeKind::BoundGenericStruct: {
      CachedMemberInfo *cached_member_info = GetCachedMemberInfo(type);
      if (cached_member_info) {
        ConstString const_name(name);
        const size_t num_members = cached_member_info->member_infos.size();
        if (num_members > 0) {
          for (size_t i = 0; i < num_members; ++i) {
            const MemberInfo &member_info = cached_member_info->member_infos[i];
            if (member_info.name &&
                member_info.member_type != MemberType::BaseClass) {
              if (const_name == member_info.name)
                return i;
            }
          }
          // Check the base class name if we have one...
          if (cached_member_info->member_infos[0].member_type ==
                  MemberType::BaseClass &&
              cached_member_info->member_infos[0].name == const_name) {
            return 0;
          }
        }
      }
    }

    break;

    case swift::TypeKind::ExistentialMetatype:
    case swift::TypeKind::Metatype:
      break;

    case swift::TypeKind::Module:
    case swift::TypeKind::Archetype:
    case swift::TypeKind::Function:
    case swift::TypeKind::GenericFunction:
      break;
    case swift::TypeKind::InOut:
    case swift::TypeKind::LValue: {
      CompilerType pointee_type(GetNonReferenceType(type));

      if (pointee_type.IsAggregateType()) {
        return pointee_type.GetIndexOfChildWithName(name,
                                                    omit_empty_base_classes);
      }
    } break;
    case swift::TypeKind::UnboundGeneric:
      break;
    case swift::TypeKind::TypeVariable:
      break;

    case swift::TypeKind::DynamicSelf:
    case swift::TypeKind::SILBox:
    case swift::TypeKind::SILFunction:
    case swift::TypeKind::SILBlockStorage:
    case swift::TypeKind::Unresolved:
      break;

    case swift::TypeKind::Optional:
    case swift::TypeKind::ImplicitlyUnwrappedOptional:
    case swift::TypeKind::NameAlias:
    case swift::TypeKind::Paren:
    case swift::TypeKind::Dictionary:
    case swift::TypeKind::ArraySlice:
      assert(false && "Not a canonical type");
      break;
    }
  }
  return UINT32_MAX;
}

size_t SwiftASTContext::GetNumTemplateArguments(void *type) {
  if (!type)
    return 0;

  swift::CanType swift_can_type(GetCanonicalSwiftType(type));

  const swift::TypeKind type_kind = swift_can_type->getKind();
  switch (type_kind) {
  case swift::TypeKind::UnboundGeneric: {
    swift::UnboundGenericType *unbound_generic_type =
        swift_can_type->castTo<swift::UnboundGenericType>();
    auto *nominal_type_decl = unbound_generic_type->getDecl();
    swift::GenericParamList *generic_param_list =
        nominal_type_decl->getGenericParams();
    return generic_param_list->getParams().size();
  } break;
  case swift::TypeKind::BoundGenericClass:
  case swift::TypeKind::BoundGenericStruct:
  case swift::TypeKind::BoundGenericEnum: {
    swift::BoundGenericType *bound_generic_type =
        swift_can_type->castTo<swift::BoundGenericType>();
    return bound_generic_type->getGenericArgs().size();
  }
  default:
    break;
  }

  return 0;
}

bool SwiftASTContext::GetSelectedEnumCase(const CompilerType &type,
                                          const DataExtractor &data,
                                          ConstString *name, bool *has_payload,
                                          CompilerType *payload,
                                          bool *is_indirect) {
  if (auto ast =
          llvm::dyn_cast_or_null<SwiftASTContext>(type.GetTypeSystem())) {
    swift::CanType swift_can_type(GetCanonicalSwiftType(type));

    const swift::TypeKind type_kind = swift_can_type->getKind();
    switch (type_kind) {
    default:
      break;
    case swift::TypeKind::Enum:
    case swift::TypeKind::BoundGenericEnum: {
      SwiftEnumDescriptor *cached_enum_info =
          ast->GetCachedEnumInfo(swift_can_type.getPointer());
      if (cached_enum_info) {
        auto enum_elem_info = cached_enum_info->GetElementFromData(data);
        if (enum_elem_info) {
          if (name)
            *name = enum_elem_info->name;
          if (has_payload)
            *has_payload = enum_elem_info->has_payload;
          if (payload)
            *payload = enum_elem_info->payload_type;
          if (is_indirect)
            *is_indirect = enum_elem_info->is_indirect;
          return true;
        }
      }
    } break;
    }
  }

  return false;
}

CompilerType
SwiftASTContext::GetTemplateArgument(void *type, size_t arg_idx,
                                     lldb::TemplateArgumentKind &kind) {
  VALID_OR_RETURN(CompilerType());

  if (type) {
    swift::CanType swift_can_type(GetCanonicalSwiftType(type));

    if (auto *unbound_generic_type =
          swift_can_type->getAs<swift::UnboundGenericType>()) {
      auto *nominal_type_decl = unbound_generic_type->getDecl();
      swift::GenericSignature *generic_sig =
          nominal_type_decl->getGenericSignature();
      auto depTy = generic_sig->getGenericParams()[arg_idx];
      return CompilerType(GetASTContext(),
                          nominal_type_decl->mapTypeIntoContext(depTy)
                              ->castTo<swift::ArchetypeType>());
    }
    if (auto *bound_generic_type =
          swift_can_type->getAs<swift::BoundGenericType>()) {
      if (arg_idx < bound_generic_type->getGenericArgs().size()) {
        kind = eTemplateArgumentKindType;
        return CompilerType(GetASTContext(),
                            bound_generic_type->getGenericArgs()[arg_idx].getPointer());
      }
    }
  }

  kind = eTemplateArgumentKindNull;
  return CompilerType();
}

CompilerType SwiftASTContext::GetTypeForFormatters(void *type) {
  VALID_OR_RETURN(CompilerType());

  if (type) {
    swift::Type swift_type(GetSwiftType(type));
    return CompilerType(GetASTContext(), swift_type);
  }
  return CompilerType();
}

LazyBool SwiftASTContext::ShouldPrintAsOneLiner(void *type,
                                                ValueObject *valobj) {
  if (type) {
    CompilerType can_compiler_type(GetCanonicalType(type));
    if (IsImportedType(can_compiler_type, nullptr))
      return eLazyBoolNo;
  }
  if (valobj) {
    if (valobj->IsBaseClass())
      return eLazyBoolNo;
    if ((valobj->GetLanguageFlags() & LanguageFlags::eIsIndirectEnumCase) ==
        LanguageFlags::eIsIndirectEnumCase)
      return eLazyBoolNo;
  }

  return eLazyBoolCalculate;
}

bool SwiftASTContext::IsMeaninglessWithoutDynamicResolution(void *type) {
  if (type) {
    swift::CanType swift_can_type(GetCanonicalSwiftType(type));

    const swift::TypeKind type_kind = swift_can_type->getKind();
    switch (type_kind) {
    case swift::TypeKind::Archetype:
      return true;
    default:
      return false;
    }
  }

  return false;
}

//----------------------------------------------------------------------
// Dumping types
//----------------------------------------------------------------------
#define DEPTH_INCREMENT 2

void SwiftASTContext::DumpValue(
    void *type, ExecutionContext *exe_ctx, Stream *s, lldb::Format format,
    const lldb_private::DataExtractor &data, lldb::offset_t data_byte_offset,
    size_t data_byte_size, uint32_t bitfield_bit_size,
    uint32_t bitfield_bit_offset, bool show_types, bool show_summary,
    bool verbose, uint32_t depth) {}

bool SwiftASTContext::DumpTypeValue(
    void *type, Stream *s, lldb::Format format,
    const lldb_private::DataExtractor &data, lldb::offset_t byte_offset,
    size_t byte_size, uint32_t bitfield_bit_size, uint32_t bitfield_bit_offset,
    ExecutionContextScope *exe_scope, bool is_base_class) {
  VALID_OR_RETURN(false);

  if (!type)
    return false;

  swift::CanType swift_can_type(GetCanonicalSwiftType(type));

  const swift::TypeKind type_kind = swift_can_type->getKind();
  switch (type_kind) {
  case swift::TypeKind::Error:
    break;

  case swift::TypeKind::Class:
  case swift::TypeKind::BoundGenericClass:
    // If we have a class that is in a variable then it is a pointer,
    // else if it is a base class, it has no value.
    if (is_base_class)
      break;
  // Fall through to case below
  case swift::TypeKind::BuiltinInteger:
  case swift::TypeKind::BuiltinFloat:
  case swift::TypeKind::BuiltinRawPointer:
  case swift::TypeKind::BuiltinNativeObject:
  case swift::TypeKind::BuiltinUnsafeValueBuffer:
  case swift::TypeKind::BuiltinUnknownObject:
  case swift::TypeKind::BuiltinBridgeObject:
  case swift::TypeKind::Archetype:
  case swift::TypeKind::Function:
  case swift::TypeKind::GenericFunction:
  case swift::TypeKind::LValue: {
    uint32_t item_count = 1;
    // A few formats, we might need to modify our size and count for depending
    // on how we are trying to display the value...
    switch (format) {
    default:
    case eFormatBoolean:
    case eFormatBinary:
    case eFormatComplex:
    case eFormatCString: // NULL terminated C strings
    case eFormatDecimal:
    case eFormatEnum:
    case eFormatHex:
    case eFormatHexUppercase:
    case eFormatFloat:
    case eFormatOctal:
    case eFormatOSType:
    case eFormatUnsigned:
    case eFormatPointer:
    case eFormatVectorOfChar:
    case eFormatVectorOfSInt8:
    case eFormatVectorOfUInt8:
    case eFormatVectorOfSInt16:
    case eFormatVectorOfUInt16:
    case eFormatVectorOfSInt32:
    case eFormatVectorOfUInt32:
    case eFormatVectorOfSInt64:
    case eFormatVectorOfUInt64:
    case eFormatVectorOfFloat32:
    case eFormatVectorOfFloat64:
    case eFormatVectorOfUInt128:
      break;

    case eFormatAddressInfo:
      if (byte_size == 0) {
        byte_size = exe_scope->CalculateTarget()
                        ->GetArchitecture()
                        .GetAddressByteSize();
        item_count = 1;
      }
      break;

    case eFormatChar:
    case eFormatCharPrintable:
    case eFormatCharArray:
    case eFormatBytes:
    case eFormatBytesWithASCII:
      item_count = byte_size;
      byte_size = 1;
      break;

    case eFormatUnicode16:
      item_count = byte_size / 2;
      byte_size = 2;
      break;

    case eFormatUnicode32:
      item_count = byte_size / 4;
      byte_size = 4;
      break;
    }
    return DumpDataExtractor(data, s, byte_offset, format, byte_size, item_count, UINT32_MAX,
                     LLDB_INVALID_ADDRESS, bitfield_bit_size,
                     bitfield_bit_offset, exe_scope);
  } break;
  case swift::TypeKind::BuiltinVector:
    break;

  case swift::TypeKind::Tuple:
    break;

  case swift::TypeKind::UnmanagedStorage:
  case swift::TypeKind::UnownedStorage:
  case swift::TypeKind::WeakStorage:
    return CompilerType(GetASTContext(),
                        swift_can_type->getReferenceStorageReferent())
        .DumpTypeValue(s, format, data, byte_offset, byte_size,
                       bitfield_bit_size, bitfield_bit_offset, exe_scope,
                       is_base_class);
  case swift::TypeKind::Enum:
  case swift::TypeKind::BoundGenericEnum: {
    SwiftEnumDescriptor *cached_enum_info = GetCachedEnumInfo(type);
    if (cached_enum_info) {
      auto enum_elem_info = cached_enum_info->GetElementFromData(data);
      if (enum_elem_info)
        s->Printf("%s", enum_elem_info->name.GetCString());
      else {
        lldb::offset_t ptr = 0;
        if (data.GetByteSize())
          s->Printf("<invalid> (0x%" PRIx8 ")", data.GetU8(&ptr));
        else
          s->Printf("<empty>");
      }
      return true;
    } else
      s->Printf("<unknown type>");
  } break;

  case swift::TypeKind::Struct:
  case swift::TypeKind::Protocol:
  case swift::TypeKind::GenericTypeParam:
  case swift::TypeKind::DependentMember:
    return false;

  case swift::TypeKind::ExistentialMetatype:
  case swift::TypeKind::Metatype: {
    return DumpDataExtractor(data, s, byte_offset, eFormatPointer, byte_size, 1, UINT32_MAX,
                     LLDB_INVALID_ADDRESS, bitfield_bit_size,
                     bitfield_bit_offset, exe_scope);
  } break;

  case swift::TypeKind::Module:
  case swift::TypeKind::ProtocolComposition:
  case swift::TypeKind::UnboundGeneric:
  case swift::TypeKind::BoundGenericStruct:
  case swift::TypeKind::TypeVariable:
  case swift::TypeKind::DynamicSelf:
  case swift::TypeKind::SILBox:
  case swift::TypeKind::SILFunction:
  case swift::TypeKind::SILBlockStorage:
  case swift::TypeKind::InOut:
  case swift::TypeKind::Unresolved:
    break;

  case swift::TypeKind::Optional:
  case swift::TypeKind::ImplicitlyUnwrappedOptional:
  case swift::TypeKind::NameAlias:
  case swift::TypeKind::Paren:
  case swift::TypeKind::Dictionary:
  case swift::TypeKind::ArraySlice:
    assert(false && "Not a canonical type");
    break;
  }

  return 0;
}

bool SwiftASTContext::IsImportedType(const CompilerType &type,
                                     CompilerType *original_type) {
  bool success = false;

  if (llvm::dyn_cast_or_null<SwiftASTContext>(type.GetTypeSystem())) {
    do {
      swift::CanType swift_can_type(GetCanonicalSwiftType(type));
      swift::NominalType *nominal_type =
          swift_can_type->getAs<swift::NominalType>();
      if (!nominal_type)
        break;
      swift::NominalTypeDecl *nominal_type_decl = nominal_type->getDecl();
      if (nominal_type_decl && nominal_type_decl->hasClangNode()) {
        const clang::Decl *clang_decl = nominal_type_decl->getClangDecl();
        if (!clang_decl)
          break;
        success = true;
        if (!original_type)
          break;

        if (const clang::ObjCInterfaceDecl *objc_interface_decl =
                llvm::dyn_cast<clang::ObjCInterfaceDecl>(
                    clang_decl)) // ObjCInterfaceDecl is not a TypeDecl
        {
          *original_type =
              CompilerType(&objc_interface_decl->getASTContext(),
                           clang::QualType::getFromOpaquePtr(
                               objc_interface_decl->getTypeForDecl()));
        } else if (const clang::TypeDecl *type_decl =
                       llvm::dyn_cast<clang::TypeDecl>(clang_decl)) {
          *original_type = CompilerType(
              &type_decl->getASTContext(),
              clang::QualType::getFromOpaquePtr(type_decl->getTypeForDecl()));
        } else // TODO: any more cases that we care about?
        {
          *original_type = CompilerType();
        }
      }
    } while (0);
  }

  return success;
}

bool SwiftASTContext::IsImportedObjectiveCType(const CompilerType &type,
                                               CompilerType *original_type) {
  bool success = false;

  if (llvm::dyn_cast_or_null<SwiftASTContext>(type.GetTypeSystem())) {
    CompilerType local_original_type;

    if (IsImportedType(type, &local_original_type)) {
      if (local_original_type.IsValid()) {
        ClangASTContext *clang_ast = llvm::dyn_cast_or_null<ClangASTContext>(
            local_original_type.GetTypeSystem());
        if (clang_ast &&
            clang_ast->IsObjCObjectOrInterfaceType(local_original_type)) {
          if (original_type)
            *original_type = local_original_type;
          success = true;
        }
      }
    }
  }

  return success;
}

void SwiftASTContext::DumpSummary(void *type, ExecutionContext *exe_ctx,
                                  Stream *s,
                                  const lldb_private::DataExtractor &data,
                                  lldb::offset_t data_byte_offset,
                                  size_t data_byte_size) {}

size_t SwiftASTContext::ConvertStringToFloatValue(void *type, const char *s,
                                                  uint8_t *dst,
                                                  size_t dst_size) {
  return 0;
}

void SwiftASTContext::DumpTypeDescription(void *type) {
  StreamFile s(stdout, false);
  DumpTypeDescription(type, &s);
}

void SwiftASTContext::DumpTypeDescription(void *type, Stream *s) {
  DumpTypeDescription(type, s, false, true);
}

void SwiftASTContext::DumpTypeDescription(void *type,
                                          bool print_help_if_available,
                                          bool print_extensions_if_available) {
  StreamFile s(stdout, false);
  DumpTypeDescription(type, &s, print_help_if_available,
                      print_extensions_if_available);
}

static void PrintSwiftNominalType(swift::NominalTypeDecl *nominal_type_decl,
                                  Stream *s, bool print_help_if_available,
                                  bool print_extensions_if_available) {
  if (nominal_type_decl && s) {
    std::string buffer;
    llvm::raw_string_ostream ostream(buffer);
    const swift::PrintOptions &print_options(
        SwiftASTContext::GetUserVisibleTypePrintingOptions(
            print_help_if_available));
    nominal_type_decl->print(ostream, print_options);
    ostream.flush();
    if (buffer.empty() == false)
      s->Printf("%s\n", buffer.c_str());
    if (print_extensions_if_available) {
      for (auto ext : nominal_type_decl->getExtensions()) {
        if (ext) {
          buffer.clear();
          llvm::raw_string_ostream ext_ostream(buffer);
          ext->print(ext_ostream, print_options);
          ext_ostream.flush();
          if (buffer.empty() == false)
            s->Printf("%s\n", buffer.c_str());
        }
      }
    }
  }
}

void SwiftASTContext::DumpTypeDescription(void *type, Stream *s,
                                          bool print_help_if_available,
                                          bool print_extensions_if_available) {
  llvm::SmallVector<char, 1024> buf;
  llvm::raw_svector_ostream llvm_ostrm(buf);

  if (type) {
    swift::CanType swift_can_type(GetCanonicalSwiftType(type));
    switch (swift_can_type->getKind()) {
    case swift::TypeKind::Module: {
      swift::ModuleType *module_type =
          swift_can_type->castTo<swift::ModuleType>();
      swift::ModuleDecl *module = module_type->getModule();
      llvm::SmallVector<swift::Decl *, 10> decls;
      module->getDisplayDecls(decls);
      for (swift::Decl *decl : decls) {
        swift::DeclKind kind = decl->getKind();
        if (kind >= swift::DeclKind::First_TypeDecl &&
            kind <= swift::DeclKind::Last_TypeDecl) {
          swift::TypeDecl *type_decl =
              llvm::dyn_cast_or_null<swift::TypeDecl>(decl);
          if (type_decl) {
            CompilerType clang_type(&module->getASTContext(),
                                    type_decl->getDeclaredInterfaceType().getPointer());
            if (clang_type) {
              Flags clang_type_flags(clang_type.GetTypeInfo());
              DumpTypeDescription(clang_type.GetOpaqueQualType(), s,
                                  print_help_if_available,
                                  print_extensions_if_available);
            }
          }
        } else if (kind == swift::DeclKind::Func ||
                   kind == swift::DeclKind::Var) {
          std::string buffer;
          llvm::raw_string_ostream stream(buffer);
          decl->print(stream,
                      SwiftASTContext::GetUserVisibleTypePrintingOptions(
                          print_help_if_available));
          stream.flush();
          s->Printf("%s\n", buffer.c_str());
        } else if (kind == swift::DeclKind::Import) {
          swift::ImportDecl *import_decl =
              llvm::dyn_cast_or_null<swift::ImportDecl>(decl);
          if (import_decl) {
            switch (import_decl->getImportKind()) {
            case swift::ImportKind::Module: {
              swift::ModuleDecl *imported_module = import_decl->getModule();
              if (imported_module) {
                s->Printf("import %s\n", imported_module->getName().get());
              }
            } break;
            default: {
              for (swift::Decl *imported_decl : import_decl->getDecls()) {
                // all of the non-module things you can import should be a
                // ValueDecl
                if (swift::ValueDecl *imported_value_decl =
                        llvm::dyn_cast_or_null<swift::ValueDecl>(
                            imported_decl)) {
                  if (swift::TypeBase *decl_type =
                          imported_value_decl->getInterfaceType().getPointer()) {
                    DumpTypeDescription(decl_type, s,
                                        print_help_if_available,
                                        print_extensions_if_available);
                  }
                }
              }
            } break;
            }
          }
        }
      }
      break;
    }
    case swift::TypeKind::Metatype: {
      s->PutCString("metatype ");
      swift::MetatypeType *metatype_type =
          swift_can_type->castTo<swift::MetatypeType>();
      DumpTypeDescription(metatype_type->getInstanceType().getPointer(),
                          print_help_if_available,
                          print_extensions_if_available);
    } break;
    case swift::TypeKind::UnboundGeneric: {
      swift::UnboundGenericType *unbound_generic_type =
          swift_can_type->castTo<swift::UnboundGenericType>();
      auto nominal_type_decl = llvm::dyn_cast<swift::NominalTypeDecl>(
          unbound_generic_type->getDecl());
      if (nominal_type_decl) {
        PrintSwiftNominalType(nominal_type_decl, s, print_help_if_available,
                              print_extensions_if_available);
      }
    } break;
    case swift::TypeKind::GenericFunction:
    case swift::TypeKind::Function: {
      swift::AnyFunctionType *any_function_type =
          swift_can_type->castTo<swift::AnyFunctionType>();
      std::string buffer;
      llvm::raw_string_ostream ostream(buffer);
      const swift::PrintOptions &print_options(
          SwiftASTContext::GetUserVisibleTypePrintingOptions(
              print_help_if_available));

      any_function_type->print(ostream, print_options);
      ostream.flush();
      if (buffer.empty() == false)
        s->Printf("%s\n", buffer.c_str());
    } break;
    case swift::TypeKind::Tuple: {
      swift::TupleType *tuple_type = swift_can_type->castTo<swift::TupleType>();
      std::string buffer;
      llvm::raw_string_ostream ostream(buffer);
      const swift::PrintOptions &print_options(
          SwiftASTContext::GetUserVisibleTypePrintingOptions(
              print_help_if_available));

      tuple_type->print(ostream, print_options);
      ostream.flush();
      if (buffer.empty() == false)
        s->Printf("%s\n", buffer.c_str());
    } break;
    case swift::TypeKind::BoundGenericClass:
    case swift::TypeKind::BoundGenericEnum:
    case swift::TypeKind::BoundGenericStruct: {
      swift::BoundGenericType *bound_generic_type =
          swift_can_type->castTo<swift::BoundGenericType>();
      swift::NominalTypeDecl *nominal_type_decl =
          bound_generic_type->getDecl();
      PrintSwiftNominalType(nominal_type_decl, s, print_help_if_available,
                            print_extensions_if_available);
    } break;
    case swift::TypeKind::BuiltinInteger: {
      swift::BuiltinIntegerType *builtin_integer_type =
          swift_can_type->castTo<swift::BuiltinIntegerType>();
      s->Printf("builtin integer type of width %u bits\n",
                builtin_integer_type->getWidth().getGreatestWidth());
      break;
    }
    case swift::TypeKind::BuiltinFloat: {
      swift::BuiltinFloatType *builtin_float_type =
          swift_can_type->castTo<swift::BuiltinFloatType>();
      s->Printf("builtin floating-point type of width %u bits\n",
                builtin_float_type->getBitWidth());
      break;
    }
    case swift::TypeKind::ProtocolComposition: {
      swift::ProtocolCompositionType *protocol_composition_type =
          swift_can_type->castTo<swift::ProtocolCompositionType>();
      std::string buffer;
      llvm::raw_string_ostream ostream(buffer);
      const swift::PrintOptions &print_options(
          SwiftASTContext::GetUserVisibleTypePrintingOptions(
              print_help_if_available));

      protocol_composition_type->print(ostream, print_options);
      ostream.flush();
      if (buffer.empty() == false)
        s->Printf("%s\n", buffer.c_str());
      break;
    }
    default: {
      swift::NominalType *nominal_type =
          llvm::dyn_cast_or_null<swift::NominalType>(
              swift_can_type.getPointer());
      if (nominal_type) {
        swift::NominalTypeDecl *nominal_type_decl = nominal_type->getDecl();
        PrintSwiftNominalType(nominal_type_decl, s, print_help_if_available,
                              print_extensions_if_available);
      }
    } break;
    }

    if (buf.size() > 0) {
      s->Write(buf.data(), buf.size());
    }
  }
}

TypeSP SwiftASTContext::GetCachedType(const ConstString &mangled) {
  TypeSP type_sp;
  if (m_swift_type_map.Lookup(mangled.GetCString(), type_sp))
    return type_sp;
  else
    return TypeSP();
}

void SwiftASTContext::SetCachedType(const ConstString &mangled,
                                    const TypeSP &type_sp) {
  m_swift_type_map.Insert(mangled.GetCString(), type_sp);
}

DWARFASTParser *SwiftASTContext::GetDWARFParser() {
  if (!m_dwarf_ast_parser_ap)
    m_dwarf_ast_parser_ap.reset(new DWARFASTParserSwift(*this));
  return m_dwarf_ast_parser_ap.get();
}

std::vector<lldb::DataBufferSP> &
SwiftASTContext::GetASTVectorForModule(const Module *module) {
  return m_ast_file_data_map[const_cast<Module *>(module)];
}

SwiftASTContextForExpressions::SwiftASTContextForExpressions(Target &target)
    : SwiftASTContext(target.GetArchitecture().GetTriple().getTriple().c_str(),
                      &target),
      m_persistent_state_up(new SwiftPersistentExpressionState) {}

UserExpression *SwiftASTContextForExpressions::GetUserExpression(
    llvm::StringRef expr, llvm::StringRef prefix, lldb::LanguageType language,
    Expression::ResultType desired_type,
    const EvaluateExpressionOptions &options) {
  TargetSP target_sp = m_target_wp.lock();
  if (!target_sp)
    return nullptr;

  return new SwiftUserExpression(*target_sp.get(), expr, prefix, language,
                                 desired_type, options);
}

PersistentExpressionState *
SwiftASTContextForExpressions::GetPersistentExpressionState() {
  return m_persistent_state_up.get();
}

Thanks for tackling this! Do you understand better why turning it into an LValue type is the right thing to do here? I'm asking because down in ...