Skip to content

[5.7][Static Mirror] Extract names of external-type conformances #42424

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 38 additions & 10 deletions include/swift/Reflection/TypeRefBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -1148,11 +1148,21 @@ class TypeRefBuilder {
}

/// Extract conforming type's name from a Conformance Descriptor
llvm::Optional<std::string> getConformingTypeName(
/// Returns a pair of (mangledTypeName, fullyQualifiedTypeName)
llvm::Optional<std::pair<std::string, std::string>> getConformingTypeName(
const uintptr_t conformanceDescriptorAddress,
const ExternalProtocolConformanceDescriptor<
ObjCInteropKind, PointerSize> &conformanceDescriptor) {
std::string typeName;
std::string mangledTypeName = "";

// If this is a conformance added to an ObjC class, detect that here and return class name
if (conformanceDescriptor.getTypeKind() == TypeReferenceKind::DirectObjCClassName) {
auto className = conformanceDescriptor.getDirectObjCClassName();
typeName = MANGLING_MODULE_OBJC.str() + std::string(".") + className;
return std::make_pair(mangledTypeName, typeName);
}

// Compute the address of the type descriptor as follows:
// - Compute the address of the TypeRef field in the protocol
// descriptor
Expand All @@ -1179,6 +1189,21 @@ class TypeRefBuilder {
(const char *)contextDescriptorFieldAddress,
(int32_t)*contextDescriptorOffset);

// Instead of a type descriptor this may just be a symbol reference, check that first
if (auto symbol = OpaquePointerReader(remote::RemoteAddress(contextTypeDescriptorAddress),
PointerSize)) {
if (!symbol->getSymbol().empty()) {
mangledTypeName = symbol->getSymbol().str();
Demangle::Context Ctx;
auto demangledRoot =
Ctx.demangleSymbolAsNode(mangledTypeName);
assert(demangledRoot->getKind() == Node::Kind::Global);
typeName =
nodeToString(demangledRoot->getChild(0)->getChild(0));
return std::make_pair(mangledTypeName, typeName);
}
}

auto contextTypeDescriptorBytes = OpaqueByteReader(
remote::RemoteAddress(contextTypeDescriptorAddress),
sizeof(ExternalContextDescriptor<ObjCInteropKind, PointerSize>));
Expand Down Expand Up @@ -1213,7 +1238,7 @@ class TypeRefBuilder {
typeName = optionalParentName.getValue() + "." + typeName;
}

return typeName;
return std::make_pair(mangledTypeName, typeName);
}

/// Extract protocol name from a Conformance Descriptor
Expand Down Expand Up @@ -1317,9 +1342,9 @@ class TypeRefBuilder {
(const ExternalProtocolConformanceDescriptor<
ObjCInteropKind, PointerSize> *)descriptorBytes.get();

auto optionalConformingTypeName = getConformingTypeName(
auto optionalConformingTypeNamePair = getConformingTypeName(
conformanceDescriptorAddress, *conformanceDescriptorPtr);
if (!optionalConformingTypeName.hasValue())
if (!optionalConformingTypeNamePair.hasValue())
return llvm::None;

auto optionalConformanceProtocol = getConformanceProtocolName(
Expand All @@ -1328,15 +1353,18 @@ class TypeRefBuilder {
return llvm::None;

std::string mangledTypeName;
auto it =
typeNameToManglingMap.find(optionalConformingTypeName.getValue());
if (it != typeNameToManglingMap.end()) {
mangledTypeName = it->second;
if (optionalConformingTypeNamePair.getValue().first.empty()) {
auto it = typeNameToManglingMap.find(optionalConformingTypeNamePair.getValue().second);
if (it != typeNameToManglingMap.end()) {
mangledTypeName = it->second;
} else {
mangledTypeName = "";
}
} else {
mangledTypeName = "";
mangledTypeName = optionalConformingTypeNamePair.getValue().first;
}

return ProtocolConformanceInfo{optionalConformingTypeName.getValue(),
return ProtocolConformanceInfo{optionalConformingTypeNamePair.getValue().second,
optionalConformanceProtocol.getValue(),
mangledTypeName};
}
Expand Down
4 changes: 4 additions & 0 deletions test/Reflection/Inputs/cmodules/module.modulemap
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
module testModA {
header "testModA.h"
export *
}
4 changes: 4 additions & 0 deletions test/Reflection/Inputs/cmodules/testModA.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#import <Foundation/Foundation.h>
@interface testModAClass : NSObject
@property int x;
@end
9 changes: 9 additions & 0 deletions test/Reflection/Inputs/cmodules/testModA.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#import "testModA.h"

@implementation testModAClass
- (instancetype) init {
if ((self = [super init]) == nil) return nil;
self.x = 42;
return self;
}
@end
3 changes: 3 additions & 0 deletions test/Reflection/Inputs/swiftmodules/testModB.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import Foundation

public struct testModBStruct {}
29 changes: 29 additions & 0 deletions test/Reflection/conformance_descriptors_of_external_types.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// REQUIRES: objc_interop, OS=macosx
// Temporarily disable on arm64e (rdar://88579818)
// UNSUPPORTED: CPU=arm64e

// RUN: %empty-directory(%t)
// RUN: %empty-directory(%t/includes)

// Build external Swift library/module
// RUN: %target-build-swift %S/Inputs/swiftmodules/testModB.swift -parse-as-library -emit-module -emit-library -module-name testModB -o %t/includes/testModB.o

// Build external Clang library
// RUN: %target-clang %S/Inputs/cmodules/testModA.m -c -o %t/testModA.o

// Build the test into a binary
// RUN: %target-build-swift %s -parse-as-library -emit-module -emit-library -module-name ExternalConformanceCheck -I %t/includes -I %S/Inputs/cmodules -o %t/ExternalConformances %t/testModA.o %t/includes/testModB.o

// RUN: %target-swift-reflection-dump -binary-filename %t/ExternalConformances -binary-filename %platform-module-dir/%target-library-name(swiftCore) | %FileCheck %s

import testModA
import testModB

protocol myTestProto {}
extension testModBStruct : myTestProto {}
extension testModAClass : myTestProto {}

// CHECK: CONFORMANCES:
// CHECK: =============
// CHECK-DAG: (__C.testModAClass) : ExternalConformanceCheck.myTestProto
// CHECK-DAG: _$s8testModB0aB7BStructVMn (testModB.testModBStruct) : ExternalConformanceCheck.myTestProto