ruff server: Support noqa comment code action (#11276)

## Summary

Fixes https://github.com/astral-sh/ruff/issues/10594.

Code actions to disable a diagnostic via `noqa` comment are now
available.


6d3bcf11-a9d9-499b-8c7f-a10cd39cfbba

`DiagnosticFix` has been changed so that `noqa` code actions appear even
for diagnostics with no available quick fix. It can contain quick fix
edits, `noqa` comment edits, or both.

## Test Plan

The scenarios that need to be tested are as follows:
* A code action to disable a diagnostic should be available for every
diagnostic.
* Using this code action should append to the appropriate line with the
diagnostic, or modify an existing `noqa` comment.
* Adding a `noqa` comment manually should make a diagnostic disappear
* `Fix all auto-fixable problems` should not add `noqa` comments
* Removing a code from a `noqa` comment should make the diagnostic
re-appear
This commit is contained in:
Jane Lewis 2024-05-12 14:39:46 -07:00 committed by GitHub
parent 4b330b11c6
commit d7f093ef9e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 126 additions and 38 deletions

View file

@ -1,5 +1,5 @@
use crate::edit::WorkspaceEditTracker;
use crate::lint::fixes_for_diagnostics;
use crate::lint::{fixes_for_diagnostics, DiagnosticFix};
use crate::server::api::LSPResult;
use crate::server::SupportedCodeAction;
use crate::server::{client::Notifier, Result};
@ -29,13 +29,24 @@ impl super::BackgroundDocumentRequestHandler for CodeActions {
let supported_code_actions = supported_code_actions(params.context.only.clone());
let fixes = fixes_for_diagnostics(
snapshot.document(),
snapshot.encoding(),
params.context.diagnostics,
)
.with_failure_code(ErrorCode::InternalError)?;
if snapshot.client_settings().fix_violation()
&& supported_code_actions.contains(&SupportedCodeAction::QuickFix)
{
response.extend(
quick_fix(&snapshot, params.context.diagnostics.clone())
.with_failure_code(ErrorCode::InternalError)?,
);
response
.extend(quick_fix(&snapshot, &fixes).with_failure_code(ErrorCode::InternalError)?);
}
if snapshot.client_settings().noqa_comments()
&& supported_code_actions.contains(&SupportedCodeAction::QuickFix)
{
response.extend(noqa_comments(&snapshot, &fixes));
}
if snapshot.client_settings().fix_all()
@ -56,21 +67,19 @@ impl super::BackgroundDocumentRequestHandler for CodeActions {
fn quick_fix(
snapshot: &DocumentSnapshot,
diagnostics: Vec<types::Diagnostic>,
fixes: &[DiagnosticFix],
) -> crate::Result<Vec<CodeActionOrCommand>> {
let document = snapshot.document();
let fixes = fixes_for_diagnostics(document, snapshot.encoding(), diagnostics)?;
fixes
.into_iter()
.iter()
.filter(|fix| !fix.edits.is_empty())
.map(|fix| {
let mut tracker = WorkspaceEditTracker::new(snapshot.resolved_client_capabilities());
tracker.set_edits_for_document(
snapshot.url().clone(),
document.version(),
fix.edits,
fix.edits.clone(),
)?;
Ok(types::CodeActionOrCommand::CodeAction(types::CodeAction {
@ -87,6 +96,36 @@ fn quick_fix(
.collect()
}
fn noqa_comments(snapshot: &DocumentSnapshot, fixes: &[DiagnosticFix]) -> Vec<CodeActionOrCommand> {
fixes
.iter()
.filter_map(|fix| {
let edit = fix.noqa_edit.clone()?;
let mut tracker = WorkspaceEditTracker::new(snapshot.resolved_client_capabilities());
tracker
.set_edits_for_document(
snapshot.url().clone(),
snapshot.document().version(),
vec![edit],
)
.ok()?;
Some(types::CodeActionOrCommand::CodeAction(types::CodeAction {
title: format!("{DIAGNOSTIC_NAME} ({}): Disable for this line", fix.code),
kind: Some(types::CodeActionKind::QUICKFIX),
edit: Some(tracker.into_workspace_edit()),
diagnostics: Some(vec![fix.fixed_diagnostic.clone()]),
data: Some(
serde_json::to_value(snapshot.url()).expect("document url to serialize"),
),
..Default::default()
}))
})
.collect()
}
fn fix_all(snapshot: &DocumentSnapshot) -> crate::Result<CodeActionOrCommand> {
let document = snapshot.document();