Skip to content

Commit a6b9718

Browse files
committed
[Macros] Introduce AbstractSourceLocation and its APIs
Introduce `AbstractSourceLocation` as a macro-focused API that uses opaque syntax rather than direct values. Update the MacroExpansionContext APIs for location access to use this type, leaving the old versions in place to allow for some staging for clients. This aligns the location APIs with what is proposed in SE-0382.
1 parent f5d6072 commit a6b9718

File tree

4 files changed

+107
-11
lines changed

4 files changed

+107
-11
lines changed
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2023 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
import SwiftSyntax
14+
15+
/// Abstractly represents a source location in the macro.
16+
public struct AbstractSourceLocation {
17+
/// A primary expression that represents the file and is `ExpressibleByStringLiteral`.
18+
public let file: ExprSyntax
19+
20+
/// A primary expression that represents the line and is `ExpressibleByIntegerLiteral`.
21+
public let line: ExprSyntax
22+
23+
/// A primary expression that represents the column and is `ExpressibleByIntegerLiteral`.
24+
public let column: ExprSyntax
25+
}

Sources/SwiftSyntaxMacros/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ add_swift_host_library(SwiftSyntaxMacros
1919
MacroProtocols/MemberMacro.swift
2020
MacroProtocols/PeerMacro.swift
2121

22+
AbstractSourceLocation.swift
2223
BasicMacroExpansionContext.swift
2324
MacroExpansionContext.swift
2425
MacroSystem.swift

Sources/SwiftSyntaxMacros/MacroExpansionContext.swift

Lines changed: 75 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,9 @@
1010
//
1111
//===----------------------------------------------------------------------===//
1212

13-
import SwiftSyntax
1413
import SwiftDiagnostics
14+
import SwiftSyntax
15+
import SwiftSyntaxBuilder
1516

1617
/// Interface to extract information about the context in which a given
1718
/// macro is expanded.
@@ -41,11 +42,31 @@ public protocol MacroExpansionContext: AnyObject {
4142
/// - Returns: the source location within the given node, or `nil` if the
4243
/// given syntax node is not rooted in a source file that the macro
4344
/// expansion context knows about.
45+
@available(*, deprecated, message: "Please use AbstractSourceLocation version")
4446
func location<Node: SyntaxProtocol>(
4547
of node: Node,
4648
at position: PositionInSyntaxNode,
4749
filePathMode: SourceLocationFilePathMode
4850
) -> SourceLocation?
51+
52+
/// Retrieve a source location for the given syntax node.
53+
///
54+
/// - Parameters:
55+
/// - node: The syntax node whose source location to produce.
56+
/// - position: The position within the syntax node for the resulting
57+
/// location.
58+
/// - filePathMode: How the file name contained in the source location is
59+
/// formed.
60+
///
61+
/// - Returns: the source location within the given node, or `nil` if the
62+
/// given syntax node is not rooted in a source file that the macro
63+
/// expansion context knows about.
64+
@_disfavoredOverload
65+
func location<Node: SyntaxProtocol>(
66+
of node: Node,
67+
at position: PositionInSyntaxNode,
68+
filePathMode: SourceLocationFilePathMode
69+
) -> AbstractSourceLocation?
4970
}
5071

5172
extension MacroExpansionContext {
@@ -58,11 +79,64 @@ extension MacroExpansionContext {
5879
/// - Returns: the source location within the given node, or `nil` if the
5980
/// given syntax node is not rooted in a source file that the macro
6081
/// expansion context knows about.
82+
@available(*, deprecated, message: "Please use AbstractSourceLocation version")
6183
public func location<Node: SyntaxProtocol>(
6284
of node: Node
6385
) -> SourceLocation? {
6486
return location(of: node, at: .afterLeadingTrivia, filePathMode: .fileID)
6587
}
88+
89+
/// Retrieve a source location for the given syntax node's starting token
90+
/// (after leading trivia) using file naming according to `#fileID`.
91+
///
92+
/// - Parameters:
93+
/// - node: The syntax node whose source location to produce.
94+
///
95+
/// - Returns: the source location within the given node, or `nil` if the
96+
/// given syntax node is not rooted in a source file that the macro
97+
/// expansion context knows about.
98+
@_disfavoredOverload
99+
public func location<Node: SyntaxProtocol>(
100+
of node: Node
101+
) -> AbstractSourceLocation? {
102+
return location(of: node, at: .afterLeadingTrivia, filePathMode: .fileID)
103+
}
104+
}
105+
106+
extension MacroExpansionContext {
107+
/// Retrieve a source location for the given syntax node.
108+
///
109+
/// - Parameters:
110+
/// - node: The syntax node whose source location to produce.
111+
/// - position: The position within the syntax node for the resulting
112+
/// location.
113+
/// - filePathMode: How the file name contained in the source location is
114+
/// formed.
115+
///
116+
/// - Returns: the source location within the given node, or `nil` if the
117+
/// given syntax node is not rooted in a source file that the macro
118+
/// expansion context knows about.
119+
@_disfavoredOverload
120+
@available(*, deprecated, message: "Please use AbstractSourceLocation version")
121+
public func location<Node: SyntaxProtocol>(
122+
of node: Node,
123+
at position: PositionInSyntaxNode,
124+
filePathMode: SourceLocationFilePathMode
125+
) -> AbstractSourceLocation? {
126+
guard let sourceLoc: SourceLocation = location(of: node, at: position, filePathMode: filePathMode),
127+
let file = sourceLoc.file,
128+
let line = sourceLoc.line,
129+
let column = sourceLoc.column
130+
else {
131+
return nil
132+
}
133+
134+
return AbstractSourceLocation(
135+
file: "\(literal: file)",
136+
line: "\(literal: line)",
137+
column: "\(literal: column)"
138+
)
139+
}
66140
}
67141

68142
/// Diagnostic message used for thrown errors.

Tests/SwiftSyntaxMacrosTest/MacroSystemTests.swift

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -130,17 +130,15 @@ public struct ColumnMacro: ExpressionMacro {
130130
of macro: Node,
131131
in context: Context
132132
) throws -> ExprSyntax {
133-
guard let sourceLoc = context.location(of: macro),
134-
let column = sourceLoc.column
133+
guard let sourceLoc: AbstractSourceLocation = context.location(of: macro)
135134
else {
136135
throw CustomError.message("can't find location for macro")
137136
}
138137

139-
let fileLiteral: ExprSyntax = "\(literal: column)"
140138
if let leadingTrivia = macro.leadingTrivia {
141-
return fileLiteral.with(\.leadingTrivia, leadingTrivia)
139+
return sourceLoc.column.with(\.leadingTrivia, leadingTrivia)
142140
}
143-
return fileLiteral
141+
return sourceLoc.column
144142
}
145143
}
146144

@@ -152,17 +150,15 @@ public struct FileIDMacro: ExpressionMacro {
152150
of macro: Node,
153151
in context: Context
154152
) throws -> ExprSyntax {
155-
guard let sourceLoc = context.location(of: macro),
156-
let fileID = sourceLoc.file
153+
guard let sourceLoc: AbstractSourceLocation = context.location(of: macro)
157154
else {
158155
throw CustomError.message("can't find location for macro")
159156
}
160157

161-
let fileLiteral: ExprSyntax = "\(literal: fileID)"
162158
if let leadingTrivia = macro.leadingTrivia {
163-
return fileLiteral.with(\.leadingTrivia, leadingTrivia)
159+
return sourceLoc.file.with(\.leadingTrivia, leadingTrivia)
164160
}
165-
return fileLiteral
161+
return sourceLoc.file
166162
}
167163
}
168164

0 commit comments

Comments
 (0)