mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
[SwiftSyntax] Refactor AbsolutePosition
AbsolutePosition being a mutable reference type easily leads to bugs where an AbsolutePosition is modified. Making it immutable eliminates this issue. Furthermore, the introduction of SourceLength should allow easier manipulation of AbsolutePositions on the client side. We still cannot make AbsolutePosition a value type since it is used inside AtomicCache, but the immutability gives the same safety.
This commit is contained in:
@@ -67,8 +67,43 @@ fileprivate indirect enum RawSyntaxData {
|
||||
struct RawSyntax: Codable {
|
||||
fileprivate let data: RawSyntaxData
|
||||
let presence: SourcePresence
|
||||
|
||||
/// A ID that uniquely identifies this node and is persistent across
|
||||
/// incremental parses
|
||||
let id: SyntaxNodeId
|
||||
|
||||
var _contentLength = AtomicCache<SourceLength>()
|
||||
|
||||
/// The length of this node excluding its leading and trailing trivia
|
||||
var contentLength: SourceLength {
|
||||
return _contentLength.value() {
|
||||
switch data {
|
||||
case .node(kind: _, layout: let layout):
|
||||
let firstElementIndex = layout.firstIndex(where: { $0 != nil })
|
||||
let lastElementIndex = layout.lastIndex(where: { $0 != nil })
|
||||
|
||||
var contentLength = SourceLength.zero
|
||||
for (offset, element) in layout.enumerated() {
|
||||
guard let element = element else {
|
||||
continue
|
||||
}
|
||||
// Skip the node's leading trivia
|
||||
if offset != firstElementIndex {
|
||||
contentLength += element.leadingTriviaLength
|
||||
}
|
||||
contentLength += element.contentLength
|
||||
// Skip the node's trailing trivia
|
||||
if offset != lastElementIndex {
|
||||
contentLength += element.trailingTriviaLength
|
||||
}
|
||||
}
|
||||
return contentLength
|
||||
case .token(kind: let kind, leadingTrivia: _, trailingTrivia: _):
|
||||
return SourceLength(of: kind.text)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
init(kind: SyntaxKind, layout: [RawSyntax?], presence: SourcePresence,
|
||||
id: SyntaxNodeId? = nil) {
|
||||
self.data = .node(kind: kind, layout: layout)
|
||||
@@ -289,25 +324,6 @@ extension RawSyntax: TextOutputStreamable {
|
||||
}
|
||||
|
||||
extension RawSyntax {
|
||||
func accumulateAbsolutePosition(_ pos: AbsolutePosition) {
|
||||
switch data {
|
||||
case .node(_, let layout):
|
||||
for child in layout {
|
||||
guard let child = child else { continue }
|
||||
child.accumulateAbsolutePosition(pos)
|
||||
}
|
||||
case let .token(kind, leadingTrivia, trailingTrivia):
|
||||
guard isPresent else { return }
|
||||
for piece in leadingTrivia {
|
||||
piece.accumulateAbsolutePosition(pos)
|
||||
}
|
||||
pos.add(text: kind.text)
|
||||
for piece in trailingTrivia {
|
||||
piece.accumulateAbsolutePosition(pos)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var leadingTrivia: Trivia? {
|
||||
switch data {
|
||||
case .node(_, let layout):
|
||||
@@ -335,18 +351,19 @@ extension RawSyntax {
|
||||
return trailingTrivia
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func accumulateLeadingTrivia(_ pos: AbsolutePosition) {
|
||||
guard let trivia = leadingTrivia else { return }
|
||||
for piece in trivia {
|
||||
piece.accumulateAbsolutePosition(pos)
|
||||
}
|
||||
extension RawSyntax {
|
||||
var leadingTriviaLength: SourceLength {
|
||||
return leadingTrivia?.sourceLength ?? .zero
|
||||
}
|
||||
|
||||
func accumulateTrailingTrivia(_ pos: AbsolutePosition) {
|
||||
guard let trivia = trailingTrivia else { return }
|
||||
for piece in trivia {
|
||||
piece.accumulateAbsolutePosition(pos)
|
||||
}
|
||||
var trailingTriviaLength: SourceLength {
|
||||
return trailingTrivia?.sourceLength ?? .zero
|
||||
}
|
||||
|
||||
/// The length of this node including all of its trivia
|
||||
var totalLength: SourceLength {
|
||||
return leadingTriviaLength + contentLength + trailingTriviaLength
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user