From b993468288f254fed5d74d79f6b471ab35a43d7c Mon Sep 17 00:00:00 2001 From: Andrew Gallant Date: Tue, 11 Feb 2025 10:35:53 -0500 Subject: [PATCH 1/5] ruff_db: add `Diagnostic::span` routine This is a small change to facilitate migrating to a trait without separate `file` and `range` methods. --- crates/ruff_db/src/diagnostic.rs | 56 ++++++++++++++++++++++++++++---- 1 file changed, 49 insertions(+), 7 deletions(-) diff --git a/crates/ruff_db/src/diagnostic.rs b/crates/ruff_db/src/diagnostic.rs index 4b3be76ab9f14..4db992f5fdbb1 100644 --- a/crates/ruff_db/src/diagnostic.rs +++ b/crates/ruff_db/src/diagnostic.rs @@ -178,6 +178,22 @@ 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). fn range(&self) -> Option; + /// The primary span of the diagnostic. + /// + /// The range can be `None` if the diagnostic doesn't have a file + /// or it applies to the entire file (e.g. the file should be executable but isn't). + fn span(&self) -> Option { + // NOTE: This temporary implementation specifically rejects the + // possible case of a present `TextRange` but a missing `File`. + // During this re-factor, we'll specifically prevent this case + // from happening by construction. + let mut span = self.file().map(Span::from)?; + if let Some(range) = self.range() { + span = span.with_range(range); + } + Some(span) + } + fn severity(&self) -> Severity; fn display<'a>(&'a self, db: &'a dyn Db) -> DisplayDiagnostic<'a> @@ -191,6 +207,32 @@ pub trait Diagnostic: Send + Sync + std::fmt::Debug { } } +/// A span represents the source of a diagnostic. +/// +/// It consists of a `File` and an optional range into that file. When the +/// range isn't present, it semantically implies that the diagnostic refers to +/// the entire file. For example, when the file should be executable but isn't. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct Span { + file: File, + range: Option, +} + +impl Span { + pub fn with_range(self, range: TextRange) -> Span { + Span { + range: Some(range), + ..self + } + } +} + +impl From for Span { + fn from(file: File) -> Span { + Span { file, range: None } + } +} + #[derive(Debug, Clone, Copy, PartialEq, Eq, Ord, PartialOrd)] pub enum Severity { Info, @@ -236,8 +278,8 @@ impl std::fmt::Display for DisplayDiagnostic<'_> { let rendered = renderer.render(message); writeln!(f, "{rendered}") }; - match (self.diagnostic.file(), self.diagnostic.range()) { - (None, _) => { + match self.diagnostic.span() { + None => { // NOTE: This is pretty sub-optimal. It doesn't render well. We // really want a snippet, but without a `File`, we can't really // render anything. It looks like this case currently happens @@ -248,20 +290,20 @@ impl std::fmt::Display for DisplayDiagnostic<'_> { let msg = format!("{}: {}", self.diagnostic.id(), self.diagnostic.message()); render(f, level.title(&msg)) } - (Some(file), range) => { - let path = file.path(self.db).to_string(); - let source = source_text(self.db, file); + Some(span) => { + let path = span.file.path(self.db).to_string(); + let source = source_text(self.db, span.file); let title = self.diagnostic.id().to_string(); let message = self.diagnostic.message(); - let Some(range) = range else { + let Some(range) = span.range else { let snippet = Snippet::source(source.as_str()).origin(&path).line_start(1); return render(f, level.title(&title).snippet(snippet)); }; // The bits below are a simplified copy from // `crates/ruff_linter/src/message/text.rs`. - let index = line_index(self.db, file); + let index = line_index(self.db, span.file); let source_code = SourceCode::new(source.as_str(), &index); let content_start_index = source_code.line_index(range.start()); From 8b86a5f88aeeb93fada466e5b0d2bd1696dcb728 Mon Sep 17 00:00:00 2001 From: Andrew Gallant Date: Tue, 11 Feb 2025 10:50:59 -0500 Subject: [PATCH 2/5] ruff_db: remove default implementation of `Diagnostic::span` ... in favor of the implementations providing this routine themselves. --- crates/red_knot_project/src/lib.rs | 6 +++- .../red_knot_project/src/metadata/options.rs | 10 +++++- .../src/types/diagnostic.rs | 6 +++- crates/red_knot_test/src/diagnostic.rs | 6 +++- crates/red_knot_test/src/matcher.rs | 6 +++- crates/ruff_db/src/diagnostic.rs | 36 +++++++++++++------ 6 files changed, 54 insertions(+), 16 deletions(-) diff --git a/crates/red_knot_project/src/lib.rs b/crates/red_knot_project/src/lib.rs index 3d8ee4ae4ce17..6bfc490e6817b 100644 --- a/crates/red_knot_project/src/lib.rs +++ b/crates/red_knot_project/src/lib.rs @@ -8,7 +8,7 @@ pub use metadata::{ProjectDiscoveryError, ProjectMetadata}; use red_knot_python_semantic::lint::{LintRegistry, LintRegistryBuilder, RuleSelection}; use red_knot_python_semantic::register_lints; use red_knot_python_semantic::types::check_types; -use ruff_db::diagnostic::{Diagnostic, DiagnosticId, ParseDiagnostic, Severity}; +use ruff_db::diagnostic::{Diagnostic, DiagnosticId, ParseDiagnostic, Severity, Span}; use ruff_db::files::{system_path_to_file, File}; use ruff_db::parsed::parsed_module; use ruff_db::source::{source_text, SourceTextError}; @@ -466,6 +466,10 @@ impl Diagnostic for IOErrorDiagnostic { None } + fn span(&self) -> Option { + Some(Span::from(self.file)) + } + fn severity(&self) -> Severity { Severity::Error } diff --git a/crates/red_knot_project/src/metadata/options.rs b/crates/red_knot_project/src/metadata/options.rs index 401dcf1233345..b0b2753083325 100644 --- a/crates/red_knot_project/src/metadata/options.rs +++ b/crates/red_knot_project/src/metadata/options.rs @@ -4,7 +4,7 @@ use red_knot_python_semantic::lint::{GetLintError, Level, LintSource, RuleSelect use red_knot_python_semantic::{ ProgramSettings, PythonPlatform, PythonVersion, SearchPathSettings, SitePackages, }; -use ruff_db::diagnostic::{Diagnostic, DiagnosticId, Severity}; +use ruff_db::diagnostic::{Diagnostic, DiagnosticId, Severity, Span}; use ruff_db::files::{system_path_to_file, File}; use ruff_db::system::{System, SystemPath}; use ruff_macros::Combine; @@ -393,6 +393,14 @@ impl Diagnostic for OptionDiagnostic { self.range } + fn span(&self) -> Option { + let mut span = self.file.map(Span::from)?; + if let Some(range) = self.range { + span = span.with_range(range); + } + Some(span) + } + fn severity(&self) -> Severity { self.severity } diff --git a/crates/red_knot_python_semantic/src/types/diagnostic.rs b/crates/red_knot_python_semantic/src/types/diagnostic.rs index 99d07dd9f973a..a1979e8c88f0e 100644 --- a/crates/red_knot_python_semantic/src/types/diagnostic.rs +++ b/crates/red_knot_python_semantic/src/types/diagnostic.rs @@ -8,7 +8,7 @@ use crate::types::string_annotation::{ }; use crate::types::{ClassLiteralType, KnownInstanceType, Type}; use crate::{declare_lint, Db}; -use ruff_db::diagnostic::{Diagnostic, DiagnosticId, Severity}; +use ruff_db::diagnostic::{Diagnostic, DiagnosticId, Severity, Span}; use ruff_db::files::File; use ruff_python_ast::{self as ast, AnyNodeRef}; use ruff_text_size::{Ranged, TextRange}; @@ -810,6 +810,10 @@ impl Diagnostic for TypeCheckDiagnostic { Some(Ranged::range(self)) } + fn span(&self) -> Option { + Some(Span::from(self.file).with_range(self.range)) + } + fn severity(&self) -> Severity { self.severity } diff --git a/crates/red_knot_test/src/diagnostic.rs b/crates/red_knot_test/src/diagnostic.rs index bb5a099b50ef1..5d2a98d9dbd12 100644 --- a/crates/red_knot_test/src/diagnostic.rs +++ b/crates/red_knot_test/src/diagnostic.rs @@ -144,7 +144,7 @@ struct DiagnosticWithLine { mod tests { use crate::db::Db; use crate::diagnostic::Diagnostic; - use ruff_db::diagnostic::{DiagnosticId, LintName, Severity}; + use ruff_db::diagnostic::{DiagnosticId, LintName, Severity, Span}; use ruff_db::files::{system_path_to_file, File}; use ruff_db::source::line_index; use ruff_db::system::{DbWithTestSystem, SystemPathBuf}; @@ -206,6 +206,10 @@ mod tests { Some(self.range) } + fn span(&self) -> Option { + Some(Span::from(self.file).with_range(self.range)) + } + fn severity(&self) -> Severity { Severity::Error } diff --git a/crates/red_knot_test/src/matcher.rs b/crates/red_knot_test/src/matcher.rs index e7add5c50adb2..8f87d2dcb7ffe 100644 --- a/crates/red_knot_test/src/matcher.rs +++ b/crates/red_knot_test/src/matcher.rs @@ -334,7 +334,7 @@ impl Matcher { #[cfg(test)] mod tests { use super::FailuresByLine; - use ruff_db::diagnostic::{Diagnostic, DiagnosticId, Severity}; + use ruff_db::diagnostic::{Diagnostic, DiagnosticId, Severity, Span}; use ruff_db::files::{system_path_to_file, File}; use ruff_db::system::{DbWithTestSystem, SystemPathBuf}; use ruff_python_trivia::textwrap::dedent; @@ -393,6 +393,10 @@ mod tests { Some(self.range) } + fn span(&self) -> Option { + Some(Span::from(self.file).with_range(self.range)) + } + fn severity(&self) -> Severity { Severity::Error } diff --git a/crates/ruff_db/src/diagnostic.rs b/crates/ruff_db/src/diagnostic.rs index 4db992f5fdbb1..3715bbdfe0e24 100644 --- a/crates/ruff_db/src/diagnostic.rs +++ b/crates/ruff_db/src/diagnostic.rs @@ -182,17 +182,7 @@ pub trait Diagnostic: Send + Sync + std::fmt::Debug { /// /// The range can be `None` if the diagnostic doesn't have a file /// or it applies to the entire file (e.g. the file should be executable but isn't). - fn span(&self) -> Option { - // NOTE: This temporary implementation specifically rejects the - // possible case of a present `TextRange` but a missing `File`. - // During this re-factor, we'll specifically prevent this case - // from happening by construction. - let mut span = self.file().map(Span::from)?; - if let Some(range) = self.range() { - span = span.with_range(range); - } - Some(span) - } + fn span(&self) -> Option; fn severity(&self) -> Severity; @@ -365,6 +355,10 @@ where (**self).range() } + fn span(&self) -> Option { + (**self).span() + } + fn severity(&self) -> Severity { (**self).severity() } @@ -390,6 +384,10 @@ where (**self).range() } + fn span(&self) -> Option { + (**self).span() + } + fn severity(&self) -> Severity { (**self).severity() } @@ -412,6 +410,10 @@ impl Diagnostic for Box { (**self).range() } + fn span(&self) -> Option { + (**self).span() + } + fn severity(&self) -> Severity { (**self).severity() } @@ -434,6 +436,10 @@ impl Diagnostic for &'_ dyn Diagnostic { (**self).range() } + fn span(&self) -> Option { + (**self).span() + } + fn severity(&self) -> Severity { (**self).severity() } @@ -456,6 +462,10 @@ impl Diagnostic for std::sync::Arc { (**self).range() } + fn span(&self) -> Option { + (**self).span() + } + fn severity(&self) -> Severity { (**self).severity() } @@ -490,6 +500,10 @@ impl Diagnostic for ParseDiagnostic { Some(self.error.location) } + fn span(&self) -> Option { + Some(Span::from(self.file).with_range(self.error.location)) + } + fn severity(&self) -> Severity { Severity::Error } From 868e3b5b82fa8a861344507023a860b1f5b2d55b Mon Sep 17 00:00:00 2001 From: Andrew Gallant Date: Tue, 11 Feb 2025 11:22:30 -0500 Subject: [PATCH 3/5] ruff_db: remove `Diagnostic::file` and `Diagnostic::range` ... and update all of the consumers to use `Diagnostic::span`. --- crates/red_knot_project/src/lib.rs | 17 ++-- .../red_knot_project/src/metadata/options.rs | 8 -- .../src/types/diagnostic.rs | 8 -- .../src/server/api/requests/diagnostic.rs | 10 ++- crates/red_knot_test/src/diagnostic.rs | 11 +-- crates/red_knot_test/src/matcher.rs | 11 +-- crates/ruff_benchmark/benches/red_knot.rs | 10 ++- crates/ruff_db/src/diagnostic.rs | 77 ++++--------------- 8 files changed, 40 insertions(+), 112 deletions(-) diff --git a/crates/red_knot_project/src/lib.rs b/crates/red_knot_project/src/lib.rs index 6bfc490e6817b..2126f36a841e9 100644 --- a/crates/red_knot_project/src/lib.rs +++ b/crates/red_knot_project/src/lib.rs @@ -15,7 +15,6 @@ use ruff_db::source::{source_text, SourceTextError}; use ruff_db::system::walk_directory::WalkState; use ruff_db::system::{FileType, SystemPath}; use ruff_python_ast::PySourceType; -use ruff_text_size::TextRange; use rustc_hash::{FxBuildHasher, FxHashSet}; use salsa::Durability; use salsa::Setter; @@ -345,7 +344,13 @@ fn check_file_impl(db: &dyn Db, file: File) -> Vec> { boxed })); - diagnostics.sort_unstable_by_key(|diagnostic| diagnostic.range().unwrap_or_default().start()); + diagnostics.sort_unstable_by_key(|diagnostic| { + diagnostic + .span() + .and_then(|span| span.range()) + .unwrap_or_default() + .start() + }); diagnostics } @@ -458,14 +463,6 @@ impl Diagnostic for IOErrorDiagnostic { self.error.to_string().into() } - fn file(&self) -> Option { - Some(self.file) - } - - fn range(&self) -> Option { - None - } - fn span(&self) -> Option { Some(Span::from(self.file)) } diff --git a/crates/red_knot_project/src/metadata/options.rs b/crates/red_knot_project/src/metadata/options.rs index b0b2753083325..302481baeed82 100644 --- a/crates/red_knot_project/src/metadata/options.rs +++ b/crates/red_knot_project/src/metadata/options.rs @@ -385,14 +385,6 @@ impl Diagnostic for OptionDiagnostic { Cow::Borrowed(&self.message) } - fn file(&self) -> Option { - self.file - } - - fn range(&self) -> Option { - self.range - } - fn span(&self) -> Option { let mut span = self.file.map(Span::from)?; if let Some(range) = self.range { diff --git a/crates/red_knot_python_semantic/src/types/diagnostic.rs b/crates/red_knot_python_semantic/src/types/diagnostic.rs index a1979e8c88f0e..2f08b84f88bc0 100644 --- a/crates/red_knot_python_semantic/src/types/diagnostic.rs +++ b/crates/red_knot_python_semantic/src/types/diagnostic.rs @@ -802,14 +802,6 @@ impl Diagnostic for TypeCheckDiagnostic { TypeCheckDiagnostic::message(self).into() } - fn file(&self) -> Option { - Some(TypeCheckDiagnostic::file(self)) - } - - fn range(&self) -> Option { - Some(Ranged::range(self)) - } - fn span(&self) -> Option { Some(Span::from(self.file).with_range(self.range)) } diff --git a/crates/red_knot_server/src/server/api/requests/diagnostic.rs b/crates/red_knot_server/src/server/api/requests/diagnostic.rs index 968c05abe65e0..ba788817ec4c0 100644 --- a/crates/red_knot_server/src/server/api/requests/diagnostic.rs +++ b/crates/red_knot_server/src/server/api/requests/diagnostic.rs @@ -75,11 +75,13 @@ fn to_lsp_diagnostic( diagnostic: &dyn ruff_db::diagnostic::Diagnostic, encoding: crate::PositionEncoding, ) -> Diagnostic { - let range = if let (Some(file), Some(range)) = (diagnostic.file(), diagnostic.range()) { - let index = line_index(db.upcast(), file); - let source = source_text(db.upcast(), file); + let range = if let Some(span) = diagnostic.span() { + let index = line_index(db.upcast(), span.file()); + let source = source_text(db.upcast(), span.file()); - range.to_range(&source, &index, encoding) + span.range() + .map(|range| range.to_range(&source, &index, encoding)) + .unwrap_or_default() } else { Range::default() }; diff --git a/crates/red_knot_test/src/diagnostic.rs b/crates/red_knot_test/src/diagnostic.rs index 5d2a98d9dbd12..56ee51223cc8b 100644 --- a/crates/red_knot_test/src/diagnostic.rs +++ b/crates/red_knot_test/src/diagnostic.rs @@ -26,7 +26,8 @@ where .into_iter() .map(|diagnostic| DiagnosticWithLine { line_number: diagnostic - .range() + .span() + .and_then(|span| span.range()) .map_or(OneIndexed::from_zero_indexed(0), |range| { line_index.line_index(range.start()) }), @@ -198,14 +199,6 @@ mod tests { "dummy".into() } - fn file(&self) -> Option { - Some(self.file) - } - - fn range(&self) -> Option { - Some(self.range) - } - fn span(&self) -> Option { Some(Span::from(self.file).with_range(self.range)) } diff --git a/crates/red_knot_test/src/matcher.rs b/crates/red_knot_test/src/matcher.rs index 8f87d2dcb7ffe..d350ec7c61c3e 100644 --- a/crates/red_knot_test/src/matcher.rs +++ b/crates/red_knot_test/src/matcher.rs @@ -257,7 +257,8 @@ impl Matcher { fn column(&self, diagnostic: &T) -> OneIndexed { diagnostic - .range() + .span() + .and_then(|span| span.range()) .map(|range| { self.line_index .source_location(range.start(), &self.source) @@ -385,14 +386,6 @@ mod tests { self.message.into() } - fn file(&self) -> Option { - Some(self.file) - } - - fn range(&self) -> Option { - Some(self.range) - } - fn span(&self) -> Option { Some(Span::from(self.file).with_range(self.range)) } diff --git a/crates/ruff_benchmark/benches/red_knot.rs b/crates/ruff_benchmark/benches/red_knot.rs index 5c6362dc0ac0c..87366b04dec1b 100644 --- a/crates/ruff_benchmark/benches/red_knot.rs +++ b/crates/ruff_benchmark/benches/red_knot.rs @@ -229,8 +229,14 @@ fn assert_diagnostics(db: &dyn Db, diagnostics: &[Box]) { .map(|diagnostic| { ( diagnostic.id(), - diagnostic.file().map(|file| file.path(db).as_str()), - diagnostic.range().map(Range::::from), + diagnostic + .span() + .map(|span| span.file()) + .map(|file| file.path(db).as_str()), + diagnostic + .span() + .and_then(|span| span.range()) + .map(Range::::from), diagnostic.message(), diagnostic.severity(), ) diff --git a/crates/ruff_db/src/diagnostic.rs b/crates/ruff_db/src/diagnostic.rs index 3715bbdfe0e24..02c70126743d4 100644 --- a/crates/ruff_db/src/diagnostic.rs +++ b/crates/ruff_db/src/diagnostic.rs @@ -164,20 +164,6 @@ pub trait Diagnostic: Send + Sync + std::fmt::Debug { fn message(&self) -> Cow; - /// The file this diagnostic is associated with. - /// - /// File can be `None` for diagnostics that don't originate from a file. - /// For example: - /// * A diagnostic indicating that a directory couldn't be read. - /// * A diagnostic related to a CLI argument - fn file(&self) -> Option; - - /// The primary range of the diagnostic in `file`. - /// - /// The range can be `None` if the diagnostic doesn't have a file - /// or it applies to the entire file (e.g. the file should be executable but isn't). - fn range(&self) -> Option; - /// The primary span of the diagnostic. /// /// The range can be `None` if the diagnostic doesn't have a file @@ -209,6 +195,21 @@ pub struct Span { } impl Span { + /// Returns the `File` attached to this `Span`. + pub fn file(&self) -> File { + self.file + } + + /// Returns the range, if available, attached to this `Span`. + /// + /// When there is no range, it is convention to assume that this `Span` + /// refers to the corresponding `File` as a whole. In some cases, consumers + /// of this API may use the range `0..0` to represent this case. + pub fn range(&self) -> Option { + self.range + } + + /// Returns a new `Span` with the given `range` attached to it. pub fn with_range(self, range: TextRange) -> Span { Span { range: Some(range), @@ -347,14 +348,6 @@ where (**self).message() } - fn file(&self) -> Option { - (**self).file() - } - - fn range(&self) -> Option { - (**self).range() - } - fn span(&self) -> Option { (**self).span() } @@ -376,14 +369,6 @@ where (**self).message() } - fn file(&self) -> Option { - (**self).file() - } - - fn range(&self) -> Option { - (**self).range() - } - fn span(&self) -> Option { (**self).span() } @@ -402,14 +387,6 @@ impl Diagnostic for Box { (**self).message() } - fn file(&self) -> Option { - (**self).file() - } - - fn range(&self) -> Option { - (**self).range() - } - fn span(&self) -> Option { (**self).span() } @@ -428,14 +405,6 @@ impl Diagnostic for &'_ dyn Diagnostic { (**self).message() } - fn file(&self) -> Option { - (**self).file() - } - - fn range(&self) -> Option { - (**self).range() - } - fn span(&self) -> Option { (**self).span() } @@ -454,14 +423,6 @@ impl Diagnostic for std::sync::Arc { (**self).message() } - fn file(&self) -> Option { - (**self).file() - } - - fn range(&self) -> Option { - (**self).range() - } - fn span(&self) -> Option { (**self).span() } @@ -492,14 +453,6 @@ impl Diagnostic for ParseDiagnostic { self.error.error.to_string().into() } - fn file(&self) -> Option { - Some(self.file) - } - - fn range(&self) -> Option { - Some(self.error.location) - } - fn span(&self) -> Option { Some(Span::from(self.file).with_range(self.error.location)) } From 1266c2680b2d8b1947d54ae6b4afe2d1a78575f9 Mon Sep 17 00:00:00 2001 From: Andrew Gallant Date: Tue, 11 Feb 2025 13:36:33 -0500 Subject: [PATCH 4/5] red_knot_project: simplify `Span` construction --- .../red_knot_project/src/metadata/options.rs | 35 ++++++++----------- 1 file changed, 14 insertions(+), 21 deletions(-) diff --git a/crates/red_knot_project/src/metadata/options.rs b/crates/red_knot_project/src/metadata/options.rs index 302481baeed82..d34473a5f7fdd 100644 --- a/crates/red_knot_project/src/metadata/options.rs +++ b/crates/red_knot_project/src/metadata/options.rs @@ -5,10 +5,9 @@ use red_knot_python_semantic::{ ProgramSettings, PythonPlatform, PythonVersion, SearchPathSettings, SitePackages, }; use ruff_db::diagnostic::{Diagnostic, DiagnosticId, Severity, Span}; -use ruff_db::files::{system_path_to_file, File}; +use ruff_db::files::system_path_to_file; use ruff_db::system::{System, SystemPath}; use ruff_macros::Combine; -use ruff_text_size::TextRange; use rustc_hash::FxHashMap; use serde::{Deserialize, Serialize}; use std::borrow::Cow; @@ -189,7 +188,14 @@ impl Options { ), }; - diagnostics.push(diagnostic.with_file(file).with_range(rule_name.range())); + let span = file.map(Span::from).map(|span| { + if let Some(range) = rule_name.range() { + span.with_range(range) + } else { + span + } + }); + diagnostics.push(diagnostic.with_span(span)); } } } @@ -348,8 +354,7 @@ pub struct OptionDiagnostic { id: DiagnosticId, message: String, severity: Severity, - file: Option, - range: Option, + span: Option, } impl OptionDiagnostic { @@ -358,21 +363,13 @@ impl OptionDiagnostic { id, message, severity, - file: None, - range: None, + span: None, } } #[must_use] - fn with_file(mut self, file: Option) -> Self { - self.file = file; - self - } - - #[must_use] - fn with_range(mut self, range: Option) -> Self { - self.range = range; - self + fn with_span(self, span: Option) -> Self { + OptionDiagnostic { span, ..self } } } @@ -386,11 +383,7 @@ impl Diagnostic for OptionDiagnostic { } fn span(&self) -> Option { - let mut span = self.file.map(Span::from)?; - if let Some(range) = self.range { - span = span.with_range(range); - } - Some(span) + self.span } fn severity(&self) -> Severity { From ace04558f769770132b3197f24545396de8c2393 Mon Sep 17 00:00:00 2001 From: Andrew Gallant Date: Tue, 11 Feb 2025 14:42:25 -0500 Subject: [PATCH 5/5] ruff_db: remove `Copy` impl for `Span` I think ideally this type would be `Copy`, but it sounds like that might prove difficult for Ruff since it doesn't have a `Copy` file handle. --- crates/red_knot_project/src/metadata/options.rs | 2 +- crates/ruff_db/src/diagnostic.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/red_knot_project/src/metadata/options.rs b/crates/red_knot_project/src/metadata/options.rs index d34473a5f7fdd..09a167ca98ae0 100644 --- a/crates/red_knot_project/src/metadata/options.rs +++ b/crates/red_knot_project/src/metadata/options.rs @@ -383,7 +383,7 @@ impl Diagnostic for OptionDiagnostic { } fn span(&self) -> Option { - self.span + self.span.clone() } fn severity(&self) -> Severity { diff --git a/crates/ruff_db/src/diagnostic.rs b/crates/ruff_db/src/diagnostic.rs index 02c70126743d4..e342014b3f97e 100644 --- a/crates/ruff_db/src/diagnostic.rs +++ b/crates/ruff_db/src/diagnostic.rs @@ -188,7 +188,7 @@ pub trait Diagnostic: Send + Sync + std::fmt::Debug { /// It consists of a `File` and an optional range into that file. When the /// range isn't present, it semantically implies that the diagnostic refers to /// the entire file. For example, when the file should be executable but isn't. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq)] pub struct Span { file: File, range: Option,