//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 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 "Private.h"
#include "swift/ABI/TypeIdentity.h"
#include "swift/Basic/Range.h"
#include "swift/Runtime/Metadata.h"
#include "swift/Runtime/Portability.h"
#include "swift/Strings.h"

#include <vector>
#include <inttypes.h>

#if SWIFT_OBJC_INTEROP
#include <objc/runtime.h>
#endif

#ifdef _WIN32
// We'll probably want dbghelp.h here
#else
#include <cxxabi.h>
#endif

using namespace swift;

Demangle::NodePointer
swift::_buildDemanglingForContext(const ContextDescriptor *context,
                                  llvm::ArrayRef<NodePointer> demangledGenerics,
                                  Demangle::Demangler &Dem) {
  unsigned usedDemangledGenerics = 0;
  NodePointer node = nullptr;

  // Walk up the context tree.
  llvm::SmallVector<const ContextDescriptor *, 8> descriptorPath;
  {
    const ContextDescriptor *parent = context;
    while (parent) {
      descriptorPath.push_back(parent);
      parent = parent->Parent;
    }
  }

  auto getGenericArgsTypeListForContext =
    [&](const ContextDescriptor *context) -> NodePointer {
      if (demangledGenerics.empty())
        return nullptr;

      if (context->getKind() == ContextDescriptorKind::Anonymous)
        return nullptr;
      
      auto generics = context->getGenericContext();
      if (!generics)
        return nullptr;
      
      auto numParams = generics->getGenericContextHeader().NumParams;
      if (numParams <= usedDemangledGenerics)
        return nullptr;
      
      auto genericArgsList = Dem.createNode(Node::Kind::TypeList);
      for (unsigned e = generics->getGenericContextHeader().NumParams;
           usedDemangledGenerics < e;
           ++usedDemangledGenerics) {
        genericArgsList->addChild(demangledGenerics[usedDemangledGenerics],
                                  Dem);
      }
      return genericArgsList;
    };
  
  for (auto component : llvm::reverse(descriptorPath)) {
    switch (auto kind = component->getKind()) {
    case ContextDescriptorKind::Module: {
      assert(node == nullptr && "module should be top level");
      auto name = llvm::cast<ModuleContextDescriptor>(component)->Name.get();
      node = Dem.createNode(Node::Kind::Module, name);
      break;
    }
    
    case ContextDescriptorKind::Extension: {
      auto extension = llvm::cast<ExtensionContextDescriptor>(component);
      // Demangle the extension self type.
      auto selfType = Dem.demangleType(extension->getMangledExtendedContext(),
                                       ResolveToDemanglingForContext(Dem));
      if (selfType->getKind() == Node::Kind::Type)
        selfType = selfType->getChild(0);
      
      // Substitute in the generic arguments.
      auto genericArgsList = getGenericArgsTypeListForContext(component);
      
      if (selfType->getKind() == Node::Kind::BoundGenericEnum
          || selfType->getKind() == Node::Kind::BoundGenericStructure
          || selfType->getKind() == Node::Kind::BoundGenericClass
          || selfType->getKind() == Node::Kind::BoundGenericOtherNominalType) {
        if (genericArgsList) {
          auto substSelfType = Dem.createNode(selfType->getKind());
          substSelfType->addChild(selfType->getChild(0), Dem);
          substSelfType->addChild(genericArgsList, Dem);
          selfType = substSelfType;
        } else {
          // TODO: Use the unsubstituted type if we can't handle the
          // substitutions yet.
          selfType = selfType->getChild(0)->getChild(0);
        }
      }
      
      auto extNode = Dem.createNode(Node::Kind::Extension);
      extNode->addChild(node, Dem);
      extNode->addChild(selfType, Dem);
      
      // TODO: Turn the generic signature into a demangling as the third
      // generic argument.
      
      node = extNode;
      break;
    }

    case ContextDescriptorKind::Protocol: {
      auto protocol = llvm::cast<ProtocolDescriptor>(component);
      auto name = protocol->Name.get();

      auto protocolNode = Dem.createNode(Node::Kind::Protocol);
      protocolNode->addChild(node, Dem);
      auto nameNode = Dem.createNode(Node::Kind::Identifier, name);
      protocolNode->addChild(nameNode, Dem);

      node = protocolNode;
      break;
    }

    default:
      // Form a type context demangling for type contexts.
      if (auto type = llvm::dyn_cast<TypeContextDescriptor>(component)) {
        auto identity = ParsedTypeIdentity::parse(type);

        Node::Kind nodeKind;
        Node::Kind genericNodeKind;
        switch (kind) {
        case ContextDescriptorKind::Class:
          nodeKind = Node::Kind::Class;
          genericNodeKind = Node::Kind::BoundGenericClass;
          break;
        case ContextDescriptorKind::Struct:
          nodeKind = Node::Kind::Structure;
          genericNodeKind = Node::Kind::BoundGenericStructure;
          break;
        case ContextDescriptorKind::Enum:
          nodeKind = Node::Kind::Enum;
          genericNodeKind = Node::Kind::BoundGenericEnum;
          break;
        default:
          // We don't know about this kind of type. Use an "other type" mangling
          // for it.
          nodeKind = Node::Kind::OtherNominalType;
          genericNodeKind = Node::Kind::BoundGenericOtherNominalType;
          break;
        }
        
        // Override the node kind if this is a Clang-imported type so we give it
        // a stable mangling.
        if (identity.isCTypedef()) {
          nodeKind = Node::Kind::TypeAlias;
        } else if (nodeKind != Node::Kind::Structure &&
                   _isCImportedTagType(type, identity)) {
          nodeKind = Node::Kind::Structure;
        }
        
        auto typeNode = Dem.createNode(nodeKind);
        typeNode->addChild(node, Dem);
        auto nameNode = Dem.createNode(Node::Kind::Identifier,
                                       identity.getABIName());
        if (identity.isAnyRelatedEntity()) {
          auto kindNode = Dem.createNode(Node::Kind::Identifier,
                                     identity.getRelatedEntityName());
          auto relatedName = Dem.createNode(Node::Kind::RelatedEntityDeclName);
          relatedName->addChild(kindNode, Dem);
          relatedName->addChild(nameNode, Dem);
          nameNode = relatedName;
        }
        typeNode->addChild(nameNode, Dem);
        node = typeNode;
        
        // Apply generic arguments if the context is generic.
        if (auto genericArgsList = getGenericArgsTypeListForContext(component)){
          auto unspecializedType = Dem.createNode(Node::Kind::Type);
          unspecializedType->addChild(node, Dem);

          auto genericNode = Dem.createNode(genericNodeKind);
          genericNode->addChild(unspecializedType, Dem);
          genericNode->addChild(genericArgsList, Dem);
          node = genericNode;
        }
        
        break;
      }

      // This runtime doesn't understand this context, or it's a context with
      // no richer runtime information available about it (such as an anonymous
      // context). Use an unstable mangling to represent the context by its
      // pointer identity.
      char addressBuf[sizeof(void*) * 2 + 1 + 1];
      snprintf(addressBuf, sizeof(addressBuf), "$%" PRIxPTR, (uintptr_t)component);
      
      auto anonNode = Dem.createNode(Node::Kind::AnonymousContext);
      CharVector addressStr;
      addressStr.append(addressBuf, Dem);
      auto name = Dem.createNode(Node::Kind::Identifier, addressStr);
      anonNode->addChild(name, Dem);
      anonNode->addChild(node, Dem);
      
      // Collect generic arguments if the context is generic.
      auto genericArgsList = getGenericArgsTypeListForContext(component);
      if (!genericArgsList)
        genericArgsList = Dem.createNode(Node::Kind::TypeList);
      anonNode->addChild(genericArgsList, Dem);
      
      node = anonNode;
      
      break;
    }
  }
  
  // Wrap the final result in a top-level Type node.
  auto top = Dem.createNode(Node::Kind::Type);
  top->addChild(node, Dem);
  return top;
}

// FIXME: This stuff should be merged with the existing logic in
// include/swift/RemoteInspection/TypeRefBuilder.h as part of the rewrite
// to change stdlib reflection over to using remote mirrors.

Demangle::NodePointer
swift::_swift_buildDemanglingForMetadata(const Metadata *type,
                                         Demangle::Demangler &Dem);

static Demangle::NodePointer
_buildDemanglerForBuiltinType(const Metadata *type, Demangle::Demangler &Dem) {
#define BUILTIN_TYPE(Symbol, Name) \
  if (type == &METADATA_SYM(Symbol).base) \
    return Dem.createNode(Node::Kind::BuiltinTypeName, Name);
#if !SWIFT_STDLIB_ENABLE_VECTOR_TYPES
#define BUILTIN_VECTOR_TYPE(ElementSymbol, ElementName, Width)
#endif
#include "swift/Runtime/BuiltinTypes.def"
  return nullptr;
}

// Build a demangled type tree for a type pack.
static Demangle::NodePointer
_buildDemanglingForMetadataPack(MetadataPackPointer pack, size_t count,
                                Demangle::Demangler &Dem) {
  using namespace Demangle;

  auto node = Dem.createNode(Node::Kind::Pack);

  for (size_t i = 0; i < count; ++i) {
    auto elt = _swift_buildDemanglingForMetadata(pack.getElements()[i], Dem);
    if (elt == nullptr)
      return nullptr;

    node->addChild(elt, Dem);
  }

  return node;
}

static Demangle::NodePointer
_buildDemanglingForValue(intptr_t value, GenericValueDescriptor valueDescriptor,
                         Demangle::Demangler &Dem) {
  switch (valueDescriptor.Type) {
  case GenericValueType::Int: {
    if (value < 0) {
      return Dem.createNode(Node::Kind::NegativeInteger, value);
    }

    return Dem.createNode(Node::Kind::Integer, value);
  }
  }
}

/// Build an array of demangling trees for each generic argument to the given
/// generic type context descriptor.
///
/// Note:
/// - The input array has an entry for those generic parameter descriptors which
///   are key arguments only.
/// - The output array has an entry for each generic parameter descriptor,
///   whether or not it is a key argument.
///
/// The generic parameters which are not key arguments were made non-canonical
/// by constraining them to a concrete type or another generic parameter.
///
/// We figure out their type by looking at the same-type requirements of the
/// generic context. We demangle their type from the requirement, using the
/// generic arguments area as the substitution map; this gives us the metadata
/// for their argument. Then we convert the metadata to a mangling.
///
/// The output array is flat; the generic parameters of each depth are
/// concatenated together.
static bool _buildDemanglingForGenericArgs(
    const TypeContextDescriptor *description,
    const Metadata *const *genericArgs,
    llvm::SmallVectorImpl<NodePointer> &demangledGenerics,
    Demangle::Demangler &Dem) {
  auto generics = description->getGenericContext();
  if (!generics)
    return true;

  auto packHeader = generics->getGenericPackShapeHeader();
  auto packDescriptors = generics->getGenericPackShapeDescriptors();

  llvm::SmallVector<MetadataPackOrValue> allGenericArgs;

  auto numKeyArgs = 0;
  for (auto param : generics->getGenericParams()) {
    if (param.hasKeyArgument()) {
      numKeyArgs += 1;
    }
  }

  // _gatherWrittenGenericParameters expects to immediately read key generic
  // arguments, so skip past the shape classes if we have any.
  auto nonShapeClassGenericArgs = genericArgs + packHeader.NumShapeClasses;

  llvm::ArrayRef<const void *> genericArgsRef(
      reinterpret_cast<const void * const *>(nonShapeClassGenericArgs), numKeyArgs);

  if (!_gatherWrittenGenericParameters(description, genericArgsRef,
                                       allGenericArgs, Dem)) {
    return false;
  }

  auto argIndex = 0;
  auto packIndex = 0;

  for (auto param : generics->getGenericParams()) {
    auto genericArg = allGenericArgs[argIndex];

    switch (param.getKind()) {
    case GenericParamKind::Type: {
      auto metadata = genericArg.getMetadata();
      auto genericArgDemangling =
        _swift_buildDemanglingForMetadata(metadata, Dem);

      if (!genericArgDemangling) {
        return false;
      }

      demangledGenerics.push_back(genericArgDemangling);
      break;
    }

    case GenericParamKind::TypePack: {
      auto packDescriptor = packDescriptors[packIndex];
      assert(packDescriptor.Kind == GenericPackKind::Metadata);
      assert(packDescriptor.ShapeClass < packHeader.NumShapeClasses);

      // Arg index is not interested in the shape classes, but the pack
      // descriptor's index is in terms of the shape classes.
      assert(packDescriptor.Index == argIndex + packHeader.NumShapeClasses);

      MetadataPackPointer pack(genericArg.getMetadataPack());
      size_t count = reinterpret_cast<size_t>(genericArgs[packDescriptor.ShapeClass]);

      auto genericArgDemangling = _buildDemanglingForMetadataPack(pack, count, Dem);
      if (genericArgDemangling == nullptr)
        return false;

      demangledGenerics.push_back(genericArgDemangling);
      packIndex += 1;
      break;
    }

    case GenericParamKind::Value: {
      // FIXME: We really want to get the specific value descriptor when
      // building a demangling, but when all value parameters become non-key
      // we lose the value header. May need to do extra work to walk up parents
      // and find this parameter's specific value descriptor.

      auto valueDescriptor = GenericValueDescriptor{GenericValueType::Int};
      auto value = genericArg.getValue();
      auto genericArgDemangling = _buildDemanglingForValue(value,
                                                           valueDescriptor,
                                                           Dem);

      if (!genericArgDemangling)
        return false;

      demangledGenerics.push_back(genericArgDemangling);
      break;
    }

    default:
      // We don't know about this kind of parameter.
      return false;
    }

    argIndex += 1;
  }

  return true;
}

/// Build a demangled type tree for a nominal type.
static Demangle::NodePointer
_buildDemanglingForNominalType(const Metadata *type, Demangle::Demangler &Dem) {
  using namespace Demangle;

  // Get the context descriptor from the type metadata.
  const TypeContextDescriptor *description;

  switch (type->getKind()) {
  case MetadataKind::Class: {
    auto classType = static_cast<const ClassMetadata *>(type);

    if (!classType->isTypeMetadata()) {
      return nullptr;
    }

#if SWIFT_OBJC_INTEROP
    // Peek through artificial subclasses.
    while (classType->isArtificialSubclass())
      classType = classType->Superclass;
#endif
    description = classType->getDescription();
    break;
  }
  case MetadataKind::Enum:
  case MetadataKind::Optional: {
    auto enumType = static_cast<const EnumMetadata *>(type);
    description = enumType->Description;
    break;
  }
  case MetadataKind::Struct: {
    auto structType = static_cast<const StructMetadata *>(type);
    description = structType->Description;
    break;
  }
  case MetadataKind::ForeignClass: {
    auto foreignType = static_cast<const ForeignClassMetadata *>(type);
    description = foreignType->Description;
    break;
  }
  case MetadataKind::ForeignReferenceType: {
    auto foreignType = static_cast<const ForeignReferenceTypeMetadata *>(type);
    description = foreignType->Description;
    break;
  }
  default:
    return nullptr;
  }

  llvm::SmallVector<NodePointer, 8> demangledGenerics;
  if (description->isGeneric()) {
    auto genericArgs = description->getGenericArguments(type);
    // Gather the complete set of generic arguments that must be written to
    // form this type.
    if (!_buildDemanglingForGenericArgs(description, genericArgs,
                                        demangledGenerics, Dem))
      return nullptr;
  }

  return _buildDemanglingForContext(description, demangledGenerics, Dem);
}

static Demangle::NodePointer
_replaceGeneralizationArg(Demangle::NodePointer type,
                          SubstGenericParametersFromMetadata substitutions,
                          Demangle::Demangler &Dem) {
  assert(type->getKind() == Node::Kind::Type);
  auto genericParam = type->getChild(0);

  if (genericParam->getKind() != Node::Kind::DependentGenericParamType)
    return type;

  auto depth = genericParam->getChild(0)->getIndex();
  auto index = genericParam->getChild(1)->getIndex();

  auto arg = substitutions.getMetadata(depth, index);
  assert(arg.isMetadata());
  return _swift_buildDemanglingForMetadata(arg.getMetadata(), Dem);
}

static Demangle::NodePointer
_buildDemanglingForExtendedExistential(const Metadata *type,
                                       Demangle::Demangler &Dem) {
  auto ee = cast<ExtendedExistentialTypeMetadata>(type);

  auto demangledExistential = Dem.demangleType(ee->Shape->ExistentialType.get(),
                                               ResolveToDemanglingForContext(Dem));

  if (!ee->Shape->hasGeneralizationSignature())
    return demangledExistential;

  SubstGenericParametersFromMetadata substitutions(ee->Shape,
                                              ee->getGeneralizationArguments());

  // Dig out the requirement list.
  auto constrainedExistential = demangledExistential;
  while (constrainedExistential->getKind() == Node::Kind::Type
         || constrainedExistential->getKind() == Node::Kind::ExistentialMetatype)
    constrainedExistential = constrainedExistential->getFirstChild();
  assert(constrainedExistential->getKind() == Node::Kind::ConstrainedExistential);
  auto reqList = constrainedExistential->getChild(1);
  assert(reqList->getKind() == Node::Kind::ConstrainedExistentialRequirementList);

  auto newReqList = Dem.createNode(Node::Kind::ConstrainedExistentialRequirementList);

  for (auto req : *reqList) {
    // Currently, the only requirements that can create generalization arguments
    // are same types.
    if (req->getKind() != Node::Kind::DependentGenericSameTypeRequirement) {
      newReqList->addChild(req, Dem);
      continue;
    }

    auto lhs = _replaceGeneralizationArg(req->getChild(0), substitutions, Dem);
    auto rhs = _replaceGeneralizationArg(req->getChild(1), substitutions, Dem);

    auto newReq = Dem.createNode(Node::Kind::DependentGenericSameTypeRequirement);
    newReq->addChild(lhs, Dem);
    newReq->addChild(rhs, Dem);

    newReqList->addChild(newReq, Dem);
  }

  constrainedExistential->replaceChild(1, newReqList);

  return demangledExistential;
}

// Build a demangled type tree for a type.
//
// FIXME: This should use MetadataReader.h.
Demangle::NodePointer
swift::_swift_buildDemanglingForMetadata(const Metadata *type,
                                         Demangle::Demangler &Dem) {
  using namespace Demangle;

  switch (type->getKind()) {
  case MetadataKind::Class:
  case MetadataKind::Enum:
  case MetadataKind::Optional:
  case MetadataKind::Struct:
  case MetadataKind::ForeignClass:
  case MetadataKind::ForeignReferenceType:
    return _buildDemanglingForNominalType(type, Dem);
  case MetadataKind::ObjCClassWrapper: {
#if SWIFT_OBJC_INTEROP
    auto objcWrapper = static_cast<const ObjCClassWrapperMetadata *>(type);
    const char *className = class_getName(objcWrapper->getObjCClassObject());
    
    auto module = Dem.createNode(Node::Kind::Module, MANGLING_MODULE_OBJC);
    auto node = Dem.createNode(Node::Kind::Class);
    node->addChild(module, Dem);
    node->addChild(Dem.createNode(Node::Kind::Identifier,
                                       llvm::StringRef(className)), Dem);
    
    return node;
#else
    assert(false && "no ObjC interop");
    return nullptr;
#endif
  }
  case MetadataKind::Existential: {
    auto exis = static_cast<const ExistentialTypeMetadata *>(type);
    auto protocols = exis->getProtocols();

    auto type_list = Dem.createNode(Node::Kind::TypeList);
    auto proto_list = Dem.createNode(Node::Kind::ProtocolList);
    proto_list->addChild(type_list, Dem);

    // The protocol descriptors should be pre-sorted since the compiler will
    // only ever make a swift_getExistentialTypeMetadata invocation using
    // its canonical ordering of protocols.

    for (auto protocol : protocols) {
#if SWIFT_OBJC_INTEROP
      if (protocol.isObjC()) {
        // The protocol name is mangled as a type symbol, with the _Tt prefix.
        StringRef ProtoName(protocol.getName());
        NodePointer protocolNode = Dem.demangleSymbol(ProtoName);

        // ObjC protocol names aren't mangled.
        if (!protocolNode) {
          auto module = Dem.createNode(Node::Kind::Module,
                                            MANGLING_MODULE_OBJC);
          auto node = Dem.createNode(Node::Kind::Protocol);
          node->addChild(module, Dem);
          node->addChild(Dem.createNode(Node::Kind::Identifier, ProtoName),
                         Dem);
          auto typeNode = Dem.createNode(Node::Kind::Type);
          typeNode->addChild(node, Dem);
          type_list->addChild(typeNode, Dem);
          continue;
        }

        // Dig out the protocol node.
        // Global -> (Protocol|TypeMangling)
        protocolNode = protocolNode->getChild(0);
        if (protocolNode->getKind() == Node::Kind::TypeMangling) {
          protocolNode = protocolNode->getChild(0); // TypeMangling -> Type
          protocolNode = protocolNode->getChild(0); // Type -> ProtocolList
          protocolNode = protocolNode->getChild(0); // ProtocolList -> TypeList
          protocolNode = protocolNode->getChild(0); // TypeList -> Type

          assert(protocolNode->getKind() == Node::Kind::Type);
          assert(protocolNode->getChild(0)->getKind() == Node::Kind::Protocol);
        } else {
          assert(protocolNode->getKind() == Node::Kind::Protocol);
        }

        type_list->addChild(protocolNode, Dem);
        continue;
      }
#endif

      auto protocolNode =
          _buildDemanglingForContext(protocol.getSwiftProtocol(), {}, Dem);
      if (!protocolNode)
        return nullptr;

      type_list->addChild(protocolNode, Dem);
    }

    if (auto superclass = exis->getSuperclassConstraint()) {
      // If there is a superclass constraint, we mangle it specially.
      auto result = Dem.createNode(Node::Kind::ProtocolListWithClass);
      auto superclassNode = _swift_buildDemanglingForMetadata(superclass, Dem);
      if (!superclassNode)
        return nullptr;

      result->addChild(proto_list, Dem);
      result->addChild(superclassNode, Dem);
      return result;
    }

    if (exis->isClassBounded()) {
      // Check if the class constraint is implied by any of our
      // protocols.
      bool requiresClassImplicit = false;

      for (auto protocol : protocols) {
        if (protocol.getClassConstraint() == ProtocolClassConstraint::Class)
          requiresClassImplicit = true;
      }

      // If it was implied, we don't do anything special.
      if (requiresClassImplicit)
        return proto_list;

      // If the existential type has an explicit AnyObject constraint,
      // we must mangle it as such.
      auto result = Dem.createNode(Node::Kind::ProtocolListWithAnyObject);
      result->addChild(proto_list, Dem);
      return result;
    }

    // Just a simple composition of protocols.
    return proto_list;
  }
  case MetadataKind::ExtendedExistential: {
    return _buildDemanglingForExtendedExistential(type, Dem);
  }
  case MetadataKind::ExistentialMetatype: {
    auto metatype = static_cast<const ExistentialMetatypeMetadata *>(type);
    auto instance = _swift_buildDemanglingForMetadata(metatype->InstanceType,
                                                      Dem);
    if (!instance)
      return nullptr;
    auto node = Dem.createNode(Node::Kind::ExistentialMetatype);
    node->addChild(instance, Dem);
    return node;
  }
  case MetadataKind::Function: {
    auto func = static_cast<const FunctionTypeMetadata *>(type);

    Node::Kind kind;
    switch (func->getConvention()) {
    case FunctionMetadataConvention::Swift:
      if (!func->isEscaping())
        kind = Node::Kind::NoEscapeFunctionType;
      else
        kind = Node::Kind::FunctionType;
      break;
    case FunctionMetadataConvention::Block:
      kind = Node::Kind::ObjCBlock;
      break;
    case FunctionMetadataConvention::CFunctionPointer:
      kind = Node::Kind::CFunctionPointer;
      break;
    case FunctionMetadataConvention::Thin:
      kind = Node::Kind::ThinFunctionType;
      break;
    }

    llvm::SmallVector<std::pair<NodePointer, bool>, 8> inputs;
    for (unsigned i = 0, e = func->getNumParameters(); i < e; ++i) {
      auto param = func->getParameter(i);
      auto flags = func->getParameterFlags(i);
      auto input = _swift_buildDemanglingForMetadata(param, Dem);

      // If we failed to build the demangling for an input, we have to fail
      // building the demangling for the function type too.
      if (!input)
        return nullptr;

      auto wrapInput = [&](Node::Kind kind) {
        auto parent = Dem.createNode(kind);
        parent->addChild(input, Dem);
        input = parent;
      };
      if (flags.isNoDerivative()) {
        wrapInput(Node::Kind::NoDerivative);
      }
      switch (flags.getOwnership()) {
      case ParameterOwnership::Default:
        /* nothing */
        break;
      case ParameterOwnership::InOut:
        wrapInput(Node::Kind::InOut);
        break;
      case ParameterOwnership::Shared:
        wrapInput(Node::Kind::Shared);
        break;
      case ParameterOwnership::Owned:
        wrapInput(Node::Kind::Owned);
        break;
      }
      if (flags.isIsolated()) {
        wrapInput(Node::Kind::Isolated);
      }
      if (flags.isSending()) {
        wrapInput(Node::Kind::Sending);
      }

      inputs.push_back({input, flags.isVariadic()});
    }

    NodePointer totalInput = nullptr;
    switch (inputs.size()) {
    case 1: {
      auto singleParam = inputs.front();

      // If the sole unlabeled parameter has a non-tuple type, encode
      // the parameter list as a single type.
      if (!singleParam.second) {
        auto singleType = singleParam.first;
        if (singleType->getKind() == Node::Kind::Type)
          singleType = singleType->getFirstChild();
        if (singleType->getKind() != Node::Kind::Tuple) {
          totalInput = singleParam.first;
          break;
        }
      }

      // Otherwise it requires a tuple wrapper.
      SWIFT_FALLTHROUGH;
    }

    // This covers both none and multiple parameters.
    default:
      auto tuple = Dem.createNode(Node::Kind::Tuple);
      for (auto &input : inputs) {
        NodePointer eltType;
        bool isVariadic;
        std::tie(eltType, isVariadic) = input;

        // Tuple element := variadic-marker label? type
        auto tupleElt = Dem.createNode(Node::Kind::TupleElement);

        if (isVariadic)
          tupleElt->addChild(Dem.createNode(Node::Kind::VariadicMarker), Dem);

        if (eltType->getKind() == Node::Kind::Type) {
          tupleElt->addChild(eltType, Dem);
        } else {
          auto type = Dem.createNode(Node::Kind::Type);
          type->addChild(eltType, Dem);
          tupleElt->addChild(type, Dem);
        }

        tuple->addChild(tupleElt, Dem);
      }
      totalInput = tuple;
      break;
    }

    NodePointer parameters = Dem.createNode(Node::Kind::ArgumentTuple);
    NodePointer paramType = Dem.createNode(Node::Kind::Type);

    paramType->addChild(totalInput, Dem);
    parameters->addChild(paramType, Dem);

    NodePointer resultTy = _swift_buildDemanglingForMetadata(func->ResultType,
                                                             Dem);
    if (!resultTy)
      return nullptr;

    NodePointer result = Dem.createNode(Node::Kind::ReturnType);
    result->addChild(resultTy, Dem);

    auto funcNode = Dem.createNode(kind);
    // Add the components of the function-signature production in the same
    // order that the demangler would.
    // TODO: C function type would go here
    if (func->getExtendedFlags().hasSendingResult())
      funcNode->addChild(Dem.createNode(Node::Kind::SendingResultFunctionType),
                         Dem);
    if (func->hasGlobalActor()) {
      auto globalActorTypeNode =
          _swift_buildDemanglingForMetadata(func->getGlobalActor(), Dem);
      if (!globalActorTypeNode)
        return nullptr;
      NodePointer globalActorNode =
          Dem.createNode(Node::Kind::GlobalActorFunctionType);
      globalActorNode->addChild(globalActorTypeNode, Dem);
      funcNode->addChild(globalActorNode, Dem);
    } else if (func->getExtendedFlags().isIsolatedAny()) {
      funcNode->addChild(Dem.createNode(
          Node::Kind::IsolatedAnyFunctionType), Dem);
    } else if (func->getExtendedFlags().isNonisolatedNonsending()) {
      funcNode->addChild(Dem.createNode(
        Node::Kind::NonIsolatedCallerFunctionType), Dem);
    }
    switch (func->getDifferentiabilityKind().Value) {
    case FunctionMetadataDifferentiabilityKind::NonDifferentiable:
      break;
    case FunctionMetadataDifferentiabilityKind::Forward:
      funcNode->addChild(Dem.createNode(
          Node::Kind::DifferentiableFunctionType,
          (Node::IndexType)MangledDifferentiabilityKind::Forward), Dem);
      break;
    case FunctionMetadataDifferentiabilityKind::Reverse:
      funcNode->addChild(Dem.createNode(
          Node::Kind::DifferentiableFunctionType,
          (Node::IndexType)MangledDifferentiabilityKind::Reverse), Dem);
      break;
    case FunctionMetadataDifferentiabilityKind::Normal:
      funcNode->addChild(Dem.createNode(
          Node::Kind::DifferentiableFunctionType,
          (Node::IndexType)MangledDifferentiabilityKind::Normal), Dem);
      break;
    case FunctionMetadataDifferentiabilityKind::Linear:
      funcNode->addChild(Dem.createNode(
          Node::Kind::DifferentiableFunctionType,
          (Node::IndexType)MangledDifferentiabilityKind::Linear), Dem);
      break;
    }
    if (func->isThrowing()) {
      if (auto thrownError = func->getThrownError()) {
        auto thrownErrorTypeNode =
          _swift_buildDemanglingForMetadata(thrownError, Dem);
        if (!thrownErrorTypeNode)
          return nullptr;
        NodePointer thrownErrorNode =
            Dem.createNode(Node::Kind::TypedThrowsAnnotation);
        thrownErrorNode->addChild(thrownErrorTypeNode, Dem);
        funcNode->addChild(thrownErrorNode, Dem);
      } else {
        funcNode->addChild(Dem.createNode(Node::Kind::ThrowsAnnotation), Dem);
      }
    }
    if (func->isSendable()) {
      funcNode->addChild(
          Dem.createNode(Node::Kind::ConcurrentFunctionType), Dem);
    }
    if (func->isAsync())
      funcNode->addChild(Dem.createNode(Node::Kind::AsyncAnnotation), Dem);

    funcNode->addChild(parameters, Dem);
    funcNode->addChild(result, Dem);
    return funcNode;
  }
  case MetadataKind::Metatype: {
    auto metatype = static_cast<const MetatypeMetadata *>(type);
    auto instance = _swift_buildDemanglingForMetadata(metatype->InstanceType,
                                                      Dem);
    if (!instance)
      return nullptr;

    auto typeNode = Dem.createNode(Node::Kind::Type);
    typeNode->addChild(instance, Dem);
    auto node = Dem.createNode(Node::Kind::Metatype);
    node->addChild(typeNode, Dem);
    return node;
  }
  case MetadataKind::Tuple: {
    auto tuple = static_cast<const TupleTypeMetadata *>(type);
    const char *labels = tuple->Labels;
    auto tupleNode = Dem.createNode(Node::Kind::Tuple);
    for (unsigned i = 0, e = tuple->NumElements; i < e; ++i) {
      auto elt = Dem.createNode(Node::Kind::TupleElement);

      // Add a label child if applicable:
      if (labels) {
        // Look for the next space in the labels string.
        if (const char *space = strchr(labels, ' ')) {
          // If there is one, and the label isn't empty, add a label child.
          if (labels != space) {
            auto eltName =
              Dem.createNode(Node::Kind::TupleElementName,
                                  llvm::StringRef(labels, space - labels));
            elt->addChild(eltName, Dem);
          }

          // Skip past the space.
          labels = space + 1;
        }
      }

      // Add the element type child.
      auto eltType =
        _swift_buildDemanglingForMetadata(tuple->getElement(i).Type, Dem);
      if (!eltType)
        return nullptr;

      if (eltType->getKind() == Node::Kind::Type) {
        elt->addChild(eltType, Dem);
      } else {
        auto type = Dem.createNode(Node::Kind::Type);
        type->addChild(eltType, Dem);
        elt->addChild(type, Dem);
      }

      // Add the completed element to the tuple.
      tupleNode->addChild(elt, Dem);
    }
    return tupleNode;
  }
  case MetadataKind::HeapLocalVariable:
  case MetadataKind::HeapGenericLocalVariable:
  case MetadataKind::ErrorObject:
    break;
  case MetadataKind::Opaque:
  default: {
    if (auto builtinType = _buildDemanglerForBuiltinType(type, Dem))
      return builtinType;
    
    // FIXME: Some opaque types do have manglings, but we don't have enough info
    // to figure them out.
    break;
  }
  }
  // Not a type.
  return nullptr;
}

Demangle::NodePointer
swift::_buildDemanglingForGenericType(const TypeContextDescriptor *description,
                                      const void *const *arguments,
                                      Demangle::Demangler &Dem) {
  auto kind = description->getKind();
  if (kind != ContextDescriptorKind::Class &&
      kind != ContextDescriptorKind::Enum &&
      kind != ContextDescriptorKind::Struct)
    return nullptr;

  llvm::SmallVector<NodePointer, 8> demangledGenerics;
  if (!_buildDemanglingForGenericArgs(description,
                                      (const Metadata *const *)arguments,
                                      demangledGenerics, Dem))
    return nullptr;

  return _buildDemanglingForContext(description, demangledGenerics, Dem);
}

// NB: This function is not used directly in the Swift codebase, but is
// exported for Xcode support and is used by the sanitizers. Please coordinate
// before changing.
//
/// Demangles a Swift symbol name.
///
/// \param mangledName is the symbol name that needs to be demangled.
/// \param mangledNameLength is the length of the string that should be
/// demangled.
/// \param outputBuffer is the user provided buffer where the demangled name
/// will be placed. If nullptr, a new buffer will be malloced. In that case,
/// the user of this API is responsible for freeing the returned buffer.
/// \param outputBufferSize is the size of the output buffer. If the demangled
/// name does not fit into the outputBuffer, the output will be truncated and
/// the size will be updated, indicating how large the buffer should be.
/// \param flags can be used to select the demangling style. TODO: We should
//// define what these will be.
/// \returns the demangled name. Returns nullptr if the input String is not a
/// Swift mangled name.
SWIFT_RUNTIME_EXPORT
char *swift_demangle(const char *mangledName,
                     size_t mangledNameLength,
                     char *outputBuffer,
                     size_t *outputBufferSize,
                     uint32_t flags) {
  if (flags != 0) {
    swift::fatalError(0, "Only 'flags' value of '0' is currently supported.");
  }
  if (outputBuffer != nullptr && outputBufferSize == nullptr) {
    swift::fatalError(0, "'outputBuffer' is passed but the size is 'nullptr'.");
  }

  // Check if we are dealing with Swift mangled name, otherwise, don't try
  // to demangle and send indication to the user.
  if (!Demangle::isSwiftSymbol(mangledName))
    return nullptr; // Not a mangled name

#if !SWIFT_STDLIB_HAS_TYPE_PRINTING
  return nullptr;
#else
  // Demangle the name.
  auto options = Demangle::DemangleOptions();
  options.DisplayDebuggerGeneratedModule = false;
  auto result =
      Demangle::demangleSymbolAsString(mangledName,
                                       mangledNameLength,
                                       options);

  // If the output buffer is not provided, malloc memory ourselves.
  if (outputBuffer == nullptr || *outputBufferSize == 0) {
#if defined(_WIN32)
    return _strdup(result.c_str());
#else
    return strdup(result.c_str());
#endif
  }

  // Copy into the provided buffer.
  _swift_strlcpy(outputBuffer, result.c_str(), *outputBufferSize);

  // Indicate a failure if the result did not fit and was truncated
  // by setting the required outputBufferSize.
  if (*outputBufferSize < result.length() + 1) {
    *outputBufferSize = result.length() + 1;
  }

  return outputBuffer;
#endif
}

namespace swift {
  namespace runtime {

    static bool isUTF8CodePointContinuationByte(unsigned char byte) {
      return (byte & 0b11000000) == 0b10000000;
    }

    // Demangle entry point for backtrace and public demangle() Swift API.
    SWIFT_RUNTIME_STDLIB_SPI size_t
    _swift_runtime_demangle(const char *mangledName,
                            size_t mangledNameLength,
                            char *outputBuffer,
                            size_t *outputBufferSize,
                            size_t flags) {
      assert(outputBuffer != nullptr);
      assert(outputBufferSize != nullptr);

      if (!mangledName || mangledNameLength == 0) {
        *outputBufferSize = 0;
        return 0;
      }
      if (flags > 0) {
        *outputBufferSize = 0;
        return 0; // ignore not supported flags
      }

      llvm::StringRef name = llvm::StringRef(mangledName, mangledNameLength);
      if (Demangle::isSwiftSymbol(name)) {
        // Determine demangling/formatting options:
        auto options = DemangleOptions();

        auto result = Demangle::demangleSymbolAsString(name, options);
        size_t toCopy = std::min(*outputBufferSize, result.length());

        // Are we accidentally cutting of an UTF8 codepoint in the middle?
        // there may be up to 4 continuations of a codepoint so we need to see if we're cutting off in the middle,
        // and if so, back out until we find the actual non-continuation byte.
        while (toCopy > 0 &&
               toCopy < result.length() &&
               isUTF8CodePointContinuationByte(result.data()[toCopy])) {
          // we're in the middle of an utf8 scalar, and would overwrite it with a null terminator resulting in a truncated UTF8-scalar.
          // don't do that, and instead truncate further back
          toCopy -= 1;
        }

        ::memcpy(outputBuffer, result.data(), toCopy);
        *outputBufferSize = toCopy; // indicate how many bytes were written

        // we return the total size of the result, even if we wrote less'
        // this is how we can detect truncation
        return result.length();
      }

      // We could attempt to demangle C++ symbols here, but we choose not to support this in Runtime.demangle(...)

      *outputBufferSize = 0; // indicate we did not write to buffer
      return 0; // we don't know how many bytes we'd need, the symbol was invalid to begin with
    }

    SWIFT_RUNTIME_STDLIB_SPI char *
    _swift_runtime_demangle_allocate(const char *mangledName,
                                    size_t mangledNameLength,
                                    size_t *outputSize,
                                    size_t flags) {
      if (!mangledName || !outputSize)
        return nullptr;
      if (flags > 0)
        return nullptr; // ignore not supported flags

      llvm::StringRef name = llvm::StringRef(mangledName, mangledNameLength);
      if (Demangle::isSwiftSymbol(name)) {
        // Determine demangling/formatting options:
        auto options = DemangleOptions();
        auto result = Demangle::demangleSymbolAsString(name, options);

        // we allocate the buffer for the result; truncation cannot happen in this case.
        auto totalLength = result.length();
        auto outputBuffer = (char *)::malloc(totalLength);
        if (!outputBuffer) {
          // malloc could have failed, let's handle it gracefully
          *outputSize = 0;
          return nullptr;
        }

        ::memcpy(outputBuffer, result.data(), totalLength);
        *outputSize = totalLength;
        return outputBuffer;
      }

      // We could attempt to demangle C++ symbols here, but we choose not to support this in Runtime.demangle(...)
      return nullptr;
    }

  } // namespace runtime
} // namespace swift
