Skip to content

Commit f17fe86

Browse files
committed
[Refactoring] Support refactoring to async if callback is @convention(block)
We already have special logic to extrac the closure for closures with capture lists, add the same kind of logic for closures that are marked `@convention(block)` etc. Resolves rdar://75301524 [SR-14328]
1 parent c8ba622 commit f17fe86

File tree

2 files changed

+40
-6
lines changed

2 files changed

+40
-6
lines changed

lib/IDE/Refactoring.cpp

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5012,6 +5012,22 @@ class AsyncConverter : private SourceEntityWalker {
50125012
}
50135013
}
50145014

5015+
/// From the given expression \p E, which is an argument to a function call,
5016+
/// extract the passed closure if there is one. Otherwise return \c nullptr.
5017+
ClosureExpr *extractCallback(Expr *E) {
5018+
if (auto Closure = dyn_cast<ClosureExpr>(E)) {
5019+
return Closure;
5020+
} else if (auto CaptureList = dyn_cast<CaptureListExpr>(E)) {
5021+
return CaptureList->getClosureBody();
5022+
} else if (auto FunctionConversion = dyn_cast<FunctionConversionExpr>(E)) {
5023+
// Closure arguments marked as e.g. `@convention(block)` produce arguments
5024+
// that are `FunctionConversionExpr`.
5025+
return extractCallback(FunctionConversion->getSubExpr());
5026+
} else {
5027+
return nullptr;
5028+
}
5029+
}
5030+
50155031
void addAsyncAlternativeCall(const CallExpr *CE,
50165032
const AsyncHandlerDesc &HandlerDesc) {
50175033
auto ArgList = callArgs(CE);
@@ -5020,11 +5036,7 @@ class AsyncConverter : private SourceEntityWalker {
50205036
return;
50215037
}
50225038

5023-
auto Callback = dyn_cast<ClosureExpr>(ArgList.ref()[HandlerDesc.Index]);
5024-
auto Capture = dyn_cast<CaptureListExpr>(ArgList.ref()[HandlerDesc.Index]);
5025-
if (Capture) {
5026-
Callback = Capture->getClosureBody();
5027-
}
5039+
ClosureExpr *Callback = extractCallback(ArgList.ref()[HandlerDesc.Index]);
50285040
if (!Callback) {
50295041
DiagEngine.diagnose(CE->getStartLoc(), diag::missing_callback_arg);
50305042
return;

test/refactoring/ConvertAsync/basic.swift

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -176,10 +176,18 @@ func alreadyThrows(completion: (String) -> Void) throws { }
176176
// RUN: not %refactor -add-async-alternative -dump-text -source-filename %s -pos=%(line+1):1
177177
func noParamAutoclosure(completion: @autoclosure () -> Void) { }
178178

179+
// RUN: %refactor -add-async-alternative -dump-text -source-filename %s -pos=%(line+1):1 | %FileCheck -check-prefix BLOCK-CONVENTION %s
180+
func blockConvention(completion: @convention(block) () -> Void) { }
181+
// BLOCK-CONVENTION: func blockConvention() async { }
182+
183+
// RUN: %refactor -add-async-alternative -dump-text -source-filename %s -pos=%(line+1):1 | %FileCheck -check-prefix C-CONVENTION %s
184+
func cConvention(completion: @convention(c) () -> Void) { }
185+
// C-CONVENTION: func cConvention() async { }
186+
179187
// 2. Check that the various ways to call a function (and the positions the
180188
// refactoring is called from) are handled correctly
181189

182-
// RUN: %refactor -convert-to-async -dump-text -source-filename %s -pos=%(line+1):1 | %FileCheck -check-prefixes=CONVERT-FUNC,CALL,CALL-NOLABEL,CALL-WRAPPED,TRAILING,TRAILING-PARENS,TRAILING-WRAPPED,CALL-ARG,MANY-CALL,MEMBER-CALL,MEMBER-CALL2,MEMBER-PARENS,EMPTY-CAPTURE,CAPTURE,DEFAULT-ARGS-MISSING,DEFAULT-ARGS-CALL %s
190+
// RUN: %refactor -convert-to-async -dump-text -source-filename %s -pos=%(line+1):1 | %FileCheck -check-prefixes=CONVERT-FUNC,CALL,CALL-NOLABEL,CALL-WRAPPED,TRAILING,TRAILING-PARENS,TRAILING-WRAPPED,CALL-ARG,MANY-CALL,MEMBER-CALL,MEMBER-CALL2,MEMBER-PARENS,EMPTY-CAPTURE,CAPTURE,DEFAULT-ARGS-MISSING,DEFAULT-ARGS-CALL,BLOCK-CONVENTION-CALL,C-CONVENTION-CALL %s
183191
func testCalls() {
184192
// CONVERT-FUNC: {{^}}func testCalls() async {
185193
// RUN: %refactor -convert-call-to-async-alternative -dump-text -source-filename %s -pos=%(line+4):3 | %FileCheck -check-prefix=CALL %s
@@ -320,5 +328,19 @@ func testCalls() {
320328
}
321329
// DEFAULT-ARGS-CALL: let str = await defaultArgs(a: 1, b: 2){{$}}
322330
// DEFAULT-ARGS-CALL-NEXT: {{^}}print("defaultArgs")
331+
332+
// RUN: %refactor -convert-call-to-async-alternative -dump-text -source-filename %s -pos=%(line+1):3 | %FileCheck -check-prefix=BLOCK-CONVENTION-CALL %s
333+
blockConvention {
334+
print("blockConvention")
335+
}
336+
// BLOCK-CONVENTION-CALL: await blockConvention(){{$}}
337+
// BLOCK-CONVENTION-CALL-NEXT: {{^}}print("blockConvention")
338+
339+
// RUN: %refactor -convert-call-to-async-alternative -dump-text -source-filename %s -pos=%(line+1):3 | %FileCheck -check-prefix=C-CONVENTION-CALL %s
340+
cConvention {
341+
print("cConvention")
342+
}
343+
// C-CONVENTION-CALL: await cConvention(){{$}}
344+
// C-CONVENTION-CALL-NEXT: {{^}}print("cConvention")
323345
}
324346
// CONVERT-FUNC: {{^}}}

0 commit comments

Comments
 (0)