Skip to content

Commit 054e206

Browse files
bors[bot]Veykril
andauthored
Merge #7272
7272: Group file source edits by FileId r=matklad a=Veykril Co-authored-by: Lukas Wirth <lukastw97@gmail.com>
2 parents dc48de2 + d509532 commit 054e206

File tree

16 files changed

+240
-267
lines changed

16 files changed

+240
-267
lines changed

crates/assists/src/assist_context.rs

Lines changed: 8 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use ide_db::{
1010
};
1111
use ide_db::{
1212
label::Label,
13-
source_change::{FileSystemEdit, SourceChange, SourceFileEdit},
13+
source_change::{FileSystemEdit, SourceChange},
1414
RootDatabase,
1515
};
1616
use syntax::{
@@ -180,20 +180,12 @@ impl Assists {
180180
pub(crate) struct AssistBuilder {
181181
edit: TextEditBuilder,
182182
file_id: FileId,
183-
is_snippet: bool,
184-
source_file_edits: Vec<SourceFileEdit>,
185-
file_system_edits: Vec<FileSystemEdit>,
183+
source_change: SourceChange,
186184
}
187185

188186
impl AssistBuilder {
189187
pub(crate) fn new(file_id: FileId) -> AssistBuilder {
190-
AssistBuilder {
191-
edit: TextEdit::builder(),
192-
file_id,
193-
is_snippet: false,
194-
source_file_edits: Vec::default(),
195-
file_system_edits: Vec::default(),
196-
}
188+
AssistBuilder { edit: TextEdit::builder(), file_id, source_change: SourceChange::default() }
197189
}
198190

199191
pub(crate) fn edit_file(&mut self, file_id: FileId) {
@@ -204,15 +196,7 @@ impl AssistBuilder {
204196
fn commit(&mut self) {
205197
let edit = mem::take(&mut self.edit).finish();
206198
if !edit.is_empty() {
207-
match self.source_file_edits.binary_search_by_key(&self.file_id, |edit| edit.file_id) {
208-
Ok(idx) => self.source_file_edits[idx]
209-
.edit
210-
.union(edit)
211-
.expect("overlapping edits for same file"),
212-
Err(idx) => self
213-
.source_file_edits
214-
.insert(idx, SourceFileEdit { file_id: self.file_id, edit }),
215-
}
199+
self.source_change.insert_source_edit(self.file_id, edit);
216200
}
217201
}
218202

@@ -231,7 +215,7 @@ impl AssistBuilder {
231215
offset: TextSize,
232216
snippet: impl Into<String>,
233217
) {
234-
self.is_snippet = true;
218+
self.source_change.is_snippet = true;
235219
self.insert(offset, snippet);
236220
}
237221
/// Replaces specified `range` of text with a given string.
@@ -245,7 +229,7 @@ impl AssistBuilder {
245229
range: TextRange,
246230
snippet: impl Into<String>,
247231
) {
248-
self.is_snippet = true;
232+
self.source_change.is_snippet = true;
249233
self.replace(range, snippet);
250234
}
251235
pub(crate) fn replace_ast<N: AstNode>(&mut self, old: N, new: N) {
@@ -260,15 +244,11 @@ impl AssistBuilder {
260244
pub(crate) fn create_file(&mut self, dst: AnchoredPathBuf, content: impl Into<String>) {
261245
let file_system_edit =
262246
FileSystemEdit::CreateFile { dst: dst.clone(), initial_contents: content.into() };
263-
self.file_system_edits.push(file_system_edit);
247+
self.source_change.push_file_system_edit(file_system_edit);
264248
}
265249

266250
fn finish(mut self) -> SourceChange {
267251
self.commit();
268-
SourceChange {
269-
source_file_edits: mem::take(&mut self.source_file_edits),
270-
file_system_edits: mem::take(&mut self.file_system_edits),
271-
is_snippet: self.is_snippet,
272-
}
252+
mem::take(&mut self.source_change)
273253
}
274254
}

crates/assists/src/tests.rs

Lines changed: 17 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -80,10 +80,8 @@ fn check_doc_test(assist_id: &str, before: &str, after: &str) {
8080
let actual = {
8181
let source_change = assist.source_change.unwrap();
8282
let mut actual = before;
83-
for source_file_edit in source_change.source_file_edits {
84-
if source_file_edit.file_id == file_id {
85-
source_file_edit.edit.apply(&mut actual)
86-
}
83+
if let Some(source_file_edit) = source_change.get_source_edit(file_id) {
84+
source_file_edit.apply(&mut actual);
8785
}
8886
actual
8987
};
@@ -116,37 +114,33 @@ fn check(handler: Handler, before: &str, expected: ExpectedResult, assist_label:
116114

117115
match (assist, expected) {
118116
(Some(assist), ExpectedResult::After(after)) => {
119-
let mut source_change = assist.source_change.unwrap();
117+
let source_change = assist.source_change.unwrap();
120118
assert!(!source_change.source_file_edits.is_empty());
121119
let skip_header = source_change.source_file_edits.len() == 1
122120
&& source_change.file_system_edits.len() == 0;
123-
source_change.source_file_edits.sort_by_key(|it| it.file_id);
124121

125122
let mut buf = String::new();
126-
for source_file_edit in source_change.source_file_edits {
127-
let mut text = db.file_text(source_file_edit.file_id).as_ref().to_owned();
128-
source_file_edit.edit.apply(&mut text);
123+
for (file_id, edit) in source_change.source_file_edits {
124+
let mut text = db.file_text(file_id).as_ref().to_owned();
125+
edit.apply(&mut text);
129126
if !skip_header {
130-
let sr = db.file_source_root(source_file_edit.file_id);
127+
let sr = db.file_source_root(file_id);
131128
let sr = db.source_root(sr);
132-
let path = sr.path_for_file(&source_file_edit.file_id).unwrap();
129+
let path = sr.path_for_file(&file_id).unwrap();
133130
format_to!(buf, "//- {}\n", path)
134131
}
135132
buf.push_str(&text);
136133
}
137134

138-
for file_system_edit in source_change.file_system_edits.clone() {
139-
match file_system_edit {
140-
FileSystemEdit::CreateFile { dst, initial_contents } => {
141-
let sr = db.file_source_root(dst.anchor);
142-
let sr = db.source_root(sr);
143-
let mut base = sr.path_for_file(&dst.anchor).unwrap().clone();
144-
base.pop();
145-
let created_file_path = format!("{}{}", base.to_string(), &dst.path[1..]);
146-
format_to!(buf, "//- {}\n", created_file_path);
147-
buf.push_str(&initial_contents);
148-
}
149-
_ => (),
135+
for file_system_edit in source_change.file_system_edits {
136+
if let FileSystemEdit::CreateFile { dst, initial_contents } = file_system_edit {
137+
let sr = db.file_source_root(dst.anchor);
138+
let sr = db.source_root(sr);
139+
let mut base = sr.path_for_file(&dst.anchor).unwrap().clone();
140+
base.pop();
141+
let created_file_path = format!("{}{}", base.to_string(), &dst.path[1..]);
142+
format_to!(buf, "//- {}\n", created_file_path);
143+
buf.push_str(&initial_contents);
150144
}
151145
}
152146

crates/ide/src/diagnostics.rs

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,7 @@ use hir::{
1313
diagnostics::{Diagnostic as _, DiagnosticCode, DiagnosticSinkBuilder},
1414
Semantics,
1515
};
16-
use ide_db::base_db::SourceDatabase;
17-
use ide_db::RootDatabase;
16+
use ide_db::{base_db::SourceDatabase, RootDatabase};
1817
use itertools::Itertools;
1918
use rustc_hash::FxHashSet;
2019
use syntax::{
@@ -23,7 +22,7 @@ use syntax::{
2322
};
2423
use text_edit::TextEdit;
2524

26-
use crate::{FileId, Label, SourceChange, SourceFileEdit};
25+
use crate::{FileId, Label, SourceChange};
2726

2827
use self::fixes::DiagnosticWithFix;
2928

@@ -220,7 +219,7 @@ fn check_unnecessary_braces_in_use_statement(
220219
Diagnostic::hint(use_range, "Unnecessary braces in use statement".to_string())
221220
.with_fix(Some(Fix::new(
222221
"Remove unnecessary braces",
223-
SourceFileEdit { file_id, edit }.into(),
222+
SourceChange::from_text_edit(file_id, edit),
224223
use_range,
225224
))),
226225
);
@@ -265,13 +264,11 @@ mod tests {
265264
.unwrap();
266265
let fix = diagnostic.fix.unwrap();
267266
let actual = {
268-
let file_id = fix.source_change.source_file_edits.first().unwrap().file_id;
267+
let file_id = *fix.source_change.source_file_edits.keys().next().unwrap();
269268
let mut actual = analysis.file_text(file_id).unwrap().to_string();
270269

271-
// Go from the last one to the first one, so that ranges won't be affected by previous edits.
272-
// FIXME: https://github.com/rust-analyzer/rust-analyzer/issues/4901#issuecomment-644675309
273-
for edit in fix.source_change.source_file_edits.iter().rev() {
274-
edit.edit.apply(&mut actual);
270+
for edit in fix.source_change.source_file_edits.values() {
271+
edit.apply(&mut actual);
275272
}
276273
actual
277274
};
@@ -616,7 +613,7 @@ fn test_fn() {
616613
Fix {
617614
label: "Create module",
618615
source_change: SourceChange {
619-
source_file_edits: [],
616+
source_file_edits: {},
620617
file_system_edits: [
621618
CreateFile {
622619
dst: AnchoredPathBuf {

crates/ide/src/diagnostics/field_shorthand.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
//! Suggests shortening `Foo { field: field }` to `Foo { field }` in both
22
//! expressions and patterns.
33
4-
use ide_db::base_db::FileId;
5-
use ide_db::source_change::SourceFileEdit;
4+
use ide_db::{base_db::FileId, source_change::SourceChange};
65
use syntax::{ast, match_ast, AstNode, SyntaxNode};
76
use text_edit::TextEdit;
87

@@ -50,7 +49,7 @@ fn check_expr_field_shorthand(
5049
Diagnostic::hint(field_range, "Shorthand struct initialization".to_string()).with_fix(
5150
Some(Fix::new(
5251
"Use struct shorthand initialization",
53-
SourceFileEdit { file_id, edit }.into(),
52+
SourceChange::from_text_edit(file_id, edit),
5453
field_range,
5554
)),
5655
),
@@ -89,7 +88,7 @@ fn check_pat_field_shorthand(
8988
acc.push(Diagnostic::hint(field_range, "Shorthand struct pattern".to_string()).with_fix(
9089
Some(Fix::new(
9190
"Use struct field shorthand",
92-
SourceFileEdit { file_id, edit }.into(),
91+
SourceChange::from_text_edit(file_id, edit),
9392
field_range,
9493
)),
9594
));

crates/ide/src/diagnostics/fixes.rs

Lines changed: 10 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@ use hir::{
88
},
99
HasSource, HirDisplay, InFile, Semantics, VariantDef,
1010
};
11-
use ide_db::base_db::{AnchoredPathBuf, FileId};
1211
use ide_db::{
13-
source_change::{FileSystemEdit, SourceFileEdit},
12+
base_db::{AnchoredPathBuf, FileId},
13+
source_change::{FileSystemEdit, SourceChange},
1414
RootDatabase,
1515
};
1616
use syntax::{
@@ -88,7 +88,7 @@ impl DiagnosticWithFix for MissingFields {
8888
};
8989
Some(Fix::new(
9090
"Fill struct fields",
91-
SourceFileEdit { file_id: self.file.original_file(sema.db), edit }.into(),
91+
SourceChange::from_text_edit(self.file.original_file(sema.db), edit),
9292
sema.original_range(&field_list_parent.syntax()).range,
9393
))
9494
}
@@ -101,8 +101,7 @@ impl DiagnosticWithFix for MissingOkOrSomeInTailExpr {
101101
let tail_expr_range = tail_expr.syntax().text_range();
102102
let replacement = format!("{}({})", self.required, tail_expr.syntax());
103103
let edit = TextEdit::replace(tail_expr_range, replacement);
104-
let source_change =
105-
SourceFileEdit { file_id: self.file.original_file(sema.db), edit }.into();
104+
let source_change = SourceChange::from_text_edit(self.file.original_file(sema.db), edit);
106105
let name = if self.required == "Ok" { "Wrap with Ok" } else { "Wrap with Some" };
107106
Some(Fix::new(name, source_change, tail_expr_range))
108107
}
@@ -122,8 +121,7 @@ impl DiagnosticWithFix for RemoveThisSemicolon {
122121
.text_range();
123122

124123
let edit = TextEdit::delete(semicolon);
125-
let source_change =
126-
SourceFileEdit { file_id: self.file.original_file(sema.db), edit }.into();
124+
let source_change = SourceChange::from_text_edit(self.file.original_file(sema.db), edit);
127125

128126
Some(Fix::new("Remove this semicolon", source_change, semicolon))
129127
}
@@ -204,15 +202,11 @@ fn missing_record_expr_field_fix(
204202
new_field = format!(",{}", new_field);
205203
}
206204

207-
let source_change = SourceFileEdit {
208-
file_id: def_file_id,
209-
edit: TextEdit::insert(last_field_syntax.text_range().end(), new_field),
210-
};
211-
return Some(Fix::new(
212-
"Create field",
213-
source_change.into(),
214-
record_expr_field.syntax().text_range(),
215-
));
205+
let source_change = SourceChange::from_text_edit(
206+
def_file_id,
207+
TextEdit::insert(last_field_syntax.text_range().end(), new_field),
208+
);
209+
return Some(Fix::new("Create field", source_change, record_expr_field.syntax().text_range()));
216210

217211
fn record_field_list(field_def_list: ast::FieldList) -> Option<ast::RecordFieldList> {
218212
match field_def_list {

crates/ide/src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ pub use ide_db::{
9898
label::Label,
9999
line_index::{LineCol, LineIndex},
100100
search::SearchScope,
101-
source_change::{FileSystemEdit, SourceChange, SourceFileEdit},
101+
source_change::{FileSystemEdit, SourceChange},
102102
symbol_index::Query,
103103
RootDatabase,
104104
};
@@ -553,7 +553,7 @@ impl Analysis {
553553
let rule: ssr::SsrRule = query.parse()?;
554554
let mut match_finder = ssr::MatchFinder::in_context(db, resolve_context, selections);
555555
match_finder.add_rule(rule)?;
556-
let edits = if parse_only { Vec::new() } else { match_finder.edits() };
556+
let edits = if parse_only { Default::default() } else { match_finder.edits() };
557557
Ok(SourceChange::from(edits))
558558
})
559559
}

0 commit comments

Comments
 (0)