Skip to content

Commit 89f7a82

Browse files
authored
Merge pull request #81673 from hamishknight/macrotrail
[IDE] Better handle macro trailing closures
2 parents 6f24696 + 52d8b36 commit 89f7a82

File tree

7 files changed

+238
-50
lines changed

7 files changed

+238
-50
lines changed

include/swift/AST/ASTWalker.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -603,6 +603,13 @@ class ASTWalker {
603603
/// params in AbstractFunctionDecl and NominalTypeDecl.
604604
virtual bool shouldWalkIntoGenericParams() { return false; }
605605

606+
/// Whether the walker should walk into any attached CustomAttrs.
607+
virtual bool shouldWalkIntoCustomAttrs() const {
608+
// Default to false currently since some walkers don't handle this case
609+
// well.
610+
return false;
611+
}
612+
606613
/// This method configures how the walker should walk the initializers of
607614
/// lazy variables. These initializers are semantically different from other
608615
/// initializers in their context and so sometimes should be visited as part

include/swift/IDE/CompletionLookup.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -458,6 +458,8 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
458458
void addEnumElementRef(const EnumElementDecl *EED, DeclVisibilityKind Reason,
459459
DynamicLookupInfo dynamicLookupInfo,
460460
bool HasTypeContext);
461+
void addMacroCallArguments(const MacroDecl *MD, DeclVisibilityKind Reason,
462+
bool forTrivialTrailingClosure = false);
461463
void addMacroExpansion(const MacroDecl *MD, DeclVisibilityKind Reason);
462464

463465
void addKeyword(

lib/AST/ASTWalker.cpp

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,8 @@ class Traversal : public ASTVisitor<Traversal, Expr*, Stmt*,
120120
[[nodiscard]]
121121
bool visit(Decl *D) {
122122
SetParentRAII SetParent(Walker, D);
123+
if (visitDeclCommon(D))
124+
return true;
123125
return inherited::visit(D);
124126
}
125127

@@ -138,6 +140,40 @@ class Traversal : public ASTVisitor<Traversal, Expr*, Stmt*,
138140
// Decls
139141
//===--------------------------------------------------------------------===//
140142

143+
[[nodiscard]]
144+
bool visitCustomAttr(CustomAttr *CA) {
145+
auto *newTypeExpr = doIt(CA->getTypeExpr());
146+
if (!newTypeExpr)
147+
return true;
148+
149+
ASSERT(newTypeExpr == CA->getTypeExpr() &&
150+
"Cannot change CustomAttr TypeExpr");
151+
152+
if (auto *args = CA->getArgs()) {
153+
auto *newArgs = doIt(args);
154+
if (!newArgs)
155+
return true;
156+
157+
CA->setArgs(newArgs);
158+
}
159+
return false;
160+
}
161+
162+
[[nodiscard]]
163+
bool visitDeclCommon(Decl *D) {
164+
if (Walker.shouldWalkIntoCustomAttrs()) {
165+
for (auto *attr : D->getAttrs()) {
166+
auto *CA = dyn_cast<CustomAttr>(attr);
167+
if (!CA)
168+
continue;
169+
170+
if (visitCustomAttr(CA))
171+
return true;
172+
}
173+
}
174+
return false;
175+
}
176+
141177
[[nodiscard]]
142178
bool visitGenericParamListIfNeeded(GenericContext *GC) {
143179
// Must check this first in case extensions have not been bound yet
@@ -2218,6 +2254,15 @@ bool Traversal::visitErrorTypeRepr(ErrorTypeRepr *T) {
22182254
}
22192255

22202256
bool Traversal::visitAttributedTypeRepr(AttributedTypeRepr *T) {
2257+
if (Walker.shouldWalkIntoCustomAttrs()) {
2258+
for (auto attr : T->getAttrs()) {
2259+
auto *CA = attr.dyn_cast<CustomAttr *>();
2260+
if (!CA)
2261+
continue;
2262+
if (visitCustomAttr(CA))
2263+
return true;
2264+
}
2265+
}
22212266
return doIt(T->getTypeRepr());
22222267
}
22232268

lib/IDE/CompletionLookup.cpp

Lines changed: 42 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -104,12 +104,18 @@ static Type defaultTypeLiteralKind(CodeCompletionLiteralKind kind,
104104
llvm_unreachable("Unhandled CodeCompletionLiteralKind in switch.");
105105
}
106106

107-
/// Whether funcType has a single argument (not including defaulted arguments)
108-
/// that is of type () -> ().
109-
static bool hasTrivialTrailingClosure(const FuncDecl *FD,
110-
AnyFunctionType *funcType) {
111-
ParameterListInfo paramInfo(funcType->getParams(), FD,
112-
/*skipCurriedSelf*/ FD->hasCurriedSelf());
107+
/// Whether the provided type has a single argument (not including defaulted
108+
/// arguments) that is of type () -> ().
109+
static bool hasTrivialTrailingClosure(const ValueDecl *VD, Type type) {
110+
if (!VD->hasParameterList())
111+
return false;
112+
113+
auto *funcType = type->getAs<AnyFunctionType>();
114+
if (!funcType)
115+
return false;
116+
117+
ParameterListInfo paramInfo(funcType->getParams(), VD,
118+
/*skipCurriedSelf*/ VD->hasCurriedSelf());
113119

114120
if (paramInfo.size() - paramInfo.numNonDefaultedParameters() == 1) {
115121
auto param = funcType->getParams().back();
@@ -1946,34 +1952,22 @@ static StringRef getTypeAnnotationString(const MacroDecl *MD,
19461952
return {stash.data(), stash.size()};
19471953
}
19481954

1949-
void CompletionLookup::addMacroExpansion(const MacroDecl *MD,
1950-
DeclVisibilityKind Reason) {
1951-
if (!MD->hasName() || !MD->isAccessibleFrom(CurrDeclContext) ||
1952-
MD->shouldHideFromEditor())
1953-
return;
1954-
1955-
OptionSet<CustomAttributeKind> expectedKinds =
1956-
expectedTypeContext.getExpectedCustomAttributeKinds();
1957-
if (expectedKinds) {
1958-
CodeCompletionMacroRoles expectedRoles =
1959-
getCompletionMacroRoles(expectedKinds);
1960-
CodeCompletionMacroRoles roles = getCompletionMacroRoles(MD);
1961-
if (!(roles & expectedRoles))
1962-
return;
1963-
}
1964-
1955+
void CompletionLookup::addMacroCallArguments(const MacroDecl *MD,
1956+
DeclVisibilityKind Reason,
1957+
bool forTrivialTrailingClosure) {
19651958
CodeCompletionResultBuilder Builder =
19661959
makeResultBuilder(CodeCompletionResultKind::Declaration,
19671960
getSemanticContext(MD, Reason, DynamicLookupInfo()));
19681961
Builder.setAssociatedDecl(MD);
19691962

19701963
addValueBaseName(Builder, MD->getBaseIdentifier());
19711964

1972-
Type macroType = MD->getInterfaceType();
1973-
if (MD->parameterList && MD->parameterList->size() > 0) {
1965+
if (forTrivialTrailingClosure) {
1966+
Builder.addBraceStmtWithCursor(" { code }");
1967+
} else if (MD->parameterList && MD->parameterList->size() > 0) {
1968+
auto *macroTy = MD->getInterfaceType()->castTo<AnyFunctionType>();
19741969
Builder.addLeftParen();
1975-
addCallArgumentPatterns(Builder, macroType->castTo<AnyFunctionType>(),
1976-
MD->parameterList,
1970+
addCallArgumentPatterns(Builder, macroTy, MD->parameterList,
19771971
MD->getGenericSignature());
19781972
Builder.addRightParen();
19791973
}
@@ -1988,6 +1982,28 @@ void CompletionLookup::addMacroExpansion(const MacroDecl *MD,
19881982
}
19891983
}
19901984

1985+
void CompletionLookup::addMacroExpansion(const MacroDecl *MD,
1986+
DeclVisibilityKind Reason) {
1987+
if (!MD->hasName() || !MD->isAccessibleFrom(CurrDeclContext) ||
1988+
MD->shouldHideFromEditor())
1989+
return;
1990+
1991+
OptionSet<CustomAttributeKind> expectedKinds =
1992+
expectedTypeContext.getExpectedCustomAttributeKinds();
1993+
if (expectedKinds) {
1994+
CodeCompletionMacroRoles expectedRoles =
1995+
getCompletionMacroRoles(expectedKinds);
1996+
CodeCompletionMacroRoles roles = getCompletionMacroRoles(MD);
1997+
if (!(roles & expectedRoles))
1998+
return;
1999+
}
2000+
2001+
if (hasTrivialTrailingClosure(MD, MD->getInterfaceType()))
2002+
addMacroCallArguments(MD, Reason, /*forTrivialTrailingClosure*/ true);
2003+
2004+
addMacroCallArguments(MD, Reason);
2005+
}
2006+
19912007
void CompletionLookup::addKeyword(StringRef Name, Type TypeAnnotation,
19922008
SemanticContextKind SK,
19932009
CodeCompletionKeywordKind KeyKind,

test/IDE/complete_macros.swift

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,15 @@ public macro freestandingExprStringMacro() -> String
2121
@freestanding(expression)
2222
public macro freestandingExprTMacro<T>(_ value: T) -> T
2323

24+
@freestanding(expression)
25+
public macro freestandingExprVoidClosureMacro(fn: () -> Void)
26+
27+
@freestanding(expression)
28+
public macro freestandingExprIntClosureMacro(fn: () -> Int)
29+
30+
@freestanding(declaration)
31+
public macro freestandingDeclVoidClosureMacro(fn: () -> Void)
32+
2433
@freestanding(declaration)
2534
public macro freestandingDeclMacro()
2635

@@ -158,8 +167,21 @@ func nestedFreestanding() {
158167
// ALL_FREESTANDING-DAG: Decl[Macro]/{{.*}}: freestandingExprTMacro({#(value): T#})[#T#]; name=freestandingExprTMacro(:)
159168
// ALL_FREESTANDING-DAG: Decl[Macro]/{{.*}}: EverythingMacro[#Expression Macro, Declaration Macro, Accessor Macro, Member Attribute Macro, Member Macro, Peer Macro, Extension Macro#]; name=EverythingMacro
160169
//
170+
// We offer a trailing closure completion for the Void case, but not the
171+
// Int case currently. Placeholder expansion will turn the latter into the
172+
// former though.
173+
//
174+
// ALL_FREESTANDING-DAG: Decl[Macro]/{{.*}}: freestandingExprVoidClosureMacro {|}[#Void#]; name=freestandingExprVoidClosureMacro
175+
// ALL_FREESTANDING-DAG: Decl[Macro]/{{.*}}: freestandingExprVoidClosureMacro({#fn: () -> Void##() -> Void#})[#Void#]; name=freestandingExprVoidClosureMacro(fn:)
176+
//
177+
// ALL_FREESTANDING-DAG: Decl[Macro]/{{.*}}: freestandingExprIntClosureMacro({#fn: () -> Int##() -> Int#})[#Void#]; name=freestandingExprIntClosureMacro(fn:)
178+
//
179+
// ALL_FREESTANDING-DAG: Decl[Macro]/{{.*}}: freestandingDeclVoidClosureMacro {|}[#Declaration Macro#]; name=freestandingDeclVoidClosureMacro
180+
// ALL_FREESTANDING-DAG: Decl[Macro]/{{.*}}: freestandingDeclVoidClosureMacro({#fn: () -> Void##() -> Void#})[#Declaration Macro#]; name=freestandingDeclVoidClosureMacro(fn:)
181+
//
161182
// ALL_FREESTANDING_NOT-NOT: Attached
162183
// ALL_FREESTANDING_NOT-NOT: BodyMacro
184+
// ALL_FREESTANDING_NOT-NOT: freestandingExprIntClosureMacro {|}
163185

164186
func exprFreestanding(arg: Int) {
165187
_ = arg + ##^EXPR_FREESTANDING?check=EXPR_FREESTANDING;check=EXPR_FREESTANDING_NOT^#
@@ -181,6 +203,9 @@ struct NestedFreestanding {
181203
// ITEM_FREESTANDING-DAG: Decl[Macro]/{{.*}}: freestandingDeclMacro[#Declaration Macro#]; name=freestandingDeclMacro
182204
// ITEM_FREESTANDING-DAG: Decl[Macro]/{{.*}}: EverythingMacro[#Expression Macro, Declaration Macro, Accessor Macro, Member Attribute Macro, Member Macro, Peer Macro, Extension Macro#]; name=EverythingMacro
183205
//
206+
// ITEM_FREESTANDING-DAG: Decl[Macro]/{{.*}}: freestandingDeclVoidClosureMacro {|}[#Declaration Macro#]; name=freestandingDeclVoidClosureMacro
207+
// ITEM_FREESTANDING-DAG: Decl[Macro]/{{.*}}: freestandingDeclVoidClosureMacro({#fn: () -> Void##() -> Void#})[#Declaration Macro#]; name=freestandingDeclVoidClosureMacro(fn:)
208+
//
184209
// ITEM_FREESTANDING_NOT-NOT: Attached
185210
// ITEM_FREESTANDING_NOT-NOT: freestandingExpr
186211
// ITEM_FREESTANDING_NOT-NOT: freestandingCodeItemMacro

test/SourceKit/CodeExpand/code-expand.swift

Lines changed: 62 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,61 @@ 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+
}
318+
319+
@Foo(<#Int#>)
320+
func testDeclAttr1() {}
321+
// CHECK: @Foo(<#Int#>)
322+
// CHECK-NEXT: func testDeclAttr1() {}
323+
324+
@Foo(<#T##() -> ()#>)
325+
func testDeclAttr2() {}
326+
// CHECK: @Foo({
327+
// CHECK-NEXT: <#code#>
328+
// CHECK-NEXT: })
329+
// CHECK-NEXT: func testDeclAttr2() {}
330+
331+
func testTypeAttr1(x: @Foo(<#Int#>) String) {}
332+
// CHECK: func testTypeAttr1(x: @Foo(<#Int#>) String) {}
333+
334+
func testTypeAttr2(x: @Foo(<#T##() -> ()#>) Int) {}
335+
// CHECK: func testTypeAttr2(x: @Foo({
336+
// CHECK-NEXT: <#code#>
337+
// CHECK-NEXT: }) Int) {}

0 commit comments

Comments
 (0)