Skip to content

Commit 6ad2757

Browse files
committed
[Concurrency] Use completion/completionHandler parameter names for async import
Extend the check for completion handler parameters to also consider the name of the parameter (not its argument label). If it's `completion` or `completionHandler`, we have a completion handler. This extends our API coverage for importing Objective-C methods with completion handlers as 'async'.
1 parent 1e5d30f commit 6ad2757

File tree

4 files changed

+26
-12
lines changed

4 files changed

+26
-12
lines changed

lib/ClangImporter/ImportName.cpp

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1213,10 +1213,13 @@ NameImporter::considerAsyncImport(
12131213
// handler.
12141214
Optional<StringRef> newBaseName;
12151215
if (isCompletionHandlerParamName(paramNames[completionHandlerParamNameIndex])) {
1216-
// The parameter itself has an appropriate name.
1216+
// The argument label itself has an appropriate name.
12171217
} else if (!hasCustomName && completionHandlerParamIndex == 0 &&
12181218
(newBaseName = isCompletionHandlerInBaseName(baseName))) {
12191219
// The base name implies that the first parameter is a completion handler.
1220+
} else if (isCompletionHandlerParamName(
1221+
params[completionHandlerParamIndex]->getName())) {
1222+
// The parameter has an appropriate name.
12201223
} else {
12211224
return None;
12221225
}
@@ -1238,6 +1241,10 @@ NameImporter::considerAsyncImport(
12381241
if (isInitializer)
12391242
return notAsync("initializers cannot be async");
12401243

1244+
// Accessors are never imported as async.
1245+
if (clangDecl->isPropertyAccessor())
1246+
return notAsync("method is a property accessor");
1247+
12411248
// Check whether we method has a suitable return type.
12421249
if (clangDecl->getReturnType()->isVoidType()) {
12431250
// 'void' is the common case; the method produces no synchronous result.
@@ -1515,7 +1522,8 @@ ImportedName NameImporter::importNameImpl(const clang::NamedDecl *D,
15151522
else if (parsedName.IsSetter)
15161523
result.info.accessorKind = ImportedAccessorKind::PropertySetter;
15171524

1518-
if (method && parsedName.IsFunctionName) {
1525+
if (method && parsedName.IsFunctionName &&
1526+
result.info.accessorKind == ImportedAccessorKind::None) {
15191527
// Get the parameters.
15201528
ArrayRef<const clang::ParmVarDecl *> params{method->param_begin(),
15211529
method->param_end()};
@@ -1787,16 +1795,6 @@ ImportedName NameImporter::importNameImpl(const clang::NamedDecl *D,
17871795
result.info.errorInfo = *errorInfo;
17881796
}
17891797

1790-
if (version.supportsConcurrency()) {
1791-
if (auto asyncInfo = considerAsyncImport(
1792-
objcMethod, baseName, argumentNames, params, isInitializer,
1793-
/*hasCustomName=*/false,
1794-
result.getErrorInfo())) {
1795-
result.info.hasAsyncInfo = true;
1796-
result.info.asyncInfo = *asyncInfo;
1797-
}
1798-
}
1799-
18001798
isFunction = true;
18011799

18021800
// Is this one of the accessors for subscripts?
@@ -1814,6 +1812,17 @@ ImportedName NameImporter::importNameImpl(const clang::NamedDecl *D,
18141812
result.info.accessorKind = ImportedAccessorKind::SubscriptSetter;
18151813
}
18161814

1815+
if (version.supportsConcurrency() &&
1816+
result.info.accessorKind == ImportedAccessorKind::None) {
1817+
if (auto asyncInfo = considerAsyncImport(
1818+
objcMethod, baseName, argumentNames, params, isInitializer,
1819+
/*hasCustomName=*/false,
1820+
result.getErrorInfo())) {
1821+
result.info.hasAsyncInfo = true;
1822+
result.info.asyncInfo = *asyncInfo;
1823+
}
1824+
}
1825+
18171826
break;
18181827
}
18191828
}

test/ClangImporter/objc_async.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ func testSlowServer(slowServer: SlowServer) async {
1111
let _: String = await slowServer.findAnswerFailingly() ?? "nope"
1212
// FIXME: expected-error@-2{{call can throw, but it is not marked with 'try'}}
1313
// FIXME: expected-error@-2{{call can throw, but it is not marked with 'try'}}
14+
let _: Void = await slowServer.doSomethingFun("jump")
15+
let _: (Int) -> Void = slowServer.completionHandler
1416
}
1517

1618
func testSlowServerOldSchool(slowServer: SlowServer) {

test/IDE/print_clang_objc_async.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,5 @@
1616
// CHECK-DAG: func findAnswer() async throws -> String?
1717
// CHECK-DAG: func findAnswerFailingly(completionHandler handler: @escaping (String?, Error?) -> Void) throws
1818
// CHECK-DAG: func findAnswerFailingly() async throws -> String?
19+
// CHECK-DAG: func doSomethingFun(_ operation: String) async
1920
// CHECK: {{^[}]$}}

test/Inputs/clang-importer-sdk/usr/include/ObjCConcurrency.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
-(void)checkAvailabilityWithCompletionHandler:(void (^)(BOOL isAvailable))completionHandler;
1010
-(void)findAnswerAsynchronously:(void (^)(NSString *_Nullable, NSError * _Nullable))handler __attribute__((swift_name("findAnswer(completionHandler:)")));
1111
-(BOOL)findAnswerFailinglyWithError:(NSError * _Nullable * _Nullable)error completion:(void (^)(NSString *_Nullable, NSError * _Nullable))handler __attribute__((swift_name("findAnswerFailingly(completionHandler:)")));
12+
-(void)doSomethingFun:(NSString *)operation then:(void (^)(void))completionHandler;
13+
@property(readwrite) void (^completionHandler)(NSInteger);
1214
@end
1315

1416
#pragma clang assume_nonnull end

0 commit comments

Comments
 (0)