mirror of
https://github.com/rust-lang/rust.git
synced 2026-06-01 14:10:03 +03:00
Merge pull request #21784 from 80avin/fix-inline-type-assist
fix: remove angle brackets if all lifetime args removed in inline type alias code assist.
This commit is contained in:
@@ -12,7 +12,7 @@
|
||||
use syntax::ast::syntax_factory::SyntaxFactory;
|
||||
use syntax::syntax_editor::SyntaxEditor;
|
||||
use syntax::{
|
||||
AstNode, NodeOrToken, SyntaxNode,
|
||||
AstNode, NodeOrToken, SyntaxKind, SyntaxNode, T,
|
||||
ast::{self, HasGenericParams, HasName},
|
||||
};
|
||||
|
||||
@@ -322,12 +322,42 @@ fn create_replacement(
|
||||
if let Some(old_lifetime) = ast::Lifetime::cast(syntax.clone()) {
|
||||
if let Some(new_lifetime) = lifetime_map.0.get(&old_lifetime.to_string()) {
|
||||
if new_lifetime.text() == "'_" {
|
||||
removals.push(NodeOrToken::Node(syntax.clone()));
|
||||
// Check if this lifetime is inside a LifetimeArg (in angle brackets)
|
||||
if let Some(lifetime_arg) =
|
||||
old_lifetime.syntax().parent().and_then(ast::LifetimeArg::cast)
|
||||
{
|
||||
// Remove LifetimeArg and associated comma/whitespace
|
||||
let lifetime_arg_syntax = lifetime_arg.syntax();
|
||||
removals.push(NodeOrToken::Node(lifetime_arg_syntax.clone()));
|
||||
|
||||
if let Some(ws) = syntax.next_sibling_or_token() {
|
||||
removals.push(ws.clone());
|
||||
// Remove comma and whitespace (look forward then backward)
|
||||
let comma_and_ws: Vec<_> = lifetime_arg_syntax
|
||||
.siblings_with_tokens(syntax::Direction::Next)
|
||||
.skip(1)
|
||||
.take_while(|it| it.as_token().is_some())
|
||||
.take_while_inclusive(|it| it.kind() == T![,])
|
||||
.collect();
|
||||
|
||||
if comma_and_ws.iter().any(|it| it.kind() == T![,]) {
|
||||
removals.extend(comma_and_ws);
|
||||
} else {
|
||||
// No comma after, try before
|
||||
let comma_and_ws: Vec<_> = lifetime_arg_syntax
|
||||
.siblings_with_tokens(syntax::Direction::Prev)
|
||||
.skip(1)
|
||||
.take_while(|it| it.as_token().is_some())
|
||||
.take_while_inclusive(|it| it.kind() == T![,])
|
||||
.collect();
|
||||
removals.extend(comma_and_ws);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
removals.push(NodeOrToken::Node(syntax.clone()));
|
||||
if let Some(ws) = syntax.next_sibling_or_token()
|
||||
&& ws.kind() == SyntaxKind::WHITESPACE
|
||||
{
|
||||
removals.push(ws);
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -349,6 +379,34 @@ fn create_replacement(
|
||||
}
|
||||
}
|
||||
|
||||
// Deduplicate removals to avoid intersecting changes
|
||||
removals.sort_by_key(|n| n.text_range().start());
|
||||
removals.dedup();
|
||||
|
||||
// Remove GenericArgList entirely if all its args are being removed (avoids empty angle brackets)
|
||||
let generic_arg_lists_to_check: Vec<_> =
|
||||
updated_concrete_type.descendants().filter_map(ast::GenericArgList::cast).collect();
|
||||
|
||||
for generic_arg_list in generic_arg_lists_to_check {
|
||||
let will_be_empty = generic_arg_list.generic_args().all(|arg| match arg {
|
||||
ast::GenericArg::LifetimeArg(lt_arg) => removals.iter().any(|removal| {
|
||||
if let NodeOrToken::Node(node) = removal { node == lt_arg.syntax() } else { false }
|
||||
}),
|
||||
_ => false,
|
||||
});
|
||||
|
||||
if will_be_empty && generic_arg_list.generic_args().next().is_some() {
|
||||
removals.retain(|removal| {
|
||||
if let NodeOrToken::Node(node) = removal {
|
||||
!node.ancestors().any(|anc| anc == *generic_arg_list.syntax())
|
||||
} else {
|
||||
true
|
||||
}
|
||||
});
|
||||
removals.push(NodeOrToken::Node(generic_arg_list.syntax().clone()));
|
||||
}
|
||||
}
|
||||
|
||||
for (old, new) in replacements {
|
||||
editor.replace(old, new);
|
||||
}
|
||||
@@ -946,6 +1004,48 @@ trait Tr {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn inline_types_with_lifetime() {
|
||||
check_assist(
|
||||
inline_type_alias_uses,
|
||||
r#"
|
||||
struct A<'a, 'b>(pub &'a mut &'b mut ());
|
||||
|
||||
type $0T<'a, 'b> = A<'a, 'b>;
|
||||
|
||||
fn foo(_: T) {}
|
||||
"#,
|
||||
r#"
|
||||
struct A<'a, 'b>(pub &'a mut &'b mut ());
|
||||
|
||||
|
||||
|
||||
fn foo(_: A) {}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn mixed_lifetime_and_type_args() {
|
||||
check_assist(
|
||||
inline_type_alias,
|
||||
r#"
|
||||
type Foo<'a, T> = Bar<'a, T>;
|
||||
struct Bar<'a, T>(&'a T);
|
||||
fn main() {
|
||||
let a: $0Foo<u32>;
|
||||
}
|
||||
"#,
|
||||
r#"
|
||||
type Foo<'a, T> = Bar<'a, T>;
|
||||
struct Bar<'a, T>(&'a T);
|
||||
fn main() {
|
||||
let a: Bar<u32>;
|
||||
}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
mod inline_type_alias_uses {
|
||||
use crate::{handlers::inline_type_alias::inline_type_alias_uses, tests::check_assist};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user