Skip to content

Commit 5e10466

Browse files
authored
Merge pull request #110 from akyrtzi/fix-contextual-classification-subnode
[classification] Make sure to inherit the contextual classification for classifications of sub-nodes
2 parents c49eb29 + 5854539 commit 5e10466

File tree

2 files changed

+62
-19
lines changed

2 files changed

+62
-19
lines changed

Sources/SwiftSyntax/SyntaxClassifier.swift

Lines changed: 56 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -10,18 +10,24 @@
1010
//
1111
//===----------------------------------------------------------------------===//
1212

13-
extension TokenSyntax {
14-
/// The `SyntaxClassifiedRange` for the token text, excluding trivia.
15-
public var tokenClassification: SyntaxClassifiedRange {
16-
var contextualClassification: (SyntaxClassification, Bool)? = nil
17-
var curData = self.data
13+
extension SyntaxData {
14+
var contextualClassification: (SyntaxClassification, Bool)? {
15+
var contextualClassif: (SyntaxClassification, Bool)? = nil
16+
var curData = self
1817
repeat {
1918
guard let parent = curData.parent else { break }
20-
contextualClassification = SyntaxClassification.classify(parentKind: parent.raw.kind,
19+
contextualClassif = SyntaxClassification.classify(parentKind: parent.raw.kind,
2120
indexInParent: curData.indexInParent, childKind: raw.kind)
2221
curData = parent.data
23-
} while contextualClassification == nil
22+
} while contextualClassif == nil
23+
return contextualClassif
24+
}
25+
}
2426

27+
extension TokenSyntax {
28+
/// The `SyntaxClassifiedRange` for the token text, excluding trivia.
29+
public var tokenClassification: SyntaxClassifiedRange {
30+
let contextualClassification = self.data.contextualClassification
2531
let relativeOffset = raw.tokenLeadingTriviaLength.utf8Length
2632
let absoluteOffset = position.utf8Offset + relativeOffset
2733
let classifiedRange = raw.withUnsafeTokenText(
@@ -85,10 +91,14 @@ fileprivate struct AbsoluteNode {
8591
let classification: (SyntaxClassification, Bool)?
8692

8793
/// Use this constructor for the root node.
88-
init(raw: RawSyntax, position: AbsoluteSyntaxPosition) {
94+
init(
95+
raw: RawSyntax,
96+
position: AbsoluteSyntaxPosition,
97+
contextualClassification: (SyntaxClassification, Bool)?
98+
) {
8999
self.raw = raw
90100
self.position = position
91-
self.classification = nil
101+
self.classification = contextualClassification
92102
}
93103

94104
init(raw: RawSyntax, position: AbsoluteSyntaxPosition, parent: AbsoluteNode) {
@@ -137,10 +147,16 @@ fileprivate struct SyntaxCursor {
137147
let absRange: ByteSourceRange
138148
var finished: Bool
139149

140-
init(root: RawSyntax, offset: Int, in absRange: ByteSourceRange) {
150+
init(
151+
root: RawSyntax,
152+
offset: Int,
153+
in absRange: ByteSourceRange,
154+
contextualClassification: (SyntaxClassification, Bool)?
155+
) {
141156
self.absRange = absRange
142157
self.node = AbsoluteNode(raw: root,
143-
position: .init(offset: UInt32(truncatingIfNeeded: offset), indexInParent: 0))
158+
position: .init(offset: UInt32(truncatingIfNeeded: offset), indexInParent: 0),
159+
contextualClassification: contextualClassification)
144160
self.parents = []
145161
self.finished = false
146162
}
@@ -214,8 +230,14 @@ fileprivate struct FastTokenSequence: Sequence {
214230
struct Iterator: IteratorProtocol {
215231
var cursor: SyntaxCursor
216232

217-
init(root: RawSyntax, offset: Int, in absRange: ByteSourceRange) {
218-
self.cursor = SyntaxCursor(root: root, offset: offset, in: absRange)
233+
init(
234+
root: RawSyntax,
235+
offset: Int,
236+
in absRange: ByteSourceRange,
237+
contextualClassification: (SyntaxClassification, Bool)?
238+
) {
239+
self.cursor = SyntaxCursor(root: root, offset: offset, in: absRange,
240+
contextualClassification: contextualClassification)
219241
_ = self.cursor.advanceToFirstToken()
220242
}
221243

@@ -231,15 +253,23 @@ fileprivate struct FastTokenSequence: Sequence {
231253
private let root: RawSyntax
232254
private let offset: Int
233255
private let absRange: ByteSourceRange
234-
235-
init(_ root: RawSyntax, offset: Int, in absRange: ByteSourceRange) {
256+
private let contextualClassification: (SyntaxClassification, Bool)?
257+
258+
init(
259+
_ root: RawSyntax,
260+
offset: Int,
261+
in absRange: ByteSourceRange,
262+
contextualClassification: (SyntaxClassification, Bool)?
263+
) {
236264
self.root = root
237265
self.offset = offset
238266
self.absRange = absRange
267+
self.contextualClassification = contextualClassification
239268
}
240269

241270
func makeIterator() -> Iterator {
242-
return .init(root: root, offset: offset, in: absRange)
271+
return .init(root: root, offset: offset, in: absRange,
272+
contextualClassification: contextualClassification)
243273
}
244274
}
245275

@@ -335,9 +365,15 @@ public struct SyntaxClassifications: Sequence {
335365
fileprivate var curOffset: Int
336366
fileprivate var curTokenEndOffset: Int
337367

338-
init(root: RawSyntax, offset: Int, in absRange: ByteSourceRange) {
368+
init(
369+
root: RawSyntax,
370+
offset: Int,
371+
in absRange: ByteSourceRange,
372+
contextualClassification: (SyntaxClassification, Bool)?
373+
) {
339374
self.absRange = absRange
340-
self.tokenIterator = .init(root: root, offset: offset, in: absRange)
375+
self.tokenIterator = .init(root: root, offset: offset, in: absRange,
376+
contextualClassification: contextualClassification)
341377
self.pendingClassifiedRange = .init(kind: .none,
342378
range: ByteSourceRange(offset: absRange.offset, length: 0))
343379
self.curOffset = absRange.offset
@@ -431,6 +467,7 @@ public struct SyntaxClassifications: Sequence {
431467
let nodeOffset = node.position.utf8Offset
432468
let absRange = ByteSourceRange(offset: nodeOffset + relRange.offset,
433469
length: relRange.length)
434-
return .init(root: node.raw, offset: nodeOffset, in: absRange)
470+
return .init(root: node.raw, offset: nodeOffset, in: absRange,
471+
contextualClassification: node.data.contextualClassification)
435472
}
436473
}

Tests/SwiftSyntaxTest/ClassificationTests.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,5 +113,11 @@ public class ClassificationTests: XCTestCase {
113113
XCTAssertEqual(classif[3].kind, .typeIdentifier)
114114
XCTAssertEqual(classif[3].range, ByteSourceRange(offset: 7, length: 3))
115115
}
116+
do {
117+
let tok = tree.lastToken!.previousToken!
118+
XCTAssertEqual("\(tok)", "Int")
119+
let classif = Array(tok.classifications).first!
120+
XCTAssertEqual(classif.kind, .typeIdentifier)
121+
}
116122
}
117123
}

0 commit comments

Comments
 (0)