Skip to content

Store the replacement string in IncrementalEdit #2527

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
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
12 changes: 8 additions & 4 deletions Release Notes/600.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
# Swift Syntax 600 Release Notes

## New APIs
- FixIt now has a new computed propery named edits
- Description: the edits represent the non-overlapping textual edits that need to be performed when the Fix-It is applied.
- FixIt now has a new computed property named `edits`
- Description: the `edits` represent the non-overlapping textual `edits` that need to be performed when the Fix-It is applied.
- Issue: https://github.com/apple/sourcekit-lsp/issues/909
- Pull Request: https://github.com/apple/swift-syntax/pull/2314

- SourceEdit
- Description: SourceEdit has been moved from SwiftRefactor to SwiftSyntax
- `SourceEdit`
- Description: `SourceEdit` has been moved from SwiftRefactor to SwiftSyntax
- Issue: https://github.com/apple/sourcekit-lsp/issues/909
- Pull Request: https://github.com/apple/swift-syntax/pull/2314

Expand Down Expand Up @@ -58,6 +58,10 @@
- Description: Uses heuristics to infer the indentation width used in a syntax tree.
- Pull Request: https://github.com/apple/swift-syntax/pull/2514

- `IncrementalEdit` stores replacement text
- Description: `IncrementalEdit` used to store the range that was replaced and the length of the replacement but not the replacement bytes by itself. `IncrementalEdit` now has a `replacement` property that contains the replacement bytes.
- Pull Request: https://github.com/apple/swift-syntax/pull/2527

## API Behavior Changes

## Deprecations
Expand Down
9 changes: 7 additions & 2 deletions Sources/SwiftParser/IncrementalParseTransition.swift
Original file line number Diff line number Diff line change
Expand Up @@ -347,17 +347,22 @@ public struct ConcurrentEdits: Sendable {
if existingEdit.replacementRange.intersectsOrTouches(editToAdd.range) {
let intersectionLength =
existingEdit.replacementRange.intersected(editToAdd.range).length
let replacement: [UInt8]
replacement =
existingEdit.replacement.prefix(max(0, editToAdd.offset - existingEdit.replacementRange.offset))
+ editToAdd.replacement
+ existingEdit.replacement.suffix(max(0, existingEdit.replacementRange.endOffset - editToAdd.endOffset))
editToAdd = IncrementalEdit(
offset: Swift.min(existingEdit.offset, editToAdd.offset),
length: existingEdit.length + editToAdd.length - intersectionLength,
replacementLength: existingEdit.replacementLength + editToAdd.replacementLength - intersectionLength
replacement: replacement
)
editIndicesMergedWithNewEdit.append(index)
} else if existingEdit.offset < editToAdd.endOffset {
editToAdd = IncrementalEdit(
offset: editToAdd.offset - existingEdit.replacementLength + existingEdit.length,
length: editToAdd.length,
replacementLength: editToAdd.replacementLength
replacement: editToAdd.replacement
)
}
}
Expand Down
21 changes: 18 additions & 3 deletions Sources/SwiftSyntax/Utils.swift
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,12 @@ public struct ByteSourceRange: Equatable, Sendable {
public struct IncrementalEdit: Equatable, Sendable {
/// The byte range of the original source buffer that the edit applies to.
public let range: ByteSourceRange

/// The UTF-8 bytes that should be inserted as part of the edit
public let replacement: [UInt8]

/// The length of the edit replacement in UTF8 bytes.
public let replacementLength: Int
public var replacementLength: Int { replacement.count }

public var offset: Int { return range.offset }

Expand All @@ -64,14 +68,25 @@ public struct IncrementalEdit: Equatable, Sendable {
return ByteSourceRange(offset: offset, length: replacementLength)
}

@available(*, deprecated, message: "Use IncrementalEdit(range:replacement:) instead")
public init(range: ByteSourceRange, replacementLength: Int) {
self.range = range
self.replacementLength = replacementLength
self.replacement = Array(repeating: UInt8(ascii: " "), count: replacementLength)
}

@available(*, deprecated, message: "Use IncrementalEdit(offset:length:replacement:) instead")
public init(offset: Int, length: Int, replacementLength: Int) {
self.range = ByteSourceRange(offset: offset, length: length)
self.replacementLength = replacementLength
self.replacement = Array(repeating: UInt8(ascii: " "), count: replacementLength)
}

public init(offset: Int, length: Int, replacement: [UInt8]) {
self.range = ByteSourceRange(offset: offset, length: length)
self.replacement = replacement
}

public init(offset: Int, length: Int, replacement: String) {
self.init(offset: offset, length: length, replacement: Array(replacement.utf8))
}

public func intersectsOrTouchesRange(_ other: ByteSourceRange) -> Bool {
Expand Down
13 changes: 3 additions & 10 deletions Sources/_SwiftSyntaxTestSupport/IncrementalParseTestUtils.swift
Original file line number Diff line number Diff line change
Expand Up @@ -182,10 +182,7 @@ public func extractEditsAndSources(from source: String) -> (edits: ConcurrentEdi
from: source.index(after: startIndex),
to: separateIndex
),
replacementLength: source.utf8.distance(
from: source.index(after: separateIndex),
to: endIndex
)
replacement: Array(source.utf8[source.index(after: separateIndex)..<endIndex])
)
originalSource += source[source.index(after: startIndex)..<separateIndex]

Expand Down Expand Up @@ -213,12 +210,8 @@ public func extractEditsAndSources(from source: String) -> (edits: ConcurrentEdi
public func applyEdits(
_ edits: [IncrementalEdit],
concurrent: Bool,
to testString: String,
replacementChar: Character = "?"
to testString: String
) -> String {
guard let replacementAscii = replacementChar.asciiValue else {
fatalError("replacementChar must be an ASCII character")
}
var edits = edits
if concurrent {
XCTAssert(ConcurrentEdits._isValidConcurrentEditArray(edits))
Expand All @@ -232,7 +225,7 @@ public func applyEdits(
for edit in edits {
assert(edit.endOffset <= bytes.count)
bytes.removeSubrange(edit.offset..<edit.endOffset)
bytes.insert(contentsOf: [UInt8](repeating: replacementAscii, count: edit.replacementLength), at: edit.offset)
bytes.insert(contentsOf: edit.replacement, at: edit.offset)
}
return String(bytes: bytes, encoding: .utf8)!
}
Loading