/// For a mangled node that refers to an Objective-C class or protocol, /// return the class or protocol name. static Optional<StringRef> getObjCClassOrProtocolName( const Demangle::NodePointer &node) { if (node->getKind() != Demangle::Node::Kind::Class && node->getKind() != Demangle::Node::Kind::Protocol) return None; if (node->getNumChildren() != 2) return None; // Check whether we have the __ObjC module. auto moduleNode = node->getChild(0); if (moduleNode->getKind() != Demangle::Node::Kind::Module || moduleNode->getText() != MANGLING_MODULE_OBJC) return None; // Check whether we have an identifier. auto nameNode = node->getChild(1); if (nameNode->getKind() != Demangle::Node::Kind::Identifier) return None; return nameNode->getText(); }
bool swift::_contextDescriptorMatchesMangling(const ContextDescriptor *context, Demangle::NodePointer node) { while (context) { if (node->getKind() == Demangle::Node::Kind::Type) node = node->getChild(0); // We can directly match symbolic references to the current context. if (node && node->getKind() == Demangle::Node::Kind::SymbolicReference) { if (equalContexts(context, reinterpret_cast<const ContextDescriptor *>( node->getIndex()))) { return true; } } switch (context->getKind()) { case ContextDescriptorKind::Module: { auto module = cast<ModuleContextDescriptor>(context); // Match to a mangled module name. if (node->getKind() != Demangle::Node::Kind::Module) return false; if (!node->getText().equals(module->Name.get())) return false; node = nullptr; break; } case ContextDescriptorKind::Extension: { auto extension = cast<ExtensionContextDescriptor>(context); // Check whether the extension context matches the mangled context. if (node->getKind() != Demangle::Node::Kind::Extension) return false; if (node->getNumChildren() < 2) return false; // Check that the context being extended matches as well. auto extendedContextNode = node->getChild(1); auto extendedContextMangledName = extension->getMangledExtendedContext(); auto demangler = getDemanglerForRuntimeTypeResolution(); auto extendedContextDemangled = demangler.demangleType(extendedContextMangledName); if (!extendedContextDemangled) return false; if (extendedContextDemangled->getKind() == Node::Kind::Type) { if (extendedContextDemangled->getNumChildren() < 1) return false; extendedContextDemangled = extendedContextDemangled->getChild(0); } extendedContextDemangled = stripGenericArgsFromContextNode(extendedContextDemangled, demangler); auto extendedDescriptorFromNode = _findNominalTypeDescriptor(extendedContextNode, demangler); auto extendedDescriptorFromDemangled = _findNominalTypeDescriptor(extendedContextDemangled, demangler); if (!extendedDescriptorFromNode || !extendedDescriptorFromDemangled || !equalContexts(extendedDescriptorFromNode, extendedDescriptorFromDemangled)) return false; // Check whether the generic signature of the extension matches the // mangled constraints, if any. if (node->getNumChildren() >= 3) { // NB: If we ever support extensions with independent generic arguments // like `extension <T> Array where Element == Optional<T>`, we'd need // to look at the mangled context name to match up generic arguments. // That would probably need a new extension mangling form, though. // TODO } // The parent context of the extension should match in the mangling and // context descriptor. node = node->getChild(0); break; } default: if (auto type = llvm::dyn_cast<TypeContextDescriptor>(context)) { switch (node->getKind()) { // If the mangled name doesn't indicate a type kind, accept anything. // Otherwise, try to match them up. case Demangle::Node::Kind::OtherNominalType: break; case Demangle::Node::Kind::Structure: if (type->getKind() != ContextDescriptorKind::Struct && !type->getTypeContextDescriptorFlags().isCTag()) return false; break; case Demangle::Node::Kind::Class: if (type->getKind() != ContextDescriptorKind::Class) return false; break; case Demangle::Node::Kind::Enum: if (type->getKind() != ContextDescriptorKind::Enum) return false; break; case Demangle::Node::Kind::TypeAlias: if (!type->getTypeContextDescriptorFlags().isCTypedef()) return false; break; default: return false; } auto nameNode = node->getChild(1); // Declarations synthesized by the Clang importer get a small tag // string in addition to their name. if (nameNode->getKind() == Demangle::Node::Kind::RelatedEntityDeclName){ if (nameNode->getText() != type->getSynthesizedDeclRelatedEntityTag()) return false; nameNode = nameNode->getChild(0); } else if (type->isSynthesizedRelatedEntity()) { return false; } // We should only match public or internal declarations with stable // names. The runtime metadata for private declarations would be // anonymized. if (nameNode->getKind() == Demangle::Node::Kind::Identifier) { if (nameNode->getText() != type->Name.get()) return false; node = node->getChild(0); break; } return false; } // We don't know about this kind of context, or it doesn't have a stable // name we can match to. return false; } context = context->Parent; } // We should have reached the top of the node tree at the same time we reached // the top of the context tree. if (node) return false; return true; }
bool swift::_contextDescriptorMatchesMangling(const ContextDescriptor *context, Demangle::NodePointer node) { while (context) { if (node->getKind() == Demangle::Node::Kind::Type) node = node->getChild(0); // We can directly match symbolic references to the current context. if (node && node->getKind() == Demangle::Node::Kind::SymbolicReference) { if (equalContexts(context, reinterpret_cast<const ContextDescriptor *>( node->getIndex()))) { return true; } } switch (context->getKind()) { case ContextDescriptorKind::Module: { auto module = cast<ModuleContextDescriptor>(context); // Match to a mangled module name. if (node->getKind() != Demangle::Node::Kind::Module) return false; if (!node->getText().equals(module->Name.get())) return false; node = nullptr; break; } case ContextDescriptorKind::Extension: { auto extension = cast<ExtensionContextDescriptor>(context); // Check whether the extension context matches the mangled context. if (node->getKind() != Demangle::Node::Kind::Extension) return false; if (node->getNumChildren() < 2) return false; // Check that the context being extended matches as well. auto extendedContextNode = node->getChild(1); auto extendedContextMangledName = extension->getMangledExtendedContext(); auto demangler = getDemanglerForRuntimeTypeResolution(); auto extendedContextDemangled = demangler.demangleType(extendedContextMangledName); if (!extendedContextDemangled) return false; if (extendedContextDemangled->getKind() == Node::Kind::Type) { if (extendedContextDemangled->getNumChildren() < 1) return false; extendedContextDemangled = extendedContextDemangled->getChild(0); } extendedContextDemangled = stripGenericArgsFromContextNode(extendedContextDemangled, demangler); auto extendedDescriptorFromNode = _findNominalTypeDescriptor(extendedContextNode, demangler); auto extendedDescriptorFromDemangled = _findNominalTypeDescriptor(extendedContextDemangled, demangler); // Determine whether the contexts match. bool contextsMatch = extendedDescriptorFromNode && extendedDescriptorFromDemangled && equalContexts(extendedDescriptorFromNode, extendedDescriptorFromDemangled); #if SWIFT_OBJC_INTEROP if (!contextsMatch && (!extendedDescriptorFromNode || !extendedDescriptorFromDemangled) && sameObjCTypeManglings(extendedContextNode, extendedContextDemangled)) { contextsMatch = true; } #endif if (!contextsMatch) return false; // Check whether the generic signature of the extension matches the // mangled constraints, if any. if (node->getNumChildren() >= 3) { // NB: If we ever support extensions with independent generic arguments // like `extension <T> Array where Element == Optional<T>`, we'd need // to look at the mangled context name to match up generic arguments. // That would probably need a new extension mangling form, though. // TODO } // The parent context of the extension should match in the mangling and // context descriptor. node = node->getChild(0); break; } case ContextDescriptorKind::Protocol: // Match a protocol context. if (node->getKind() == Demangle::Node::Kind::Protocol) { auto proto = llvm::cast<ProtocolDescriptor>(context); auto nameNode = node->getChild(1); if (nameNode->getText() == proto->Name.get()) { node = node->getChild(0); break; } } return false; default: if (auto type = llvm::dyn_cast<TypeContextDescriptor>(context)) { Optional<ParsedTypeIdentity> _identity; auto getIdentity = [&]() -> const ParsedTypeIdentity & { if (_identity) return *_identity; _identity = ParsedTypeIdentity::parse(type); return *_identity; }; switch (node->getKind()) { // If the mangled name doesn't indicate a type kind, accept anything. // Otherwise, try to match them up. case Demangle::Node::Kind::OtherNominalType: break; case Demangle::Node::Kind::Structure: // We allow non-structs to match Kind::Structure if they are // imported C tag types. This is necessary because we artificially // make imported C tag types Kind::Structure. if (type->getKind() != ContextDescriptorKind::Struct && !_isCImportedTagType(type, getIdentity())) return false; break; case Demangle::Node::Kind::Class: if (type->getKind() != ContextDescriptorKind::Class) return false; break; case Demangle::Node::Kind::Enum: if (type->getKind() != ContextDescriptorKind::Enum) return false; break; case Demangle::Node::Kind::TypeAlias: if (!getIdentity().isCTypedef()) return false; break; default: return false; } auto nameNode = node->getChild(1); // Declarations synthesized by the Clang importer get a small tag // string in addition to their name. if (nameNode->getKind() == Demangle::Node::Kind::RelatedEntityDeclName){ if (!getIdentity().isRelatedEntity(nameNode->getText())) return false; nameNode = nameNode->getChild(0); } else if (getIdentity().isAnyRelatedEntity()) { return false; } // We should only match public or internal declarations with stable // names. The runtime metadata for private declarations would be // anonymized. if (nameNode->getKind() == Demangle::Node::Kind::Identifier) { if (nameNode->getText() != getIdentity().getABIName()) return false; node = node->getChild(0); break; } return false; } // We don't know about this kind of context, or it doesn't have a stable // name we can match to. return false; } context = context->Parent; } // We should have reached the top of the node tree at the same time we reached // the top of the context tree. if (node) return false; return true; }