Skip to content

Report codeActions for fixIts produced by swift syntax #941

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
57 changes: 39 additions & 18 deletions Sources/SourceKitLSP/Swift/Diagnostic.swift
Original file line number Diff line number Diff line change
Expand Up @@ -44,22 +44,10 @@ extension CodeAction {
if let fromNote = fromNote {
title = fromNote
} else {
guard let startIndex = snapshot.index(of: edits[0].range.lowerBound),
let endIndex = snapshot.index(of: edits[0].range.upperBound),
startIndex <= endIndex,
snapshot.text.indices.contains(startIndex),
endIndex <= snapshot.text.endIndex
else {
logger.fault("position mapped, but indices failed for edit range \(String(reflecting: edits[0]))")
guard let generatedTitle = Self.title(for: edits, in: snapshot) else {
return nil
}
let oldText = String(snapshot.text[startIndex..<endIndex])
let description = Self.fixitTitle(replace: oldText, with: edits[0].newText)
if edits.count == 1 {
title = description
} else {
title = description + "..."
}
title = generatedTitle
}

self.init(
Expand All @@ -71,10 +59,43 @@ extension CodeAction {
}

init?(_ fixIt: FixIt, in snapshot: DocumentSnapshot) {
// FIXME: Once https://github.com/apple/swift-syntax/pull/2226 is merged and
// FixItApplier is public, use it to compute the edits that should be
// applied to the source.
return nil
var textEdits = [TextEdit]()
for edit in fixIt.edits {
guard let startPosition = snapshot.position(of: edit.range.lowerBound),
let endPosition = snapshot.position(of: edit.range.upperBound)
else {
continue
}
textEdits.append(TextEdit(range: startPosition..<endPosition, newText: edit.replacement))
}

self.init(
title: fixIt.message.message.withFirstLetterUppercased(),
kind: .quickFix,
diagnostics: nil,
edit: WorkspaceEdit(changes: [snapshot.uri: textEdits])
)
}

private static func title(for edits: [TextEdit], in snapshot: DocumentSnapshot) -> String? {
if edits.isEmpty {
return nil
}
guard let startIndex = snapshot.index(of: edits[0].range.lowerBound),
let endIndex = snapshot.index(of: edits[0].range.upperBound),
startIndex <= endIndex,
snapshot.text.indices.contains(startIndex),
endIndex <= snapshot.text.endIndex
else {
logger.fault("position mapped, but indices failed for edit range \(String(reflecting: edits[0]))")
return nil
}
let oldText = String(snapshot.text[startIndex..<endIndex])
let description = Self.fixitTitle(replace: oldText, with: edits[0].newText)
if edits.count == 1 {
return description
}
return description + "..."
}

/// Describe a fixit's edit briefly.
Expand Down
47 changes: 47 additions & 0 deletions Tests/SourceKitLSPTests/CodeActionTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -425,4 +425,51 @@ final class CodeActionTests: XCTestCase {

try await fulfillmentOfOrThrow([editReceived])
}

func testCodeActionForFixItsProducedBySwiftSyntax() async throws {
let ws = try await MultiFileTestWorkspace(files: [
"test.swift": "protocol 1️⃣Multi 2️⃣ident 3️⃣{}",
"compile_commands.json": "[]",
])

let (uri, positions) = try ws.openDocument("test.swift")

let report = try await ws.testClient.send(DocumentDiagnosticsRequest(textDocument: TextDocumentIdentifier(uri)))
guard case .full(let fullReport) = report else {
XCTFail("Expected full diagnostics report")
return
}

XCTAssertEqual(fullReport.items.count, 1)
let diagnostic = try XCTUnwrap(fullReport.items.first)
let codeActions = try XCTUnwrap(diagnostic.codeActions)

let expectedCodeActions = [
CodeAction(
title: "Join the identifiers together",
kind: .quickFix,
edit: WorkspaceEdit(
changes: [
uri: [
TextEdit(range: positions["1️⃣"]..<positions["2️⃣"], newText: "Multiident "),
TextEdit(range: positions["2️⃣"]..<positions["3️⃣"], newText: ""),
]
]
)
),
CodeAction(
title: "Join the identifiers together with camel-case",
kind: .quickFix,
edit: WorkspaceEdit(
changes: [
uri: [
TextEdit(range: positions["1️⃣"]..<positions["2️⃣"], newText: "MultiIdent "),
TextEdit(range: positions["2️⃣"]..<positions["3️⃣"], newText: ""),
]
]
)
),
]
XCTAssertEqual(expectedCodeActions, codeActions)
}
}