mirror of
https://github.com/astral-sh/ruff.git
synced 2025-10-03 07:04:53 +00:00
ruff_db: add "secondary" messages to Diagnostic
trait
This is a small little hack to make the `Diagnostic` trait capable of supporting attaching multiple spans. This design should be considered transient. This was just the quickest way that I could see to pass multiple spans through from the type checker to the diagnostic renderer.
This commit is contained in:
parent
18a9eddf60
commit
87668e24b1
5 changed files with 85 additions and 7 deletions
|
@ -325,6 +325,7 @@ impl<'a> CheckSuppressionsContext<'a> {
|
||||||
range,
|
range,
|
||||||
severity,
|
severity,
|
||||||
file: self.file,
|
file: self.file,
|
||||||
|
secondary_messages: vec![],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@ use std::fmt;
|
||||||
|
|
||||||
use drop_bomb::DebugDropBomb;
|
use drop_bomb::DebugDropBomb;
|
||||||
use ruff_db::{
|
use ruff_db::{
|
||||||
diagnostic::{DiagnosticId, Severity},
|
diagnostic::{DiagnosticId, SecondaryDiagnosticMessage, Severity},
|
||||||
files::File,
|
files::File,
|
||||||
};
|
};
|
||||||
use ruff_python_ast::AnyNodeRef;
|
use ruff_python_ast::AnyNodeRef;
|
||||||
|
@ -73,6 +73,17 @@ impl<'db> InferContext<'db> {
|
||||||
lint: &'static LintMetadata,
|
lint: &'static LintMetadata,
|
||||||
node: AnyNodeRef,
|
node: AnyNodeRef,
|
||||||
message: fmt::Arguments,
|
message: fmt::Arguments,
|
||||||
|
) {
|
||||||
|
self.report_lint_with_secondary_messages(lint, node, message, vec![]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Reports a lint located at `node`.
|
||||||
|
pub(super) fn report_lint_with_secondary_messages(
|
||||||
|
&self,
|
||||||
|
lint: &'static LintMetadata,
|
||||||
|
node: AnyNodeRef,
|
||||||
|
message: fmt::Arguments,
|
||||||
|
secondary_messages: Vec<SecondaryDiagnosticMessage>,
|
||||||
) {
|
) {
|
||||||
if !self.db.is_file_open(self.file) {
|
if !self.db.is_file_open(self.file) {
|
||||||
return;
|
return;
|
||||||
|
@ -94,7 +105,13 @@ impl<'db> InferContext<'db> {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.report_diagnostic(node, DiagnosticId::Lint(lint.name()), severity, message);
|
self.report_diagnostic(
|
||||||
|
node,
|
||||||
|
DiagnosticId::Lint(lint.name()),
|
||||||
|
severity,
|
||||||
|
message,
|
||||||
|
secondary_messages,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Adds a new diagnostic.
|
/// Adds a new diagnostic.
|
||||||
|
@ -106,6 +123,7 @@ impl<'db> InferContext<'db> {
|
||||||
id: DiagnosticId,
|
id: DiagnosticId,
|
||||||
severity: Severity,
|
severity: Severity,
|
||||||
message: fmt::Arguments,
|
message: fmt::Arguments,
|
||||||
|
secondary_messages: Vec<SecondaryDiagnosticMessage>,
|
||||||
) {
|
) {
|
||||||
if !self.db.is_file_open(self.file) {
|
if !self.db.is_file_open(self.file) {
|
||||||
return;
|
return;
|
||||||
|
@ -123,6 +141,7 @@ impl<'db> InferContext<'db> {
|
||||||
message: message.to_string(),
|
message: message.to_string(),
|
||||||
range: node.range(),
|
range: node.range(),
|
||||||
severity,
|
severity,
|
||||||
|
secondary_messages,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ use crate::types::string_annotation::{
|
||||||
};
|
};
|
||||||
use crate::types::{ClassLiteralType, KnownInstanceType, Type};
|
use crate::types::{ClassLiteralType, KnownInstanceType, Type};
|
||||||
use crate::{declare_lint, Db};
|
use crate::{declare_lint, Db};
|
||||||
use ruff_db::diagnostic::{Diagnostic, DiagnosticId, Severity, Span};
|
use ruff_db::diagnostic::{Diagnostic, DiagnosticId, SecondaryDiagnosticMessage, Severity, Span};
|
||||||
use ruff_db::files::File;
|
use ruff_db::files::File;
|
||||||
use ruff_python_ast::{self as ast, AnyNodeRef};
|
use ruff_python_ast::{self as ast, AnyNodeRef};
|
||||||
use ruff_text_size::TextRange;
|
use ruff_text_size::TextRange;
|
||||||
|
@ -777,6 +777,7 @@ pub struct TypeCheckDiagnostic {
|
||||||
pub(crate) range: TextRange,
|
pub(crate) range: TextRange,
|
||||||
pub(crate) severity: Severity,
|
pub(crate) severity: Severity,
|
||||||
pub(crate) file: File,
|
pub(crate) file: File,
|
||||||
|
pub(crate) secondary_messages: Vec<SecondaryDiagnosticMessage>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TypeCheckDiagnostic {
|
impl TypeCheckDiagnostic {
|
||||||
|
@ -806,6 +807,10 @@ impl Diagnostic for TypeCheckDiagnostic {
|
||||||
Some(Span::from(self.file).with_range(self.range))
|
Some(Span::from(self.file).with_range(self.range))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn secondary_messages(&self) -> &[SecondaryDiagnosticMessage] {
|
||||||
|
&self.secondary_messages
|
||||||
|
}
|
||||||
|
|
||||||
fn severity(&self) -> Severity {
|
fn severity(&self) -> Severity {
|
||||||
self.severity
|
self.severity
|
||||||
}
|
}
|
||||||
|
|
|
@ -3272,6 +3272,7 @@ impl<'db> TypeInferenceBuilder<'db> {
|
||||||
"Revealed type is `{}`",
|
"Revealed type is `{}`",
|
||||||
revealed_type.display(self.db())
|
revealed_type.display(self.db())
|
||||||
),
|
),
|
||||||
|
vec![],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -173,6 +173,12 @@ pub trait Diagnostic: Send + Sync + std::fmt::Debug {
|
||||||
/// or it applies to the entire file (e.g. the file should be executable but isn't).
|
/// or it applies to the entire file (e.g. the file should be executable but isn't).
|
||||||
fn span(&self) -> Option<Span>;
|
fn span(&self) -> Option<Span>;
|
||||||
|
|
||||||
|
/// Returns an optional sequence of "secondary" messages (with spans) to
|
||||||
|
/// include in the rendering of this diagnostic.
|
||||||
|
fn secondary_messages(&self) -> &[SecondaryDiagnosticMessage] {
|
||||||
|
&[]
|
||||||
|
}
|
||||||
|
|
||||||
fn severity(&self) -> Severity;
|
fn severity(&self) -> Severity;
|
||||||
|
|
||||||
fn display<'db, 'diag, 'config>(
|
fn display<'db, 'diag, 'config>(
|
||||||
|
@ -191,6 +197,22 @@ pub trait Diagnostic: Send + Sync + std::fmt::Debug {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A single secondary message assigned to a `Diagnostic`.
|
||||||
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
|
pub struct SecondaryDiagnosticMessage {
|
||||||
|
span: Span,
|
||||||
|
message: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SecondaryDiagnosticMessage {
|
||||||
|
pub fn new(span: Span, message: impl Into<String>) -> SecondaryDiagnosticMessage {
|
||||||
|
SecondaryDiagnosticMessage {
|
||||||
|
span,
|
||||||
|
message: message.into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A span represents the source of a diagnostic.
|
/// A span represents the source of a diagnostic.
|
||||||
///
|
///
|
||||||
/// It consists of a `File` and an optional range into that file. When the
|
/// It consists of a `File` and an optional range into that file. When the
|
||||||
|
@ -219,10 +241,12 @@ impl Span {
|
||||||
|
|
||||||
/// Returns a new `Span` with the given `range` attached to it.
|
/// Returns a new `Span` with the given `range` attached to it.
|
||||||
pub fn with_range(self, range: TextRange) -> Span {
|
pub fn with_range(self, range: TextRange) -> Span {
|
||||||
Span {
|
self.with_optional_range(Some(range))
|
||||||
range: Some(range),
|
|
||||||
..self
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns a new `Span` with the given optional `range` attached to it.
|
||||||
|
pub fn with_optional_range(self, range: Option<TextRange>) -> Span {
|
||||||
|
Span { range, ..self }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -311,6 +335,14 @@ impl std::fmt::Display for DisplayDiagnostic<'_, '_, '_> {
|
||||||
&span,
|
&span,
|
||||||
&self.diagnostic.message(),
|
&self.diagnostic.message(),
|
||||||
));
|
));
|
||||||
|
for secondary_msg in self.diagnostic.secondary_messages() {
|
||||||
|
message.add_snippet(Snippet::new(
|
||||||
|
self.db,
|
||||||
|
Severity::Info,
|
||||||
|
&secondary_msg.span,
|
||||||
|
&secondary_msg.message,
|
||||||
|
));
|
||||||
|
}
|
||||||
render(f, message.to_annotate())
|
render(f, message.to_annotate())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -445,6 +477,10 @@ where
|
||||||
(**self).span()
|
(**self).span()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn secondary_messages(&self) -> &[SecondaryDiagnosticMessage] {
|
||||||
|
(**self).secondary_messages()
|
||||||
|
}
|
||||||
|
|
||||||
fn severity(&self) -> Severity {
|
fn severity(&self) -> Severity {
|
||||||
(**self).severity()
|
(**self).severity()
|
||||||
}
|
}
|
||||||
|
@ -466,6 +502,10 @@ where
|
||||||
(**self).span()
|
(**self).span()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn secondary_messages(&self) -> &[SecondaryDiagnosticMessage] {
|
||||||
|
(**self).secondary_messages()
|
||||||
|
}
|
||||||
|
|
||||||
fn severity(&self) -> Severity {
|
fn severity(&self) -> Severity {
|
||||||
(**self).severity()
|
(**self).severity()
|
||||||
}
|
}
|
||||||
|
@ -484,6 +524,10 @@ impl Diagnostic for Box<dyn Diagnostic> {
|
||||||
(**self).span()
|
(**self).span()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn secondary_messages(&self) -> &[SecondaryDiagnosticMessage] {
|
||||||
|
(**self).secondary_messages()
|
||||||
|
}
|
||||||
|
|
||||||
fn severity(&self) -> Severity {
|
fn severity(&self) -> Severity {
|
||||||
(**self).severity()
|
(**self).severity()
|
||||||
}
|
}
|
||||||
|
@ -502,6 +546,10 @@ impl Diagnostic for &'_ dyn Diagnostic {
|
||||||
(**self).span()
|
(**self).span()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn secondary_messages(&self) -> &[SecondaryDiagnosticMessage] {
|
||||||
|
(**self).secondary_messages()
|
||||||
|
}
|
||||||
|
|
||||||
fn severity(&self) -> Severity {
|
fn severity(&self) -> Severity {
|
||||||
(**self).severity()
|
(**self).severity()
|
||||||
}
|
}
|
||||||
|
@ -520,6 +568,10 @@ impl Diagnostic for std::sync::Arc<dyn Diagnostic> {
|
||||||
(**self).span()
|
(**self).span()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn secondary_messages(&self) -> &[SecondaryDiagnosticMessage] {
|
||||||
|
(**self).secondary_messages()
|
||||||
|
}
|
||||||
|
|
||||||
fn severity(&self) -> Severity {
|
fn severity(&self) -> Severity {
|
||||||
(**self).severity()
|
(**self).severity()
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue