Auto merge of #17571 - winstxnhdw:bool-to-enum-no-dupe, r=Veykril

feat: do not add new enum if it already exists

## Summary

This PR introduces a check for the existence of another enum within the current scope, and if it exist, we skip `add_enum_def`.

## Why?

Currently, when using the `bool_to_enum` assist more than once, it is possible to add multiple enum definitions. For example, the following snippet,

```rs
#[derive(PartialEq, Eq)]
enum Bool {
    True,
    False,
}

fn main() {
    let a = Bool::True;
    let b = true;
    println!("Hello, world!");
}
```

will be transformed into,

```rs
#[derive(PartialEq, Eq)]
enum Bool {
    True,
    False,
}

#[derive(PartialEq, Eq)]
enum Bool {
    True,
    False,
}

fn main() {
    let a = Bool::True;
    let b = Bool::True;
    println!("Hello, world!");
}
```

This can be annoying for users to clean up.
This commit is contained in:
bors 2024-07-11 08:55:34 +00:00
commit 5577e4e3b1

View file

@ -96,7 +96,7 @@ struct BoolNodeData {
/// Attempts to find an appropriate node to apply the action to. /// Attempts to find an appropriate node to apply the action to.
fn find_bool_node(ctx: &AssistContext<'_>) -> Option<BoolNodeData> { fn find_bool_node(ctx: &AssistContext<'_>) -> Option<BoolNodeData> {
let name: ast::Name = ctx.find_node_at_offset()?; let name = ctx.find_node_at_offset::<ast::Name>()?;
if let Some(ident_pat) = name.syntax().parent().and_then(ast::IdentPat::cast) { if let Some(ident_pat) = name.syntax().parent().and_then(ast::IdentPat::cast) {
let def = ctx.sema.to_def(&ident_pat)?; let def = ctx.sema.to_def(&ident_pat)?;
@ -461,7 +461,20 @@ fn add_enum_def(
usages: &UsageSearchResult, usages: &UsageSearchResult,
target_node: SyntaxNode, target_node: SyntaxNode,
target_module: &hir::Module, target_module: &hir::Module,
) { ) -> Option<()> {
let insert_before = node_to_insert_before(target_node);
if ctx
.sema
.scope(&insert_before)?
.module()
.scope(ctx.db(), Some(*target_module))
.iter()
.any(|(name, _)| name.as_str() == Some("Bool"))
{
return None;
}
let make_enum_pub = usages let make_enum_pub = usages
.iter() .iter()
.flat_map(|(_, refs)| refs) .flat_map(|(_, refs)| refs)
@ -472,7 +485,6 @@ fn add_enum_def(
.any(|module| module.nearest_non_block_module(ctx.db()) != *target_module); .any(|module| module.nearest_non_block_module(ctx.db()) != *target_module);
let enum_def = make_bool_enum(make_enum_pub); let enum_def = make_bool_enum(make_enum_pub);
let insert_before = node_to_insert_before(target_node);
let indent = IndentLevel::from_node(&insert_before); let indent = IndentLevel::from_node(&insert_before);
enum_def.reindent_to(indent); enum_def.reindent_to(indent);
@ -480,6 +492,8 @@ fn add_enum_def(
insert_before.text_range().start(), insert_before.text_range().start(),
format!("{}\n\n{indent}", enum_def.syntax().text()), format!("{}\n\n{indent}", enum_def.syntax().text()),
); );
Some(())
} }
/// Finds where to put the new enum definition. /// Finds where to put the new enum definition.
@ -553,6 +567,33 @@ fn function(foo: Bool, bar: bool) {
) )
} }
#[test]
fn no_duplicate_enums() {
check_assist(
bool_to_enum,
r#"
#[derive(PartialEq, Eq)]
enum Bool { True, False }
fn function(foo: bool, $0bar: bool) {
if bar {
println!("bar");
}
}
"#,
r#"
#[derive(PartialEq, Eq)]
enum Bool { True, False }
fn function(foo: bool, bar: Bool) {
if bar == Bool::True {
println!("bar");
}
}
"#,
)
}
#[test] #[test]
fn parameter_with_last_param_usage() { fn parameter_with_last_param_usage() {
check_assist( check_assist(