Skip to content

Add a function to get the SyntaxChildrenIndex of the n-th element in a SyntaxCollection #2014

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion Sources/SwiftSyntax/SyntaxChildren.swift
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,10 @@ struct RawSyntaxChildren: BidirectionalCollection {
}

func index(after index: SyntaxChildrenIndex) -> SyntaxChildrenIndex {
let node = parent.layoutView!.children[Int(index.data!.indexInParent)]
guard let indexData = index.data else {
preconditionFailure("Cannot get the index after the end index")
}
let node = parent.layoutView!.children[Int(indexData.indexInParent)]
return self.index(index, advancedBy: node)
}

Expand Down
22 changes: 22 additions & 0 deletions Sources/SwiftSyntax/SyntaxCollection.swift
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,28 @@ extension SyntaxCollection {
return node.indexInParent
}

/// Returns the index of the n-th element in this collection.
///
/// The behavior is undefined if `offset` is greater than the number of
/// elements in this collection.
///
/// - Complexity: O(`offset`) because all previous element need to be iterated
/// to find the byte offset of the `offset`-th node within the source file.
///
/// - Note: Because getting the `n`-th element in a ``SyntaxCollection`` is
/// not O(1), ``SyntaxCollection`` doesn’t provide a subscript to retrieve
/// the `n`-th element. Such a subscript would mask the complexity of
/// getting the `n`-th element.
public func index(at offset: Int) -> SyntaxChildrenIndex {
if offset > self.count / 2 {
// If we are closer to the end of the collection, it's more efficient to
// calculate the index starting from the back.
return self.index(self.endIndex, offsetBy: -(self.count - offset))
} else {
return self.index(self.startIndex, offsetBy: offset)
}
}

/// Creates a new collection by appending the provided syntax element
/// to the children.
///
Expand Down

This file was deleted.

4 changes: 2 additions & 2 deletions Tests/SwiftRefactorTest/ExpandEditorPlaceholdersTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ fileprivate func assertRefactorPlaceholderCall(
) throws {
var parser = Parser(expr)
let call = try XCTUnwrap(ExprSyntax.parse(from: &parser).as(FunctionCallExprSyntax.self), file: file, line: line)
let arg = try XCTUnwrap(call.arguments[placeholder].as(LabeledExprSyntax.self), file: file, line: line)
let arg = try XCTUnwrap(call.arguments[call.arguments.index(at: placeholder)].as(LabeledExprSyntax.self), file: file, line: line)
let token: TokenSyntax = try XCTUnwrap(arg.expression.as(EditorPlaceholderExprSyntax.self), file: file, line: line).placeholder

try assertRefactor(token, context: (), provider: ExpandEditorPlaceholders.self, expected: [SourceEdit.replace(call, with: expected)], file: file, line: line)
Expand All @@ -126,7 +126,7 @@ fileprivate func assertRefactorPlaceholderToken(
) throws {
var parser = Parser(expr)
let call = try XCTUnwrap(ExprSyntax.parse(from: &parser).as(FunctionCallExprSyntax.self), file: file, line: line)
let arg = try XCTUnwrap(call.arguments[placeholder].as(LabeledExprSyntax.self), file: file, line: line)
let arg = try XCTUnwrap(call.arguments[call.arguments.index(at: placeholder)].as(LabeledExprSyntax.self), file: file, line: line)
let token: TokenSyntax = try XCTUnwrap(arg.expression.as(EditorPlaceholderExprSyntax.self), file: file, line: line).placeholder

try assertRefactor(token, context: (), provider: ExpandEditorPlaceholders.self, expected: [SourceEdit.replace(token, with: expected)], file: file, line: line)
Expand Down
4 changes: 2 additions & 2 deletions Tests/SwiftSyntaxMacroExpansionTest/MacroSystemTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ public struct ErrorMacro: DeclarationMacro {
let stringLiteral = firstElement.expression
.as(StringLiteralExprSyntax.self),
stringLiteral.segments.count == 1,
case let .stringSegment(messageString) = stringLiteral.segments[0]
case let .stringSegment(messageString) = stringLiteral.segments.first
else {
throw CustomError.message("#error macro requires a string literal")
}
Expand Down Expand Up @@ -195,7 +195,7 @@ struct DefineBitwidthNumberedStructsMacro: DeclarationMacro {
let stringLiteral = firstElement.expression
.as(StringLiteralExprSyntax.self),
stringLiteral.segments.count == 1,
case let .stringSegment(prefix) = stringLiteral.segments[0]
case let .stringSegment(prefix) = stringLiteral.segments.first
else {
throw CustomError.message(
"#bitwidthNumberedStructs macro requires a string literal"
Expand Down
11 changes: 6 additions & 5 deletions Tests/SwiftSyntaxTest/AbsolutePositionTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,10 @@ public class AbsolutePositionTests: XCTestCase {
statements: CodeBlockItemListSyntax(l),
endOfFileToken: .endOfFileToken()
)
_ = root.statements[idx].position
_ = root.statements[idx].totalLength.utf8Length
_ = root.statements[idx].positionAfterSkippingLeadingTrivia
let statements = root.statements
_ = statements[statements.index(at: idx)].position
_ = statements[statements.index(at: idx)].totalLength.utf8Length
_ = statements[statements.index(at: idx)].positionAfterSkippingLeadingTrivia
}

static let leadingTrivia = Trivia(pieces: [
Expand Down Expand Up @@ -76,7 +77,7 @@ public class AbsolutePositionTests: XCTestCase {
let root = self.createSourceFile(idx + 1)
XCTAssertEqual(3, root.leadingTrivia.count)
XCTAssertEqual(0, root.trailingTrivia.count)
let state = root.statements[idx]
let state = root.statements[root.statements.index(at: idx)]
XCTAssertEqual(3, state.leadingTrivia.count)
XCTAssertEqual(2, state.trailingTrivia.count)
XCTAssertEqual(
Expand Down Expand Up @@ -137,7 +138,7 @@ public class AbsolutePositionTests: XCTestCase {
let filePath = "/tmp/test.swift"
let root = self.createSourceFile(2)
let converter = SourceLocationConverter(fileName: filePath, tree: root)
let secondReturnStmt = root.statements[1]
let secondReturnStmt = root.statements[root.statements.index(at: 1)]
let startLoc = secondReturnStmt.startLocation(converter: converter)
XCTAssertEqual(startLoc.line, 8)
XCTAssertEqual(startLoc.column, 1)
Expand Down
12 changes: 6 additions & 6 deletions Tests/SwiftSyntaxTest/SyntaxCollectionsTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ public class SyntaxCollectionsTests: XCTestCase {
assertSyntaxCollectionManipulation(
initialElements: [0, 1, 2],
transformation: {
let index = $0.elements.index(after: $0.elements.startIndex)
let index = $0.elements.index(at: 1)
$0.elements.insert(intElement(5), at: index)
},
expectedElements: [0, 5, 1, 2]
Expand Down Expand Up @@ -119,7 +119,7 @@ public class SyntaxCollectionsTests: XCTestCase {
assertSyntaxCollectionManipulation(
initialElements: [0, 1, 2],
transformation: {
let index = $0.elements.index(after: $0.elements.startIndex)
let index = $0.elements.index(at: 1)
$0.elements.insert(contentsOf: [intElement(5), intElement(6)], at: index)
},
expectedElements: [0, 5, 6, 1, 2]
Expand Down Expand Up @@ -148,7 +148,7 @@ public class SyntaxCollectionsTests: XCTestCase {
assertSyntaxCollectionManipulation(
initialElements: [0, 1, 2],
transformation: {
let index = $0.elements.index(after: $0.elements.startIndex)
let index = $0.elements.index(at: 1)
$0.elements.remove(at: index)
},
expectedElements: [0, 2]
Expand All @@ -157,7 +157,7 @@ public class SyntaxCollectionsTests: XCTestCase {
assertSyntaxCollectionManipulation(
initialElements: [0, 1, 2],
transformation: {
let index = $0.elements.index($0.elements.startIndex, offsetBy: 2)
let index = $0.elements.index(at: 2)
$0.elements.remove(at: index)
},
expectedElements: [0, 1]
Expand All @@ -169,7 +169,7 @@ public class SyntaxCollectionsTests: XCTestCase {
initialElements: [0, 1, 2],
transformation: {
let startIndex = $0.elements.startIndex
let endIndex = $0.elements.index(after: $0.elements.startIndex)
let endIndex = $0.elements.index(at: 1)
$0.elements.removeSubrange(startIndex..<endIndex)
},
expectedElements: [1, 2]
Expand All @@ -179,7 +179,7 @@ public class SyntaxCollectionsTests: XCTestCase {
initialElements: [0, 1, 2],
transformation: {
let startIndex = $0.elements.startIndex
let endIndex = $0.elements.index($0.elements.startIndex, offsetBy: 2)
let endIndex = $0.elements.index(at: 2)
$0.elements.removeSubrange(startIndex..<endIndex)
},
expectedElements: [2]
Expand Down