Skip to content

Commit 0ee81de

Browse files
Merge pull request #21695 from A4-Tacks/redundant-item-order
fix: Improve inserted order for trait_impl_redundant_assoc_item
2 parents a75b500 + a6596c0 commit 0ee81de

1 file changed

Lines changed: 107 additions & 5 deletions

File tree

crates/ide-diagnostics/src/handlers/trait_impl_redundant_assoc_item.rs

Lines changed: 107 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,10 @@ use ide_db::{
55
label::Label,
66
source_change::SourceChangeBuilder,
77
};
8-
use syntax::ToSmolStr;
9-
use syntax::ast::edit::AstNodeEdit;
8+
use syntax::{
9+
AstNode, ToSmolStr,
10+
ast::{HasName, edit::AstNodeEdit},
11+
};
1012

1113
use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext};
1214

@@ -82,16 +84,18 @@ fn quickfix_for_redundant_assoc_item(
8284
let db = ctx.sema.db;
8385
let root = db.parse_or_expand(d.file_id);
8486
// don't modify trait def in outer crate
85-
let current_crate = ctx.sema.scope(&d.impl_.syntax_node_ptr().to_node(&root))?.krate();
87+
let impl_def = d.impl_.to_node(&root);
88+
let current_crate = ctx.sema.scope(impl_def.syntax())?.krate();
8689
let trait_def_crate = d.trait_.module(db).krate(db);
8790
if trait_def_crate != current_crate {
8891
return None;
8992
}
9093

9194
let trait_def = d.trait_.source(db)?.value;
92-
let l_curly = trait_def.assoc_item_list()?.l_curly_token()?.text_range();
95+
let insert_after = find_insert_after(range, &impl_def, &trait_def)?;
96+
9397
let where_to_insert =
94-
hir::InFile::new(d.file_id, l_curly).original_node_file_range_rooted_opt(db)?;
98+
hir::InFile::new(d.file_id, insert_after).original_node_file_range_rooted_opt(db)?;
9599
if where_to_insert.file_id != file_id {
96100
return None;
97101
}
@@ -112,6 +116,41 @@ fn quickfix_for_redundant_assoc_item(
112116
}])
113117
}
114118

119+
fn find_insert_after(
120+
redundant_range: TextRange,
121+
impl_def: &syntax::ast::Impl,
122+
trait_def: &syntax::ast::Trait,
123+
) -> Option<TextRange> {
124+
let impl_items_before_redundant = impl_def
125+
.assoc_item_list()?
126+
.assoc_items()
127+
.take_while(|it| it.syntax().text_range().start() < redundant_range.start())
128+
.filter_map(|it| name_of(&it))
129+
.collect::<Vec<_>>();
130+
131+
let after_item = trait_def
132+
.assoc_item_list()?
133+
.assoc_items()
134+
.filter(|it| {
135+
name_of(it).is_some_and(|name| {
136+
impl_items_before_redundant.iter().any(|it| it.text() == name.text())
137+
})
138+
})
139+
.last()
140+
.map(|it| it.syntax().text_range());
141+
142+
return after_item.or_else(|| Some(trait_def.assoc_item_list()?.l_curly_token()?.text_range()));
143+
144+
fn name_of(it: &syntax::ast::AssocItem) -> Option<syntax::ast::Name> {
145+
match it {
146+
syntax::ast::AssocItem::Const(it) => it.name(),
147+
syntax::ast::AssocItem::Fn(it) => it.name(),
148+
syntax::ast::AssocItem::TypeAlias(it) => it.name(),
149+
syntax::ast::AssocItem::MacroCall(_) => None,
150+
}
151+
}
152+
}
153+
115154
#[cfg(test)]
116155
mod tests {
117156
use crate::tests::{check_diagnostics, check_fix, check_no_fix};
@@ -274,6 +313,69 @@ mod indent {
274313
);
275314
}
276315

316+
#[test]
317+
fn quickfix_order() {
318+
check_fix(
319+
r#"
320+
trait Marker {
321+
fn foo();
322+
fn baz();
323+
}
324+
struct Foo;
325+
impl Marker for Foo {
326+
fn foo() {}
327+
fn missing() {}$0
328+
fn baz() {}
329+
}
330+
"#,
331+
r#"
332+
trait Marker {
333+
fn foo();
334+
fn missing();
335+
fn baz();
336+
}
337+
struct Foo;
338+
impl Marker for Foo {
339+
fn foo() {}
340+
fn missing() {}
341+
fn baz() {}
342+
}
343+
"#,
344+
);
345+
346+
check_fix(
347+
r#"
348+
trait Marker {
349+
type Item;
350+
fn bar();
351+
fn baz();
352+
}
353+
struct Foo;
354+
impl Marker for Foo {
355+
type Item = Foo;
356+
fn missing() {}$0
357+
fn bar() {}
358+
fn baz() {}
359+
}
360+
"#,
361+
r#"
362+
trait Marker {
363+
type Item;
364+
fn missing();
365+
fn bar();
366+
fn baz();
367+
}
368+
struct Foo;
369+
impl Marker for Foo {
370+
type Item = Foo;
371+
fn missing() {}
372+
fn bar() {}
373+
fn baz() {}
374+
}
375+
"#,
376+
);
377+
}
378+
277379
#[test]
278380
fn quickfix_dont_work() {
279381
check_no_fix(

0 commit comments

Comments
 (0)