Skip to content

Commit b3af130

Browse files
committed
[IDE] Visit auxiliary declarations if walking expansions
After visiting declarations, also walk into their auxiliary decls if expansions are being walked. Resolves rdar://109548265.
1 parent 861fd2f commit b3af130

File tree

4 files changed

+300
-28
lines changed

4 files changed

+300
-28
lines changed

Diff for: lib/AST/ASTWalker.cpp

+5-5
Original file line numberDiff line numberDiff line change
@@ -455,20 +455,20 @@ class Traversal : public ASTVisitor<Traversal, Expr*, Stmt*,
455455
else
456456
return true;
457457
}
458+
458459
bool alreadyFailed = false;
459460
if (shouldWalkExpansion) {
460461
MED->forEachExpandedNode([&](ASTNode expandedNode) {
461462
if (alreadyFailed) return;
463+
462464
if (auto *expr = expandedNode.dyn_cast<Expr *>()) {
463-
if (!doIt(expr))
464-
alreadyFailed = true;
465+
alreadyFailed = doIt(expr) == nullptr;
465466
} else if (auto *stmt = expandedNode.dyn_cast<Stmt *>()) {
466-
if (!doIt(stmt))
467-
alreadyFailed = true;
467+
alreadyFailed = doIt(stmt) == nullptr;
468468
} else {
469469
auto decl = expandedNode.get<Decl *>();
470470
if (!isa<VarDecl>(decl))
471-
alreadyFailed = inherited::visit(decl);
471+
alreadyFailed = doIt(decl);
472472
}
473473
});
474474
}

Diff for: lib/IDE/SourceEntityWalker.cpp

+16
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,22 @@ ASTWalker::PreWalkAction SemaAnnotator::walkToDeclPreProper(Decl *D) {
236236
ASTWalker::PostWalkAction SemaAnnotator::walkToDeclPost(Decl *D) {
237237
auto Action = walkToDeclPostProper(D);
238238
SEWalker.endBalancedASTOrderDeclVisit(D);
239+
240+
if (Action.Action == PostWalkAction::Stop)
241+
return Action;
242+
243+
// Walk into peer and conformance expansions if walking expansions
244+
if (shouldWalkMacroArgumentsAndExpansion().second) {
245+
D->visitAuxiliaryDecls([&](Decl *auxDecl) {
246+
if (Action.Action == PostWalkAction::Stop)
247+
return;
248+
249+
if (auxDecl->walk(*this)) {
250+
Action = Action::Stop();
251+
}
252+
}, /*visitFreestandingExpanded=*/false);
253+
}
254+
239255
return Action;
240256
}
241257

Diff for: test/Index/index_macros.swift

+277-20
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,284 @@
1+
// REQUIRES: swift_swift_parser
2+
13
// RUN: %empty-directory(%t)
2-
// RUN: %target-swift-ide-test -print-indexed-symbols -source-filename %s | %FileCheck %s
3-
// REQUIRES: OS=macosx
4+
// RUN: split-file --leading-lines %s %t
5+
6+
// Check that we index code expanded from macros, especially nested references
7+
// (ie. calls within an added function).
8+
9+
// Create the plugin with various macros for testing
10+
// RUN: %host-build-swift -swift-version 5 -emit-library -o %t/%target-library-name(IndexMacros) -module-name=IndexMacros %t/IndexMacros.swift -g -no-toolchain-stdlib-rpath
11+
12+
// Check indexed symbols
13+
// RUN: %target-swift-ide-test -print-indexed-symbols -source-filename %t/IndexTest.swift -load-plugin-library %t/%target-library-name(IndexMacros) -parse-as-library 2>&1 | tee %t/test.idx | %FileCheck %s
14+
15+
//--- IndexTest.swift
16+
@freestanding(expression)
17+
macro freestandingExpr() = #externalMacro(module: "IndexMacros", type: "FreestandingExprMacro")
18+
// CHECK: [[@LINE-1]]:7 | macro/Swift | freestandingExpr() | [[EXPR_USR:.*]] | Def
19+
20+
@freestanding(declaration, names: named(TestFree))
21+
macro freestandingDecl() = #externalMacro(module: "IndexMacros", type: "FreestandingDeclMacro")
22+
// CHECK: [[@LINE-1]]:7 | macro/Swift | freestandingDecl() | [[DECL_USR:.*]] | Def
23+
24+
@attached(accessor)
25+
macro Accessor() = #externalMacro(module: "IndexMacros", type: "SomeAccessorMacro")
26+
// CHECK: [[@LINE-1]]:7 | macro/Swift | Accessor() | [[ACCESSOR_USR:.*]] | Def
27+
28+
@attached(conformance)
29+
macro Conformance() = #externalMacro(module: "IndexMacros", type: "SomeConformanceMacro")
30+
// CHECK: [[@LINE-1]]:7 | macro/Swift | Conformance() | [[CONFORMANCE_USR:.*]] | Def
31+
32+
@attached(member, names: named(memberFunc))
33+
macro Member() = #externalMacro(module: "IndexMacros", type: "SomeMemberMacro")
34+
// CHECK: [[@LINE-1]]:7 | macro/Swift | Member() | [[MEMBER_USR:.*]] | Def
35+
36+
@attached(memberAttribute)
37+
macro MemberAttribute() = #externalMacro(module: "IndexMacros", type: "SomeMemberAttributeMacro")
38+
// CHECK: [[@LINE-1]]:7 | macro/Swift | MemberAttribute() | [[MEMBER_ATTRIBUTE_USR:.*]] | Def
39+
40+
@attached(peer, names: named(TestPeer))
41+
macro Peer() = #externalMacro(module: "IndexMacros", type: "SomePeerMacro")
42+
// CHECK: [[@LINE-1]]:7 | macro/Swift | Peer() | [[PEER_USR:.*]] | Def
43+
44+
@attached(peer, names: named(peerMember))
45+
macro PeerMember() = #externalMacro(module: "IndexMacros", type: "SomePeerMemberMacro")
46+
// CHECK: [[@LINE-1]]:7 | macro/Swift | PeerMember() | [[PEER_MEMBER_USR:.*]] | Def
47+
48+
protocol TestProto {}
49+
// CHECK: [[@LINE-1]]:10 | protocol/Swift | TestProto | [[PROTO_USR:.*]] | Def
50+
51+
func accessorLog() {}
52+
// CHECK: [[@LINE-1]]:6 | function/Swift | accessorLog() | [[ACC_LOG_USR:.*]] | Def
53+
func exprLog() {}
54+
// CHECK: [[@LINE-1]]:6 | function/Swift | exprLog() | [[EXPR_LOG_USR:.*]] | Def
55+
func freeLog() {}
56+
// CHECK: [[@LINE-1]]:6 | function/Swift | freeLog() | [[FREE_LOG_USR:.*]] | Def
57+
func memberLog() {}
58+
// CHECK: [[@LINE-1]]:6 | function/Swift | memberLog() | [[MEMBER_LOG_USR:.*]] | Def
59+
func peerLog() {}
60+
// CHECK: [[@LINE-1]]:6 | function/Swift | peerLog() | [[PEER_LOG_USR:.*]] | Def
61+
62+
// CHECK: [[@LINE+2]]:8 | struct/Swift | AddOne | [[ADD_ONE_USR:.*]] | Def
63+
@propertyWrapper
64+
struct AddOne {
65+
var value: Int = 1
66+
var wrappedValue: Int {
67+
get { value }
68+
set { value = newValue + 1 }
69+
}
70+
init(wrappedValue: Int) {
71+
self.wrappedValue = wrappedValue
72+
}
73+
}
74+
75+
// Creates a `TestFree` struct with `freeFunc` calling `freeLog`
76+
#freestandingDecl
77+
// CHECK: [[@LINE-1]]:2 | macro/Swift | freestandingDecl() | [[DECL_USR]] | Ref
78+
// CHECK: [[@LINE-2]]:1 | struct/Swift | TestFree | [[FREE_STRUCT_USR:.*]] | Def,Impl
79+
// CHECK: [[@LINE-3]]:1 | instance-method/Swift | freeFunc() | [[FREE_FUNC_USR:.*]] | Def,Impl,RelChild
80+
// CHECK-NEXT: RelChild | struct/Swift | TestFree | [[FREE_STRUCT_USR]]
81+
// CHECK: [[@LINE-5]]:1 | function/Swift | freeLog() | [[FREE_LOG_USR]] | Ref,Call,Impl,RelCall,RelCont
82+
// CHECK-NEXT: RelCall,RelCont | instance-method/Swift | freeFunc() | [[FREE_FUNC_USR]]
83+
84+
// CHECK: [[@LINE+4]]:40 | macro/Swift | Peer() | [[PEER_USR]] | Ref
85+
// CHECK: [[@LINE+3]]:23 | macro/Swift | MemberAttribute() | [[MEMBER_ATTRIBUTE_USR]] | Ref
86+
// CHECK: [[@LINE+2]]:15 | macro/Swift | Member() | [[MEMBER_USR]] | Ref
87+
// CHECK: [[@LINE+1]]:2 | macro/Swift | Conformance() | [[CONFORMANCE_USR]] | Ref
88+
@Conformance @Member @MemberAttribute @Peer
89+
struct TestAttached {
90+
var attachedMember: Int
91+
92+
@Accessor
93+
var attachedMemberAccessors: Int
94+
}
95+
// `MemberAttribute` adds `@AddOne` to attachedMember
96+
// CHECK: [[@LINE-8]]:22 | struct/Swift | AddOne | [[ADD_ONE_USR]] | Ref,Impl,RelCont
97+
// CHECK-NEXT: RelCont | instance-property/Swift | attachedMember
98+
99+
// `Accessor` adds getters/setters to `attachedMemberAccessors` that both call `accessorLog`
100+
// CHECK: [[@LINE-8]]:3 | function/Swift | accessorLog() | [[ACC_LOG_USR]] | Ref,Call,Impl,RelCall,RelCont
101+
// CHECK-NEXT: RelCall,RelCont | instance-method/acc-get/Swift | getter:attachedMemberAccessors
4102

103+
// `Member` adds a new member `memberFunc` that calls `memberLog`
104+
// CHECK: [[@LINE-16]]:14 | instance-method/Swift | memberFunc() | [[MEMBER_FUNC_USR:.*]] | Def,Impl,RelChild
105+
// CHECK: [[@LINE-17]]:14 | function/Swift | memberLog() | [[MEMBER_LOG_USR]] | Ref,Call,Impl,RelCall,RelCont
106+
// CHECK-NEXT: RelCall,RelCont | instance-method/Swift | memberFunc() | [[MEMBER_FUNC_USR]]
5107

6-
@freestanding(expression) macro myLine() -> Int = #externalMacro(module: "MacroDefinition", type: "LineMacro")
7-
@freestanding(expression) macro myFilename<T: ExpressibleByStringLiteral>() -> T = #externalMacro(module: "MacroDefinition", type: "FileMacro")
8-
@freestanding(expression) macro myStringify<T>(_: T) -> (T, String) = #externalMacro(module: "MacroDefinition", type: "StringifyMacro")
108+
// `Peer` adds a new inner type `TestPeer` that contains `peerFunc` with a call to `peerLog`
109+
// CHECK: [[@LINE-21]]:39 | struct/Swift | TestPeer | [[PEER_STRUCT_USR:.*]] | Def,Impl
110+
// CHECK: [[@LINE-22]]:39 | instance-method/Swift | peerFunc() | [[PEER_FUNC_USR:.*]] | Def,Impl,RelChild
111+
// CHECK-NEXT: RelChild | struct/Swift | TestPeer | [[PEER_STRUCT_USR]]
112+
// CHECK: [[@LINE-24]]:39 | function/Swift | peerLog() | [[PEER_LOG_USR]] | Ref,Call,Impl,RelCall,RelCont
113+
// CHECK-NEXT: RelCall,RelCont | instance-method/Swift | peerFunc() | [[PEER_FUNC_USR]]
9114

10-
func test(x: Int) {
11-
_ = #myLine
12-
let _: String = #myFilename
13-
_ = #myStringify(x + x)
115+
// `Conformance` adds `TestProto` as a conformance on an extension of `TestAttached`
116+
// CHECK: [[@LINE-28]]:1 | extension/ext-struct/Swift | TestAttached | {{.*}} | Def,Impl
117+
// CHECK: [[@LINE-29]]:1 | protocol/Swift | TestProto | [[PROTO_USR]] | Ref,Impl,RelBase
118+
// CHECK-NEXT: RelBase | extension/ext-struct/Swift | TestAttached
119+
120+
// CHECK: [[@LINE+1]]:8 | struct/Swift | Outer | [[OUTER_USR:.*]] | Def
121+
struct Outer {
122+
// CHECK: [[@LINE+1]]:4 | macro/Swift | PeerMember() | [[PEER_MEMBER_USR]] | Ref
123+
@PeerMember
124+
var anyMember: Int
125+
// `PeerMember` adds a new `peerMember`
126+
// CHECK: [[@LINE-3]]:3 | instance-property/Swift | peerMember | {{.*}} | Def,Impl,RelChild
127+
// CHECK-NEXT: RelChild | struct/Swift | Outer | [[OUTER_USR]]
128+
129+
// CHECK: [[@LINE+2]]:17 | macro/Swift | Member() | [[MEMBER_USR]] | Ref
130+
// CHECK: [[@LINE+1]]:4 | macro/Swift | Conformance() | [[CONFORMANCE_USR]] | Ref
131+
@Conformance @Member
132+
struct TestInner {}
133+
}
134+
// `Member` adds a new member `memberFunc` that calls `memberLog`
135+
// CHECK: [[@LINE-4]]:16 | instance-method/Swift | memberFunc() | [[INNER_FUNC_USR:.*]] | Def,Impl
136+
// CHECK-NEXT: RelChild | struct/Swift | TestInner
137+
// CHECK: [[@LINE-6]]:16 | function/Swift | memberLog() | [[MEMBER_LOG_USR]] | Ref,Call,Impl,RelCall,RelCont
138+
// CHECK-NEXT: RelCall,RelCont | instance-method/Swift | memberFunc() | [[INNER_FUNC_USR]]
139+
140+
// `Conformance` adds `TestProto` as a conformance on an extension of `TestInner`
141+
// CHECK: [[@LINE-10]]:3 | extension/ext-struct/Swift | TestInner | {{.*}} | Def,Impl
142+
// CHECK: [[@LINE-11]]:3 | protocol/Swift | TestProto | [[PROTO_USR]] | Ref,Impl,RelBase
143+
// CHECK-NEXT: RelBase | extension/ext-struct/Swift | TestInner
144+
145+
func testExpr() {
146+
#freestandingExpr
147+
// CHECK: [[@LINE-1]]:3 | function/Swift | exprLog() | [[EXPR_LOG_USR]] | Ref,Call,Impl,RelCall,RelCont
148+
// CHECK-NEXT: RelCall,RelCont | function/Swift | testExpr()
14149
}
15150

16-
// CHECK: 6:33 | macro/Swift | myLine() | s:14swift_ide_test6myLineSiycfm | Def | rel: 0
17-
// CHECK: 6:45 | struct/Swift | Int | s:Si | Ref | rel: 0
18-
// CHECK: 7:33 | macro/Swift | myFilename() | s:14swift_ide_test10myFilenamexycs26ExpressibleByStringLiteralRzlufm | Def | rel: 0
19-
// CHECK: 7:47 | protocol/Swift | ExpressibleByStringLiteral | s:s26ExpressibleByStringLiteralP | Ref | rel: 0
20-
// CHECK: 8:33 | macro/Swift | myStringify(_:) | s:14swift_ide_test11myStringifyyx_SStxclufm | Def | rel: 0
151+
//--- IndexMacros.swift
152+
import SwiftSyntax
153+
import SwiftSyntaxBuilder
154+
import SwiftSyntaxMacros
155+
156+
public struct FreestandingExprMacro: ExpressionMacro {
157+
public static func expansion(
158+
of node: some FreestandingMacroExpansionSyntax,
159+
in context: some MacroExpansionContext
160+
) -> ExprSyntax {
161+
return "exprLog()"
162+
}
163+
}
164+
165+
public struct FreestandingDeclMacro: DeclarationMacro {
166+
public static func expansion(
167+
of node: some FreestandingMacroExpansionSyntax,
168+
in context: some MacroExpansionContext
169+
) throws -> [DeclSyntax] {
170+
return ["""
171+
struct TestFree {
172+
func freeFunc() {
173+
freeLog()
174+
}
175+
}
176+
"""]
177+
}
178+
}
179+
180+
public struct SomeAccessorMacro: AccessorMacro {
181+
public static func expansion(
182+
of node: AttributeSyntax,
183+
providingAccessorsOf declaration: some DeclSyntaxProtocol,
184+
in context: some MacroExpansionContext
185+
) throws -> [AccessorDeclSyntax] {
186+
return [
187+
"""
188+
get {
189+
accessorLog()
190+
return 1
191+
}
192+
""",
193+
"""
194+
set {
195+
accessorLog()
196+
}
197+
""",
198+
]
199+
}
200+
}
21201

22-
// CHECK: 11:8 | macro/Swift | myLine() | s:14swift_ide_test6myLineSiycfm | Ref,RelCont | rel: 1
23-
// CHECK: 12:20 | macro/Swift | myFilename() | s:14swift_ide_test10myFilenamexycs26ExpressibleByStringLiteralRzlufm | Ref,RelCont | rel: 1
24-
// CHECK: 13:8 | macro/Swift | myStringify(_:) | s:14swift_ide_test11myStringifyyx_SStxclufm | Ref,RelCont | rel: 1
25-
// CHECK: 13:20 | param/Swift | x | s:14swift_ide_test0C01xySi_tFACL_Sivp | Ref,Read,RelCont | rel: 1
26-
// CHECK: 13:22 | static-method/infix-operator/Swift | +(_:_:) | s:Si1poiyS2i_SitFZ | Ref,Call,RelCall,RelCont | rel: 1
27-
// CHECK: 13:24 | param/Swift | x | s:14swift_ide_test0C01xySi_tFACL_Sivp | Ref,Read,RelCont | rel: 1
202+
public struct SomeConformanceMacro: ConformanceMacro {
203+
public static func expansion(
204+
of node: AttributeSyntax,
205+
providingConformancesOf decl: some DeclGroupSyntax,
206+
in context: some MacroExpansionContext
207+
) throws -> [(TypeSyntax, GenericWhereClauseSyntax?)] {
208+
let protocolName: TypeSyntax = "TestProto"
209+
return [(protocolName, nil)]
210+
}
211+
}
212+
213+
public struct SomeMemberMacro: MemberMacro {
214+
public static func expansion(
215+
of node: AttributeSyntax,
216+
providingMembersOf declaration: some DeclGroupSyntax,
217+
in context: some MacroExpansionContext
218+
) throws -> [DeclSyntax] {
219+
let newFunc: DeclSyntax =
220+
"""
221+
func memberFunc() {
222+
memberLog()
223+
}
224+
"""
225+
return [
226+
newFunc,
227+
]
228+
}
229+
}
230+
231+
public struct SomeMemberAttributeMacro: MemberAttributeMacro {
232+
public static func expansion(
233+
of node: AttributeSyntax,
234+
attachedTo parent: some DeclGroupSyntax,
235+
providingAttributesFor member: some DeclSyntaxProtocol,
236+
in context: some MacroExpansionContext
237+
) throws -> [AttributeSyntax] {
238+
guard let varDecl = member.as(VariableDeclSyntax.self),
239+
let binding = varDecl.bindings.first,
240+
let identifier = binding.pattern.as(IdentifierPatternSyntax.self)?.identifier.text,
241+
identifier == "attachedMember"
242+
else {
243+
return []
244+
}
245+
246+
return [AttributeSyntax(
247+
attributeName: SimpleTypeIdentifierSyntax(
248+
name: .identifier("AddOne")
249+
)
250+
)]
251+
}
252+
}
253+
254+
public struct SomePeerMacro: PeerMacro {
255+
public static func expansion(
256+
of node: AttributeSyntax,
257+
providingPeersOf declaration: some DeclSyntaxProtocol,
258+
in context: some MacroExpansionContext
259+
) throws -> [DeclSyntax] {
260+
return [
261+
"""
262+
struct TestPeer {
263+
func peerFunc() {
264+
peerLog()
265+
}
266+
}
267+
"""
268+
]
269+
}
270+
}
271+
272+
public struct SomePeerMemberMacro: PeerMacro {
273+
public static func expansion(
274+
of node: AttributeSyntax,
275+
providingPeersOf declaration: some DeclSyntaxProtocol,
276+
in context: some MacroExpansionContext
277+
) throws -> [DeclSyntax] {
278+
return [
279+
"""
280+
var peerMember: Int
281+
"""
282+
]
283+
}
284+
}

Diff for: test/Macros/Inputs/syntax_macro_definitions.swift

+2-3
Original file line numberDiff line numberDiff line change
@@ -1449,23 +1449,22 @@ public struct SimpleCodeItemMacro: CodeItemMacro {
14491449
) throws -> [CodeBlockItemSyntax] {
14501450
[
14511451
.init(item: .decl("""
1452-
14531452
struct \(context.makeUniqueName("foo")) {
14541453
var x: Int
14551454
}
14561455
""")),
14571456
.init(item: .stmt("""
1458-
14591457
if true {
14601458
print("from stmt")
14611459
usedInExpandedStmt()
14621460
}
1461+
""")),
1462+
.init(item: .stmt("""
14631463
if false {
14641464
print("impossible")
14651465
}
14661466
""")),
14671467
.init(item: .expr("""
1468-
14691468
print("from expr")
14701469
""")),
14711470
]

0 commit comments

Comments
 (0)