From f51457a643b768794092f73add6dda4aecd400a1 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Thu, 14 Jan 2021 18:35:22 +0100 Subject: Group file source edits by FileId --- crates/ide/src/diagnostics.rs | 19 ++-- crates/ide/src/diagnostics/field_shorthand.rs | 7 +- crates/ide/src/diagnostics/fixes.rs | 18 ++-- crates/ide/src/lib.rs | 4 +- crates/ide/src/references/rename.rs | 138 +++++++++++--------------- crates/ide/src/typing.rs | 9 +- 6 files changed, 86 insertions(+), 109 deletions(-) (limited to 'crates/ide') diff --git a/crates/ide/src/diagnostics.rs b/crates/ide/src/diagnostics.rs index 055c0a79c..a43188fb0 100644 --- a/crates/ide/src/diagnostics.rs +++ b/crates/ide/src/diagnostics.rs @@ -13,8 +13,7 @@ use hir::{ diagnostics::{Diagnostic as _, DiagnosticCode, DiagnosticSinkBuilder}, Semantics, }; -use ide_db::base_db::SourceDatabase; -use ide_db::RootDatabase; +use ide_db::{base_db::SourceDatabase, source_change::SourceFileEdits, RootDatabase}; use itertools::Itertools; use rustc_hash::FxHashSet; use syntax::{ @@ -23,7 +22,7 @@ use syntax::{ }; use text_edit::TextEdit; -use crate::{FileId, Label, SourceChange, SourceFileEdit}; +use crate::{FileId, Label, SourceChange}; use self::fixes::DiagnosticWithFix; @@ -220,7 +219,7 @@ fn check_unnecessary_braces_in_use_statement( Diagnostic::hint(use_range, "Unnecessary braces in use statement".to_string()) .with_fix(Some(Fix::new( "Remove unnecessary braces", - SourceFileEdit { file_id, edit }.into(), + SourceFileEdits::from_text_edit(file_id, edit).into(), use_range, ))), ); @@ -265,13 +264,11 @@ mod tests { .unwrap(); let fix = diagnostic.fix.unwrap(); let actual = { - let file_id = fix.source_change.source_file_edits.first().unwrap().file_id; + let file_id = *fix.source_change.source_file_edits.edits.keys().next().unwrap(); let mut actual = analysis.file_text(file_id).unwrap().to_string(); - // Go from the last one to the first one, so that ranges won't be affected by previous edits. - // FIXME: https://github.com/rust-analyzer/rust-analyzer/issues/4901#issuecomment-644675309 - for edit in fix.source_change.source_file_edits.iter().rev() { - edit.edit.apply(&mut actual); + for edit in fix.source_change.source_file_edits.edits.values() { + edit.apply(&mut actual); } actual }; @@ -616,7 +613,9 @@ fn test_fn() { Fix { label: "Create module", source_change: SourceChange { - source_file_edits: [], + source_file_edits: SourceFileEdits { + edits: {}, + }, file_system_edits: [ CreateFile { dst: AnchoredPathBuf { diff --git a/crates/ide/src/diagnostics/field_shorthand.rs b/crates/ide/src/diagnostics/field_shorthand.rs index 16c6ea827..f4ec51b64 100644 --- a/crates/ide/src/diagnostics/field_shorthand.rs +++ b/crates/ide/src/diagnostics/field_shorthand.rs @@ -1,8 +1,7 @@ //! Suggests shortening `Foo { field: field }` to `Foo { field }` in both //! expressions and patterns. -use ide_db::base_db::FileId; -use ide_db::source_change::SourceFileEdit; +use ide_db::{base_db::FileId, source_change::SourceFileEdits}; use syntax::{ast, match_ast, AstNode, SyntaxNode}; use text_edit::TextEdit; @@ -50,7 +49,7 @@ fn check_expr_field_shorthand( Diagnostic::hint(field_range, "Shorthand struct initialization".to_string()).with_fix( Some(Fix::new( "Use struct shorthand initialization", - SourceFileEdit { file_id, edit }.into(), + SourceFileEdits::from_text_edit(file_id, edit).into(), field_range, )), ), @@ -89,7 +88,7 @@ fn check_pat_field_shorthand( acc.push(Diagnostic::hint(field_range, "Shorthand struct pattern".to_string()).with_fix( Some(Fix::new( "Use struct field shorthand", - SourceFileEdit { file_id, edit }.into(), + SourceFileEdits::from_text_edit(file_id, edit).into(), field_range, )), )); diff --git a/crates/ide/src/diagnostics/fixes.rs b/crates/ide/src/diagnostics/fixes.rs index d7ad88ed5..b04964ccd 100644 --- a/crates/ide/src/diagnostics/fixes.rs +++ b/crates/ide/src/diagnostics/fixes.rs @@ -8,9 +8,9 @@ use hir::{ }, HasSource, HirDisplay, InFile, Semantics, VariantDef, }; -use ide_db::base_db::{AnchoredPathBuf, FileId}; use ide_db::{ - source_change::{FileSystemEdit, SourceFileEdit}, + base_db::{AnchoredPathBuf, FileId}, + source_change::{FileSystemEdit, SourceFileEdits}, RootDatabase, }; use syntax::{ @@ -88,7 +88,7 @@ impl DiagnosticWithFix for MissingFields { }; Some(Fix::new( "Fill struct fields", - SourceFileEdit { file_id: self.file.original_file(sema.db), edit }.into(), + SourceFileEdits::from_text_edit(self.file.original_file(sema.db), edit).into(), sema.original_range(&field_list_parent.syntax()).range, )) } @@ -102,7 +102,7 @@ impl DiagnosticWithFix for MissingOkOrSomeInTailExpr { let replacement = format!("{}({})", self.required, tail_expr.syntax()); let edit = TextEdit::replace(tail_expr_range, replacement); let source_change = - SourceFileEdit { file_id: self.file.original_file(sema.db), edit }.into(); + SourceFileEdits::from_text_edit(self.file.original_file(sema.db), edit).into(); let name = if self.required == "Ok" { "Wrap with Ok" } else { "Wrap with Some" }; Some(Fix::new(name, source_change, tail_expr_range)) } @@ -123,7 +123,7 @@ impl DiagnosticWithFix for RemoveThisSemicolon { let edit = TextEdit::delete(semicolon); let source_change = - SourceFileEdit { file_id: self.file.original_file(sema.db), edit }.into(); + SourceFileEdits::from_text_edit(self.file.original_file(sema.db), edit).into(); Some(Fix::new("Remove this semicolon", source_change, semicolon)) } @@ -204,10 +204,10 @@ fn missing_record_expr_field_fix( new_field = format!(",{}", new_field); } - let source_change = SourceFileEdit { - file_id: def_file_id, - edit: TextEdit::insert(last_field_syntax.text_range().end(), new_field), - }; + let source_change = SourceFileEdits::from_text_edit( + def_file_id, + TextEdit::insert(last_field_syntax.text_range().end(), new_field), + ); return Some(Fix::new( "Create field", source_change.into(), diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs index 1e03832ec..110920e58 100644 --- a/crates/ide/src/lib.rs +++ b/crates/ide/src/lib.rs @@ -98,7 +98,7 @@ pub use ide_db::{ label::Label, line_index::{LineCol, LineIndex}, search::SearchScope, - source_change::{FileSystemEdit, SourceChange, SourceFileEdit}, + source_change::{FileSystemEdit, SourceChange, SourceFileEdits}, symbol_index::Query, RootDatabase, }; @@ -553,7 +553,7 @@ impl Analysis { let rule: ssr::SsrRule = query.parse()?; let mut match_finder = ssr::MatchFinder::in_context(db, resolve_context, selections); match_finder.add_rule(rule)?; - let edits = if parse_only { Vec::new() } else { match_finder.edits() }; + let edits = if parse_only { Default::default() } else { match_finder.edits() }; Ok(SourceChange::from(edits)) }) } diff --git a/crates/ide/src/references/rename.rs b/crates/ide/src/references/rename.rs index c3ae568c2..cd9c7c7e5 100644 --- a/crates/ide/src/references/rename.rs +++ b/crates/ide/src/references/rename.rs @@ -21,7 +21,7 @@ use text_edit::TextEdit; use crate::{ FilePosition, FileSystemEdit, RangeInfo, ReferenceKind, ReferenceSearchResult, SourceChange, - SourceFileEdit, TextRange, TextSize, + SourceFileEdits, TextRange, TextSize, }; type RenameResult = Result; @@ -58,7 +58,7 @@ pub(crate) fn prepare_rename( rename_self_to_param(&sema, position, self_token, "dummy") } else { let RangeInfo { range, .. } = find_all_refs(&sema, position)?; - Ok(RangeInfo::new(range, SourceChange::from(vec![]))) + Ok(RangeInfo::new(range, SourceChange::default())) } .map(|info| RangeInfo::new(info.range, ())) } @@ -176,7 +176,7 @@ fn source_edit_from_references( file_id: FileId, references: &[FileReference], new_name: &str, -) -> SourceFileEdit { +) -> (FileId, TextEdit) { let mut edit = TextEdit::builder(); for reference in references { let mut replacement_text = String::new(); @@ -209,8 +209,7 @@ fn source_edit_from_references( }; edit.replace(range, replacement_text); } - - SourceFileEdit { file_id, edit: edit.finish() } + (file_id, edit.finish()) } fn edit_text_range_for_record_field_expr_or_pat( @@ -250,7 +249,7 @@ fn rename_mod( if IdentifierKind::Ident != check_identifier(new_name)? { bail!("Invalid name `{0}`: cannot rename module to {0}", new_name); } - let mut source_file_edits = Vec::new(); + let mut source_file_edits = SourceFileEdits::default(); let mut file_system_edits = Vec::new(); let src = module.definition_source(sema.db); @@ -273,11 +272,8 @@ fn rename_mod( if let Some(src) = module.declaration_source(sema.db) { let file_id = src.file_id.original_file(sema.db); let name = src.value.name().unwrap(); - let edit = SourceFileEdit { - file_id, - edit: TextEdit::replace(name.syntax().text_range(), new_name.into()), - }; - source_file_edits.push(edit); + source_file_edits + .insert(file_id, TextEdit::replace(name.syntax().text_range(), new_name.into())); } let RangeInfo { range, info: refs } = find_all_refs(sema, position)?; @@ -335,20 +331,13 @@ fn rename_to_self( let RangeInfo { range, info: refs } = find_all_refs(sema, position)?; - let mut edits = refs - .references() - .iter() - .map(|(&file_id, references)| { - source_edit_from_references(sema, file_id, references, "self") - }) - .collect::>(); + let mut edits = SourceFileEdits::default(); + edits.extend(refs.references().iter().map(|(&file_id, references)| { + source_edit_from_references(sema, file_id, references, "self") + })); + edits.insert(position.file_id, TextEdit::replace(param_range, String::from(self_param))); - edits.push(SourceFileEdit { - file_id: position.file_id, - edit: TextEdit::replace(param_range, String::from(self_param)), - }); - - Ok(RangeInfo::new(range, SourceChange::from(edits))) + Ok(RangeInfo::new(range, edits.into())) } fn text_edit_from_self_param( @@ -402,7 +391,7 @@ fn rename_self_to_param( .ok_or_else(|| format_err!("No surrounding method declaration found"))?; let search_range = fn_def.syntax().text_range(); - let mut edits: Vec = vec![]; + let mut edits = SourceFileEdits::default(); for (idx, _) in text.match_indices("self") { let offset: TextSize = idx.try_into().unwrap(); @@ -416,7 +405,7 @@ fn rename_self_to_param( } else { TextEdit::replace(usage.text_range(), String::from(new_name)) }; - edits.push(SourceFileEdit { file_id: position.file_id, edit }); + edits.insert(position.file_id, edit); } } @@ -427,7 +416,7 @@ fn rename_self_to_param( let range = ast::SelfParam::cast(self_token.parent()) .map_or(self_token.text_range(), |p| p.syntax().text_range()); - Ok(RangeInfo::new(range, SourceChange::from(edits))) + Ok(RangeInfo::new(range, edits.into())) } fn rename_reference( @@ -464,14 +453,12 @@ fn rename_reference( (IdentifierKind::Ident, _) | (IdentifierKind::Underscore, _) => mark::hit!(rename_ident), } - let edit = refs - .into_iter() - .map(|(file_id, references)| { - source_edit_from_references(sema, file_id, &references, new_name) - }) - .collect::>(); + let mut edits = SourceFileEdits::default(); + edits.extend(refs.into_iter().map(|(file_id, references)| { + source_edit_from_references(sema, file_id, &references, new_name) + })); - Ok(RangeInfo::new(range, SourceChange::from(edit))) + Ok(RangeInfo::new(range, edits.into())) } #[cfg(test)] @@ -493,9 +480,9 @@ mod tests { Ok(source_change) => { let mut text_edit_builder = TextEdit::builder(); let mut file_id: Option = None; - for edit in source_change.info.source_file_edits { - file_id = Some(edit.file_id); - for indel in edit.edit.into_iter() { + for edit in source_change.info.source_file_edits.edits { + file_id = Some(edit.0); + for indel in edit.1.into_iter() { text_edit_builder.replace(indel.delete, indel.insert); } } @@ -895,12 +882,11 @@ mod foo$0; RangeInfo { range: 4..7, info: SourceChange { - source_file_edits: [ - SourceFileEdit { - file_id: FileId( + source_file_edits: SourceFileEdits { + edits: { + FileId( 1, - ), - edit: TextEdit { + ): TextEdit { indels: [ Indel { insert: "foo2", @@ -909,7 +895,7 @@ mod foo$0; ], }, }, - ], + }, file_system_edits: [ MoveFile { src: FileId( @@ -950,12 +936,11 @@ use crate::foo$0::FooContent; RangeInfo { range: 11..14, info: SourceChange { - source_file_edits: [ - SourceFileEdit { - file_id: FileId( + source_file_edits: SourceFileEdits { + edits: { + FileId( 0, - ), - edit: TextEdit { + ): TextEdit { indels: [ Indel { insert: "quux", @@ -963,12 +948,9 @@ use crate::foo$0::FooContent; }, ], }, - }, - SourceFileEdit { - file_id: FileId( + FileId( 2, - ), - edit: TextEdit { + ): TextEdit { indels: [ Indel { insert: "quux", @@ -977,7 +959,7 @@ use crate::foo$0::FooContent; ], }, }, - ], + }, file_system_edits: [ MoveFile { src: FileId( @@ -1012,12 +994,11 @@ mod fo$0o; RangeInfo { range: 4..7, info: SourceChange { - source_file_edits: [ - SourceFileEdit { - file_id: FileId( + source_file_edits: SourceFileEdits { + edits: { + FileId( 0, - ), - edit: TextEdit { + ): TextEdit { indels: [ Indel { insert: "foo2", @@ -1026,7 +1007,7 @@ mod fo$0o; ], }, }, - ], + }, file_system_edits: [ MoveFile { src: FileId( @@ -1062,12 +1043,11 @@ mod outer { mod fo$0o; } RangeInfo { range: 16..19, info: SourceChange { - source_file_edits: [ - SourceFileEdit { - file_id: FileId( + source_file_edits: SourceFileEdits { + edits: { + FileId( 0, - ), - edit: TextEdit { + ): TextEdit { indels: [ Indel { insert: "bar", @@ -1076,7 +1056,7 @@ mod outer { mod fo$0o; } ], }, }, - ], + }, file_system_edits: [ MoveFile { src: FileId( @@ -1135,34 +1115,30 @@ pub mod foo$0; RangeInfo { range: 8..11, info: SourceChange { - source_file_edits: [ - SourceFileEdit { - file_id: FileId( - 1, - ), - edit: TextEdit { + source_file_edits: SourceFileEdits { + edits: { + FileId( + 0, + ): TextEdit { indels: [ Indel { insert: "foo2", - delete: 8..11, + delete: 27..30, }, ], }, - }, - SourceFileEdit { - file_id: FileId( - 0, - ), - edit: TextEdit { + FileId( + 1, + ): TextEdit { indels: [ Indel { insert: "foo2", - delete: 27..30, + delete: 8..11, }, ], }, }, - ], + }, file_system_edits: [ MoveFile { src: FileId( diff --git a/crates/ide/src/typing.rs b/crates/ide/src/typing.rs index 88c905003..b3fc32645 100644 --- a/crates/ide/src/typing.rs +++ b/crates/ide/src/typing.rs @@ -15,8 +15,11 @@ mod on_enter; -use ide_db::base_db::{FilePosition, SourceDatabase}; -use ide_db::{source_change::SourceFileEdit, RootDatabase}; +use ide_db::{ + base_db::{FilePosition, SourceDatabase}, + source_change::SourceFileEdits, + RootDatabase, +}; use syntax::{ algo::find_node_at_offset, ast::{self, edit::IndentLevel, AstToken}, @@ -56,7 +59,7 @@ pub(crate) fn on_char_typed( let file = &db.parse(position.file_id).tree(); assert_eq!(file.syntax().text().char_at(position.offset), Some(char_typed)); let edit = on_char_typed_inner(file, position.offset, char_typed)?; - Some(SourceFileEdit { file_id: position.file_id, edit }.into()) + Some(SourceFileEdits::from_text_edit(position.file_id, edit).into()) } fn on_char_typed_inner(file: &SourceFile, offset: TextSize, char_typed: char) -> Option { -- cgit v1.2.3