mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
Finish off the log part of _swift_checkClassAndWarnForKeyedArchiving. (#10418)
Logs a warning the first time a problematic class is archived or unarchived. We expect people to actually fix these issues, so the performance of the warning isn't too important. Sample output: [timestamp] Attempting to archive Swift class '_Test.Outer.ArchivedThenUnarchived', which does not have a stable runtime name. [timestamp] Use the 'objc' attribute to ensure that the runtime name will not change: "@objc(_TtCC5_Test5Outer22ArchivedThenUnarchived)" [timestamp] If there are no existing archives containing this class, you can choose a unique, prefixed name instead: "@objc(ABCArchivedThenUnarchived)" Finishes rdar://problem/32414508
This commit is contained in:
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include <objc/runtime.h>
|
#include <objc/runtime.h>
|
||||||
|
|
||||||
|
#include "swift/Runtime/HeapObject.h"
|
||||||
#include "swift/Runtime/Metadata.h"
|
#include "swift/Runtime/Metadata.h"
|
||||||
|
|
||||||
@interface NSKeyedUnarchiver (SwiftAdditions)
|
@interface NSKeyedUnarchiver (SwiftAdditions)
|
||||||
@@ -10,9 +11,116 @@
|
|||||||
NS_SWIFT_NAME(_swift_checkClassAndWarnForKeyedArchiving(_:operation:));
|
NS_SWIFT_NAME(_swift_checkClassAndWarnForKeyedArchiving(_:operation:));
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
static bool isASCIIIdentifierChar(char c) {
|
||||||
|
if (c >= 'a' && c <= 'z') return true;
|
||||||
|
if (c >= 'A' && c <= 'Z') return true;
|
||||||
|
if (c >= '0' && c <= '9') return true;
|
||||||
|
if (c == '_') return true;
|
||||||
|
if (c == '$') return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void logIfFirstOccurrence(Class objcClass, void (^log)(void)) {
|
||||||
|
static auto queue = dispatch_queue_create(
|
||||||
|
"SwiftFoundation._checkClassAndWarnForKeyedArchivingQueue",
|
||||||
|
DISPATCH_QUEUE_SERIAL);
|
||||||
|
static NSHashTable *seenClasses = nil;
|
||||||
|
|
||||||
|
dispatch_sync(queue, ^{
|
||||||
|
// Will be NO when seenClasses is still nil.
|
||||||
|
if ([seenClasses containsObject:objcClass])
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!seenClasses) {
|
||||||
|
NSPointerFunctionsOptions options = 0;
|
||||||
|
options |= NSPointerFunctionsOpaqueMemory;
|
||||||
|
options |= NSPointerFunctionsObjectPointerPersonality;
|
||||||
|
seenClasses = [[NSHashTable alloc] initWithOptions:options capacity:16];
|
||||||
|
}
|
||||||
|
[seenClasses addObject:objcClass];
|
||||||
|
|
||||||
|
// Synchronize logging so that multiple lines aren't interleaved.
|
||||||
|
log();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
class StringRefLite {
|
||||||
|
StringRefLite(const char *data, size_t len) : data(data), length(len) {}
|
||||||
|
public:
|
||||||
|
const char *data;
|
||||||
|
size_t length;
|
||||||
|
|
||||||
|
StringRefLite() : data(nullptr), length(0) {}
|
||||||
|
|
||||||
|
template <size_t N>
|
||||||
|
StringRefLite(const char (&staticStr)[N]) : data(staticStr), length(N) {}
|
||||||
|
|
||||||
|
StringRefLite(swift::TwoWordPair<const char *, uintptr_t> pair)
|
||||||
|
: data(pair.first), length(pair.second) {}
|
||||||
|
|
||||||
|
NS_RETURNS_RETAINED
|
||||||
|
NSString *newNSStringNoCopy() const {
|
||||||
|
return [[NSString alloc] initWithBytesNoCopy:const_cast<char *>(data)
|
||||||
|
length:length
|
||||||
|
encoding:NSUTF8StringEncoding
|
||||||
|
freeWhenDone:NO];
|
||||||
|
}
|
||||||
|
|
||||||
|
const char &operator[](size_t offset) const {
|
||||||
|
assert(offset < length);
|
||||||
|
return data[offset];
|
||||||
|
}
|
||||||
|
|
||||||
|
StringRefLite slice(size_t from, size_t to) const {
|
||||||
|
assert(from <= to);
|
||||||
|
assert(to <= length);
|
||||||
|
return {data + from, to - from};
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *begin() const {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
const char *end() const {
|
||||||
|
return data + length;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Assume that a non-generic demangled class name always ends in ".MyClass"
|
||||||
|
/// or ".(MyClass plus extra info)".
|
||||||
|
static StringRefLite findBaseName(StringRefLite demangledName) {
|
||||||
|
size_t end = demangledName.length;
|
||||||
|
size_t parenCount = 0;
|
||||||
|
for (size_t i = end; i != 0; --i) {
|
||||||
|
switch (demangledName[i - 1]) {
|
||||||
|
case '.':
|
||||||
|
if (parenCount == 0) {
|
||||||
|
if (i != end && demangledName[i] == '(')
|
||||||
|
++i;
|
||||||
|
return demangledName.slice(i, end);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ')':
|
||||||
|
parenCount += 1;
|
||||||
|
break;
|
||||||
|
case '(':
|
||||||
|
if (parenCount > 0)
|
||||||
|
parenCount -= 1;
|
||||||
|
break;
|
||||||
|
case ' ':
|
||||||
|
end = i - 1;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
@implementation NSKeyedUnarchiver (SwiftAdditions)
|
@implementation NSKeyedUnarchiver (SwiftAdditions)
|
||||||
|
|
||||||
/// Checks if class \p cls is good for archiving.
|
/// Checks if class \p objcClass is good for archiving.
|
||||||
///
|
///
|
||||||
/// If not, a runtime warning is printed.
|
/// If not, a runtime warning is printed.
|
||||||
///
|
///
|
||||||
@@ -25,20 +133,21 @@
|
|||||||
/// 2: a Swift non-generic class where adding @objc is valid
|
/// 2: a Swift non-generic class where adding @objc is valid
|
||||||
/// Future versions of this API will return nonzero values for additional cases
|
/// Future versions of this API will return nonzero values for additional cases
|
||||||
/// that mean the class shouldn't be archived.
|
/// that mean the class shouldn't be archived.
|
||||||
+ (int)_swift_checkClassAndWarnForKeyedArchiving:(Class)cls
|
+ (int)_swift_checkClassAndWarnForKeyedArchiving:(Class)objcClass
|
||||||
operation:(int)operation {
|
operation:(int)operation {
|
||||||
const swift::ClassMetadata *theClass = (swift::ClassMetadata *)cls;
|
using namespace swift;
|
||||||
|
const ClassMetadata *theClass = (ClassMetadata *)objcClass;
|
||||||
|
|
||||||
// Is it a (real) swift class?
|
// Is it a (real) swift class?
|
||||||
if (!theClass->isTypeMetadata() || theClass->isArtificialSubclass())
|
if (!theClass->isTypeMetadata() || theClass->isArtificialSubclass())
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
// Does the class already have a custom name?
|
// Does the class already have a custom name?
|
||||||
if (theClass->getFlags() & swift::ClassFlags::HasCustomObjCName)
|
if (theClass->getFlags() & ClassFlags::HasCustomObjCName)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
// Is it a mangled name?
|
// Is it a mangled name?
|
||||||
const char *className = class_getName(cls);
|
const char *className = class_getName(objcClass);
|
||||||
if (!(className[0] == '_' && className[1] == 'T'))
|
if (!(className[0] == '_' && className[1] == 'T'))
|
||||||
return 0;
|
return 0;
|
||||||
// Is it a name in the form <module>.<class>? Note: the module name could
|
// Is it a name in the form <module>.<class>? Note: the module name could
|
||||||
@@ -48,13 +157,74 @@
|
|||||||
|
|
||||||
// Is it a generic class?
|
// Is it a generic class?
|
||||||
if (theClass->getDescription()->GenericParams.isGeneric()) {
|
if (theClass->getDescription()->GenericParams.isGeneric()) {
|
||||||
// TODO: print a warning
|
logIfFirstOccurrence(objcClass, ^{
|
||||||
|
// Use actual NSStrings to force UTF-8.
|
||||||
|
StringRefLite demangledName = swift_getTypeName(theClass,
|
||||||
|
/*qualified*/true);
|
||||||
|
NSString *demangledString = demangledName.newNSStringNoCopy();
|
||||||
|
NSString *mangledString = NSStringFromClass(objcClass);
|
||||||
|
switch (operation) {
|
||||||
|
case 1:
|
||||||
|
NSLog(@"Attempting to unarchive generic Swift class '%@' with mangled "
|
||||||
|
"runtime name '%@'. Runtime names for generic classes are "
|
||||||
|
"unstable and may change in the future, leading to "
|
||||||
|
"non-decodable data.", demangledString, mangledString);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
NSLog(@"Attempting to archive generic Swift class '%@' with mangled "
|
||||||
|
"runtime name '%@'. Runtime names for generic classes are "
|
||||||
|
"unstable and may change in the future, leading to "
|
||||||
|
"non-decodable data.", demangledString, mangledString);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
NSLog(@"To avoid this failure, create a concrete subclass and register "
|
||||||
|
"it with NSKeyedUnarchiver.setClass(_:forClassName:) instead, "
|
||||||
|
"using the name \"%@\".", mangledString);
|
||||||
|
NSLog(@"If you need to produce archives compatible with older versions "
|
||||||
|
"of your program, use NSKeyedArchiver.setClassName(_:for:) "
|
||||||
|
"as well.");
|
||||||
|
[demangledString release];
|
||||||
|
});
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// It's a swift class with a (compiler generated) mangled name, which should
|
// It's a swift class with a (compiler generated) mangled name, which should
|
||||||
// be written into an NSArchive.
|
// be written into an NSArchive.
|
||||||
// TODO: print a warning
|
logIfFirstOccurrence(objcClass, ^{
|
||||||
|
// Use actual NSStrings to force UTF-8.
|
||||||
|
StringRefLite demangledName = swift_getTypeName(theClass,/*qualified*/true);
|
||||||
|
NSString *demangledString = demangledName.newNSStringNoCopy();
|
||||||
|
NSString *mangledString = NSStringFromClass(objcClass);
|
||||||
|
switch (operation) {
|
||||||
|
case 1:
|
||||||
|
NSLog(@"Attempting to unarchive Swift class '%@' with mangled runtime "
|
||||||
|
"name '%@'. The runtime name for this class is unstable and may "
|
||||||
|
"change in the future, leading to non-decodable data.",
|
||||||
|
demangledString, mangledString);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
NSLog(@"Attempting to archive Swift class '%@' with mangled runtime "
|
||||||
|
"name '%@'. The runtime name for this class is unstable and may "
|
||||||
|
"change in the future, leading to non-decodable data.",
|
||||||
|
demangledString, mangledString);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
[demangledString release];
|
||||||
|
NSLog(@"You can use the 'objc' attribute to ensure that the name will not "
|
||||||
|
"change: \"@objc(%@)\"", mangledString);
|
||||||
|
|
||||||
|
StringRefLite baseName = findBaseName(demangledName);
|
||||||
|
// Offer a more generic message if the base name we found doesn't look like
|
||||||
|
// an ASCII identifier. This avoids printing names like "ABCモデル".
|
||||||
|
if (baseName.length == 0 ||
|
||||||
|
!std::all_of(baseName.begin(), baseName.end(), isASCIIIdentifierChar)) {
|
||||||
|
baseName = "MyModel";
|
||||||
|
}
|
||||||
|
|
||||||
|
NSLog(@"If there are no existing archives containing this class, you "
|
||||||
|
"should choose a unique, prefixed name instead: "
|
||||||
|
"\"@objc(ABC%1$.*2$s)\"", baseName.data, (int)baseName.length);
|
||||||
|
});
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
@end
|
@end
|
||||||
|
|||||||
173
test/Interpreter/SDK/check_class_for_archiving_log.swift
Normal file
173
test/Interpreter/SDK/check_class_for_archiving_log.swift
Normal file
@@ -0,0 +1,173 @@
|
|||||||
|
// RUN: %empty-directory(%t)
|
||||||
|
// RUN: %target-build-swift %s -module-name=_Test -import-objc-header %S/Inputs/check_class_for_archiving.h -o %t/a.out
|
||||||
|
// RUN: %target-run %t/a.out 2>&1 | %FileCheck %s
|
||||||
|
|
||||||
|
// REQUIRES: executable_test
|
||||||
|
// REQUIRES: objc_interop
|
||||||
|
|
||||||
|
// This test doesn't use StdlibUnittest because it's primarily concerned with
|
||||||
|
// checking the presence and absence of output.
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
class SwiftClass {}
|
||||||
|
|
||||||
|
func checkArchiving(_ cls: AnyObject.Type) {
|
||||||
|
NSKeyedUnarchiver._swift_checkClassAndWarnForKeyedArchiving(cls, operation: 0)
|
||||||
|
}
|
||||||
|
func checkUnarchiving(_ cls: AnyObject.Type) {
|
||||||
|
NSKeyedUnarchiver._swift_checkClassAndWarnForKeyedArchiving(cls, operation: 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func mark(line: Int32 = #line) {
|
||||||
|
NSLog("--%d--", line)
|
||||||
|
}
|
||||||
|
|
||||||
|
mark() // CHECK: --[[@LINE]]--
|
||||||
|
checkArchiving(SwiftClass.self)
|
||||||
|
mark() // CHECK-NEXT: --[[@LINE]]--
|
||||||
|
|
||||||
|
|
||||||
|
private class ArchivedTwice {}
|
||||||
|
|
||||||
|
checkArchiving(ArchivedTwice.self)
|
||||||
|
// CHECK-NEXT: Attempting to archive Swift class '_Test.(ArchivedTwice in {{.+}})' with mangled runtime name '_TtC{{.+[0-9]+}}ArchivedTwice'
|
||||||
|
// CHECK-NEXT: @objc(_TtC{{.+[0-9]+}}ArchivedTwice)
|
||||||
|
// CHECK-NEXT: @objc(ABCArchivedTwice)
|
||||||
|
mark() // CHECK-NEXT: --[[@LINE]]--
|
||||||
|
checkArchiving(ArchivedTwice.self)
|
||||||
|
mark() // CHECK-NEXT: --[[@LINE]]--
|
||||||
|
|
||||||
|
private class UnarchivedTwice {}
|
||||||
|
|
||||||
|
checkUnarchiving(UnarchivedTwice.self)
|
||||||
|
// CHECK-NEXT: Attempting to unarchive Swift class '_Test.(UnarchivedTwice in {{.+}})' with mangled runtime name '_TtC{{.+[0-9]+}}UnarchivedTwice'
|
||||||
|
// CHECK-NEXT: @objc(_TtC{{.+[0-9]+}}UnarchivedTwice)
|
||||||
|
// CHECK-NEXT: @objc(ABCUnarchivedTwice)
|
||||||
|
mark() // CHECK-NEXT: --[[@LINE]]--
|
||||||
|
checkUnarchiving(UnarchivedTwice.self)
|
||||||
|
mark() // CHECK-NEXT: --[[@LINE]]--
|
||||||
|
|
||||||
|
private class ArchivedThenUnarchived {}
|
||||||
|
|
||||||
|
checkArchiving(ArchivedThenUnarchived.self)
|
||||||
|
// CHECK-NEXT: Attempting to archive Swift class '_Test.(ArchivedThenUnarchived in {{.+}})' with mangled runtime name '_TtC{{.+[0-9]+}}ArchivedThenUnarchived'
|
||||||
|
// CHECK-NEXT: @objc(_TtC{{.+[0-9]+}}ArchivedThenUnarchived)
|
||||||
|
// CHECK-NEXT: @objc(ABCArchivedThenUnarchived)
|
||||||
|
mark() // CHECK-NEXT: --[[@LINE]]--
|
||||||
|
checkUnarchiving(ArchivedThenUnarchived.self)
|
||||||
|
mark() // CHECK-NEXT: --[[@LINE]]--
|
||||||
|
|
||||||
|
private class UnarchivedThenArchived {}
|
||||||
|
|
||||||
|
checkUnarchiving(UnarchivedThenArchived.self)
|
||||||
|
// CHECK-NEXT: Attempting to unarchive Swift class '_Test.(UnarchivedThenArchived in {{.+}})' with mangled runtime name '_TtC{{.+[0-9]+}}UnarchivedThenArchived'
|
||||||
|
// CHECK-NEXT: @objc(_TtC{{.+[0-9]+}}UnarchivedThenArchived)
|
||||||
|
// CHECK-NEXT: @objc(ABCUnarchivedThenArchived)
|
||||||
|
mark() // CHECK-NEXT: --[[@LINE]]--
|
||||||
|
checkArchiving(UnarchivedThenArchived.self)
|
||||||
|
mark() // CHECK-NEXT: --[[@LINE]]--
|
||||||
|
|
||||||
|
class Outer {
|
||||||
|
class ArchivedTwice {}
|
||||||
|
class UnarchivedTwice {}
|
||||||
|
class ArchivedThenUnarchived {}
|
||||||
|
class UnarchivedThenArchived {}
|
||||||
|
}
|
||||||
|
|
||||||
|
checkArchiving(Outer.ArchivedTwice.self)
|
||||||
|
// CHECK-NEXT: Attempting to archive Swift class '_Test.Outer.ArchivedTwice'
|
||||||
|
// CHECK-NEXT: @objc(_TtC{{.+[0-9]+}}ArchivedTwice)
|
||||||
|
// CHECK-NEXT: @objc(ABCArchivedTwice)
|
||||||
|
mark() // CHECK-NEXT: --[[@LINE]]--
|
||||||
|
checkArchiving(Outer.ArchivedTwice.self)
|
||||||
|
mark() // CHECK-NEXT: --[[@LINE]]--
|
||||||
|
|
||||||
|
checkUnarchiving(Outer.UnarchivedTwice.self)
|
||||||
|
// CHECK-NEXT: Attempting to unarchive Swift class '_Test.Outer.UnarchivedTwice'
|
||||||
|
// CHECK-NEXT: @objc(_TtC{{.+[0-9]+}}UnarchivedTwice)
|
||||||
|
// CHECK-NEXT: @objc(ABCUnarchivedTwice)
|
||||||
|
mark() // CHECK-NEXT: --[[@LINE]]--
|
||||||
|
checkUnarchiving(Outer.UnarchivedTwice.self)
|
||||||
|
mark() // CHECK-NEXT: --[[@LINE]]--
|
||||||
|
|
||||||
|
checkArchiving(Outer.ArchivedThenUnarchived.self)
|
||||||
|
// CHECK-NEXT: Attempting to archive Swift class '_Test.Outer.ArchivedThenUnarchived'
|
||||||
|
// CHECK-NEXT: @objc(_TtC{{.+[0-9]+}}ArchivedThenUnarchived)
|
||||||
|
// CHECK-NEXT: @objc(ABCArchivedThenUnarchived)
|
||||||
|
mark() // CHECK-NEXT: --[[@LINE]]--
|
||||||
|
checkUnarchiving(Outer.ArchivedThenUnarchived.self)
|
||||||
|
mark() // CHECK-NEXT: --[[@LINE]]--
|
||||||
|
|
||||||
|
checkUnarchiving(Outer.UnarchivedThenArchived.self)
|
||||||
|
// CHECK-NEXT: Attempting to unarchive Swift class '_Test.Outer.UnarchivedThenArchived'
|
||||||
|
// CHECK-NEXT: @objc(_TtC{{.+[0-9]+}}UnarchivedThenArchived)
|
||||||
|
// CHECK-NEXT: @objc(ABCUnarchivedThenArchived)
|
||||||
|
mark() // CHECK-NEXT: --[[@LINE]]--
|
||||||
|
checkArchiving(Outer.UnarchivedThenArchived.self)
|
||||||
|
mark() // CHECK-NEXT: --[[@LINE]]--
|
||||||
|
|
||||||
|
|
||||||
|
private class 日本語 {}
|
||||||
|
|
||||||
|
checkArchiving(日本語.self)
|
||||||
|
// CHECK-NEXT: Attempting to archive Swift class '_Test.(日本語 in {{.+}})'
|
||||||
|
// CHECK-NEXT: @objc(_TtC{{.+[0-9]+}}9日本語)
|
||||||
|
// CHECK-NEXT: @objc(ABCMyModel)
|
||||||
|
mark() // CHECK-NEXT: --[[@LINE]]--
|
||||||
|
checkArchiving(日本語.self)
|
||||||
|
mark() // CHECK-NEXT: --[[@LINE]]--
|
||||||
|
|
||||||
|
|
||||||
|
class ArchivedTwiceGeneric<T> {}
|
||||||
|
|
||||||
|
checkArchiving(ArchivedTwiceGeneric<Int>.self)
|
||||||
|
// CHECK-NEXT: Attempting to archive generic Swift class '_Test.ArchivedTwiceGeneric<Swift.Int>' with mangled runtime name '_TtGC5_Test20ArchivedTwiceGenericSi_'
|
||||||
|
// CHECK-NEXT: NSKeyedUnarchiver.setClass(_:forClassName:)
|
||||||
|
// CHECK-SAME: _TtGC5_Test20ArchivedTwiceGenericSi_
|
||||||
|
// CHECK-NEXT: NSKeyedArchiver.setClassName(_:for:)
|
||||||
|
mark() // CHECK-NEXT: --[[@LINE]]--
|
||||||
|
checkArchiving(ArchivedTwiceGeneric<Int>.self)
|
||||||
|
mark() // CHECK-NEXT: --[[@LINE]]--
|
||||||
|
|
||||||
|
checkArchiving(ArchivedTwiceGeneric<NSObject>.self)
|
||||||
|
// CHECK-NEXT: Attempting to archive generic Swift class '_Test.ArchivedTwiceGeneric<__ObjC.NSObject>' with mangled runtime name '_TtGC5_Test20ArchivedTwiceGenericCSo8NSObject_'
|
||||||
|
// CHECK-NEXT: NSKeyedUnarchiver.setClass(_:forClassName:)
|
||||||
|
// CHECK-SAME: _TtGC5_Test20ArchivedTwiceGenericCSo8NSObject_
|
||||||
|
// CHECK-NEXT: NSKeyedArchiver.setClassName(_:for:)
|
||||||
|
mark() // CHECK-NEXT: --[[@LINE]]--
|
||||||
|
checkArchiving(ArchivedTwiceGeneric<NSObject>.self)
|
||||||
|
mark() // CHECK-NEXT: --[[@LINE]]--
|
||||||
|
|
||||||
|
class UnarchivedTwiceGeneric<T> {}
|
||||||
|
|
||||||
|
checkUnarchiving(UnarchivedTwiceGeneric<Int>.self)
|
||||||
|
// CHECK-NEXT: Attempting to unarchive generic Swift class '_Test.UnarchivedTwiceGeneric<Swift.Int>' with mangled runtime name '_TtGC5_Test22UnarchivedTwiceGenericSi_'
|
||||||
|
// CHECK-NEXT: NSKeyedUnarchiver.setClass(_:forClassName:)
|
||||||
|
// CHECK-SAME: _TtGC5_Test22UnarchivedTwiceGenericSi_
|
||||||
|
// CHECK-NEXT: NSKeyedArchiver.setClassName(_:for:)
|
||||||
|
mark() // CHECK-NEXT: --[[@LINE]]--
|
||||||
|
checkUnarchiving(UnarchivedTwiceGeneric<Int>.self)
|
||||||
|
mark() // CHECK-NEXT: --[[@LINE]]--
|
||||||
|
|
||||||
|
class ArchivedThenUnarchivedGeneric<T> {}
|
||||||
|
|
||||||
|
checkArchiving(ArchivedThenUnarchivedGeneric<Int>.self)
|
||||||
|
// CHECK-NEXT: Attempting to archive generic Swift class '_Test.ArchivedThenUnarchivedGeneric<Swift.Int>' with mangled runtime name '_TtGC5_Test29ArchivedThenUnarchivedGenericSi_'
|
||||||
|
// CHECK-NEXT: NSKeyedUnarchiver.setClass(_:forClassName:)
|
||||||
|
// CHECK-SAME: _TtGC5_Test29ArchivedThenUnarchivedGenericSi_
|
||||||
|
// CHECK-NEXT: NSKeyedArchiver.setClassName(_:for:)
|
||||||
|
mark() // CHECK-NEXT: --[[@LINE]]--
|
||||||
|
checkUnarchiving(ArchivedThenUnarchivedGeneric<Int>.self)
|
||||||
|
mark() // CHECK-NEXT: --[[@LINE]]--
|
||||||
|
|
||||||
|
class UnarchivedThenArchivedGeneric<T> {}
|
||||||
|
|
||||||
|
checkUnarchiving(UnarchivedThenArchivedGeneric<Int>.self)
|
||||||
|
// CHECK-NEXT: Attempting to unarchive generic Swift class '_Test.UnarchivedThenArchivedGeneric<Swift.Int>' with mangled runtime name '_TtGC5_Test29UnarchivedThenArchivedGenericSi_'
|
||||||
|
// CHECK-NEXT: NSKeyedUnarchiver.setClass(_:forClassName:)
|
||||||
|
// CHECK-SAME: _TtGC5_Test29UnarchivedThenArchivedGenericSi_
|
||||||
|
// CHECK-NEXT: NSKeyedArchiver.setClassName(_:for:)
|
||||||
|
mark() // CHECK-NEXT: --[[@LINE]]--
|
||||||
|
checkArchiving(UnarchivedThenArchivedGeneric<Int>.self)
|
||||||
|
mark() // CHECK-NEXT: --[[@LINE]]--
|
||||||
Reference in New Issue
Block a user