mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-10-27 10:17:15 +00:00
internal: Migrate remove_unused_param assist to SyntaxEditor
This commit is contained in:
parent
93c9f06870
commit
f155aef64d
3 changed files with 71 additions and 17 deletions
|
|
@ -1,8 +1,9 @@
|
||||||
use ide_db::{defs::Definition, search::FileReference, EditionedFileId};
|
use ide_db::{defs::Definition, search::FileReference, EditionedFileId};
|
||||||
use syntax::{
|
use syntax::{
|
||||||
algo::find_node_at_range,
|
algo::{find_node_at_range, least_common_ancestor_element},
|
||||||
ast::{self, HasArgList},
|
ast::{self, HasArgList},
|
||||||
AstNode, SourceFile, SyntaxKind, SyntaxNode, TextRange, T,
|
syntax_editor::Element,
|
||||||
|
AstNode, SourceFile, SyntaxElement, SyntaxKind, SyntaxNode, TextRange, T,
|
||||||
};
|
};
|
||||||
|
|
||||||
use SyntaxKind::WHITESPACE;
|
use SyntaxKind::WHITESPACE;
|
||||||
|
|
@ -74,15 +75,21 @@ pub(crate) fn remove_unused_param(acc: &mut Assists, ctx: &AssistContext<'_>) ->
|
||||||
cov_mark::hit!(keep_used);
|
cov_mark::hit!(keep_used);
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
let parent = param.syntax().parent()?;
|
||||||
acc.add(
|
acc.add(
|
||||||
AssistId("remove_unused_param", AssistKind::Refactor),
|
AssistId("remove_unused_param", AssistKind::Refactor),
|
||||||
"Remove unused parameter",
|
"Remove unused parameter",
|
||||||
param.syntax().text_range(),
|
param.syntax().text_range(),
|
||||||
|builder| {
|
|builder| {
|
||||||
builder.delete(range_to_remove(param.syntax()));
|
let mut editor = builder.make_editor(&parent);
|
||||||
|
let elements = elements_to_remove(param.syntax());
|
||||||
|
for element in elements {
|
||||||
|
editor.delete(element);
|
||||||
|
}
|
||||||
for (file_id, references) in fn_def.usages(&ctx.sema).all() {
|
for (file_id, references) in fn_def.usages(&ctx.sema).all() {
|
||||||
process_usages(ctx, builder, file_id, references, param_position, is_self_present);
|
process_usages(ctx, builder, file_id, references, param_position, is_self_present);
|
||||||
}
|
}
|
||||||
|
builder.add_file_edits(ctx.file_id(), editor);
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -96,20 +103,24 @@ fn process_usages(
|
||||||
is_self_present: bool,
|
is_self_present: bool,
|
||||||
) {
|
) {
|
||||||
let source_file = ctx.sema.parse(file_id);
|
let source_file = ctx.sema.parse(file_id);
|
||||||
builder.edit_file(file_id);
|
|
||||||
let possible_ranges = references
|
let possible_ranges = references
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter_map(|usage| process_usage(&source_file, usage, arg_to_remove, is_self_present));
|
.filter_map(|usage| process_usage(&source_file, usage, arg_to_remove, is_self_present));
|
||||||
|
|
||||||
let mut ranges_to_delete: Vec<TextRange> = vec![];
|
for element_range in possible_ranges {
|
||||||
for range in possible_ranges {
|
let Some(SyntaxElement::Node(parent)) = element_range
|
||||||
if !ranges_to_delete.iter().any(|it| it.contains_range(range)) {
|
.iter()
|
||||||
ranges_to_delete.push(range)
|
.cloned()
|
||||||
|
.reduce(|a, b| least_common_ancestor_element(&a, &b).unwrap().syntax_element())
|
||||||
|
else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
let mut editor = builder.make_editor(&parent);
|
||||||
|
for element in element_range {
|
||||||
|
editor.delete(element);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
for range in ranges_to_delete {
|
builder.add_file_edits(file_id, editor);
|
||||||
builder.delete(range)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -118,7 +129,7 @@ fn process_usage(
|
||||||
FileReference { range, .. }: FileReference,
|
FileReference { range, .. }: FileReference,
|
||||||
mut arg_to_remove: usize,
|
mut arg_to_remove: usize,
|
||||||
is_self_present: bool,
|
is_self_present: bool,
|
||||||
) -> Option<TextRange> {
|
) -> Option<Vec<SyntaxElement>> {
|
||||||
let call_expr_opt: Option<ast::CallExpr> = find_node_at_range(source_file.syntax(), range);
|
let call_expr_opt: Option<ast::CallExpr> = find_node_at_range(source_file.syntax(), range);
|
||||||
if let Some(call_expr) = call_expr_opt {
|
if let Some(call_expr) = call_expr_opt {
|
||||||
let call_expr_range = call_expr.expr()?.syntax().text_range();
|
let call_expr_range = call_expr.expr()?.syntax().text_range();
|
||||||
|
|
@ -127,7 +138,7 @@ fn process_usage(
|
||||||
}
|
}
|
||||||
|
|
||||||
let arg = call_expr.arg_list()?.args().nth(arg_to_remove)?;
|
let arg = call_expr.arg_list()?.args().nth(arg_to_remove)?;
|
||||||
return Some(range_to_remove(arg.syntax()));
|
return Some(elements_to_remove(arg.syntax()));
|
||||||
}
|
}
|
||||||
|
|
||||||
let method_call_expr_opt: Option<ast::MethodCallExpr> =
|
let method_call_expr_opt: Option<ast::MethodCallExpr> =
|
||||||
|
|
@ -143,7 +154,7 @@ fn process_usage(
|
||||||
}
|
}
|
||||||
|
|
||||||
let arg = method_call_expr.arg_list()?.args().nth(arg_to_remove)?;
|
let arg = method_call_expr.arg_list()?.args().nth(arg_to_remove)?;
|
||||||
return Some(range_to_remove(arg.syntax()));
|
return Some(elements_to_remove(arg.syntax()));
|
||||||
}
|
}
|
||||||
|
|
||||||
None
|
None
|
||||||
|
|
@ -174,6 +185,29 @@ pub(crate) fn range_to_remove(node: &SyntaxNode) -> TextRange {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn elements_to_remove(node: &SyntaxNode) -> Vec<SyntaxElement> {
|
||||||
|
let up_to_comma = next_prev().find_map(|dir| {
|
||||||
|
node.siblings_with_tokens(dir)
|
||||||
|
.filter_map(|it| it.into_token())
|
||||||
|
.find(|it| it.kind() == T![,])
|
||||||
|
.map(|it| (dir, it))
|
||||||
|
});
|
||||||
|
if let Some((dir, token)) = up_to_comma {
|
||||||
|
let after = token.siblings_with_tokens(dir).nth(1).unwrap();
|
||||||
|
let mut result: Vec<_> =
|
||||||
|
node.siblings_with_tokens(dir).take_while(|it| it != &after).collect();
|
||||||
|
if node.next_sibling().is_some() {
|
||||||
|
result.extend(
|
||||||
|
token.siblings_with_tokens(dir).skip(1).take_while(|it| it.kind() == WHITESPACE),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
result
|
||||||
|
} else {
|
||||||
|
vec![node.syntax_element()]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[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};
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,8 @@
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
AstNode, Direction, NodeOrToken, SyntaxElement, SyntaxKind, SyntaxNode, SyntaxToken, TextRange,
|
syntax_editor::Element, AstNode, Direction, NodeOrToken, SyntaxElement, SyntaxKind, SyntaxNode,
|
||||||
TextSize,
|
SyntaxToken, TextRange, TextSize,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Returns ancestors of the node at the offset, sorted by length. This should
|
/// Returns ancestors of the node at the offset, sorted by length. This should
|
||||||
|
|
@ -89,6 +89,26 @@ pub fn least_common_ancestor(u: &SyntaxNode, v: &SyntaxNode) -> Option<SyntaxNod
|
||||||
Some(res)
|
Some(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn least_common_ancestor_element(u: impl Element, v: impl Element) -> Option<SyntaxNode> {
|
||||||
|
let u = u.syntax_element();
|
||||||
|
let v = v.syntax_element();
|
||||||
|
if u == v {
|
||||||
|
return match u {
|
||||||
|
NodeOrToken::Node(node) => Some(node),
|
||||||
|
NodeOrToken::Token(token) => token.parent(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
let u_depth = u.ancestors().count();
|
||||||
|
let v_depth = v.ancestors().count();
|
||||||
|
let keep = u_depth.min(v_depth);
|
||||||
|
|
||||||
|
let u_candidates = u.ancestors().skip(u_depth - keep);
|
||||||
|
let v_candidates = v.ancestors().skip(v_depth - keep);
|
||||||
|
let (res, _) = u_candidates.zip(v_candidates).find(|(x, y)| x == y)?;
|
||||||
|
Some(res)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn neighbor<T: AstNode>(me: &T, direction: Direction) -> Option<T> {
|
pub fn neighbor<T: AstNode>(me: &T, direction: Direction) -> Option<T> {
|
||||||
me.syntax().siblings(direction).skip(1).find_map(T::cast)
|
me.syntax().siblings(direction).skip(1).find_map(T::cast)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3015,7 +3015,7 @@ mod foo {
|
||||||
|
|
||||||
|
|
||||||
### `remove_unused_param`
|
### `remove_unused_param`
|
||||||
**Source:** [remove_unused_param.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/remove_unused_param.rs#L15)
|
**Source:** [remove_unused_param.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/remove_unused_param.rs#L16)
|
||||||
|
|
||||||
Removes unused function parameter.
|
Removes unused function parameter.
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue