mirror of https://github.com/astral-sh/ruff
120 lines
3.9 KiB
Rust
120 lines
3.9 KiB
Rust
use std::borrow::Cow;
|
|
|
|
use lsp_types::request::DocumentDiagnosticRequest;
|
|
use lsp_types::{
|
|
Diagnostic, DiagnosticSeverity, DiagnosticTag, DocumentDiagnosticParams,
|
|
DocumentDiagnosticReport, DocumentDiagnosticReportResult, FullDocumentDiagnosticReport,
|
|
NumberOrString, Range, RelatedFullDocumentDiagnosticReport, Url,
|
|
};
|
|
|
|
use crate::document::ToRangeExt;
|
|
use crate::server::api::traits::{BackgroundDocumentRequestHandler, RequestHandler};
|
|
use crate::server::{client::Notifier, Result};
|
|
use crate::session::DocumentSnapshot;
|
|
use ruff_db::diagnostic::Severity;
|
|
use ruff_db::source::{line_index, source_text};
|
|
use ty_project::{Db, ProjectDatabase};
|
|
|
|
pub(crate) struct DocumentDiagnosticRequestHandler;
|
|
|
|
impl RequestHandler for DocumentDiagnosticRequestHandler {
|
|
type RequestType = DocumentDiagnosticRequest;
|
|
}
|
|
|
|
impl BackgroundDocumentRequestHandler for DocumentDiagnosticRequestHandler {
|
|
fn document_url(params: &DocumentDiagnosticParams) -> Cow<Url> {
|
|
Cow::Borrowed(¶ms.text_document.uri)
|
|
}
|
|
|
|
fn run_with_snapshot(
|
|
snapshot: DocumentSnapshot,
|
|
db: ProjectDatabase,
|
|
_notifier: Notifier,
|
|
_params: DocumentDiagnosticParams,
|
|
) -> Result<DocumentDiagnosticReportResult> {
|
|
let diagnostics = compute_diagnostics(&snapshot, &db);
|
|
|
|
Ok(DocumentDiagnosticReportResult::Report(
|
|
DocumentDiagnosticReport::Full(RelatedFullDocumentDiagnosticReport {
|
|
related_documents: None,
|
|
full_document_diagnostic_report: FullDocumentDiagnosticReport {
|
|
result_id: None,
|
|
items: diagnostics,
|
|
},
|
|
}),
|
|
))
|
|
}
|
|
}
|
|
|
|
fn compute_diagnostics(snapshot: &DocumentSnapshot, db: &ProjectDatabase) -> Vec<Diagnostic> {
|
|
let Some(file) = snapshot.file(db) else {
|
|
tracing::info!(
|
|
"No file found for snapshot for `{}`",
|
|
snapshot.query().file_url()
|
|
);
|
|
return vec![];
|
|
};
|
|
|
|
let diagnostics = match db.check_file(file) {
|
|
Ok(diagnostics) => diagnostics,
|
|
Err(cancelled) => {
|
|
tracing::info!("Diagnostics computation {cancelled}");
|
|
return vec![];
|
|
}
|
|
};
|
|
|
|
diagnostics
|
|
.as_slice()
|
|
.iter()
|
|
.map(|message| to_lsp_diagnostic(db, message, snapshot.encoding()))
|
|
.collect()
|
|
}
|
|
|
|
fn to_lsp_diagnostic(
|
|
db: &dyn Db,
|
|
diagnostic: &ruff_db::diagnostic::Diagnostic,
|
|
encoding: crate::PositionEncoding,
|
|
) -> Diagnostic {
|
|
let range = if let Some(span) = diagnostic.primary_span() {
|
|
let file = span.expect_ty_file();
|
|
let index = line_index(db.upcast(), file);
|
|
let source = source_text(db.upcast(), file);
|
|
|
|
span.range()
|
|
.map(|range| range.to_lsp_range(&source, &index, encoding))
|
|
.unwrap_or_default()
|
|
} else {
|
|
Range::default()
|
|
};
|
|
|
|
let severity = match diagnostic.severity() {
|
|
Severity::Info => DiagnosticSeverity::INFORMATION,
|
|
Severity::Warning => DiagnosticSeverity::WARNING,
|
|
Severity::Error | Severity::Fatal => DiagnosticSeverity::ERROR,
|
|
};
|
|
|
|
let tags = diagnostic
|
|
.primary_tags()
|
|
.map(|tags| {
|
|
tags.iter()
|
|
.map(|tag| match tag {
|
|
ruff_db::diagnostic::DiagnosticTag::Unnecessary => DiagnosticTag::UNNECESSARY,
|
|
ruff_db::diagnostic::DiagnosticTag::Deprecated => DiagnosticTag::DEPRECATED,
|
|
})
|
|
.collect::<Vec<DiagnosticTag>>()
|
|
})
|
|
.filter(|mapped_tags| !mapped_tags.is_empty());
|
|
|
|
Diagnostic {
|
|
range,
|
|
severity: Some(severity),
|
|
tags,
|
|
code: Some(NumberOrString::String(diagnostic.id().to_string())),
|
|
code_description: None,
|
|
source: Some("ty".into()),
|
|
message: diagnostic.concise_message().to_string(),
|
|
related_information: None,
|
|
data: None,
|
|
}
|
|
}
|