internal: remove one more syntax rewriter

This commit is contained in:
Aleksey Kladov 2021-05-08 14:38:56 +03:00
parent 4e3f0186d8
commit 1fdc9d8e9e
3 changed files with 38 additions and 65 deletions

View File

@ -13,7 +13,7 @@ use ide_db::{
RootDatabase, RootDatabase,
}; };
use syntax::{ use syntax::{
algo::{self, find_node_at_offset, find_node_at_range, SyntaxRewriter}, algo::{self, find_node_at_offset, find_node_at_range},
AstNode, AstToken, SourceFile, SyntaxElement, SyntaxKind, SyntaxNode, SyntaxNodePtr, AstNode, AstToken, SourceFile, SyntaxElement, SyntaxKind, SyntaxNode, SyntaxNodePtr,
SyntaxToken, TextRange, TextSize, TokenAtOffset, SyntaxToken, TextRange, TextSize, TokenAtOffset,
}; };
@ -290,12 +290,6 @@ impl AssistBuilder {
pub(crate) fn replace_ast<N: AstNode>(&mut self, old: N, new: N) { pub(crate) fn replace_ast<N: AstNode>(&mut self, old: N, new: N) {
algo::diff(old.syntax(), new.syntax()).into_text_edit(&mut self.edit) algo::diff(old.syntax(), new.syntax()).into_text_edit(&mut self.edit)
} }
pub(crate) fn rewrite(&mut self, rewriter: SyntaxRewriter) {
if let Some(node) = rewriter.rewrite_root() {
let new = rewriter.rewrite(&node);
algo::diff(&node, &new).into_text_edit(&mut self.edit);
}
}
pub(crate) fn create_file(&mut self, dst: AnchoredPathBuf, content: impl Into<String>) { pub(crate) fn create_file(&mut self, dst: AnchoredPathBuf, content: impl Into<String>) {
let file_system_edit = let file_system_edit =
FileSystemEdit::CreateFile { dst: dst, initial_contents: content.into() }; FileSystemEdit::CreateFile { dst: dst, initial_contents: content.into() };

View File

@ -4,10 +4,10 @@ use ide_db::{
defs::{Definition, NameRefClass}, defs::{Definition, NameRefClass},
search::SearchScope, search::SearchScope,
}; };
use stdx::never;
use syntax::{ use syntax::{
algo::SyntaxRewriter,
ast::{self, make}, ast::{self, make},
AstNode, Direction, SyntaxNode, SyntaxToken, T, ted, AstNode, Direction, SyntaxNode, SyntaxToken, T,
}; };
use crate::{ use crate::{
@ -42,6 +42,7 @@ use crate::{
// ``` // ```
pub(crate) fn expand_glob_import(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { pub(crate) fn expand_glob_import(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
let star = ctx.find_token_syntax_at_offset(T![*])?; let star = ctx.find_token_syntax_at_offset(T![*])?;
let use_tree = star.parent().and_then(ast::UseTree::cast)?;
let (parent, mod_path) = find_parent_and_path(&star)?; let (parent, mod_path) = find_parent_and_path(&star)?;
let target_module = match ctx.sema.resolve_path(&mod_path)? { let target_module = match ctx.sema.resolve_path(&mod_path)? {
PathResolution::Def(ModuleDef::Module(it)) => it, PathResolution::Def(ModuleDef::Module(it)) => it,
@ -53,7 +54,6 @@ pub(crate) fn expand_glob_import(acc: &mut Assists, ctx: &AssistContext) -> Opti
let refs_in_target = find_refs_in_mod(ctx, target_module, Some(current_module))?; let refs_in_target = find_refs_in_mod(ctx, target_module, Some(current_module))?;
let imported_defs = find_imported_defs(ctx, star)?; let imported_defs = find_imported_defs(ctx, star)?;
let names_to_import = find_names_to_import(ctx, refs_in_target, imported_defs);
let target = parent.clone().either(|n| n.syntax().clone(), |n| n.syntax().clone()); let target = parent.clone().either(|n| n.syntax().clone(), |n| n.syntax().clone());
acc.add( acc.add(
@ -61,9 +61,32 @@ pub(crate) fn expand_glob_import(acc: &mut Assists, ctx: &AssistContext) -> Opti
"Expand glob import", "Expand glob import",
target.text_range(), target.text_range(),
|builder| { |builder| {
let mut rewriter = SyntaxRewriter::default(); let use_tree = builder.make_ast_mut(use_tree);
replace_ast(&mut rewriter, parent, mod_path, names_to_import);
builder.rewrite(rewriter); let names_to_import = find_names_to_import(ctx, refs_in_target, imported_defs);
let expanded = make::use_tree_list(names_to_import.iter().map(|n| {
let path =
make::path_unqualified(make::path_segment(make::name_ref(&n.to_string())));
make::use_tree(path, None, None, false)
}))
.clone_for_update();
match use_tree.star_token() {
Some(star) => {
let needs_braces = use_tree.path().is_some() && names_to_import.len() > 1;
if needs_braces {
ted::replace(star, expanded.syntax())
} else {
let without_braces = expanded
.syntax()
.children_with_tokens()
.filter(|child| !matches!(child.kind(), T!['{'] | T!['}']))
.collect();
ted::replace_with_many(star, without_braces)
}
}
None => never!(),
}
}, },
) )
} }
@ -232,53 +255,6 @@ fn find_names_to_import(
used_refs.0.iter().map(|r| r.visible_name.clone()).collect() used_refs.0.iter().map(|r| r.visible_name.clone()).collect()
} }
fn replace_ast(
rewriter: &mut SyntaxRewriter,
parent: Either<ast::UseTree, ast::UseTreeList>,
path: ast::Path,
names_to_import: Vec<Name>,
) {
let existing_use_trees = match parent.clone() {
Either::Left(_) => vec![],
Either::Right(u) => u
.use_trees()
.filter(|n|
// filter out star
n.star_token().is_none())
.collect(),
};
let new_use_trees: Vec<ast::UseTree> = names_to_import
.iter()
.map(|n| {
let path = make::path_unqualified(make::path_segment(make::name_ref(&n.to_string())));
make::use_tree(path, None, None, false)
})
.collect();
let use_trees = [&existing_use_trees[..], &new_use_trees[..]].concat();
match use_trees.as_slice() {
[name] => {
if let Some(end_path) = name.path() {
rewriter.replace_ast(
&parent.left_or_else(|tl| tl.parent_use_tree()),
&make::use_tree(make::path_concat(path, end_path), None, None, false),
);
}
}
names => match &parent {
Either::Left(parent) => rewriter.replace_ast(
parent,
&make::use_tree(path, Some(make::use_tree_list(names.to_owned())), None, false),
),
Either::Right(parent) => {
rewriter.replace_ast(parent, &make::use_tree_list(names.to_owned()))
}
},
};
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::tests::{check_assist, check_assist_not_applicable}; use crate::tests::{check_assist, check_assist_not_applicable};
@ -350,7 +326,7 @@ mod foo {
pub fn f() {} pub fn f() {}
} }
use foo::{f, Baz, Bar}; use foo::{Baz, Bar, f};
fn qux(bar: Bar, baz: Baz) { fn qux(bar: Bar, baz: Baz) {
f(); f();
@ -389,7 +365,7 @@ mod foo {
} }
use foo::Bar; use foo::Bar;
use foo::{f, Baz}; use foo::{Baz, f};
fn qux(bar: Bar, baz: Baz) { fn qux(bar: Bar, baz: Baz) {
f(); f();
@ -439,7 +415,7 @@ mod foo {
} }
} }
use foo::{bar::{f, Baz, Bar}, baz::*}; use foo::{bar::{Baz, Bar, f}, baz::*};
fn qux(bar: Bar, baz: Baz) { fn qux(bar: Bar, baz: Baz) {
f(); f();
@ -891,7 +867,7 @@ mod foo {
pub struct Bar; pub struct Bar;
} }
use foo::Bar; use foo::{Bar};
struct Baz { struct Baz {
bar: Bar bar: Bar

View File

@ -125,8 +125,11 @@ pub fn remove_all_iter(range: impl IntoIterator<Item = SyntaxElement>) {
} }
pub fn replace(old: impl Element, new: impl Element) { pub fn replace(old: impl Element, new: impl Element) {
replace_with_many(old, vec![new.syntax_element()])
}
pub fn replace_with_many(old: impl Element, new: Vec<SyntaxElement>) {
let old = old.syntax_element(); let old = old.syntax_element();
replace_all(old.clone()..=old, vec![new.syntax_element()]) replace_all(old.clone()..=old, new)
} }
pub fn replace_all(range: RangeInclusive<SyntaxElement>, new: Vec<SyntaxElement>) { pub fn replace_all(range: RangeInclusive<SyntaxElement>, new: Vec<SyntaxElement>) {
let start = range.start().index(); let start = range.start().index();