@@ -20,6 +20,9 @@ static bool isASCIIIdentifierChar(char c) {
20
20
return false ;
21
21
}
22
22
23
+ template <typename T, size_t N>
24
+ static constexpr size_t arrayLength (T (&)[N]) { return N; }
25
+
23
26
static void logIfFirstOccurrence (Class objcClass, void (^log)(void )) {
24
27
static auto queue = dispatch_queue_create (
25
28
" SwiftFoundation._checkClassAndWarnForKeyedArchivingQueue" ,
@@ -164,26 +167,52 @@ + (int)_swift_checkClassAndWarnForKeyedArchiving:(Class)objcClass
164
167
/* qualified*/ true );
165
168
NSString *demangledString = demangledName.newNSStringNoCopy ();
166
169
NSString *mangledString = NSStringFromClass (objcClass);
170
+
171
+ NSString *primaryMessage;
167
172
switch (operation) {
168
173
case 1 :
169
- NSLog (@" Attempting to unarchive generic Swift class '%@ ' with mangled "
170
- " runtime name '%@ '. Runtime names for generic classes are "
171
- " unstable and may change in the future, leading to "
172
- " non-decodable data." , demangledString, mangledString);
174
+ primaryMessage = [[NSString alloc ] initWithFormat:
175
+ @" Attempting to unarchive generic Swift class '%@ ' with mangled "
176
+ " runtime name '%@ '. Runtime names for generic classes are "
177
+ " unstable and may change in the future, leading to "
178
+ " non-decodable data." , demangledString, mangledString];
173
179
break ;
174
180
default :
175
- NSLog (@" Attempting to archive generic Swift class '%@ ' with mangled "
176
- " runtime name '%@ '. Runtime names for generic classes are "
177
- " unstable and may change in the future, leading to "
178
- " non-decodable data." , demangledString, mangledString);
181
+ primaryMessage = [[NSString alloc ] initWithFormat:
182
+ @" Attempting to archive generic Swift class '%@ ' with mangled "
183
+ " runtime name '%@ '. Runtime names for generic classes are "
184
+ " unstable and may change in the future, leading to "
185
+ " non-decodable data." , demangledString, mangledString];
179
186
break ;
180
187
}
181
- NSLog (@" To avoid this failure, create a concrete subclass and register "
182
- " it with NSKeyedUnarchiver.setClass(_:forClassName:) instead, "
183
- " using the name \" %@ \" ." , mangledString);
184
- NSLog (@" If you need to produce archives compatible with older versions "
185
- " of your program, use NSKeyedArchiver.setClassName(_:for:) "
186
- " as well." );
188
+ NSString *generatedNote = [[NSString alloc ] initWithFormat:
189
+ @" To avoid this failure, create a concrete subclass and register "
190
+ " it with NSKeyedUnarchiver.setClass(_:forClassName:) instead, "
191
+ " using the name \" %@ \" ." , mangledString];
192
+ const char *staticNote =
193
+ " If you need to produce archives compatible with older versions "
194
+ " of your program, use NSKeyedArchiver.setClassName(_:for:) as well." ;
195
+
196
+ NSLog (@" %@ " , primaryMessage);
197
+ NSLog (@" %@ " , generatedNote);
198
+ NSLog (@" %s " , staticNote);
199
+
200
+ RuntimeErrorDetails::Note notes[] = {
201
+ { [generatedNote UTF8String ], /* numFixIts*/ 0 , /* fixIts*/ nullptr },
202
+ { staticNote, /* numFixIts*/ 0 , /* fixIts*/ nullptr },
203
+ };
204
+
205
+ RuntimeErrorDetails errorInfo = {};
206
+ errorInfo.version = RuntimeErrorDetails::currentVersion;
207
+ errorInfo.errorType = " nskeyedarchiver-incompatible-class" ;
208
+ errorInfo.notes = notes;
209
+ errorInfo.numNotes = arrayLength (notes);
210
+
211
+ _swift_reportToDebugger (RuntimeErrorFlagNone, [primaryMessage UTF8String ],
212
+ &errorInfo);
213
+
214
+ [primaryMessage release ];
215
+ [generatedNote release ];
187
216
[demangledString release ];
188
217
});
189
218
return 1 ;
@@ -196,23 +225,28 @@ + (int)_swift_checkClassAndWarnForKeyedArchiving:(Class)objcClass
196
225
StringRefLite demangledName = swift_getTypeName (theClass,/* qualified*/ true );
197
226
NSString *demangledString = demangledName.newNSStringNoCopy ();
198
227
NSString *mangledString = NSStringFromClass (objcClass);
228
+
229
+ NSString *primaryMessage;
199
230
switch (operation) {
200
231
case 1 :
201
- NSLog (@" Attempting to unarchive Swift class '%@ ' with mangled runtime "
202
- " name '%@ '. The runtime name for this class is unstable and may "
203
- " change in the future, leading to non-decodable data." ,
204
- demangledString, mangledString);
232
+ primaryMessage = [[NSString alloc ] initWithFormat:
233
+ @" Attempting to unarchive Swift class '%@ ' with mangled runtime "
234
+ " name '%@ '. The runtime name for this class is unstable and may "
235
+ " change in the future, leading to non-decodable data." ,
236
+ demangledString, mangledString];
205
237
break ;
206
238
default :
207
- NSLog (@" Attempting to archive Swift class '%@ ' with mangled runtime "
208
- " name '%@ '. The runtime name for this class is unstable and may "
209
- " change in the future, leading to non-decodable data." ,
210
- demangledString, mangledString);
239
+ primaryMessage = [[NSString alloc ] initWithFormat:
240
+ @" Attempting to archive Swift class '%@ ' with mangled runtime "
241
+ " name '%@ '. The runtime name for this class is unstable and may "
242
+ " change in the future, leading to non-decodable data." ,
243
+ demangledString, mangledString];
211
244
break ;
212
245
}
213
- [demangledString release ];
214
- NSLog (@" You can use the 'objc' attribute to ensure that the name will not "
215
- " change: \" @objc(%@ )\" " , mangledString);
246
+
247
+ NSString *firstNote = [[NSString alloc ] initWithFormat:
248
+ @" You can use the 'objc' attribute to ensure that the name will not "
249
+ " change: \" @objc(%@ )\" " , mangledString];
216
250
217
251
StringRefLite baseName = findBaseName (demangledName);
218
252
// Offer a more generic message if the base name we found doesn't look like
@@ -222,9 +256,35 @@ + (int)_swift_checkClassAndWarnForKeyedArchiving:(Class)objcClass
222
256
baseName = " MyModel" ;
223
257
}
224
258
225
- NSLog (@" If there are no existing archives containing this class, you "
226
- " should choose a unique, prefixed name instead: "
227
- " \" @objc(ABC%1$.*2$s )\" " , baseName.data, (int )baseName.length);
259
+ NSString *secondNote = [[NSString alloc ] initWithFormat:
260
+ @" If there are no existing archives containing this class, you should "
261
+ " choose a unique, prefixed name instead: \" @objc(ABC%1$.*2$s )\" " ,
262
+ baseName.data, (int )baseName.length];
263
+
264
+ NSLog (@" %@ " , primaryMessage);
265
+ NSLog (@" %@ " , firstNote);
266
+ NSLog (@" %@ " , secondNote);
267
+
268
+ // FIXME: We could suggest these as fix-its if we had source locations for
269
+ // the class.
270
+ RuntimeErrorDetails::Note notes[] = {
271
+ { [firstNote UTF8String ], /* numFixIts*/ 0 , /* fixIts*/ nullptr },
272
+ { [secondNote UTF8String ], /* numFixIts*/ 0 , /* fixIts*/ nullptr },
273
+ };
274
+
275
+ RuntimeErrorDetails errorInfo = {};
276
+ errorInfo.version = RuntimeErrorDetails::currentVersion;
277
+ errorInfo.errorType = " nskeyedarchiver-incompatible-class" ;
278
+ errorInfo.notes = notes;
279
+ errorInfo.numNotes = arrayLength (notes);
280
+
281
+ _swift_reportToDebugger (RuntimeErrorFlagNone, [primaryMessage UTF8String ],
282
+ &errorInfo);
283
+
284
+ [primaryMessage release ];
285
+ [firstNote release ];
286
+ [secondNote release ];
287
+ [demangledString release ];
228
288
});
229
289
return 2 ;
230
290
}
0 commit comments