Skip to content

Commit

Permalink
Store sorted edits
Browse files Browse the repository at this point in the history
  • Loading branch information
charliermarsh committed Jul 29, 2023
1 parent cd19da7 commit 4b1eaca
Show file tree
Hide file tree
Showing 6 changed files with 33 additions and 57 deletions.
16 changes: 6 additions & 10 deletions crates/ruff/src/autofix/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ fn apply_fixes<'a>(
) -> FixResult {
let mut output = String::with_capacity(locator.len());
let mut last_pos: Option<TextSize> = None;
let mut applied: BTreeSet<Edit> = BTreeSet::default();
let mut applied: BTreeSet<&Edit> = BTreeSet::default();
let mut isolated: FxHashSet<u32> = FxHashSet::default();
let mut fixed = FxHashMap::default();
let mut source_map = SourceMap::default();
Expand All @@ -59,11 +59,8 @@ fn apply_fixes<'a>(
})
.sorted_by(|(rule1, fix1), (rule2, fix2)| cmp_fix(*rule1, *rule2, fix1, fix2))
{
// Remove any edits that were applied as part of a previous fix.
let edits = fix.edits();

let mut first = true;
'inner: for edit in edits.to_sorted() {
'inner: for edit in fix.edits() {
// Skip any edits that were already applied.
if applied.contains(&edit) {
continue 'inner;
Expand Down Expand Up @@ -95,13 +92,13 @@ fn apply_fixes<'a>(
output.push_str(slice);

// Add the start source marker for the patch.
source_map.push_start_marker(&edit, output.text_len());
source_map.push_start_marker(edit, output.text_len());

// Add the patch itself.
output.push_str(edit.content().unwrap_or_default());

// Add the end source marker for the added patch.
source_map.push_end_marker(&edit, output.text_len());
source_map.push_end_marker(edit, output.text_len());

// Track that the edit was applied.
last_pos = Some(edit.end());
Expand All @@ -124,9 +121,8 @@ fn apply_fixes<'a>(

/// Compare two fixes.
fn cmp_fix(rule1: Rule, rule2: Rule, fix1: &Fix, fix2: &Fix) -> std::cmp::Ordering {
fix1.edits()
.min_start()
.cmp(&fix2.edits().min_start())
fix1.min_start()
.cmp(&fix2.min_start())
.then_with(|| match (&rule1, &rule2) {
// Apply `EndsInPeriod` fixes before `NewLineAfterLastParagraph` fixes.
(Rule::EndsInPeriod, Rule::NewLineAfterLastParagraph) => std::cmp::Ordering::Less,
Expand Down
2 changes: 1 addition & 1 deletion crates/ruff/src/message/diff.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ impl Display for Diff<'_> {
let mut output = String::with_capacity(self.source_code.source_text().len());
let mut last_end = TextSize::default();

for edit in self.fix.edits().to_sorted() {
for edit in self.fix.edits() {
output.push_str(
self.source_code
.slice(TextRange::new(last_end, edit.start())),
Expand Down
2 changes: 1 addition & 1 deletion crates/ruff/src/message/json.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ pub(crate) fn message_to_json_value(message: &Message) -> Value {
json!({
"applicability": fix.applicability(),
"message": message.kind.suggestion.as_deref(),
"edits": &ExpandedEdits { edits: &fix.edits(), source_code: &source_code },
"edits": &ExpandedEdits { edits: fix.edits(), source_code: &source_code },
})
});

Expand Down
36 changes: 2 additions & 34 deletions crates/ruff_diagnostics/src/edit.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
use std::cmp::Ordering;
use std::ops::Deref;

use ruff_text_size::{TextRange, TextSize};
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};

use ruff_text_size::{TextRange, TextSize};

/// A text edit to be applied to a source file. Inserts, deletes, or replaces
/// content at a given location.
#[derive(Clone, Debug, PartialEq, Eq)]
Expand Down Expand Up @@ -145,35 +145,3 @@ impl EditOperationKind {
matches!(self, EditOperationKind::Replacement)
}
}

/// A collection of [`Edit`] elements to be applied to a source file.
#[derive(Debug, Clone)]
pub struct Edits<'a>(&'a [Edit]);

impl<'a> Edits<'a> {
pub(crate) fn new(edits: &'a [Edit]) -> Self {
Self(edits)
}

/// Return the [`TextSize`] of the first [`Edit`] in the [`Fix`], as determined by the
/// start position of the [`Edit`].
pub fn min_start(&self) -> Option<TextSize> {
self.0.iter().map(Edit::start).min()
}

/// Return an iterator over the [`Edit`] elements in the [`Fix`], sorted by their start
/// position.
pub fn to_sorted(&self) -> impl IntoIterator<Item = Edit> {
let mut edits = self.to_vec();
edits.sort_by_key(Edit::start);
edits.into_iter()
}
}

impl<'a> Deref for Edits<'a> {
type Target = [Edit];

fn deref(&self) -> &Self::Target {
self.0
}
}
30 changes: 21 additions & 9 deletions crates/ruff_diagnostics/src/fix.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};

use crate::edit::{Edit, Edits};
use ruff_text_size::TextSize;

use crate::edit::Edit;

/// Indicates confidence in the correctness of a suggested fix.
#[derive(Default, Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
Expand Down Expand Up @@ -41,8 +43,11 @@ pub enum IsolationLevel {
#[derive(Debug, PartialEq, Eq, Clone)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Fix {
/// The [`Edit`] elements to be applied, sorted by [`TextSize`].
edits: Vec<Edit>,
/// The [`Applicability`] of the fix.
applicability: Applicability,
/// The [`IsolationLevel`] of the fix.
isolation_level: IsolationLevel,
}

Expand Down Expand Up @@ -82,8 +87,10 @@ impl Fix {

/// Create a new [`Fix`] with [automatic applicability](Applicability::Automatic) from multiple [`Edit`] elements.
pub fn automatic_edits(edit: Edit, rest: impl IntoIterator<Item = Edit>) -> Self {
let mut edits: Vec<Edit> = std::iter::once(edit).chain(rest).collect();
edits.sort_by_key(Edit::start);
Self {
edits: std::iter::once(edit).chain(rest).collect(),
edits,
applicability: Applicability::Automatic,
isolation_level: IsolationLevel::default(),
}
Expand All @@ -100,8 +107,10 @@ impl Fix {

/// Create a new [`Fix`] with [suggested applicability](Applicability::Suggested) from multiple [`Edit`] elements.
pub fn suggested_edits(edit: Edit, rest: impl IntoIterator<Item = Edit>) -> Self {
let mut edits: Vec<Edit> = std::iter::once(edit).chain(rest).collect();
edits.sort_by_key(Edit::start);
Self {
edits: std::iter::once(edit).chain(rest).collect(),
edits,
applicability: Applicability::Suggested,
isolation_level: IsolationLevel::default(),
}
Expand All @@ -118,20 +127,23 @@ impl Fix {

/// Create a new [`Fix`] with [manual applicability](Applicability::Manual) from multiple [`Edit`] elements.
pub fn manual_edits(edit: Edit, rest: impl IntoIterator<Item = Edit>) -> Self {
let mut edits: Vec<Edit> = std::iter::once(edit).chain(rest).collect();
edits.sort_by_key(Edit::start);
Self {
edits: std::iter::once(edit).chain(rest).collect(),
edits,
applicability: Applicability::Manual,
isolation_level: IsolationLevel::default(),
}
}

/// Return a slice of the [`Edit`] elements in the [`Fix`].
pub fn edits(&self) -> Edits {
Edits::new(&self.edits)
/// Return the [`TextSize`] of the first [`Edit`] in the [`Fix`].
pub fn min_start(&self) -> Option<TextSize> {
self.edits.first().map(Edit::start)
}

pub fn into_edits(self) -> Vec<Edit> {
self.edits
/// Return a slice of the [`Edit`] elements in the [`Fix`], sorted by their [`TextSize`].
pub fn edits(&self) -> &[Edit] {
&self.edits
}

/// Return the [`Applicability`] of the [`Fix`].
Expand Down
4 changes: 2 additions & 2 deletions crates/ruff_wasm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -245,8 +245,8 @@ impl Workspace {
fix: message.fix.map(|fix| ExpandedFix {
message: message.kind.suggestion,
edits: fix
.into_edits()
.into_iter()
.edits()
.iter()
.map(|edit| ExpandedEdit {
location: source_code.source_location(edit.start()),
end_location: source_code.source_location(edit.end()),
Expand Down

0 comments on commit 4b1eaca

Please sign in to comment.