Skip to content

Commit e896274

Browse files
committed
Remove SyntaxProtocol.index in favor of index(of:) methods in SyntaxCollection and SyntaxChildren
Make `SyntaxProtocol.index` internal and `index(of:)` call the internal `index` method + validate that the node is actually in the collection (otherwise return `nil`). rdar://111944622
1 parent e990c2a commit e896274

File tree

7 files changed

+67
-12
lines changed

7 files changed

+67
-12
lines changed

Sources/SwiftParser/IncrementalParseTransition.swift

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -213,8 +213,10 @@ fileprivate struct SyntaxCursor {
213213
var node = self.node
214214
while let parent = node.parent {
215215
let children = parent.children(viewMode: viewMode)
216-
if children.index(after: node.index) != children.endIndex {
217-
return children[children.index(after: node.index)]
216+
if let nodeIndex = children.index(of: node),
217+
children.index(after: nodeIndex) != children.endIndex
218+
{
219+
return children[children.index(after: nodeIndex)]
218220
}
219221
node = parent
220222
}

Sources/SwiftParserDiagnostics/MissingNodesError.swift

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -269,7 +269,8 @@ public struct MissingNodesError: ParserError {
269269
if let missingExpr,
270270
let exprList = missingExpr.parent?.as(ExprListSyntax.self),
271271
exprList.parent?.is(SequenceExprSyntax.self) ?? false,
272-
let previousSiblingIndex = exprList.index(missingExpr.index, offsetBy: -1, limitedBy: exprList.startIndex)
272+
let missingExprIndex = exprList.index(of: missingExpr),
273+
let previousSiblingIndex = exprList.index(missingExprIndex, offsetBy: -1, limitedBy: exprList.startIndex)
273274
{
274275
let previousSibling = exprList[previousSiblingIndex]
275276
if let previousSiblingName = previousSibling.nodeTypeNameForDiagnostics(allowBlockNames: false) {
@@ -359,17 +360,17 @@ extension ParseDiagnosticsGenerator {
359360
/// Ancestors that don't contain any tokens are not very interesting to merge diagnostics (because there can't be any missing tokens we can merge them with).
360361
/// Find the first ancestor that contains any tokens.
361362
var ancestorWithMoreTokens = node.parent
362-
var index = node.index
363+
var index = ancestorWithMoreTokens?.children(viewMode: .all).index(of: node)
363364
let nodeTokens = Array(node.tokens(viewMode: .all))
364365
while let unwrappedParent = ancestorWithMoreTokens, Array(unwrappedParent.tokens(viewMode: .all)) == nodeTokens {
365366
ancestorWithMoreTokens = unwrappedParent.parent
366-
index = unwrappedParent.index
367+
index = ancestorWithMoreTokens?.children(viewMode: .all).index(of: unwrappedParent)
367368
}
368369

369370
// Walk all upcoming sibling to see if they are also missing to handle them in this diagnostic.
370371
// If this is the case, handle all of them in this diagnostic.
371372
var missingNodes = [Syntax(node)]
372-
if let parentWithTokens = ancestorWithMoreTokens {
373+
if let parentWithTokens = ancestorWithMoreTokens, let index {
373374
let siblings = parentWithTokens.children(viewMode: .all)
374375
let siblingsAfter = siblings[siblings.index(after: index)...]
375376
for sibling in siblingsAfter {

Sources/SwiftParserDiagnostics/ParseDiagnosticsGenerator.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1818,7 +1818,8 @@ public class ParseDiagnosticsGenerator: SyntaxAnyVisitor {
18181818
}
18191819
if node.colon.isMissing {
18201820
if let siblings = node.parent?.children(viewMode: .all),
1821-
let nextSibling = siblings[siblings.index(after: node.index)...].first,
1821+
let nodeIndex = siblings.index(of: node),
1822+
let nextSibling = siblings[siblings.index(after: nodeIndex)...].first,
18221823
nextSibling.is(MissingExprSyntax.self)
18231824
{
18241825
addDiagnostic(

Sources/SwiftSyntax/CommonAncestor.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ public func findCommonAncestorOrSelf(_ lhs: Syntax, _ rhs: Syntax) -> Syntax? {
1818
if lhs == rhs {
1919
return lhs
2020
}
21-
if let lhsIndex = lhs?.index.data?.indexInTree, let rhsIndex = rhs?.index.data?.indexInTree {
21+
if let lhsIndex = lhs?.indexInParent.data?.indexInTree, let rhsIndex = rhs?.indexInParent.data?.indexInTree {
2222
if lhsIndex < rhsIndex {
2323
rhs = rhs?.parent
2424
} else {

Sources/SwiftSyntax/Syntax.swift

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,13 @@ public extension SyntaxProtocol {
258258
}
259259

260260
/// The index of this node in a ``SyntaxChildren`` collection.
261+
@available(*, deprecated, message: "Use index(of:) on the collection that contains this node")
261262
var index: SyntaxChildrenIndex {
263+
return indexInParent
264+
}
265+
266+
/// The index of this node in a ``SyntaxChildren`` collection.
267+
internal var indexInParent: SyntaxChildrenIndex {
262268
return SyntaxChildrenIndex(self.data.absoluteInfo)
263269
}
264270

@@ -319,8 +325,8 @@ public extension SyntaxProtocol {
319325
let siblings = NonNilRawSyntaxChildren(parent, viewMode: viewMode)
320326
// `self` could be a missing node at index 0 and `viewMode` be `.sourceAccurate`.
321327
// In that case `siblings` skips over the missing `self` node and has a `startIndex > 0`.
322-
if self.index >= siblings.startIndex {
323-
for absoluteRaw in siblings[..<self.index].reversed() {
328+
if self.indexInParent >= siblings.startIndex {
329+
for absoluteRaw in siblings[..<self.indexInParent].reversed() {
324330
let child = Syntax(SyntaxData(absoluteRaw, parent: parent))
325331
if let token = child.lastToken(viewMode: viewMode) {
326332
return token
@@ -342,7 +348,7 @@ public extension SyntaxProtocol {
342348
return nil
343349
}
344350
let siblings = NonNilRawSyntaxChildren(parent, viewMode: viewMode)
345-
let nextSiblingIndex = siblings.index(after: self.index)
351+
let nextSiblingIndex = siblings.index(after: self.indexInParent)
346352
for absoluteRaw in siblings[nextSiblingIndex...] {
347353
let child = Syntax(SyntaxData(absoluteRaw, parent: parent))
348354
if let token = child.firstToken(viewMode: viewMode) {

Sources/SwiftSyntax/SyntaxChildren.swift

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -455,4 +455,25 @@ public struct SyntaxChildren: BidirectionalCollection {
455455
self.rawChildren = NonNilRawSyntaxChildren(node, viewMode: viewMode)
456456
self.parent = node
457457
}
458+
459+
/// Return the index of `node` within this collection.
460+
///
461+
/// If `node` is not part of this collection, returns `nil`.
462+
public func index(of node: some SyntaxProtocol) -> SyntaxChildrenIndex? {
463+
return index(of: Syntax(node))
464+
}
465+
466+
/// Return the index of `node` within this collection.
467+
///
468+
/// If `node` is not part of this collection, returns `nil`.
469+
///
470+
/// - Note: This method is functionally equivalent to the one that takes
471+
/// ``SyntaxProtocol``. It is provided because otherwise `Collection.index(of:)`
472+
/// is chosen, which is marked as deprecated and renamed to `firstIndex(of:)`.
473+
public func index(of node: Syntax) -> SyntaxChildrenIndex? {
474+
guard node.parent == parent else {
475+
return nil
476+
}
477+
return node.indexInParent
478+
}
458479
}

Sources/SwiftSyntax/SyntaxCollection.swift

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,30 @@ extension SyntaxCollection {
6565
return Syntax(newData).cast(Self.self)
6666
}
6767

68+
/// Return the index of `node` within this collection.
69+
///
70+
/// If `node` is not part of this collection, returns `nil`.
71+
public func index(of node: some SyntaxProtocol) -> SyntaxChildrenIndex? {
72+
guard let node = node as? Element else {
73+
return nil
74+
}
75+
return index(of: node)
76+
}
77+
78+
/// Return the index of `node` within this collection.
79+
///
80+
/// If `node` is not part of this collection, returns `nil`.
81+
///
82+
/// - Note: This method is functionally equivalent to the one that takes
83+
/// ``SyntaxProtocol``. It is provided because otherwise `Collection.index(of:)`
84+
/// is chosen, which is marked as deprecated and renamed to `firstIndex(of:)`.
85+
public func index(of node: Element) -> SyntaxChildrenIndex? {
86+
guard node.parent == Syntax(self) else {
87+
return nil
88+
}
89+
return node.indexInParent
90+
}
91+
6892
/// Creates a new collection by appending the provided syntax element
6993
/// to the children.
7094
///
@@ -232,7 +256,7 @@ extension SyntaxCollection {
232256
/// Make sure the index is a valid index for replacing
233257
precondition(
234258
(newLayout.startIndex..<newLayout.endIndex).contains(indexToReplace),
235-
"replacing node at invalid index \(index)"
259+
"replacing node at invalid index \(indexInParent)"
236260
)
237261
newLayout[indexToReplace] = newValue.raw
238262
self = replacingLayout(newLayout)

0 commit comments

Comments
 (0)