Skip to content

Commit 42baa2a

Browse files
authored
Merge pull request #1369 from DougGregor/macros-abstract-source-location
2 parents f5d6072 + a6b9718 commit 42baa2a

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)