Auto merge of #13091 - ice1k:hey, r=Veykril

Remove type alias definition on inline

Fix #13079
This commit is contained in:
bors 2022-09-05 10:49:19 +00:00
commit a1c26530ec
10 changed files with 102 additions and 58 deletions

View File

@ -5,6 +5,7 @@ use hir::{Adt, Crate, HasAttrs, HasSource, ModuleDef, Semantics};
use ide_db::RootDatabase; use ide_db::RootDatabase;
use ide_db::{famous_defs::FamousDefs, helpers::mod_path_to_ast}; use ide_db::{famous_defs::FamousDefs, helpers::mod_path_to_ast};
use itertools::Itertools; use itertools::Itertools;
use syntax::ast::edit_in_place::Removable;
use syntax::ast::{self, make, AstNode, HasName, MatchArmList, MatchExpr, Pat}; use syntax::ast::{self, make, AstNode, HasName, MatchArmList, MatchExpr, Pat};
use crate::{ use crate::{

View File

@ -7,6 +7,7 @@ use ide_db::{
imports::insert_use::remove_path_if_in_use_stmt, imports::insert_use::remove_path_if_in_use_stmt,
path_transform::PathTransform, path_transform::PathTransform,
search::{FileReference, SearchScope}, search::{FileReference, SearchScope},
source_change::SourceChangeBuilder,
syntax_helpers::{insert_whitespace_into_node::insert_ws_into, node_ext::expr_as_name_ref}, syntax_helpers::{insert_whitespace_into_node::insert_ws_into, node_ext::expr_as_name_ref},
RootDatabase, RootDatabase,
}; };
@ -100,18 +101,7 @@ pub(crate) fn inline_into_callers(acc: &mut Assists, ctx: &AssistContext<'_>) ->
builder.edit_file(file_id); builder.edit_file(file_id);
let count = refs.len(); let count = refs.len();
// The collects are required as we are otherwise iterating while mutating 🙅‍♀️🙅‍♂️ // The collects are required as we are otherwise iterating while mutating 🙅‍♀️🙅‍♂️
let (name_refs, name_refs_use): (Vec<_>, Vec<_>) = refs let (name_refs, name_refs_use) = split_refs_and_uses(builder, refs, Some);
.into_iter()
.filter_map(|file_ref| match file_ref.name {
ast::NameLike::NameRef(name_ref) => Some(name_ref),
_ => None,
})
.partition_map(|name_ref| {
match name_ref.syntax().ancestors().find_map(ast::UseTree::cast) {
Some(use_tree) => Either::Right(builder.make_mut(use_tree)),
None => Either::Left(name_ref),
}
});
let call_infos: Vec<_> = name_refs let call_infos: Vec<_> = name_refs
.into_iter() .into_iter()
.filter_map(CallInfo::from_name_ref) .filter_map(CallInfo::from_name_ref)
@ -130,11 +120,7 @@ pub(crate) fn inline_into_callers(acc: &mut Assists, ctx: &AssistContext<'_>) ->
.count(); .count();
if replaced + name_refs_use.len() == count { if replaced + name_refs_use.len() == count {
// we replaced all usages in this file, so we can remove the imports // we replaced all usages in this file, so we can remove the imports
name_refs_use.into_iter().for_each(|use_tree| { name_refs_use.iter().for_each(remove_path_if_in_use_stmt);
if let Some(path) = use_tree.path() {
remove_path_if_in_use_stmt(&path);
}
})
} else { } else {
remove_def = false; remove_def = false;
} }
@ -153,6 +139,23 @@ pub(crate) fn inline_into_callers(acc: &mut Assists, ctx: &AssistContext<'_>) ->
) )
} }
pub(super) fn split_refs_and_uses<T: ast::AstNode>(
builder: &mut SourceChangeBuilder,
iter: impl IntoIterator<Item = FileReference>,
mut map_ref: impl FnMut(ast::NameRef) -> Option<T>,
) -> (Vec<T>, Vec<ast::Path>) {
iter.into_iter()
.filter_map(|file_ref| match file_ref.name {
ast::NameLike::NameRef(name_ref) => Some(name_ref),
_ => None,
})
.filter_map(|name_ref| match name_ref.syntax().ancestors().find_map(ast::UseTree::cast) {
Some(use_tree) => builder.make_mut(use_tree).path().map(Either::Right),
None => map_ref(name_ref).map(Either::Left),
})
.partition_map(|either| either)
}
// Assist: inline_call // Assist: inline_call
// //
// Inlines a function or method body creating a `let` statement per parameter unless the parameter // Inlines a function or method body creating a `let` statement per parameter unless the parameter

View File

@ -3,7 +3,10 @@
// - Remove unused aliases if there are no longer any users, see inline_call.rs. // - Remove unused aliases if there are no longer any users, see inline_call.rs.
use hir::{HasSource, PathResolution}; use hir::{HasSource, PathResolution};
use ide_db::{defs::Definition, search::FileReference}; use ide_db::{
defs::Definition, imports::insert_use::ast_to_remove_for_path_in_use_stmt,
search::FileReference,
};
use itertools::Itertools; use itertools::Itertools;
use std::collections::HashMap; use std::collections::HashMap;
use syntax::{ use syntax::{
@ -16,6 +19,8 @@ use crate::{
AssistId, AssistKind, AssistId, AssistKind,
}; };
use super::inline_call::split_refs_and_uses;
// Assist: inline_type_alias_uses // Assist: inline_type_alias_uses
// //
// Inline a type alias into all of its uses where possible. // Inline a type alias into all of its uses where possible.
@ -31,7 +36,7 @@ use crate::{
// ``` // ```
// -> // ->
// ``` // ```
// type A = i32; //
// fn id(x: i32) -> i32 { // fn id(x: i32) -> i32 {
// x // x
// }; // };
@ -58,20 +63,20 @@ pub(crate) fn inline_type_alias_uses(acc: &mut Assists, ctx: &AssistContext<'_>)
name.syntax().text_range(), name.syntax().text_range(),
|builder| { |builder| {
let usages = usages.all(); let usages = usages.all();
let mut definition_deleted = false;
let mut inline_refs_for_file = |file_id, refs: Vec<FileReference>| { let mut inline_refs_for_file = |file_id, refs: Vec<FileReference>| {
builder.edit_file(file_id); builder.edit_file(file_id);
let path_types: Vec<ast::PathType> = refs let (path_types, path_type_uses) =
.into_iter() split_refs_and_uses(builder, refs, |path_type| {
.filter_map(|file_ref| match file_ref.name { path_type.syntax().ancestors().nth(3).and_then(ast::PathType::cast)
ast::NameLike::NameRef(path_type) => { });
path_type.syntax().ancestors().nth(3).and_then(ast::PathType::cast)
}
_ => None,
})
.collect();
path_type_uses
.iter()
.flat_map(ast_to_remove_for_path_in_use_stmt)
.for_each(|x| builder.delete(x.syntax().text_range()));
for (target, replacement) in path_types.into_iter().filter_map(|path_type| { for (target, replacement) in path_types.into_iter().filter_map(|path_type| {
let replacement = inline(&ast_alias, &path_type)?.to_text(&concrete_type); let replacement = inline(&ast_alias, &path_type)?.to_text(&concrete_type);
let target = path_type.syntax().text_range(); let target = path_type.syntax().text_range();
@ -79,11 +84,20 @@ pub(crate) fn inline_type_alias_uses(acc: &mut Assists, ctx: &AssistContext<'_>)
}) { }) {
builder.replace(target, replacement); builder.replace(target, replacement);
} }
if file_id == ctx.file_id() {
builder.delete(ast_alias.syntax().text_range());
definition_deleted = true;
}
}; };
for (file_id, refs) in usages.into_iter() { for (file_id, refs) in usages.into_iter() {
inline_refs_for_file(file_id, refs); inline_refs_for_file(file_id, refs);
} }
if !definition_deleted {
builder.edit_file(ctx.file_id());
builder.delete(ast_alias.syntax().text_range());
}
}, },
) )
} }
@ -929,7 +943,7 @@ fn foo() {
} }
"#, "#,
r#" r#"
type A = u32;
fn foo() { fn foo() {
let _: u32 = 3; let _: u32 = 3;
@ -960,13 +974,13 @@ fn foo() {
r#" r#"
//- /lib.rs //- /lib.rs
mod foo; mod foo;
type T<E> = Vec<E>;
fn f() -> Vec<&str> { fn f() -> Vec<&str> {
vec!["hello"] vec!["hello"]
} }
//- /foo.rs //- /foo.rs
use super::T;
fn foo() { fn foo() {
let _: Vec<i8> = Vec::new(); let _: Vec<i8> = Vec::new();
} }
@ -990,7 +1004,12 @@ fn foo() {
} }
"#, "#,
r#" r#"
use super::I; //- /lib.rs
mod foo;
//- /foo.rs
fn foo() { fn foo() {
let _: i32 = 0; let _: i32 = 0;
} }

View File

@ -1,6 +1,10 @@
use either::Either; use either::Either;
use ide_db::imports::merge_imports::{try_merge_imports, try_merge_trees, MergeBehavior}; use ide_db::imports::merge_imports::{try_merge_imports, try_merge_trees, MergeBehavior};
use syntax::{algo::neighbor, ast, match_ast, ted, AstNode, SyntaxElement, SyntaxNode}; use syntax::{
algo::neighbor,
ast::{self, edit_in_place::Removable},
match_ast, ted, AstNode, SyntaxElement, SyntaxNode,
};
use crate::{ use crate::{
assist_context::{AssistContext, Assists}, assist_context::{AssistContext, Assists},
@ -76,7 +80,7 @@ pub(crate) fn merge_imports(acc: &mut Assists, ctx: &AssistContext<'_>) -> Optio
.collect(); .collect();
for edit in edits_mut { for edit in edits_mut {
match edit { match edit {
Remove(it) => it.as_ref().either(ast::Use::remove, ast::UseTree::remove), Remove(it) => it.as_ref().either(Removable::remove, Removable::remove),
Replace(old, new) => ted::replace(old, new), Replace(old, new) => ted::replace(old, new),
} }
} }

View File

@ -1,5 +1,9 @@
use syntax::{ use syntax::{
ast::{self, edit_in_place::GenericParamsOwnerEdit, make, AstNode, HasName, HasTypeBounds}, ast::{
self,
edit_in_place::{GenericParamsOwnerEdit, Removable},
make, AstNode, HasName, HasTypeBounds,
},
match_ast, match_ast,
}; };

View File

@ -1,5 +1,5 @@
use syntax::{ use syntax::{
ast::{self, make, HasVisibility}, ast::{self, edit_in_place::Removable, make, HasVisibility},
ted::{self, Position}, ted::{self, Position},
AstNode, SyntaxKind, AstNode, SyntaxKind,
}; };

View File

@ -1390,7 +1390,7 @@ fn foo() {
} }
"#####, "#####,
r#####" r#####"
type A = i32;
fn id(x: i32) -> i32 { fn id(x: i32) -> i32 {
x x
}; };

View File

@ -12,7 +12,7 @@ use syntax::{
ast::{ ast::{
self, self,
edit::{self, AstNodeEdit}, edit::{self, AstNodeEdit},
edit_in_place::AttrsOwnerEdit, edit_in_place::{AttrsOwnerEdit, Removable},
make, HasArgList, HasAttrs, HasGenericParams, HasName, HasTypeBounds, Whitespace, make, HasArgList, HasAttrs, HasGenericParams, HasName, HasTypeBounds, Whitespace,
}, },
ted, AstNode, AstToken, Direction, SmolStr, SourceFile, ted, AstNode, AstToken, Direction, SmolStr, SourceFile,

View File

@ -7,7 +7,10 @@ use std::cmp::Ordering;
use hir::Semantics; use hir::Semantics;
use syntax::{ use syntax::{
algo, algo,
ast::{self, make, AstNode, HasAttrs, HasModuleItem, HasVisibility, PathSegmentKind}, ast::{
self, edit_in_place::Removable, make, AstNode, HasAttrs, HasModuleItem, HasVisibility,
PathSegmentKind,
},
ted, Direction, NodeOrToken, SyntaxKind, SyntaxNode, ted, Direction, NodeOrToken, SyntaxKind, SyntaxNode,
}; };
@ -192,20 +195,24 @@ pub fn insert_use(scope: &ImportScope, path: ast::Path, cfg: &InsertUseConfig) {
insert_use_(scope, &path, cfg.group, use_item); insert_use_(scope, &path, cfg.group, use_item);
} }
pub fn remove_path_if_in_use_stmt(path: &ast::Path) { pub fn ast_to_remove_for_path_in_use_stmt(path: &ast::Path) -> Option<Box<dyn Removable>> {
// FIXME: improve this // FIXME: improve this
if path.parent_path().is_some() { if path.parent_path().is_some() {
return; return None;
} }
if let Some(use_tree) = path.syntax().parent().and_then(ast::UseTree::cast) { let use_tree = path.syntax().parent().and_then(ast::UseTree::cast)?;
if use_tree.use_tree_list().is_some() || use_tree.star_token().is_some() { if use_tree.use_tree_list().is_some() || use_tree.star_token().is_some() {
return; return None;
} }
if let Some(use_) = use_tree.syntax().parent().and_then(ast::Use::cast) { if let Some(use_) = use_tree.syntax().parent().and_then(ast::Use::cast) {
use_.remove(); return Some(Box::new(use_));
return; }
} Some(Box::new(use_tree))
use_tree.remove(); }
pub fn remove_path_if_in_use_stmt(path: &ast::Path) {
if let Some(node) = ast_to_remove_for_path_in_use_stmt(path) {
node.remove();
} }
} }

View File

@ -248,8 +248,12 @@ impl ast::WhereClause {
} }
} }
impl ast::TypeBoundList { pub trait Removable: AstNode {
pub fn remove(&self) { fn remove(&self);
}
impl Removable for ast::TypeBoundList {
fn remove(&self) {
match self.syntax().siblings_with_tokens(Direction::Prev).find(|it| it.kind() == T![:]) { match self.syntax().siblings_with_tokens(Direction::Prev).find(|it| it.kind() == T![:]) {
Some(colon) => ted::remove_all(colon..=self.syntax().clone().into()), Some(colon) => ted::remove_all(colon..=self.syntax().clone().into()),
None => ted::remove(self.syntax()), None => ted::remove(self.syntax()),
@ -267,8 +271,8 @@ impl ast::PathSegment {
} }
} }
impl ast::UseTree { impl Removable for ast::UseTree {
pub fn remove(&self) { fn remove(&self) {
for dir in [Direction::Next, Direction::Prev] { for dir in [Direction::Next, Direction::Prev] {
if let Some(next_use_tree) = neighbor(self, dir) { if let Some(next_use_tree) = neighbor(self, dir) {
let separators = self let separators = self
@ -282,7 +286,9 @@ impl ast::UseTree {
} }
ted::remove(self.syntax()); ted::remove(self.syntax());
} }
}
impl ast::UseTree {
pub fn get_or_create_use_tree_list(&self) -> ast::UseTreeList { pub fn get_or_create_use_tree_list(&self) -> ast::UseTreeList {
match self.use_tree_list() { match self.use_tree_list() {
Some(it) => it, Some(it) => it,
@ -373,8 +379,8 @@ impl ast::UseTreeList {
} }
} }
impl ast::Use { impl Removable for ast::Use {
pub fn remove(&self) { fn remove(&self) {
let next_ws = self let next_ws = self
.syntax() .syntax()
.next_sibling_or_token() .next_sibling_or_token()
@ -444,8 +450,8 @@ impl ast::Fn {
} }
} }
impl ast::MatchArm { impl Removable for ast::MatchArm {
pub fn remove(&self) { fn remove(&self) {
if let Some(sibling) = self.syntax().prev_sibling_or_token() { if let Some(sibling) = self.syntax().prev_sibling_or_token() {
if sibling.kind() == SyntaxKind::WHITESPACE { if sibling.kind() == SyntaxKind::WHITESPACE {
ted::remove(sibling); ted::remove(sibling);