mirror of
https://github.com/astral-sh/ruff.git
synced 2025-09-27 12:29:28 +00:00
add diagnostic Span
(couples File
and TextRange
) (#16101)
This essentially makes it impossible to construct a `Diagnostic` that has a `TextRange` but no `File`. This is meant to be a precursor to multi-span support. (Note that I consider this more of a prototyping-change and not necessarily what this is going to look like longer term.) Reviewers can probably review this PR as one big diff instead of commit-by-commit.
This commit is contained in:
parent
9c179314ed
commit
6e34f74c16
8 changed files with 115 additions and 114 deletions
|
@ -8,14 +8,13 @@ pub use metadata::{ProjectDiscoveryError, ProjectMetadata};
|
||||||
use red_knot_python_semantic::lint::{LintRegistry, LintRegistryBuilder, RuleSelection};
|
use red_knot_python_semantic::lint::{LintRegistry, LintRegistryBuilder, RuleSelection};
|
||||||
use red_knot_python_semantic::register_lints;
|
use red_knot_python_semantic::register_lints;
|
||||||
use red_knot_python_semantic::types::check_types;
|
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::files::{system_path_to_file, File};
|
||||||
use ruff_db::parsed::parsed_module;
|
use ruff_db::parsed::parsed_module;
|
||||||
use ruff_db::source::{source_text, SourceTextError};
|
use ruff_db::source::{source_text, SourceTextError};
|
||||||
use ruff_db::system::walk_directory::WalkState;
|
use ruff_db::system::walk_directory::WalkState;
|
||||||
use ruff_db::system::{FileType, SystemPath};
|
use ruff_db::system::{FileType, SystemPath};
|
||||||
use ruff_python_ast::PySourceType;
|
use ruff_python_ast::PySourceType;
|
||||||
use ruff_text_size::TextRange;
|
|
||||||
use rustc_hash::{FxBuildHasher, FxHashSet};
|
use rustc_hash::{FxBuildHasher, FxHashSet};
|
||||||
use salsa::Durability;
|
use salsa::Durability;
|
||||||
use salsa::Setter;
|
use salsa::Setter;
|
||||||
|
@ -345,7 +344,13 @@ fn check_file_impl(db: &dyn Db, file: File) -> Vec<Box<dyn Diagnostic>> {
|
||||||
boxed
|
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
|
diagnostics
|
||||||
}
|
}
|
||||||
|
@ -458,12 +463,8 @@ impl Diagnostic for IOErrorDiagnostic {
|
||||||
self.error.to_string().into()
|
self.error.to_string().into()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn file(&self) -> Option<File> {
|
fn span(&self) -> Option<Span> {
|
||||||
Some(self.file)
|
Some(Span::from(self.file))
|
||||||
}
|
|
||||||
|
|
||||||
fn range(&self) -> Option<TextRange> {
|
|
||||||
None
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn severity(&self) -> Severity {
|
fn severity(&self) -> Severity {
|
||||||
|
|
|
@ -4,11 +4,10 @@ use red_knot_python_semantic::lint::{GetLintError, Level, LintSource, RuleSelect
|
||||||
use red_knot_python_semantic::{
|
use red_knot_python_semantic::{
|
||||||
ProgramSettings, PythonPlatform, PythonVersion, SearchPathSettings, SitePackages,
|
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::files::system_path_to_file;
|
||||||
use ruff_db::system::{System, SystemPath};
|
use ruff_db::system::{System, SystemPath};
|
||||||
use ruff_macros::Combine;
|
use ruff_macros::Combine;
|
||||||
use ruff_text_size::TextRange;
|
|
||||||
use rustc_hash::FxHashMap;
|
use rustc_hash::FxHashMap;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::borrow::Cow;
|
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,
|
id: DiagnosticId,
|
||||||
message: String,
|
message: String,
|
||||||
severity: Severity,
|
severity: Severity,
|
||||||
file: Option<File>,
|
span: Option<Span>,
|
||||||
range: Option<TextRange>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl OptionDiagnostic {
|
impl OptionDiagnostic {
|
||||||
|
@ -358,21 +363,13 @@ impl OptionDiagnostic {
|
||||||
id,
|
id,
|
||||||
message,
|
message,
|
||||||
severity,
|
severity,
|
||||||
file: None,
|
span: None,
|
||||||
range: None,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
fn with_file(mut self, file: Option<File>) -> Self {
|
fn with_span(self, span: Option<Span>) -> Self {
|
||||||
self.file = file;
|
OptionDiagnostic { span, ..self }
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
#[must_use]
|
|
||||||
fn with_range(mut self, range: Option<TextRange>) -> Self {
|
|
||||||
self.range = range;
|
|
||||||
self
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -385,12 +382,8 @@ impl Diagnostic for OptionDiagnostic {
|
||||||
Cow::Borrowed(&self.message)
|
Cow::Borrowed(&self.message)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn file(&self) -> Option<File> {
|
fn span(&self) -> Option<Span> {
|
||||||
self.file
|
self.span.clone()
|
||||||
}
|
|
||||||
|
|
||||||
fn range(&self) -> Option<TextRange> {
|
|
||||||
self.range
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn severity(&self) -> Severity {
|
fn severity(&self) -> Severity {
|
||||||
|
|
|
@ -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};
|
use ruff_db::diagnostic::{Diagnostic, DiagnosticId, 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::{Ranged, TextRange};
|
use ruff_text_size::{Ranged, TextRange};
|
||||||
|
@ -802,12 +802,8 @@ impl Diagnostic for TypeCheckDiagnostic {
|
||||||
TypeCheckDiagnostic::message(self).into()
|
TypeCheckDiagnostic::message(self).into()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn file(&self) -> Option<File> {
|
fn span(&self) -> Option<Span> {
|
||||||
Some(TypeCheckDiagnostic::file(self))
|
Some(Span::from(self.file).with_range(self.range))
|
||||||
}
|
|
||||||
|
|
||||||
fn range(&self) -> Option<TextRange> {
|
|
||||||
Some(Ranged::range(self))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn severity(&self) -> Severity {
|
fn severity(&self) -> Severity {
|
||||||
|
|
|
@ -75,11 +75,13 @@ fn to_lsp_diagnostic(
|
||||||
diagnostic: &dyn ruff_db::diagnostic::Diagnostic,
|
diagnostic: &dyn ruff_db::diagnostic::Diagnostic,
|
||||||
encoding: crate::PositionEncoding,
|
encoding: crate::PositionEncoding,
|
||||||
) -> Diagnostic {
|
) -> Diagnostic {
|
||||||
let range = if let (Some(file), Some(range)) = (diagnostic.file(), diagnostic.range()) {
|
let range = if let Some(span) = diagnostic.span() {
|
||||||
let index = line_index(db.upcast(), file);
|
let index = line_index(db.upcast(), span.file());
|
||||||
let source = source_text(db.upcast(), 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 {
|
} else {
|
||||||
Range::default()
|
Range::default()
|
||||||
};
|
};
|
||||||
|
|
|
@ -26,7 +26,8 @@ where
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|diagnostic| DiagnosticWithLine {
|
.map(|diagnostic| DiagnosticWithLine {
|
||||||
line_number: diagnostic
|
line_number: diagnostic
|
||||||
.range()
|
.span()
|
||||||
|
.and_then(|span| span.range())
|
||||||
.map_or(OneIndexed::from_zero_indexed(0), |range| {
|
.map_or(OneIndexed::from_zero_indexed(0), |range| {
|
||||||
line_index.line_index(range.start())
|
line_index.line_index(range.start())
|
||||||
}),
|
}),
|
||||||
|
@ -144,7 +145,7 @@ struct DiagnosticWithLine<T> {
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::db::Db;
|
use crate::db::Db;
|
||||||
use crate::diagnostic::Diagnostic;
|
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::files::{system_path_to_file, File};
|
||||||
use ruff_db::source::line_index;
|
use ruff_db::source::line_index;
|
||||||
use ruff_db::system::{DbWithTestSystem, SystemPathBuf};
|
use ruff_db::system::{DbWithTestSystem, SystemPathBuf};
|
||||||
|
@ -198,12 +199,8 @@ mod tests {
|
||||||
"dummy".into()
|
"dummy".into()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn file(&self) -> Option<File> {
|
fn span(&self) -> Option<Span> {
|
||||||
Some(self.file)
|
Some(Span::from(self.file).with_range(self.range))
|
||||||
}
|
|
||||||
|
|
||||||
fn range(&self) -> Option<TextRange> {
|
|
||||||
Some(self.range)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn severity(&self) -> Severity {
|
fn severity(&self) -> Severity {
|
||||||
|
|
|
@ -257,7 +257,8 @@ impl Matcher {
|
||||||
|
|
||||||
fn column<T: Diagnostic>(&self, diagnostic: &T) -> OneIndexed {
|
fn column<T: Diagnostic>(&self, diagnostic: &T) -> OneIndexed {
|
||||||
diagnostic
|
diagnostic
|
||||||
.range()
|
.span()
|
||||||
|
.and_then(|span| span.range())
|
||||||
.map(|range| {
|
.map(|range| {
|
||||||
self.line_index
|
self.line_index
|
||||||
.source_location(range.start(), &self.source)
|
.source_location(range.start(), &self.source)
|
||||||
|
@ -334,7 +335,7 @@ impl Matcher {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::FailuresByLine;
|
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::files::{system_path_to_file, File};
|
||||||
use ruff_db::system::{DbWithTestSystem, SystemPathBuf};
|
use ruff_db::system::{DbWithTestSystem, SystemPathBuf};
|
||||||
use ruff_python_trivia::textwrap::dedent;
|
use ruff_python_trivia::textwrap::dedent;
|
||||||
|
@ -385,12 +386,8 @@ mod tests {
|
||||||
self.message.into()
|
self.message.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn file(&self) -> Option<File> {
|
fn span(&self) -> Option<Span> {
|
||||||
Some(self.file)
|
Some(Span::from(self.file).with_range(self.range))
|
||||||
}
|
|
||||||
|
|
||||||
fn range(&self) -> Option<TextRange> {
|
|
||||||
Some(self.range)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn severity(&self) -> Severity {
|
fn severity(&self) -> Severity {
|
||||||
|
|
|
@ -229,8 +229,14 @@ fn assert_diagnostics(db: &dyn Db, diagnostics: &[Box<dyn Diagnostic>]) {
|
||||||
.map(|diagnostic| {
|
.map(|diagnostic| {
|
||||||
(
|
(
|
||||||
diagnostic.id(),
|
diagnostic.id(),
|
||||||
diagnostic.file().map(|file| file.path(db).as_str()),
|
diagnostic
|
||||||
diagnostic.range().map(Range::<usize>::from),
|
.span()
|
||||||
|
.map(|span| span.file())
|
||||||
|
.map(|file| file.path(db).as_str()),
|
||||||
|
diagnostic
|
||||||
|
.span()
|
||||||
|
.and_then(|span| span.range())
|
||||||
|
.map(Range::<usize>::from),
|
||||||
diagnostic.message(),
|
diagnostic.message(),
|
||||||
diagnostic.severity(),
|
diagnostic.severity(),
|
||||||
)
|
)
|
||||||
|
|
|
@ -164,19 +164,11 @@ pub trait Diagnostic: Send + Sync + std::fmt::Debug {
|
||||||
|
|
||||||
fn message(&self) -> Cow<str>;
|
fn message(&self) -> Cow<str>;
|
||||||
|
|
||||||
/// The file this diagnostic is associated with.
|
/// The primary span of the diagnostic.
|
||||||
///
|
|
||||||
/// 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<File>;
|
|
||||||
|
|
||||||
/// The primary range of the diagnostic in `file`.
|
|
||||||
///
|
///
|
||||||
/// The range can be `None` if the diagnostic doesn't have a 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).
|
/// or it applies to the entire file (e.g. the file should be executable but isn't).
|
||||||
fn range(&self) -> Option<TextRange>;
|
fn span(&self) -> Option<Span>;
|
||||||
|
|
||||||
fn severity(&self) -> Severity;
|
fn severity(&self) -> Severity;
|
||||||
|
|
||||||
|
@ -191,6 +183,47 @@ 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, PartialEq, Eq)]
|
||||||
|
pub struct Span {
|
||||||
|
file: File,
|
||||||
|
range: Option<TextRange>,
|
||||||
|
}
|
||||||
|
|
||||||
|
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<TextRange> {
|
||||||
|
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),
|
||||||
|
..self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<File> for Span {
|
||||||
|
fn from(file: File) -> Span {
|
||||||
|
Span { file, range: None }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Ord, PartialOrd)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Ord, PartialOrd)]
|
||||||
pub enum Severity {
|
pub enum Severity {
|
||||||
Info,
|
Info,
|
||||||
|
@ -236,8 +269,8 @@ impl std::fmt::Display for DisplayDiagnostic<'_> {
|
||||||
let rendered = renderer.render(message);
|
let rendered = renderer.render(message);
|
||||||
writeln!(f, "{rendered}")
|
writeln!(f, "{rendered}")
|
||||||
};
|
};
|
||||||
match (self.diagnostic.file(), self.diagnostic.range()) {
|
match self.diagnostic.span() {
|
||||||
(None, _) => {
|
None => {
|
||||||
// NOTE: This is pretty sub-optimal. It doesn't render well. We
|
// NOTE: This is pretty sub-optimal. It doesn't render well. We
|
||||||
// really want a snippet, but without a `File`, we can't really
|
// really want a snippet, but without a `File`, we can't really
|
||||||
// render anything. It looks like this case currently happens
|
// render anything. It looks like this case currently happens
|
||||||
|
@ -248,20 +281,20 @@ impl std::fmt::Display for DisplayDiagnostic<'_> {
|
||||||
let msg = format!("{}: {}", self.diagnostic.id(), self.diagnostic.message());
|
let msg = format!("{}: {}", self.diagnostic.id(), self.diagnostic.message());
|
||||||
render(f, level.title(&msg))
|
render(f, level.title(&msg))
|
||||||
}
|
}
|
||||||
(Some(file), range) => {
|
Some(span) => {
|
||||||
let path = file.path(self.db).to_string();
|
let path = span.file.path(self.db).to_string();
|
||||||
let source = source_text(self.db, file);
|
let source = source_text(self.db, span.file);
|
||||||
let title = self.diagnostic.id().to_string();
|
let title = self.diagnostic.id().to_string();
|
||||||
let message = self.diagnostic.message();
|
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);
|
let snippet = Snippet::source(source.as_str()).origin(&path).line_start(1);
|
||||||
return render(f, level.title(&title).snippet(snippet));
|
return render(f, level.title(&title).snippet(snippet));
|
||||||
};
|
};
|
||||||
|
|
||||||
// The bits below are a simplified copy from
|
// The bits below are a simplified copy from
|
||||||
// `crates/ruff_linter/src/message/text.rs`.
|
// `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 source_code = SourceCode::new(source.as_str(), &index);
|
||||||
|
|
||||||
let content_start_index = source_code.line_index(range.start());
|
let content_start_index = source_code.line_index(range.start());
|
||||||
|
@ -315,12 +348,8 @@ where
|
||||||
(**self).message()
|
(**self).message()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn file(&self) -> Option<File> {
|
fn span(&self) -> Option<Span> {
|
||||||
(**self).file()
|
(**self).span()
|
||||||
}
|
|
||||||
|
|
||||||
fn range(&self) -> Option<TextRange> {
|
|
||||||
(**self).range()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn severity(&self) -> Severity {
|
fn severity(&self) -> Severity {
|
||||||
|
@ -340,12 +369,8 @@ where
|
||||||
(**self).message()
|
(**self).message()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn file(&self) -> Option<File> {
|
fn span(&self) -> Option<Span> {
|
||||||
(**self).file()
|
(**self).span()
|
||||||
}
|
|
||||||
|
|
||||||
fn range(&self) -> Option<TextRange> {
|
|
||||||
(**self).range()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn severity(&self) -> Severity {
|
fn severity(&self) -> Severity {
|
||||||
|
@ -362,12 +387,8 @@ impl Diagnostic for Box<dyn Diagnostic> {
|
||||||
(**self).message()
|
(**self).message()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn file(&self) -> Option<File> {
|
fn span(&self) -> Option<Span> {
|
||||||
(**self).file()
|
(**self).span()
|
||||||
}
|
|
||||||
|
|
||||||
fn range(&self) -> Option<TextRange> {
|
|
||||||
(**self).range()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn severity(&self) -> Severity {
|
fn severity(&self) -> Severity {
|
||||||
|
@ -384,12 +405,8 @@ impl Diagnostic for &'_ dyn Diagnostic {
|
||||||
(**self).message()
|
(**self).message()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn file(&self) -> Option<File> {
|
fn span(&self) -> Option<Span> {
|
||||||
(**self).file()
|
(**self).span()
|
||||||
}
|
|
||||||
|
|
||||||
fn range(&self) -> Option<TextRange> {
|
|
||||||
(**self).range()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn severity(&self) -> Severity {
|
fn severity(&self) -> Severity {
|
||||||
|
@ -406,12 +423,8 @@ impl Diagnostic for std::sync::Arc<dyn Diagnostic> {
|
||||||
(**self).message()
|
(**self).message()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn file(&self) -> Option<File> {
|
fn span(&self) -> Option<Span> {
|
||||||
(**self).file()
|
(**self).span()
|
||||||
}
|
|
||||||
|
|
||||||
fn range(&self) -> Option<TextRange> {
|
|
||||||
(**self).range()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn severity(&self) -> Severity {
|
fn severity(&self) -> Severity {
|
||||||
|
@ -440,12 +453,8 @@ impl Diagnostic for ParseDiagnostic {
|
||||||
self.error.error.to_string().into()
|
self.error.error.to_string().into()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn file(&self) -> Option<File> {
|
fn span(&self) -> Option<Span> {
|
||||||
Some(self.file)
|
Some(Span::from(self.file).with_range(self.error.location))
|
||||||
}
|
|
||||||
|
|
||||||
fn range(&self) -> Option<TextRange> {
|
|
||||||
Some(self.error.location)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn severity(&self) -> Severity {
|
fn severity(&self) -> Severity {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue