Skip to content

Commit a63fc66

Browse files
committed
rebase recursively_add_derive onto main
1 parent ba38838 commit a63fc66

File tree

1 file changed

+34
-31
lines changed

1 file changed

+34
-31
lines changed

crates/ide-assists/src/handlers/recursively_add_derive.rs

Lines changed: 34 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
11
use crate::{AssistContext, Assists};
22
use hir::{HasAttrs as _, HasCrate, HirFileId, ItemInNs};
33
use ide_db::{
4-
assists::{AssistId, AssistKind},
5-
helpers::mod_path_to_ast,
6-
imports::import_assets::NameToImport,
7-
items_locator, FxHashMap,
4+
FxHashMap, assists::AssistId, helpers::mod_path_to_ast, imports::import_assets::NameToImport,
5+
items_locator,
86
};
97
use itertools::Itertools;
108
use smallvec::SmallVec;
119
use syntax::{
12-
ast::{self, edit_in_place::AttrsOwnerEdit, make, HasAttrs},
13-
syntax_editor::Position,
14-
AstNode, T,
10+
AstNode,
11+
SyntaxKind::{ATTR, COMMENT, WHITESPACE},
12+
T,
13+
ast::{self, HasAttrs, edit::IndentLevel, make},
14+
syntax_editor::{Element, Position},
1515
};
1616

1717
// Assist: recursively_add_derive
@@ -64,7 +64,7 @@ pub(crate) fn recursively_add_derive(acc: &mut Assists, ctx: &AssistContext<'_>)
6464
// The cursor is on the derive keyword, use all derive items the ADT has.
6565
let items: SmallVec<_> = adt
6666
.attrs(ctx.db())
67-
.by_key(&hir::sym::derive)
67+
.by_key(hir::sym::derive)
6868
.attrs()
6969
.filter_map(|attr| attr.parse_path_comma_token_tree(ctx.db()))
7070
.flatten()
@@ -104,7 +104,7 @@ pub(crate) fn recursively_add_derive(acc: &mut Assists, ctx: &AssistContext<'_>)
104104
})
105105
.to_string();
106106
acc.add(
107-
AssistId("recursively_add_derive", AssistKind::Generate),
107+
AssistId::generate("recursively_add_derive"),
108108
format!("Recursively add `#[derive({formatted_items})]` to each field type"),
109109
adt_src.syntax().text_range(),
110110
|edit| {
@@ -138,11 +138,7 @@ pub(crate) fn recursively_add_derive(acc: &mut Assists, ctx: &AssistContext<'_>)
138138
});
139139

140140
let maybe_derive_attr = adt_src.attrs().find_map(|attr| {
141-
if attr.path()?.syntax().text() == "derive" {
142-
attr.token_tree()
143-
} else {
144-
None
145-
}
141+
if attr.path()?.syntax().text() == "derive" { attr.token_tree() } else { None }
146142
});
147143

148144
if let Some(derive_attr) = maybe_derive_attr {
@@ -171,19 +167,29 @@ pub(crate) fn recursively_add_derive(acc: &mut Assists, ctx: &AssistContext<'_>)
171167
let tt = derive_paths
172168
.filter_map(|item| item.into_token())
173169
.map(syntax::NodeOrToken::Token)
174-
.collect();
170+
.collect::<Vec<_>>();
175171
let derive = make::attr_outer(make::meta_token_tree(
176172
make::ext::ident_path("derive"),
177173
make::token_tree(T!['('], tt).clone_for_update(),
178174
))
179175
.clone_for_update();
180176

181-
// TODO: Switch to the `SyntaxEditor` equivalent of `add_attr()` once that's available.
182-
let new_adt = adt_src.clone_for_update();
183-
new_adt.add_attr(derive);
184-
editor.replace(adt_src.syntax(), new_adt.syntax());
177+
let indent = IndentLevel::from_node(adt_src.syntax());
178+
let after_attrs_and_comments = adt_src
179+
.syntax()
180+
.children_with_tokens()
181+
.find(|it| !matches!(it.kind(), WHITESPACE | COMMENT | ATTR))
182+
.map_or(Position::first_child_of(adt_src.syntax()), Position::before);
183+
184+
editor.insert_all(
185+
after_attrs_and_comments,
186+
vec![
187+
derive.syntax().syntax_element(),
188+
make::tokens::whitespace(&format!("\n{indent}")).syntax_element(),
189+
],
190+
);
185191
}
186-
edit.add_file_edits(file_id, editor);
192+
edit.add_file_edits(file_id.file_id(ctx.db()), editor);
187193
}
188194
},
189195
)
@@ -200,31 +206,32 @@ struct DeriveItem {
200206
impl DeriveItem {
201207
fn from_path(
202208
ctx: &AssistContext<'_>,
203-
ty: &hir::Type,
209+
ty: &hir::Type<'_>,
204210
current_crate: hir::Crate,
205211
derive_macro: hir::Macro,
206212
name: String,
207213
) -> Option<Self> {
208-
if derive_macro.kind(ctx.db()) != hir::MacroKind::Derive {
209-
return None;
214+
match derive_macro.kind(ctx.db()) {
215+
hir::MacroKind::Derive | hir::MacroKind::DeriveBuiltIn => {}
216+
_ => return None,
210217
}
211218

212219
// Try to find a trait with the same name as the derive macro, which the type implements.
213220
let maybe_trait = items_locator::items_with_name(
214-
&ctx.sema,
221+
ctx.db(),
215222
current_crate,
216223
NameToImport::exact_case_sensitive(name),
217224
items_locator::AssocSearchMode::Exclude,
218225
)
219-
.find_map(|item| item.as_module_def()?.as_trait())
226+
.find_map(|(item, _)| item.into_module_def().as_trait())
220227
.filter(|trait_| ty.impls_trait(ctx.db(), *trait_, &[]));
221228
Some(DeriveItem { derive_macro, maybe_trait })
222229
}
223230

224231
fn implemented_by(&self, ctx: &AssistContext<'_>, adt: &hir::Adt, src: &ast::Adt) -> bool {
225232
// Check if the type already has the derive attribute.
226233
adt.attrs(ctx.db())
227-
.by_key(&hir::sym::derive)
234+
.by_key(hir::sym::derive)
228235
.attrs()
229236
.filter_map(|attr| attr.parse_path_comma_token_tree(ctx.db()))
230237
.flatten()
@@ -280,11 +287,7 @@ fn derive_targets(
280287
.cloned()
281288
.collect();
282289

283-
if derives.is_empty() {
284-
None
285-
} else {
286-
Some((src, derives))
287-
}
290+
if derives.is_empty() { None } else { Some((src, derives)) }
288291
}
289292

290293
fn field_types_to_derive(

0 commit comments

Comments
 (0)