Replace row/column based Location with byte-offsets. (#3931)

This commit is contained in:
Micha Reiser 2023-04-26 20:11:02 +02:00 committed by GitHub
parent ee91598835
commit cab65b25da
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
418 changed files with 6203 additions and 7040 deletions

View file

@ -8,10 +8,12 @@ mod junit;
mod pylint;
mod text;
use ruff_text_size::{TextRange, TextSize};
use rustc_hash::FxHashMap;
use std::cmp::Ordering;
use std::collections::BTreeMap;
use std::io::Write;
use std::ops::Deref;
pub use azure::AzureEmitter;
pub use github::GithubEmitter;
@ -20,49 +22,64 @@ pub use grouped::GroupedEmitter;
pub use json::JsonEmitter;
pub use junit::JunitEmitter;
pub use pylint::PylintEmitter;
pub use rustpython_parser::ast::Location;
pub use text::TextEmitter;
use crate::jupyter::JupyterIndex;
use crate::registry::AsRule;
use ruff_diagnostics::{Diagnostic, DiagnosticKind, Fix};
use ruff_python_ast::source_code::SourceFile;
use ruff_python_ast::source_code::{SourceFile, SourceLocation};
#[derive(Debug, PartialEq, Eq)]
pub struct Message {
pub kind: DiagnosticKind,
pub location: Location,
pub end_location: Location,
pub range: TextRange,
pub fix: Fix,
pub file: SourceFile,
pub noqa_row: usize,
pub noqa_offset: TextSize,
}
impl Message {
pub fn from_diagnostic(diagnostic: Diagnostic, file: SourceFile, noqa_row: usize) -> Self {
pub fn from_diagnostic(
diagnostic: Diagnostic,
file: SourceFile,
noqa_offset: TextSize,
) -> Self {
Self {
range: diagnostic.range(),
kind: diagnostic.kind,
location: Location::new(diagnostic.location.row(), diagnostic.location.column() + 1),
end_location: Location::new(
diagnostic.end_location.row(),
diagnostic.end_location.column() + 1,
),
fix: diagnostic.fix,
file,
noqa_row,
noqa_offset,
}
}
pub fn filename(&self) -> &str {
self.file.name()
}
pub fn compute_start_location(&self) -> SourceLocation {
self.file.to_source_code().source_location(self.start())
}
pub fn compute_end_location(&self) -> SourceLocation {
self.file.to_source_code().source_location(self.end())
}
pub const fn start(&self) -> TextSize {
self.range.start()
}
pub const fn end(&self) -> TextSize {
self.range.end()
}
}
impl Ord for Message {
fn cmp(&self, other: &Self) -> Ordering {
(self.filename(), self.location.row(), self.location.column()).cmp(&(
(self.filename(), self.start(), self.kind.rule()).cmp(&(
other.filename(),
other.location.row(),
other.location.column(),
other.start(),
other.kind.rule(),
))
}
}
@ -73,13 +90,28 @@ impl PartialOrd for Message {
}
}
fn group_messages_by_filename(messages: &[Message]) -> BTreeMap<&str, Vec<&Message>> {
struct MessageWithLocation<'a> {
message: &'a Message,
start_location: SourceLocation,
}
impl Deref for MessageWithLocation<'_> {
type Target = Message;
fn deref(&self) -> &Self::Target {
self.message
}
}
fn group_messages_by_filename(messages: &[Message]) -> BTreeMap<&str, Vec<MessageWithLocation>> {
let mut grouped_messages = BTreeMap::default();
for message in messages {
grouped_messages
.entry(message.filename())
.or_insert_with(Vec::new)
.push(message);
.push(MessageWithLocation {
message,
start_location: message.compute_start_location(),
});
}
grouped_messages
}
@ -120,11 +152,11 @@ impl<'a> EmitterContext<'a> {
#[cfg(test)]
mod tests {
use crate::message::{Emitter, EmitterContext, Location, Message};
use crate::message::{Emitter, EmitterContext, Message};
use crate::rules::pyflakes::rules::{UndefinedName, UnusedImport, UnusedVariable};
use ruff_diagnostics::{Diagnostic, Edit, Fix};
use ruff_python_ast::source_code::SourceFileBuilder;
use ruff_python_ast::types::Range;
use ruff_text_size::{TextRange, TextSize};
use rustc_hash::FxHashMap;
pub(super) fn create_messages() -> Vec<Message> {
@ -148,20 +180,20 @@ def fibonacci(n):
context: None,
multiple: false,
},
Range::new(Location::new(1, 7), Location::new(1, 9)),
TextRange::new(TextSize::from(7), TextSize::from(9)),
);
let fib_source = SourceFileBuilder::new("fib.py").source_text(fib).finish();
let fib_source = SourceFileBuilder::new("fib.py", fib).finish();
let unused_variable = Diagnostic::new(
UnusedVariable {
name: "x".to_string(),
},
Range::new(Location::new(6, 4), Location::new(6, 5)),
TextRange::new(TextSize::from(94), TextSize::from(95)),
)
.with_fix(Fix::new(vec![Edit::deletion(
Location::new(6, 4),
Location::new(6, 9),
TextSize::from(94),
TextSize::from(99),
)]));
let file_2 = r#"if a == 1: pass"#;
@ -170,17 +202,18 @@ def fibonacci(n):
UndefinedName {
name: "a".to_string(),
},
Range::new(Location::new(1, 3), Location::new(1, 4)),
TextRange::new(TextSize::from(3), TextSize::from(4)),
);
let file_2_source = SourceFileBuilder::new("undef.py")
.source_text(file_2)
.finish();
let file_2_source = SourceFileBuilder::new("undef.py", file_2).finish();
let unused_import_start = unused_import.start();
let unused_variable_start = unused_variable.start();
let undefined_name_start = undefined_name.start();
vec![
Message::from_diagnostic(unused_import, fib_source.clone(), 1),
Message::from_diagnostic(unused_variable, fib_source, 1),
Message::from_diagnostic(undefined_name, file_2_source, 1),
Message::from_diagnostic(unused_import, fib_source.clone(), unused_import_start),
Message::from_diagnostic(unused_variable, fib_source, unused_variable_start),
Message::from_diagnostic(undefined_name, file_2_source, undefined_name_start),
]
}