| //===----------------------------------------------------------------------===// |
| // |
| // 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 "swift/Runtime/Metadata.h" |
| #include "swift/Strings.h" |
| #include "Private.h" |
| |
| #include <vector> |
| |
| #if SWIFT_OBJC_INTEROP |
| #include <objc/runtime.h> |
| #endif |
| |
| using namespace swift; |
| |
| // FIXME: This stuff should be merged with the existing logic in |
| // include/swift/Reflection/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); |
| |
| // Build a demangled type tree for a nominal type. |
| static Demangle::NodePointer |
| _buildDemanglingForNominalType(const Metadata *type, Demangle::Demangler &Dem) { |
| using namespace Demangle; |
| |
| const Metadata *parent; |
| Node::Kind boundGenericKind; |
| const NominalTypeDescriptor *description; |
| |
| // Demangle the parent type, if any. |
| switch (type->getKind()) { |
| case MetadataKind::Class: { |
| auto classType = static_cast<const ClassMetadata *>(type); |
| #if SWIFT_OBJC_INTEROP |
| // Peek through artificial subclasses. |
| while (classType->isTypeMetadata() && classType->isArtificialSubclass()) |
| classType = classType->SuperClass; |
| #endif |
| parent = classType->getParentType(classType->getDescription()); |
| boundGenericKind = Node::Kind::BoundGenericClass; |
| description = classType->getDescription(); |
| break; |
| } |
| case MetadataKind::Enum: |
| case MetadataKind::Optional: { |
| auto enumType = static_cast<const EnumMetadata *>(type); |
| parent = enumType->Parent; |
| boundGenericKind = Node::Kind::BoundGenericEnum; |
| description = enumType->Description; |
| break; |
| } |
| case MetadataKind::Struct: { |
| auto structType = static_cast<const StructMetadata *>(type); |
| parent = structType->Parent; |
| boundGenericKind = Node::Kind::BoundGenericStructure; |
| description = structType->Description; |
| break; |
| } |
| default: |
| return nullptr; |
| } |
| |
| // Demangle the base name. |
| auto node = Dem.demangleType(StringRef(description->Name)); |
| assert(node->getKind() == Node::Kind::Type); |
| |
| // Demangle the parent. |
| if (parent) { |
| auto parentNode = _swift_buildDemanglingForMetadata(parent, Dem); |
| if (parentNode->getKind() == Node::Kind::Type) |
| parentNode = parentNode->getChild(0); |
| |
| auto typeNode = node->getChild(0); |
| auto newTypeNode = Dem.createNode(typeNode->getKind()); |
| newTypeNode->addChild(parentNode, Dem); |
| newTypeNode->addChild(typeNode->getChild(1), Dem); |
| |
| auto newNode = Dem.createNode(Node::Kind::Type); |
| newNode->addChild(newTypeNode, Dem); |
| node = newNode; |
| } |
| |
| // If generic, demangle the type parameters. |
| if (description->GenericParams.NumPrimaryParams > 0) { |
| auto typeParams = Dem.createNode(Node::Kind::TypeList); |
| auto typeBytes = reinterpret_cast<const char *>(type); |
| auto genericParam = reinterpret_cast<const Metadata * const *>( |
| typeBytes + sizeof(void*) * description->GenericParams.Offset); |
| for (unsigned i = 0, e = description->GenericParams.NumPrimaryParams; |
| i < e; ++i, ++genericParam) { |
| auto demangling = _swift_buildDemanglingForMetadata(*genericParam, Dem); |
| if (demangling == nullptr) |
| return nullptr; |
| typeParams->addChild(demangling, Dem); |
| } |
| |
| auto genericNode = Dem.createNode(boundGenericKind); |
| genericNode->addChild(node, Dem); |
| genericNode->addChild(typeParams, Dem); |
| return genericNode; |
| } |
| return node; |
| } |
| |
| // Build a demangled type tree for a type. |
| 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: |
| return _buildDemanglingForNominalType(type, Dem); |
| case MetadataKind::ObjCClassWrapper: { |
| #if SWIFT_OBJC_INTEROP |
| auto objcWrapper = static_cast<const ObjCClassWrapperMetadata *>(type); |
| const char *className = class_getName((Class)objcWrapper->Class); |
| |
| // ObjC classes mangle as being in the magic "__ObjC" module. |
| auto module = Dem.createNode(Node::Kind::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::ForeignClass: { |
| auto foreign = static_cast<const ForeignClassMetadata *>(type); |
| return Dem.demangleType(foreign->getName()); |
| } |
| case MetadataKind::Existential: { |
| auto exis = static_cast<const ExistentialTypeMetadata *>(type); |
| |
| std::vector<const ProtocolDescriptor *> protocols; |
| protocols.reserve(exis->Protocols.NumProtocols); |
| for (unsigned i = 0, e = exis->Protocols.NumProtocols; i < e; ++i) |
| protocols.push_back(exis->Protocols[i]); |
| |
| 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) { |
| // The protocol name is mangled as a type symbol, with the _Tt prefix. |
| StringRef ProtoName(protocol->Name); |
| 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, |
| llvm::StringRef(protocol->Name)), Dem); |
| auto typeNode = Dem.createNode(Node::Kind::Type); |
| typeNode->addChild(node, Dem); |
| type_list->addChild(typeNode, Dem); |
| continue; |
| } |
| |
| // FIXME: We have to dig through a ridiculous number of nodes to get |
| // to the Protocol node here. |
| protocolNode = protocolNode->getChild(0); // Global -> 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); |
| 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); |
| |
| 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->Flags.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::ExistentialMetatype: { |
| auto metatype = static_cast<const ExistentialMetatypeMetadata *>(type); |
| auto instance = _swift_buildDemanglingForMetadata(metatype->InstanceType, |
| Dem); |
| 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: |
| 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; |
| } |
| |
| std::vector<NodePointer> inputs; |
| for (unsigned i = 0, e = func->getNumArguments(); i < e; ++i) { |
| auto arg = func->getArguments()[i]; |
| auto input = _swift_buildDemanglingForMetadata(arg.getPointer(), Dem); |
| if (arg.getFlag()) { |
| NodePointer inout = Dem.createNode(Node::Kind::InOut); |
| inout->addChild(input, Dem); |
| input = inout; |
| } |
| inputs.push_back(input); |
| } |
| |
| NodePointer totalInput = nullptr; |
| if (inputs.size() > 1) { |
| auto tuple = Dem.createNode(Node::Kind::Tuple); |
| for (auto &input : inputs) |
| tuple->addChild(input, Dem); |
| totalInput = tuple; |
| } else { |
| totalInput = inputs.front(); |
| } |
| |
| NodePointer args = Dem.createNode(Node::Kind::ArgumentTuple); |
| args->addChild(totalInput, Dem); |
| |
| NodePointer resultTy = _swift_buildDemanglingForMetadata(func->ResultType, |
| Dem); |
| NodePointer result = Dem.createNode(Node::Kind::ReturnType); |
| result->addChild(resultTy, Dem); |
| |
| auto funcNode = Dem.createNode(kind); |
| if (func->throws()) |
| funcNode->addChild(Dem.createNode(Node::Kind::ThrowsAnnotation), Dem); |
| funcNode->addChild(args, Dem); |
| funcNode->addChild(result, Dem); |
| return funcNode; |
| } |
| case MetadataKind::Metatype: { |
| auto metatype = static_cast<const MetatypeMetadata *>(type); |
| auto instance = _swift_buildDemanglingForMetadata(metatype->InstanceType, |
| Dem); |
| 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); |
| elt->addChild(eltType, Dem); |
| |
| // Add the completed element to the tuple. |
| tupleNode->addChild(elt, Dem); |
| } |
| return tupleNode; |
| } |
| case MetadataKind::Opaque: |
| // FIXME: Some opaque types do have manglings, but we don't have enough info |
| // to figure them out. |
| case MetadataKind::HeapLocalVariable: |
| case MetadataKind::HeapGenericLocalVariable: |
| case MetadataKind::ErrorObject: |
| break; |
| } |
| // Not a type. |
| return nullptr; |
| } |