Skip to content

Commit 6095278

Browse files
committed
[SourceKit] Handle macro arguments in placeholder expansion
Allow macro argument placeholders to expand into trailing closures. rdar://150550747
1 parent ef74028 commit 6095278

File tree

2 files changed

+93
-24
lines changed

2 files changed

+93
-24
lines changed

test/SourceKit/CodeExpand/code-expand.swift

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,10 @@ await foo(x: <#T##() -> Void#>)
2525
// CHECK-NEXT: <#code#>
2626
// CHECK-NEXT: }
2727

28+
foo(bar(<#T##() -> Void#>))
29+
// CHECK: foo(bar({
30+
// CHECK-NEXT: <#code#>
31+
// CHECK-NEXT: }))
2832

2933
anArr.indexOfObjectPassingTest(<#T##predicate: ((AnyObject!, Int, UnsafePointer<ObjCBool>) -> Bool)?##((AnyObject!, Int, UnsafePointer<ObjCBool>) -> Bool)?#>)
3034
// CHECK: anArr.indexOfObjectPassingTest { <#AnyObject!#>, <#Int#>, <#UnsafePointer<ObjCBool>#> in
@@ -273,3 +277,41 @@ expandClosureWithInternalParameterNames {
273277
// CHECK: withtrail { a, b in
274278
// CHECK-NEXT: <#code#>
275279
}
280+
281+
// CHECK-LABEL: func expandMacro()
282+
func expandMacro() {
283+
#foo(<#T##() -> Int#>)
284+
// CHECK: #foo {
285+
// CHECK-NEXT: <#code#>
286+
// CHECK-NEXT: }
287+
288+
#foo(bar: <#T##() -> ()#>)
289+
// CHECK: #foo {
290+
// CHECK-NEXT: <#code#>
291+
// CHECK-NEXT: }
292+
293+
#foo(bar: <#T##() -> Int#>, baz: <#T##() -> ()#>)
294+
// CHECK: #foo {
295+
// CHECK-NEXT: <#code#>
296+
// CHECK-NEXT: } baz: {
297+
// CHECK-NEXT: <#code#>
298+
// CHECK-NEXT: }
299+
}
300+
301+
// CHECK-LABEL: struct ExpandDeclMacro
302+
struct ExpandDeclMacro {
303+
#foo(<#T##() -> ()#>)
304+
// CHECK: #foo {
305+
// CHECK-NEXT: <#code#>
306+
// CHECK-NEXT: }
307+
308+
#foo(bar(<#T##() -> ()#>))
309+
// CHECK: #foo(bar({
310+
// CHECK-NEXT: <#code#>
311+
// CHECK-NEXT: }))
312+
313+
#foo(#bar(<#T##() -> ()#>))
314+
// CHECK: #foo(#bar({
315+
// CHECK-NEXT: <#code#>
316+
// CHECK-NEXT: }))
317+
}

tools/SourceKit/lib/SwiftLang/SwiftEditor.cpp

Lines changed: 51 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1679,34 +1679,65 @@ class PlaceholderExpansionScanner {
16791679
public:
16801680
const SourceManager &SM;
16811681
SourceLoc TargetLoc;
1682-
std::pair<Expr *, ArgumentList *> EnclosingCallAndArg;
1682+
std::pair<ASTNode, ArgumentList *> EnclosingCallAndArg;
16831683
Expr *OuterExpr;
16841684
Stmt *OuterStmt;
1685-
explicit CallExprFinder(const SourceManager &SM)
1686-
:SM(SM) { }
1687-
1688-
bool checkCallExpr(Expr *E) {
1689-
ArgumentList *Args = nullptr;
1690-
if (auto *CE = dyn_cast<CallExpr>(E)) {
1691-
// Call expression can have argument.
1692-
Args = CE->getArgs();
1685+
Decl *OuterDecl;
1686+
1687+
explicit CallExprFinder(const SourceManager &SM) : SM(SM) {}
1688+
1689+
void checkArgumentList(ArgumentList *Args) {
1690+
ASTNode Enclosing;
1691+
if (auto *E = Parent.getAsExpr()) {
1692+
// Must have a function call or macro parent.
1693+
if (!isa<CallExpr, MacroExpansionExpr>(E) ||
1694+
E->getArgs() != Args) {
1695+
return;
1696+
}
1697+
// If the outer expression is the call itself, disregard it.
1698+
if (OuterExpr == E)
1699+
OuterExpr = nullptr;
1700+
1701+
Enclosing = E;
16931702
}
1694-
if (!Args)
1695-
return false;
1696-
if (EnclosingCallAndArg.first)
1697-
OuterExpr = EnclosingCallAndArg.first;
1698-
EnclosingCallAndArg = {E, Args};
1699-
return true;
1703+
if (auto *D = Parent.getAsDecl()) {
1704+
// Must have a macro decl parent.
1705+
auto *MED = dyn_cast<MacroExpansionDecl>(D);
1706+
if (!MED || MED->getArgs() != Args)
1707+
return;
1708+
Enclosing = D;
1709+
}
1710+
if (!Enclosing)
1711+
return;
1712+
1713+
// If we have an outer enclosing call, update the outer nodes if needed.
1714+
if (auto EnclosingCall = EnclosingCallAndArg.first) {
1715+
if (!OuterExpr)
1716+
OuterExpr = EnclosingCall.dyn_cast<Expr *>();
1717+
if (!OuterDecl)
1718+
OuterDecl = EnclosingCall.dyn_cast<Decl *>();
1719+
}
1720+
1721+
EnclosingCallAndArg = {Enclosing, Args};
17001722
}
17011723

17021724
MacroWalking getMacroWalkingBehavior() const override {
17031725
return MacroWalking::Arguments;
17041726
}
17051727

1728+
PreWalkResult<ArgumentList *>
1729+
walkToArgumentListPre(ArgumentList *ArgList) override {
1730+
auto SR = ArgList->getSourceRange();
1731+
if (SR.isValid() && SM.rangeContainsTokenLoc(SR, TargetLoc))
1732+
checkArgumentList(ArgList);
1733+
1734+
return Action::Continue(ArgList);
1735+
}
1736+
17061737
PreWalkResult<Expr *> walkToExprPre(Expr *E) override {
17071738
auto SR = E->getSourceRange();
17081739
if (SR.isValid() && SM.rangeContainsTokenLoc(SR, TargetLoc) &&
1709-
!checkCallExpr(E) && !EnclosingCallAndArg.first) {
1740+
!OuterExpr && !EnclosingCallAndArg.first) {
17101741
if (!isa<TryExpr>(E) && !isa<AwaitExpr>(E) && !isa<UnsafeExpr>(E) &&
17111742
!isa<PrefixUnaryExpr>(E)) {
17121743
// We don't want to expand to trailing closures if the call is
@@ -1782,6 +1813,7 @@ class PlaceholderExpansionScanner {
17821813
EnclosingCallAndArg = {nullptr, nullptr};
17831814
OuterExpr = nullptr;
17841815
OuterStmt = nullptr;
1816+
OuterDecl = nullptr;
17851817
TargetLoc = SL;
17861818
SF.walk(*this);
17871819
return EnclosingCallAndArg.second;
@@ -1791,14 +1823,9 @@ class PlaceholderExpansionScanner {
17911823
CallExprFinder CEFinder(SM);
17921824
auto *Args = CEFinder.findEnclosingCallArg(SF, SL);
17931825

1794-
if (!Args)
1795-
return std::make_pair(Args, false);
1796-
if (CEFinder.OuterExpr)
1797-
return std::make_pair(Args, false);
1798-
if (CEFinder.OuterStmt)
1799-
return std::make_pair(Args, false);
1800-
1801-
return std::make_pair(Args, true);
1826+
auto HasOuterNode =
1827+
CEFinder.OuterExpr || CEFinder.OuterStmt || CEFinder.OuterDecl;
1828+
return std::make_pair(Args, /*useTrailingClosure*/ Args && !HasOuterNode);
18021829
}
18031830

18041831
struct ParamClosureInfo {

0 commit comments

Comments
 (0)