@@ -48,11 +48,13 @@ public class BasicMacroExpansionContext {
48
48
/// information about that source file.
49
49
private var sourceFiles : [ SourceFileSyntax : KnownSourceFile ] = [ : ]
50
50
51
- /// Mapping from intentionally-disconnected syntax node roots to the
52
- /// absolute offsets that have within a given source file, which is used
53
- /// to establish the link between a node that been intentionally disconnected
54
- /// from a source file to hide information from the macro implementation.
55
- private var disconnectedNodes : [ Syntax : ( SourceFileSyntax , Int ) ] = [ : ]
51
+ /// Mapping from intentionally-disconnected syntax nodes to the corresponding
52
+ /// nodes in the original source file.
53
+ ///
54
+ /// This is used to establish the link between a node that been intentionally
55
+ /// disconnected from a source file to hide information from the macro
56
+ /// implementation.
57
+ private var detachedNodes : [ Syntax : Syntax ] = [ : ]
56
58
57
59
/// The macro expansion discriminator, which is used to form unique names
58
60
/// when requested.
@@ -69,24 +71,10 @@ public class BasicMacroExpansionContext {
69
71
}
70
72
71
73
extension BasicMacroExpansionContext {
72
- /// Note that the given node that was at the given position in the provided
73
- /// source file has been disconnected and is now a new root.
74
- private func addDisconnected(
75
- _ node: some SyntaxProtocol ,
76
- at offset: AbsolutePosition ,
77
- in sourceFile: SourceFileSyntax
78
- ) {
79
- disconnectedNodes [ Syntax ( node) ] = ( sourceFile, offset. utf8Offset)
80
- }
81
-
82
74
/// Detach the given node, and record where it came from.
83
75
public func detach< Node: SyntaxProtocol > ( _ node: Node ) -> Node {
84
76
let detached = node. detached
85
-
86
- if let rootSourceFile = node. root. as ( SourceFileSyntax . self) {
87
- addDisconnected ( detached, at: node. position, in: rootSourceFile)
88
- }
89
-
77
+ detachedNodes [ Syntax ( detached) ] = Syntax ( node)
90
78
return detached
91
79
}
92
80
}
@@ -136,28 +124,49 @@ extension BasicMacroExpansionContext: MacroExpansionContext {
136
124
diagnostics. append ( diagnostic)
137
125
}
138
126
127
+ /// Translates a position from a detached node to the corresponding location
128
+ /// in the original source file.
129
+ ///
130
+ /// - Parameters:
131
+ /// - position: The position to translate
132
+ /// - node: The node at which the position is anchored. This node is used to
133
+ /// find the offset in the original source file
134
+ /// - fileName: The file name that should be used in the `SourceLocation`
135
+ /// - Returns: The location in the original source file
136
+ public func location(
137
+ for position: AbsolutePosition ,
138
+ anchoredAt node: Syntax ,
139
+ fileName: String
140
+ ) -> SourceLocation {
141
+ guard let nodeInOriginalTree = detachedNodes [ node. root] else {
142
+ return SourceLocationConverter ( file: fileName, tree: node. root) . location ( for: position)
143
+ }
144
+ let adjustedPosition = position + SourceLength( utf8Length: nodeInOriginalTree. position. utf8Offset)
145
+ return SourceLocationConverter ( file: fileName, tree: nodeInOriginalTree. root) . location ( for: adjustedPosition)
146
+ }
147
+
139
148
public func location(
140
149
of node: some SyntaxProtocol ,
141
150
at position: PositionInSyntaxNode ,
142
151
filePathMode: SourceLocationFilePathMode
143
152
) -> AbstractSourceLocation ? {
144
153
// Dig out the root source file and figure out how we need to adjust the
145
154
// offset of the given syntax node to adjust for it.
146
- let rootSourceFile : SourceFileSyntax
147
- let offsetAdjustment : Int
155
+ let rootSourceFile : SourceFileSyntax ?
156
+ let offsetAdjustment : SourceLength
148
157
if let directRootSourceFile = node. root. as ( SourceFileSyntax . self) {
149
158
// The syntax node came from the source file itself.
150
159
rootSourceFile = directRootSourceFile
151
- offsetAdjustment = 0
152
- } else if let ( adjustedSourceFile , offset ) = disconnectedNodes [ Syntax ( node) ] {
160
+ offsetAdjustment = . zero
161
+ } else if let nodeInOriginalTree = detachedNodes [ Syntax ( node) ] {
153
162
// The syntax node came from a disconnected root, so adjust for that.
154
- rootSourceFile = adjustedSourceFile
155
- offsetAdjustment = offset
163
+ rootSourceFile = nodeInOriginalTree . root . as ( SourceFileSyntax . self )
164
+ offsetAdjustment = SourceLength ( utf8Length : nodeInOriginalTree . position . utf8Offset )
156
165
} else {
157
166
return nil
158
167
}
159
168
160
- guard let knownRoot = sourceFiles [ rootSourceFile] else {
169
+ guard let rootSourceFile , let knownRoot = sourceFiles [ rootSourceFile] else {
161
170
return nil
162
171
}
163
172
@@ -189,6 +198,6 @@ extension BasicMacroExpansionContext: MacroExpansionContext {
189
198
190
199
// Do the location lookup.
191
200
let converter = SourceLocationConverter ( file: fileName, tree: rootSourceFile)
192
- return AbstractSourceLocation ( converter. location ( for: rawPosition. advanced ( by : offsetAdjustment) ) )
201
+ return AbstractSourceLocation ( converter. location ( for: rawPosition + offsetAdjustment) )
193
202
}
194
203
}
0 commit comments