Skip to content

Commit cd7ded2

Browse files
committed
Introduce a source accurate and structural view of a SwiftSyntax tree
`SyntaxTreeViewMode` allows two different views on a SwiftSyntax tree: 1. Either a purely `sourceAccurate` view, which skips over all missing children but traverses garbage syntax (once implemented). This mode is intended for clients that operate at the source code level, like swift-format 2. For clients that don’t care about 100% about source fidelity but would like to view the syntax tree for structural analysis with fixes from the parser applied, there’s the `fixedUp` view. This includes missing nodes (because the user probably meant to write these) and skips over garbage nodes (because the client will likely have a hard time reasoning about these nodes if the parser couldn’t make sense of them)
1 parent 8657d66 commit cd7ded2

28 files changed

+294
-154
lines changed

Snippets/AddOneToIntegerLiterals.swift renamed to Examples/AddOneToIntegerLiterals.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ class AddOneToIntegerLiterals: SyntaxRewriter {
3131

3232
// Create a new integer literal token with `int + 1` as its text.
3333
let newIntegerLiteralToken = token.withKind(.integerLiteral("\(int + 1)"))
34-
34+
3535
// Return the new integer literal.
3636
return Syntax(newIntegerLiteralToken)
3737
}

Snippets/CodeGenerationUsingSwiftSyntaxBuilder.swift renamed to Examples/CodeGenerationUsingSwiftSyntaxBuilder.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import SwiftSyntaxBuilder
22

33
/// This example will print the following example:
4-
///
4+
///
55
///```
66
/// import Foundation
77
/// import UIKit
File renamed without changes.

Sources/SwiftSyntax/IncrementalParseTransition.swift

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -304,7 +304,7 @@ public struct IncrementalParseLookup {
304304
if !edits.edits.isEmpty && edits.edits.first!.range.offset > nextSibling.endPosition.utf8Offset {
305305
return true
306306
}
307-
if let nextToken = nextSibling.raw.firstPresentToken {
307+
if let nextToken = nextSibling.raw.firstToken(viewMode: .sourceAccurate) {
308308
nextLeafNodeLength = nextToken.totalLength - nextToken.trailingTriviaLength
309309
}
310310
}
@@ -350,6 +350,7 @@ fileprivate struct SyntaxCursor {
350350
var parents: [AbsoluteRawSyntax]
351351
var node: AbsoluteRawSyntax
352352
var finished: Bool
353+
let viewMode = SyntaxTreeViewMode.sourceAccurate
353354

354355
init(root: AbsoluteRawSyntax) {
355356
self.node = root
@@ -368,7 +369,7 @@ fileprivate struct SyntaxCursor {
368369
var parents = ArraySlice(self.parents)
369370
var node = self.node
370371
while !parents.isEmpty {
371-
if let sibling = node.nextSibling(parent: parents.last!) {
372+
if let sibling = node.nextSibling(parent: parents.last!, viewMode: viewMode) {
372373
return sibling
373374
}
374375
node = parents.removeLast()
@@ -380,7 +381,7 @@ fileprivate struct SyntaxCursor {
380381
/// Moves to the first child of the current node.
381382
/// - Returns: False if the node has no children.
382383
mutating func advanceToFirstChild() -> Bool {
383-
guard let child = node.firstChild else { return false }
384+
guard let child = node.firstChild(viewMode: viewMode) else { return false }
384385
parents.append(node)
385386
node = child
386387
return true
@@ -391,7 +392,7 @@ fileprivate struct SyntaxCursor {
391392
/// - Returns: False if it run out of nodes to walk to.
392393
mutating func advanceToNextSibling() -> Bool {
393394
while !parents.isEmpty {
394-
if let sibling = node.nextSibling(parent: parents.last!) {
395+
if let sibling = node.nextSibling(parent: parents.last!, viewMode: viewMode) {
395396
node = sibling
396397
return true
397398
}

Sources/SwiftSyntax/RawSyntax.swift

Lines changed: 12 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -993,18 +993,8 @@ final class RawSyntax: ManagedBuffer<RawSyntaxBase, RawSyntaxDataElement> {
993993
return header.totalNodes
994994
}
995995

996-
/// Whether this node is present in the original source.
997-
var isPresent: Bool {
998-
return header.isPresent
999-
}
1000-
1001-
/// Whether this node is missing from the original source.
1002-
var isMissing: Bool {
1003-
return !isPresent
1004-
}
1005-
1006996
var presence: SourcePresence {
1007-
return isPresent ? .present : .missing
997+
return header.isPresent ? .present : .missing
1008998
}
1009999

10101000
var totalLength: SourceLength {
@@ -1247,7 +1237,7 @@ extension RawSyntax: TextOutputStreamable, CustomStringConvertible {
12471237
/// - Parameter stream: The stream on which to output this node.
12481238
func write<Target>(to target: inout Target)
12491239
where Target: TextOutputStream {
1250-
guard isPresent else { return }
1240+
guard SyntaxTreeViewMode.sourceAccurate.shouldTraverse(node: self) else { return }
12511241
if isToken {
12521242
withUnsafeMutablePointers {
12531243
$0.pointee.writeToken(to: &target, extraPtr: $1)
@@ -1269,48 +1259,48 @@ extension RawSyntax: TextOutputStreamable, CustomStringConvertible {
12691259

12701260
extension RawSyntax {
12711261
/// Return the first `present` token of a layout node or self if it is a token.
1272-
var firstPresentToken: RawSyntax? {
1273-
guard isPresent else { return nil }
1262+
func firstToken(viewMode: SyntaxTreeViewMode) -> RawSyntax? {
1263+
guard viewMode.shouldTraverse(node: self) else { return nil }
12741264
if isToken { return self }
12751265
for i in 0..<self.numberOfChildren {
1276-
if let token = self.child(at: i)?.firstPresentToken {
1266+
if let token = self.child(at: i)?.firstToken(viewMode: viewMode) {
12771267
return token
12781268
}
12791269
}
12801270
return nil
12811271
}
12821272

12831273
/// Return the last `present` token of a layout node or self if it is a token.
1284-
var lastPresentToken: RawSyntax? {
1285-
guard isPresent else { return nil }
1274+
func lastToken(viewMode: SyntaxTreeViewMode) -> RawSyntax? {
1275+
guard viewMode.shouldTraverse(node: self) else { return nil }
12861276
if isToken { return self }
12871277
for i in (0..<self.numberOfChildren).reversed() {
1288-
if let token = self.child(at: i)?.lastPresentToken {
1278+
if let token = self.child(at: i)?.lastToken(viewMode: viewMode) {
12891279
return token
12901280
}
12911281
}
12921282
return nil
12931283
}
12941284

12951285
func formLeadingTrivia() -> Trivia? {
1296-
guard let token = self.firstPresentToken else { return nil }
1286+
guard let token = self.firstToken(viewMode: .sourceAccurate) else { return nil }
12971287
return token.formTokenLeadingTrivia()
12981288
}
12991289

13001290
func formTrailingTrivia() -> Trivia? {
1301-
guard let token = self.lastPresentToken else { return nil }
1291+
guard let token = self.lastToken(viewMode: .sourceAccurate) else { return nil }
13021292
return token.formTokenTrailingTrivia()
13031293
}
13041294
}
13051295

13061296
extension RawSyntax {
13071297
var leadingTriviaLength: SourceLength {
1308-
guard let token = self.firstPresentToken else { return .zero }
1298+
guard let token = self.firstToken(viewMode: .sourceAccurate) else { return .zero }
13091299
return token.tokenLeadingTriviaLength
13101300
}
13111301

13121302
var trailingTriviaLength: SourceLength {
1313-
guard let token = self.lastPresentToken else { return .zero }
1303+
guard let token = self.lastToken(viewMode: .sourceAccurate) else { return .zero }
13141304
return token.tokenTrailingTriviaLength
13151305
}
13161306

Sources/SwiftSyntax/SourceLocation.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -346,7 +346,7 @@ fileprivate func computeLines(
346346
lines.append(position)
347347
}
348348
var curPrefix: SourceLength = .zero
349-
for token in tree.tokens {
349+
for token in tree.tokens(viewMode: .sourceAccurate) {
350350
curPrefix = token.forEachLineLength(prefix: curPrefix, body: addLine)
351351
}
352352
position += curPrefix

Sources/SwiftSyntax/Syntax.swift

Lines changed: 70 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -135,9 +135,14 @@ internal extension SyntaxProtocol {
135135
}
136136

137137
public extension SyntaxProtocol {
138-
/// A sequence over the `present` children of this node.
138+
@available(*, deprecated, message: "Use children(viewMode:) instead")
139139
var children: SyntaxChildren {
140-
return SyntaxChildren(_syntaxNode)
140+
return children(viewMode: .sourceAccurate)
141+
}
142+
143+
/// A sequence over the `present` children of this node.
144+
func children(viewMode: SyntaxTreeViewMode) -> SyntaxChildren {
145+
return SyntaxChildren(_syntaxNode, viewMode: viewMode)
141146
}
142147

143148
/// The index of this node in a `SyntaxChildren` collection.
@@ -147,12 +152,12 @@ public extension SyntaxProtocol {
147152

148153
/// Whether or not this node is marked as `present`.
149154
var isPresent: Bool {
150-
return raw.isPresent
155+
return raw.presence == .present
151156
}
152157

153158
/// Whether or not this node is marked as `missing`.
154159
var isMissing: Bool {
155-
return raw.isMissing
160+
return raw.presence == .missing
156161
}
157162

158163
/// Whether or not this node is a token one.
@@ -191,45 +196,63 @@ public extension SyntaxProtocol {
191196
/// Recursively walks through the tree to find the token semantically before
192197
/// this node.
193198
var previousToken: TokenSyntax? {
199+
return self.previousToken(viewMode: .sourceAccurate)
200+
}
201+
202+
/// Recursively walks through the tree to find the token semantically before
203+
/// this node.
204+
func previousToken(viewMode: SyntaxTreeViewMode) -> TokenSyntax? {
194205
guard let parent = self.parent else {
195206
return nil
196207
}
197-
let siblings = PresentRawSyntaxChildren(parent)
208+
let siblings = NonNilRawSyntaxChildren(parent, viewMode: viewMode)
198209
for absoluteRaw in siblings[..<self.index].reversed() {
199210
let child = Syntax(SyntaxData(absoluteRaw, parent: parent))
200-
if let token = child.lastToken {
211+
if let token = child.lastToken(viewMode: viewMode) {
201212
return token
202213
}
203214
}
204-
return parent.previousToken
215+
return parent.previousToken(viewMode: viewMode)
205216
}
206217

207218
/// Recursively walks through the tree to find the next token semantically
208219
/// after this node.
209220
var nextToken: TokenSyntax? {
221+
return self.nextToken(viewMode: .sourceAccurate)
222+
}
223+
224+
/// Recursively walks through the tree to find the next token semantically
225+
/// after this node.
226+
func nextToken(viewMode: SyntaxTreeViewMode) -> TokenSyntax? {
210227
guard let parent = self.parent else {
211228
return nil
212229
}
213-
let siblings = PresentRawSyntaxChildren(parent)
230+
let siblings = NonNilRawSyntaxChildren(parent, viewMode: viewMode)
214231
let nextSiblingIndex = siblings.index(after: self.index)
215232
for absoluteRaw in siblings[nextSiblingIndex...] {
216233
let child = Syntax(SyntaxData(absoluteRaw, parent: parent))
217-
if let token = child.firstToken {
234+
if let token = child.firstToken(viewMode: viewMode) {
218235
return token
219236
}
220237
}
221-
return parent.nextToken
238+
return parent.nextToken(viewMode: viewMode)
222239
}
223240

224-
/// Returns the first token node that is part of this syntax node.
241+
/// Returns the first token in this syntax node in the source accurate view of
242+
/// the syntax tree.
225243
var firstToken: TokenSyntax? {
226-
if isMissing { return nil }
244+
return self.firstToken(viewMode: .sourceAccurate)
245+
}
246+
247+
/// Returns the first token node that is part of this syntax node.
248+
func firstToken(viewMode: SyntaxTreeViewMode) -> TokenSyntax? {
249+
guard viewMode.shouldTraverse(node: raw) else { return nil }
227250
if let token = _syntaxNode.as(TokenSyntax.self) {
228251
return token
229252
}
230253

231-
for child in children {
232-
if let token = child.firstToken {
254+
for child in children(viewMode: viewMode) {
255+
if let token = child.firstToken(viewMode: viewMode) {
233256
return token
234257
}
235258
}
@@ -238,13 +261,18 @@ public extension SyntaxProtocol {
238261

239262
/// Returns the last token node that is part of this syntax node.
240263
var lastToken: TokenSyntax? {
241-
if isMissing { return nil }
264+
return self.lastToken(viewMode: .sourceAccurate)
265+
}
266+
267+
/// Returns the last token node that is part of this syntax node.
268+
func lastToken(viewMode: SyntaxTreeViewMode) -> TokenSyntax? {
269+
guard viewMode.shouldTraverse(node: raw) else { return nil }
242270
if let token = _syntaxNode.as(TokenSyntax.self) {
243271
return token
244272
}
245273

246-
for child in children.reversed() {
247-
if let tok = child.lastToken {
274+
for child in children(viewMode: viewMode).reversed() {
275+
if let tok = child.lastToken(viewMode: viewMode) {
248276
return tok
249277
}
250278
}
@@ -377,8 +405,14 @@ public extension SyntaxProtocol {
377405
}
378406

379407
/// Sequence of tokens that are part of this Syntax node.
408+
@available(*, deprecated, message: "Use tokens(viewMode:) instead")
380409
var tokens: TokenSequence {
381-
return TokenSequence(_syntaxNode)
410+
return tokens(viewMode: .sourceAccurate)
411+
}
412+
413+
/// Sequence of tokens that are part of this Syntax node.
414+
func tokens(viewMode: SyntaxTreeViewMode) -> TokenSequence {
415+
return TokenSequence(_syntaxNode, viewMode: viewMode)
382416
}
383417

384418
/// Sequence of `SyntaxClassifiedRange`s for this syntax node.
@@ -466,15 +500,17 @@ public struct TokenSequence: Sequence {
466500
public struct Iterator: IteratorProtocol {
467501
var nextToken: TokenSyntax?
468502
let endPosition: AbsolutePosition
503+
let viewMode: SyntaxTreeViewMode
469504

470-
init(_ token: TokenSyntax?, endPosition: AbsolutePosition) {
505+
init(_ token: TokenSyntax?, endPosition: AbsolutePosition, viewMode: SyntaxTreeViewMode) {
471506
self.nextToken = token
472507
self.endPosition = endPosition
508+
self.viewMode = viewMode
473509
}
474510

475511
public mutating func next() -> TokenSyntax? {
476512
guard let token = self.nextToken else { return nil }
477-
self.nextToken = token.nextToken
513+
self.nextToken = token.nextToken(viewMode: viewMode)
478514
// Make sure we stop once we reach the end of the containing node.
479515
if let nextTok = self.nextToken, nextTok.position >= self.endPosition {
480516
self.nextToken = nil
@@ -484,17 +520,19 @@ public struct TokenSequence: Sequence {
484520
}
485521

486522
let node: Syntax
523+
let viewMode: SyntaxTreeViewMode
487524

488-
public init(_ node: Syntax) {
525+
public init(_ node: Syntax, viewMode: SyntaxTreeViewMode) {
489526
self.node = node
527+
self.viewMode = viewMode
490528
}
491529

492530
public func makeIterator() -> Iterator {
493-
return Iterator(node.firstToken, endPosition: node.endPosition)
531+
return Iterator(node.firstToken(viewMode: viewMode), endPosition: node.endPosition, viewMode: viewMode)
494532
}
495533

496534
public func reversed() -> ReversedTokenSequence {
497-
return ReversedTokenSequence(node)
535+
return ReversedTokenSequence(node, viewMode: viewMode)
498536
}
499537
}
500538

@@ -509,15 +547,17 @@ public struct ReversedTokenSequence: Sequence {
509547
public struct Iterator: IteratorProtocol {
510548
var nextToken: TokenSyntax?
511549
let startPosition: AbsolutePosition
550+
let viewMode: SyntaxTreeViewMode
512551

513-
init(_ token: TokenSyntax?, startPosition: AbsolutePosition) {
552+
init(_ token: TokenSyntax?, startPosition: AbsolutePosition, viewMode: SyntaxTreeViewMode) {
514553
self.nextToken = token
515554
self.startPosition = startPosition
555+
self.viewMode = viewMode
516556
}
517557

518558
public mutating func next() -> TokenSyntax? {
519559
guard let token = self.nextToken else { return nil }
520-
self.nextToken = token.previousToken
560+
self.nextToken = token.previousToken(viewMode: viewMode)
521561
// Make sure we stop once we went beyond the start of the containing node.
522562
if let nextTok = self.nextToken, nextTok.position < self.startPosition {
523563
self.nextToken = nil
@@ -527,17 +567,19 @@ public struct ReversedTokenSequence: Sequence {
527567
}
528568

529569
let node: Syntax
570+
let viewMode: SyntaxTreeViewMode
530571

531-
public init(_ node: Syntax) {
572+
public init(_ node: Syntax, viewMode: SyntaxTreeViewMode) {
532573
self.node = node
574+
self.viewMode = viewMode
533575
}
534576

535577
public func makeIterator() -> Iterator {
536-
return Iterator(node.lastToken, startPosition: node.position)
578+
return Iterator(node.lastToken(viewMode: viewMode), startPosition: node.position, viewMode: viewMode)
537579
}
538580

539581
public func reversed() -> TokenSequence {
540-
return TokenSequence(node)
582+
return TokenSequence(node, viewMode: viewMode)
541583
}
542584
}
543585

0 commit comments

Comments
 (0)