Skip to content

Commit ed36e08

Browse files
authored
Merge pull request swiftlang#24317 from benlangmuir/expand-stmt
[placeholder-expansion] Expand trailing closure in statements correctly
2 parents 1096179 + 6377199 commit ed36e08

File tree

2 files changed

+130
-10
lines changed

2 files changed

+130
-10
lines changed

test/SourceKit/CodeExpand/code-expand.swift

Lines changed: 95 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,9 +53,9 @@ func f() {
5353
func f1() {
5454
bar(<#T##d: () -> ()##() -> ()#>)
5555
}
56-
// CHECK: bar({
57-
// CHECK-NEXT: <#code#>
58-
// CHECK-NEXT: })
56+
// CHECK: bar {
57+
// CHECK-NEXT: <#code#>
58+
// CHECK-NEXT: }
5959

6060
func f1() {
6161
bar(<#T##d: () -> ()##() -> ()#>, <#T##d: () -> ()##() -> ()#>)
@@ -103,3 +103,95 @@ braced2(x: {<#T##() -> Void#>}, y: Int)
103103
// CHECK: braced2(x: {
104104
// CHECK-NEXT: <#code#>
105105
// CHECK-NEXT: }, y: Int)
106+
107+
func returnTrailing() -> Int {
108+
return withtrail(<#T##() -> ()#>)
109+
// CHECK: return withtrail {
110+
// CHECK-NEXT: <#code#>
111+
}
112+
113+
var yieldTrailing: Int {
114+
_read {
115+
yield withtrail(<#T##() -> ()#>)
116+
// CHECK: yield withtrail {
117+
// CHECK-NEXT: <#code#>
118+
}
119+
}
120+
121+
func caseTrailing() -> Int {
122+
switch true {
123+
case true: withtrail(<#T##() -> ()#>)
124+
// CHECK: case true: withtrail {
125+
// CHECK-NEXT: <#code#>
126+
default: withtrail(<#T##() -> ()#>)
127+
// CHECK: default: withtrail {
128+
// CHECK-NEXT: <#code#>
129+
}
130+
}
131+
132+
func throwTrailing() -> Int {
133+
throw withtrail(<#T##() -> ()#>)
134+
// CHECK: throw withtrail {
135+
// CHECK-NEXT: <#code#>
136+
}
137+
138+
func singleExprTrailing1() -> Int {
139+
withtrail(<#T##() -> ()#>)
140+
// CHECK: withtrail {
141+
// CHECK-NEXT: <#code#>
142+
}
143+
var singleExprTrailing2: Int {
144+
withtrail(<#T##() -> ()#>)
145+
// CHECK: withtrail {
146+
// CHECK-NEXT: <#code#>
147+
}
148+
var singleExprTrailing3: Int {
149+
get {
150+
withtrail(<#T##() -> ()#>)
151+
// CHECK: withtrail {
152+
// CHECK-NEXT: <#code#>
153+
}
154+
}
155+
156+
closureTrailingMulti {
157+
bah()
158+
withtrail(<#T##() -> ()#>)
159+
// CHECK: bah()
160+
// CHECK-NEXT: withtrail {
161+
// CHECK-NEXT: <#code#>
162+
}
163+
164+
closureIf {
165+
if withtrail(<#T##() -> ()#>) {}
166+
// CHECK: if withtrail({
167+
// CHECK-NEXT: <#code#>
168+
}
169+
170+
closureNonTrail {
171+
nonTrail(<#T##() -> ()#>, 1)
172+
// CHECK: nonTrail({
173+
// CHECK-NEXT: <#code#>
174+
}
175+
176+
singleExprClosureTrailing {
177+
withtrail(<#T##() -> ()#>)
178+
// CHECK: withtrail {
179+
// CHECK-NEXT: <#code#>
180+
}
181+
182+
singleExprClosureTrailingParens({
183+
withtrail(<#T##() -> ()#>)
184+
// CHECK: withtrail {
185+
// CHECK-NEXT: <#code#>
186+
})
187+
188+
singleExprClosureMultiArg(1) {
189+
withtrail(<#T##() -> ()#>)
190+
// CHECK: withtrail {
191+
// CHECK-NEXT: <#code#>
192+
}
193+
singleExprClosureMultiArg(1) {
194+
withtrail(<#T##() -> ()#>)
195+
// CHECK: withtrail {
196+
// CHECK-NEXT: <#code#>
197+
}

tools/SourceKit/lib/SwiftLang/SwiftEditor.cpp

Lines changed: 35 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1516,8 +1516,26 @@ class PlaceholderExpansionScanner {
15161516
bool walkToExprPre(Expr *E) override {
15171517
auto SR = E->getSourceRange();
15181518
if (SR.isValid() && SM.rangeContainsTokenLoc(SR, TargetLoc)) {
1519-
if (!checkCallExpr(E) && !EnclosingCallAndArg.first)
1519+
if (auto closure = dyn_cast<ClosureExpr>(E)) {
1520+
if (closure->hasSingleExpressionBody()) {
1521+
// Treat a single-expression body like a brace statement and reset
1522+
// the enclosing context. Note: when the placeholder is the whole
1523+
// body it is handled specially as wrapped in braces by
1524+
// shouldUseTrailingClosureInTuple().
1525+
auto SR = closure->getSingleExpressionBody()->getSourceRange();
1526+
if (SR.isValid() && SR.Start != TargetLoc &&
1527+
SM.rangeContainsTokenLoc(SR, TargetLoc)) {
1528+
OuterStmt = nullptr;
1529+
OuterExpr = nullptr;
1530+
EnclosingCallAndArg = {nullptr, nullptr};
1531+
return true;
1532+
}
1533+
}
1534+
}
1535+
1536+
if (!checkCallExpr(E) && !EnclosingCallAndArg.first) {
15201537
OuterExpr = E;
1538+
}
15211539
}
15221540
return true;
15231541
}
@@ -1531,12 +1549,22 @@ class PlaceholderExpansionScanner {
15311549
bool walkToStmtPre(Stmt *S) override {
15321550
auto SR = S->getSourceRange();
15331551
if (SR.isValid() && SM.rangeContainsTokenLoc(SR, TargetLoc)) {
1534-
if (!EnclosingCallAndArg.first) {
1535-
if (isa<BraceStmt>(S))
1536-
// In case OuterStmt is already set, we should clear it to nullptr.
1537-
OuterStmt = nullptr;
1538-
else
1539-
OuterStmt = S;
1552+
// A statement inside an expression - e.g. `foo({ if ... })` - resets
1553+
// the enclosing context.
1554+
OuterExpr = nullptr;
1555+
EnclosingCallAndArg = {nullptr, nullptr};
1556+
1557+
switch (S->getKind()) {
1558+
case StmtKind::Brace:
1559+
case StmtKind::Return:
1560+
case StmtKind::Yield:
1561+
case StmtKind::Throw:
1562+
// A trailing closure is allowed in these statements.
1563+
OuterStmt = nullptr;
1564+
break;
1565+
default:
1566+
OuterStmt = S;
1567+
break;
15401568
}
15411569
}
15421570
return true;

0 commit comments

Comments
 (0)