Unnamed repository; edit this file 'description' to name the repository.
Fix indent for trait_impl_redundant_assoc_item
Example --- ```rust trait Foo { } impl Foo for () { $0fn foo<T: Copy>(&self); } ``` **Before this PR**: ```rust trait Foo { fn foo<T>(&self) where T: Copy,; } impl Foo for () { fn foo<T: Copy>(&self); } ``` **After this PR**: ```rust trait Foo { fn foo<T>(&self) where T: Copy,; } impl Foo for () { fn foo<T: Copy>(&self); } ```
A4-Tacks 8 weeks ago
parent 17e7f0c · commit e44f348
-rw-r--r--crates/ide-diagnostics/src/handlers/trait_impl_redundant_assoc_item.rs97
-rw-r--r--crates/stdx/src/lib.rs19
2 files changed, 109 insertions, 7 deletions
diff --git a/crates/ide-diagnostics/src/handlers/trait_impl_redundant_assoc_item.rs b/crates/ide-diagnostics/src/handlers/trait_impl_redundant_assoc_item.rs
index cb3aac3717..f4054610f2 100644
--- a/crates/ide-diagnostics/src/handlers/trait_impl_redundant_assoc_item.rs
+++ b/crates/ide-diagnostics/src/handlers/trait_impl_redundant_assoc_item.rs
@@ -6,6 +6,7 @@ use ide_db::{
source_change::SourceChangeBuilder,
};
use syntax::ToSmolStr;
+use syntax::ast::edit::AstNodeEdit;
use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext};
@@ -23,6 +24,7 @@ pub(crate) fn trait_impl_redundant_assoc_item(
let default_range = d.impl_.syntax_node_ptr().text_range();
let trait_name = d.trait_.name(db).display_no_db(ctx.edition).to_smolstr();
+ let indent_level = d.trait_.source(db).map_or(0, |it| it.value.indent_level().0) + 1;
let (redundant_item_name, diagnostic_range, redundant_item_def) = match assoc_item {
hir::AssocItem::Function(id) => {
@@ -30,7 +32,7 @@ pub(crate) fn trait_impl_redundant_assoc_item(
(
format!("`fn {redundant_assoc_item_name}`"),
function.source(db).map(|it| it.syntax().text_range()).unwrap_or(default_range),
- format!("\n {};", function.display(db, ctx.display_target)),
+ format!("\n{};", function.display(db, ctx.display_target)),
)
}
hir::AssocItem::Const(id) => {
@@ -38,7 +40,7 @@ pub(crate) fn trait_impl_redundant_assoc_item(
(
format!("`const {redundant_assoc_item_name}`"),
constant.source(db).map(|it| it.syntax().text_range()).unwrap_or(default_range),
- format!("\n {};", constant.display(db, ctx.display_target)),
+ format!("\n{};", constant.display(db, ctx.display_target)),
)
}
hir::AssocItem::TypeAlias(id) => {
@@ -46,10 +48,8 @@ pub(crate) fn trait_impl_redundant_assoc_item(
(
format!("`type {redundant_assoc_item_name}`"),
type_alias.source(db).map(|it| it.syntax().text_range()).unwrap_or(default_range),
- format!(
- "\n type {};",
- type_alias.name(ctx.sema.db).display_no_db(ctx.edition).to_smolstr()
- ),
+ // FIXME cannot generate generic parameter and bounds
+ format!("\ntype {};", type_alias.name(ctx.sema.db).display_no_db(ctx.edition)),
)
}
};
@@ -65,7 +65,7 @@ pub(crate) fn trait_impl_redundant_assoc_item(
.with_fixes(quickfix_for_redundant_assoc_item(
ctx,
d,
- redundant_item_def,
+ stdx::indent_string(&redundant_item_def, indent_level),
diagnostic_range,
))
}
@@ -192,6 +192,89 @@ impl Marker for Foo {
}
#[test]
+ fn quickfix_indentations() {
+ check_fix(
+ r#"
+mod indent {
+ trait Marker {
+ fn boo();
+ }
+ struct Foo;
+ impl Marker for Foo {
+ fn$0 bar<T: Copy>(_a: i32, _b: T) -> String {}
+ fn boo() {}
+ }
+}
+ "#,
+ r#"
+mod indent {
+ trait Marker {
+ fn bar<T>(_a: i32, _b: T) -> String
+ where
+ T: Copy,;
+ fn boo();
+ }
+ struct Foo;
+ impl Marker for Foo {
+ fn bar<T: Copy>(_a: i32, _b: T) -> String {}
+ fn boo() {}
+ }
+}
+ "#,
+ );
+
+ check_fix(
+ r#"
+mod indent {
+ trait Marker {
+ fn foo () {}
+ }
+ struct Foo;
+ impl Marker for Foo {
+ const FLAG: bool$0 = false;
+ }
+}
+ "#,
+ r#"
+mod indent {
+ trait Marker {
+ const FLAG: bool;
+ fn foo () {}
+ }
+ struct Foo;
+ impl Marker for Foo {
+ const FLAG: bool = false;
+ }
+}
+ "#,
+ );
+
+ check_fix(
+ r#"
+mod indent {
+ trait Marker {
+ }
+ struct Foo;
+ impl Marker for Foo {
+ type T = i32;$0
+ }
+}
+ "#,
+ r#"
+mod indent {
+ trait Marker {
+ type T;
+ }
+ struct Foo;
+ impl Marker for Foo {
+ type T = i32;
+ }
+}
+ "#,
+ );
+ }
+
+ #[test]
fn quickfix_dont_work() {
check_no_fix(
r#"
diff --git a/crates/stdx/src/lib.rs b/crates/stdx/src/lib.rs
index a1af4cc6be..275e0e5ac8 100644
--- a/crates/stdx/src/lib.rs
+++ b/crates/stdx/src/lib.rs
@@ -1,5 +1,6 @@
//! Missing batteries for standard libraries.
+use std::borrow::Cow;
use std::io as sio;
use std::process::Command;
use std::{cmp::Ordering, ops, time::Instant};
@@ -250,6 +251,24 @@ pub fn dedent_by(spaces: usize, text: &str) -> String {
.collect()
}
+/// Indent non empty lines, including the first line
+#[must_use]
+pub fn indent_string(s: &str, indent_level: u8) -> String {
+ if indent_level == 0 || s.is_empty() {
+ return s.to_owned();
+ }
+ let indent_str = " ".repeat(indent_level as usize);
+ s.split_inclusive("\n")
+ .map(|line| {
+ if line.trim_end().is_empty() {
+ Cow::Borrowed(line)
+ } else {
+ format!("{indent_str}{line}").into()
+ }
+ })
+ .collect()
+}
+
pub fn equal_range_by<T, F>(slice: &[T], mut key: F) -> ops::Range<usize>
where
F: FnMut(&T) -> Ordering,