Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/ide-assists/src/handlers/remove_underscore.rs')
-rw-r--r--crates/ide-assists/src/handlers/remove_underscore.rs191
1 files changed, 191 insertions, 0 deletions
diff --git a/crates/ide-assists/src/handlers/remove_underscore.rs b/crates/ide-assists/src/handlers/remove_underscore.rs
new file mode 100644
index 0000000000..912e1936b5
--- /dev/null
+++ b/crates/ide-assists/src/handlers/remove_underscore.rs
@@ -0,0 +1,191 @@
+use ide_db::{
+ assists::AssistId,
+ defs::{Definition, NameClass, NameRefClass},
+};
+use syntax::{AstNode, ast};
+
+use crate::{AssistContext, Assists};
+
+// Assist: remove_underscore_from_used_variables
+//
+// Removes underscore from used variables.
+//
+// ```
+// fn main() {
+// let mut _$0foo = 1;
+// _foo = 2;
+// }
+// ```
+// ->
+// ```
+// fn main() {
+// let mut foo = 1;
+// foo = 2;
+// }
+// ```
+pub(crate) fn remove_underscore(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
+ let (text, text_range, def) = if let Some(name_ref) = ctx.find_node_at_offset::<ast::Name>() {
+ let text = name_ref.text();
+ if !text.starts_with('_') {
+ return None;
+ }
+
+ let def = match NameClass::classify(&ctx.sema, &name_ref)? {
+ NameClass::Definition(def @ Definition::Local(_)) => def,
+ NameClass::PatFieldShorthand { local_def, .. } => Definition::Local(local_def),
+ _ => return None,
+ };
+ (text.to_owned(), name_ref.syntax().text_range(), def)
+ } else if let Some(name_ref) = ctx.find_node_at_offset::<ast::NameRef>() {
+ let text = name_ref.text();
+ if !text.starts_with('_') {
+ return None;
+ }
+ let def = match NameRefClass::classify(&ctx.sema, &name_ref)? {
+ NameRefClass::Definition(def @ Definition::Local(_), _) => def,
+ NameRefClass::FieldShorthand { local_ref, .. } => Definition::Local(local_ref),
+ _ => return None,
+ };
+ (text.to_owned(), name_ref.syntax().text_range(), def)
+ } else {
+ return None;
+ };
+
+ if !def.usages(&ctx.sema).at_least_one() {
+ return None;
+ }
+
+ let new_name = text.trim_start_matches('_');
+ acc.add(
+ AssistId::refactor("remove_underscore_from_used_variables"),
+ "Remove underscore from a used variable",
+ text_range,
+ |builder| {
+ let changes = def.rename(&ctx.sema, new_name).unwrap();
+ builder.source_change = changes;
+ },
+ )
+}
+
+#[cfg(test)]
+mod tests {
+ use crate::tests::{check_assist, check_assist_not_applicable};
+
+ use super::*;
+
+ #[test]
+ fn remove_underscore_from_used_variable() {
+ check_assist(
+ remove_underscore,
+ r#"
+fn main() {
+ let mut _$0foo = 1;
+ _foo = 2;
+}
+"#,
+ r#"
+fn main() {
+ let mut foo = 1;
+ foo = 2;
+}
+"#,
+ );
+ }
+
+ #[test]
+ fn not_applicable_for_unused() {
+ check_assist_not_applicable(
+ remove_underscore,
+ r#"
+fn main() {
+ let _$0unused = 1;
+}
+"#,
+ );
+ }
+
+ #[test]
+ fn not_applicable_for_no_underscore() {
+ check_assist_not_applicable(
+ remove_underscore,
+ r#"
+fn main() {
+ let f$0oo = 1;
+ foo = 2;
+}
+"#,
+ );
+ }
+
+ #[test]
+ fn remove_multiple_underscores() {
+ check_assist(
+ remove_underscore,
+ r#"
+fn main() {
+ let mut _$0_foo = 1;
+ __foo = 2;
+}
+"#,
+ r#"
+fn main() {
+ let mut foo = 1;
+ foo = 2;
+}
+"#,
+ );
+ }
+
+ #[test]
+ fn remove_underscore_on_usage() {
+ check_assist(
+ remove_underscore,
+ r#"
+fn main() {
+ let mut _foo = 1;
+ _$0foo = 2;
+}
+"#,
+ r#"
+fn main() {
+ let mut foo = 1;
+ foo = 2;
+}
+"#,
+ );
+ }
+
+ #[test]
+ fn remove_underscore_in_function_parameter_usage() {
+ check_assist(
+ remove_underscore,
+ r#"
+fn foo(_foo: i32) {
+ let bar = _$0foo + 1;
+}
+"#,
+ r#"
+fn foo(foo: i32) {
+ let bar = foo + 1;
+}
+"#,
+ )
+ }
+
+ #[test]
+ fn remove_underscore_in_function_parameter() {
+ check_assist(
+ remove_underscore,
+ r#"
+fn foo(_$0foo: i32) {
+ let bar = _foo + 1;
+}
+"#,
+ r#"
+fn foo(foo: i32) {
+ let bar = foo + 1;
+}
+"#,
+ )
+ }
+}