Remove SyntaxRewriter usage in insert_use in favor of ted

This commit is contained in:
Lukas Wirth 2021-04-20 02:05:22 +02:00
parent e8744ed9bb
commit fa20a5064b
8 changed files with 185 additions and 243 deletions

View file

@ -101,9 +101,11 @@ pub(crate) fn auto_import(acc: &mut Assists, ctx: &AssistContext) -> Option<()>
format!("Import `{}`", import.import_path),
range,
|builder| {
let rewriter =
insert_use(&scope, mod_path_to_ast(&import.import_path), ctx.config.insert_use);
builder.rewrite(rewriter);
let scope = match scope.clone() {
ImportScope::File(it) => ImportScope::File(builder.make_ast_mut(it)),
ImportScope::Module(it) => ImportScope::Module(builder.make_ast_mut(it)),
};
insert_use(&scope, mod_path_to_ast(&import.import_path), ctx.config.insert_use);
},
);
}

View file

@ -13,9 +13,9 @@ use ide_db::{
};
use rustc_hash::FxHashSet;
use syntax::{
algo::{find_node_at_offset, SyntaxRewriter},
ast::{self, edit::IndentLevel, make, AstNode, NameOwner, VisibilityOwner},
SourceFile, SyntaxElement, SyntaxNode, T,
algo::find_node_at_offset,
ast::{self, make, AstNode, NameOwner, VisibilityOwner},
ted, SourceFile, SyntaxElement, SyntaxNode, T,
};
use crate::{AssistContext, AssistId, AssistKind, Assists};
@ -62,14 +62,17 @@ pub(crate) fn extract_struct_from_enum_variant(
let mut visited_modules_set = FxHashSet::default();
let current_module = enum_hir.module(ctx.db());
visited_modules_set.insert(current_module);
let mut def_rewriter = None;
let mut def_file_references = None;
for (file_id, references) in usages {
let mut rewriter = SyntaxRewriter::default();
let source_file = ctx.sema.parse(file_id);
if file_id == ctx.frange.file_id {
def_file_references = Some(references);
continue;
}
builder.edit_file(file_id);
let source_file = builder.make_ast_mut(ctx.sema.parse(file_id));
for reference in references {
update_reference(
ctx,
&mut rewriter,
reference,
&source_file,
&enum_module_def,
@ -77,25 +80,27 @@ pub(crate) fn extract_struct_from_enum_variant(
&mut visited_modules_set,
);
}
if file_id == ctx.frange.file_id {
def_rewriter = Some(rewriter);
continue;
}
builder.edit_file(file_id);
builder.rewrite(rewriter);
}
let mut rewriter = def_rewriter.unwrap_or_default();
update_variant(&mut rewriter, &variant);
builder.edit_file(ctx.frange.file_id);
let variant = builder.make_ast_mut(variant.clone());
let source_file = builder.make_ast_mut(ctx.sema.parse(ctx.frange.file_id));
for reference in def_file_references.into_iter().flatten() {
update_reference(
ctx,
reference,
&source_file,
&enum_module_def,
&variant_hir_name,
&mut visited_modules_set,
);
}
extract_struct_def(
&mut rewriter,
&enum_ast,
variant_name.clone(),
&field_list,
&variant.parent_enum().syntax().clone().into(),
enum_ast.visibility(),
);
builder.edit_file(ctx.frange.file_id);
builder.rewrite(rewriter);
update_variant(&variant);
},
)
}
@ -138,7 +143,6 @@ fn existing_definition(db: &RootDatabase, variant_name: &ast::Name, variant: &Va
fn insert_import(
ctx: &AssistContext,
rewriter: &mut SyntaxRewriter,
scope_node: &SyntaxNode,
module: &Module,
enum_module_def: &ModuleDef,
@ -151,14 +155,12 @@ fn insert_import(
mod_path.pop_segment();
mod_path.push_segment(variant_hir_name.clone());
let scope = ImportScope::find_insert_use_container(scope_node, &ctx.sema)?;
*rewriter += insert_use(&scope, mod_path_to_ast(&mod_path), ctx.config.insert_use);
insert_use(&scope, mod_path_to_ast(&mod_path), ctx.config.insert_use);
}
Some(())
}
fn extract_struct_def(
rewriter: &mut SyntaxRewriter,
enum_: &ast::Enum,
variant_name: ast::Name,
field_list: &Either<ast::RecordFieldList, ast::TupleFieldList>,
start_offset: &SyntaxElement,
@ -180,33 +182,34 @@ fn extract_struct_def(
.into(),
};
rewriter.insert_before(
start_offset,
make::struct_(visibility, variant_name, None, field_list).syntax(),
ted::insert_raw(
ted::Position::before(start_offset),
make::struct_(visibility, variant_name, None, field_list).clone_for_update().syntax(),
);
rewriter.insert_before(start_offset, &make::tokens::blank_line());
ted::insert_raw(ted::Position::before(start_offset), &make::tokens::blank_line());
if let indent_level @ 1..=usize::MAX = IndentLevel::from_node(enum_.syntax()).0 as usize {
rewriter
.insert_before(start_offset, &make::tokens::whitespace(&" ".repeat(4 * indent_level)));
}
// if let indent_level @ 1..=usize::MAX = IndentLevel::from_node(enum_.syntax()).0 as usize {
// ted::insert(ted::Position::before(start_offset), &make::tokens::blank_line());
// rewriter
// .insert_before(start_offset, &make::tokens::whitespace(&" ".repeat(4 * indent_level)));
// }
Some(())
}
fn update_variant(rewriter: &mut SyntaxRewriter, variant: &ast::Variant) -> Option<()> {
fn update_variant(variant: &ast::Variant) -> Option<()> {
let name = variant.name()?;
let tuple_field = make::tuple_field(None, make::ty(&name.text()));
let replacement = make::variant(
name,
Some(ast::FieldList::TupleFieldList(make::tuple_field_list(iter::once(tuple_field)))),
);
rewriter.replace(variant.syntax(), replacement.syntax());
)
.clone_for_update();
ted::replace(variant.syntax(), replacement.syntax());
Some(())
}
fn update_reference(
ctx: &AssistContext,
rewriter: &mut SyntaxRewriter,
reference: FileReference,
source_file: &SourceFile,
enum_module_def: &ModuleDef,
@ -230,14 +233,16 @@ fn update_reference(
let module = ctx.sema.scope(&expr).module()?;
if !visited_modules_set.contains(&module) {
if insert_import(ctx, rewriter, &expr, &module, enum_module_def, variant_hir_name).is_some()
{
if insert_import(ctx, &expr, &module, enum_module_def, variant_hir_name).is_some() {
visited_modules_set.insert(module);
}
}
rewriter.insert_after(segment.syntax(), &make::token(T!['(']));
rewriter.insert_after(segment.syntax(), segment.syntax());
rewriter.insert_after(&expr, &make::token(T![')']));
ted::insert_raw(
ted::Position::before(segment.syntax()),
make::path_from_text(&format!("{}", segment)).clone_for_update().syntax(),
);
ted::insert_raw(ted::Position::before(segment.syntax()), make::token(T!['(']));
ted::insert_raw(ted::Position::after(&expr), make::token(T![')']));
Some(())
}

View file

@ -1,5 +1,5 @@
use ide_db::helpers::insert_use::{insert_use, ImportScope};
use syntax::{algo::SyntaxRewriter, ast, match_ast, AstNode, SyntaxNode};
use syntax::{ast, match_ast, ted, AstNode, SyntaxNode};
use crate::{AssistContext, AssistId, AssistKind, Assists};
@ -40,18 +40,17 @@ pub(crate) fn replace_qualified_name_with_use(
|builder| {
// Now that we've brought the name into scope, re-qualify all paths that could be
// affected (that is, all paths inside the node we added the `use` to).
let mut rewriter = SyntaxRewriter::default();
shorten_paths(&mut rewriter, syntax.clone(), &path);
let syntax = builder.make_mut(syntax.clone());
if let Some(ref import_scope) = ImportScope::from(syntax.clone()) {
rewriter += insert_use(import_scope, path, ctx.config.insert_use);
builder.rewrite(rewriter);
insert_use(import_scope, path.clone(), ctx.config.insert_use);
}
shorten_paths(syntax.clone(), &path.clone_for_update());
},
)
}
/// Adds replacements to `re` that shorten `path` in all descendants of `node`.
fn shorten_paths(rewriter: &mut SyntaxRewriter<'static>, node: SyntaxNode, path: &ast::Path) {
fn shorten_paths(node: SyntaxNode, path: &ast::Path) {
for child in node.children() {
match_ast! {
match child {
@ -62,32 +61,28 @@ fn shorten_paths(rewriter: &mut SyntaxRewriter<'static>, node: SyntaxNode, path:
ast::Module(_it) => continue,
ast::Path(p) => {
match maybe_replace_path(rewriter, p.clone(), path.clone()) {
match maybe_replace_path(p.clone(), path.clone()) {
Some(()) => {},
None => shorten_paths(rewriter, p.syntax().clone(), path),
None => shorten_paths(p.syntax().clone(), path),
}
},
_ => shorten_paths(rewriter, child, path),
_ => shorten_paths(child, path),
}
}
}
}
fn maybe_replace_path(
rewriter: &mut SyntaxRewriter<'static>,
path: ast::Path,
target: ast::Path,
) -> Option<()> {
fn maybe_replace_path(path: ast::Path, target: ast::Path) -> Option<()> {
if !path_eq(path.clone(), target) {
return None;
}
// Shorten `path`, leaving only its last segment.
if let Some(parent) = path.qualifier() {
rewriter.delete(parent.syntax());
ted::remove(parent.syntax());
}
if let Some(double_colon) = path.coloncolon_token() {
rewriter.delete(&double_colon);
ted::remove(&double_colon);
}
Some(())
@ -150,6 +145,7 @@ Debug
",
);
}
#[test]
fn test_replace_add_use_no_anchor_with_item_below() {
check_assist(