mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-26 04:53:34 +00:00
Make replace_derive_with_manual_impl work again
This commit is contained in:
parent
be3168dabe
commit
f13c98034b
9 changed files with 118 additions and 130 deletions
|
@ -1792,6 +1792,13 @@ impl MacroDef {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_builtin_derive(&self) -> bool {
|
||||||
|
match self.id.kind {
|
||||||
|
MacroDefKind::BuiltInAttr(exp, _) => exp.is_derive(),
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn is_attr(&self) -> bool {
|
pub fn is_attr(&self) -> bool {
|
||||||
matches!(self.kind(), MacroKind::Attr)
|
matches!(self.kind(), MacroKind::Attr)
|
||||||
}
|
}
|
||||||
|
|
|
@ -386,6 +386,17 @@ impl MacroCallKind {
|
||||||
MacroCallKind::Derive { ast_id, .. } => {
|
MacroCallKind::Derive { ast_id, .. } => {
|
||||||
ast_id.with_value(ast_id.to_node(db).syntax().clone())
|
ast_id.with_value(ast_id.to_node(db).syntax().clone())
|
||||||
}
|
}
|
||||||
|
MacroCallKind::Attr { ast_id, is_derive: true, invoc_attr_index, .. } => {
|
||||||
|
ast_id.with_value(ast_id.to_node(db)).map(|it| {
|
||||||
|
it.doc_comments_and_attrs()
|
||||||
|
.nth(*invoc_attr_index as usize)
|
||||||
|
.and_then(|it| match it {
|
||||||
|
Either::Left(attr) => Some(attr.syntax().clone()),
|
||||||
|
Either::Right(_) => None,
|
||||||
|
})
|
||||||
|
.unwrap_or_else(|| it.syntax().clone())
|
||||||
|
})
|
||||||
|
}
|
||||||
MacroCallKind::Attr { ast_id, .. } => {
|
MacroCallKind::Attr { ast_id, .. } => {
|
||||||
ast_id.with_value(ast_id.to_node(db).syntax().clone())
|
ast_id.with_value(ast_id.to_node(db).syntax().clone())
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,8 +3,7 @@ use ide_db::{
|
||||||
helpers::{insert_whitespace_into_node::insert_ws_into, pick_best_token},
|
helpers::{insert_whitespace_into_node::insert_ws_into, pick_best_token},
|
||||||
RootDatabase,
|
RootDatabase,
|
||||||
};
|
};
|
||||||
use itertools::Itertools;
|
use syntax::{ast, ted, AstNode, NodeOrToken, SyntaxKind, SyntaxNode, T};
|
||||||
use syntax::{ast, ted, AstNode, SyntaxKind, SyntaxNode};
|
|
||||||
|
|
||||||
use crate::FilePosition;
|
use crate::FilePosition;
|
||||||
|
|
||||||
|
@ -52,7 +51,17 @@ pub(crate) fn expand_macro(db: &RootDatabase, position: FilePosition) -> Option<
|
||||||
let token = hir::InFile::new(hir_file, descended).upmap(db)?.value;
|
let token = hir::InFile::new(hir_file, descended).upmap(db)?.value;
|
||||||
let attr = token.ancestors().find_map(ast::Attr::cast)?;
|
let attr = token.ancestors().find_map(ast::Attr::cast)?;
|
||||||
let expansions = sema.expand_derive_macro(&attr)?;
|
let expansions = sema.expand_derive_macro(&attr)?;
|
||||||
Some(ExpandedMacro { name, expansion: expansions.into_iter().map(insert_ws_into).join("") })
|
let idx = attr
|
||||||
|
.token_tree()?
|
||||||
|
.token_trees_and_tokens()
|
||||||
|
.filter_map(NodeOrToken::into_token)
|
||||||
|
.take_while(|it| it == &token)
|
||||||
|
.filter(|it| it.kind() == T![,])
|
||||||
|
.count();
|
||||||
|
Some(ExpandedMacro {
|
||||||
|
name,
|
||||||
|
expansion: expansions.get(idx).cloned().map(insert_ws_into)?.to_string(),
|
||||||
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
if derive.is_some() {
|
if derive.is_some() {
|
||||||
|
@ -370,11 +379,9 @@ struct Foo {}
|
||||||
struct Foo {}
|
struct Foo {}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
Copy, Clone
|
Copy
|
||||||
impl < >core::marker::Copy for Foo< >{}
|
impl < >core::marker::Copy for Foo< >{}
|
||||||
|
|
||||||
impl < >core::clone::Clone for Foo< >{}
|
|
||||||
|
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@ use ide_db::helpers::{
|
||||||
insert_use::{insert_use, ImportScope},
|
insert_use::{insert_use, ImportScope},
|
||||||
mod_path_to_ast,
|
mod_path_to_ast,
|
||||||
};
|
};
|
||||||
use syntax::{ast, AstNode, AstToken, NodeOrToken, SyntaxElement};
|
use syntax::{ast, AstNode, NodeOrToken, SyntaxElement};
|
||||||
|
|
||||||
use crate::{AssistContext, AssistId, AssistKind, Assists, GroupLabel};
|
use crate::{AssistContext, AssistId, AssistKind, Assists, GroupLabel};
|
||||||
|
|
||||||
|
@ -139,9 +139,7 @@ pub(super) fn find_importable_node(ctx: &AssistContext) -> Option<(ImportAssets,
|
||||||
{
|
{
|
||||||
ImportAssets::for_ident_pat(&ctx.sema, &pat).zip(Some(pat.syntax().clone().into()))
|
ImportAssets::for_ident_pat(&ctx.sema, &pat).zip(Some(pat.syntax().clone().into()))
|
||||||
} else {
|
} else {
|
||||||
// FIXME: Descend?
|
None
|
||||||
let ident = ctx.find_token_at_offset()?;
|
|
||||||
ImportAssets::for_derive_ident(&ctx.sema, &ident).zip(Some(ident.syntax().clone().into()))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
use hir::ModuleDef;
|
use hir::{InFile, ModuleDef};
|
||||||
use ide_db::helpers::insert_whitespace_into_node::insert_ws_into;
|
use ide_db::{
|
||||||
use ide_db::helpers::{
|
helpers::{
|
||||||
get_path_at_cursor_in_tt, import_assets::NameToImport, mod_path_to_ast,
|
import_assets::NameToImport, insert_whitespace_into_node::insert_ws_into, mod_path_to_ast,
|
||||||
parse_tt_as_comma_sep_paths,
|
},
|
||||||
|
items_locator,
|
||||||
};
|
};
|
||||||
use ide_db::items_locator;
|
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use syntax::{
|
use syntax::{
|
||||||
ast::{self, AstNode, AstToken, HasName},
|
ast::{self, AstNode, HasName},
|
||||||
SyntaxKind::WHITESPACE,
|
SyntaxKind::WHITESPACE,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -25,6 +25,7 @@ use crate::{
|
||||||
// Converts a `derive` impl into a manual one.
|
// Converts a `derive` impl into a manual one.
|
||||||
//
|
//
|
||||||
// ```
|
// ```
|
||||||
|
// # //- minicore: derive
|
||||||
// # trait Debug { fn fmt(&self, f: &mut Formatter) -> Result<()>; }
|
// # trait Debug { fn fmt(&self, f: &mut Formatter) -> Result<()>; }
|
||||||
// #[derive(Deb$0ug, Display)]
|
// #[derive(Deb$0ug, Display)]
|
||||||
// struct S;
|
// struct S;
|
||||||
|
@ -45,20 +46,30 @@ pub(crate) fn replace_derive_with_manual_impl(
|
||||||
acc: &mut Assists,
|
acc: &mut Assists,
|
||||||
ctx: &AssistContext,
|
ctx: &AssistContext,
|
||||||
) -> Option<()> {
|
) -> Option<()> {
|
||||||
let attr = ctx.find_node_at_offset::<ast::Attr>()?;
|
let attr = ctx.find_node_at_offset_with_descend::<ast::Attr>()?;
|
||||||
let (name, args) = attr.as_simple_call()?;
|
let path = attr.path()?;
|
||||||
if name != "derive" {
|
let hir_file = ctx.sema.hir_file_for(attr.syntax());
|
||||||
|
if !hir_file.is_derive_attr_macro(ctx.db()) {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
if !args.syntax().text_range().contains(ctx.offset()) {
|
let InFile { file_id, value } = hir_file.call_node(ctx.db())?;
|
||||||
cov_mark::hit!(outside_of_attr_args);
|
if file_id.is_macro() {
|
||||||
|
// FIXME: make this work in macro files
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
// collect the derive paths from the #[derive] expansion
|
||||||
|
let current_derives = ctx
|
||||||
|
.sema
|
||||||
|
.parse_or_expand(hir_file)?
|
||||||
|
.descendants()
|
||||||
|
.filter_map(ast::Attr::cast)
|
||||||
|
.filter_map(|attr| attr.path())
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
let ident = args.syntax().token_at_offset(ctx.offset()).find_map(ast::Ident::cast)?;
|
let adt = value.parent().and_then(ast::Adt::cast)?;
|
||||||
let trait_path = get_path_at_cursor_in_tt(&ident)?;
|
let attr = ast::Attr::cast(value)?;
|
||||||
let adt = attr.syntax().parent().and_then(ast::Adt::cast)?;
|
let args = attr.token_tree()?;
|
||||||
|
|
||||||
let current_module = ctx.sema.scope(adt.syntax()).module()?;
|
let current_module = ctx.sema.scope(adt.syntax()).module()?;
|
||||||
let current_crate = current_module.krate();
|
let current_crate = current_module.krate();
|
||||||
|
@ -66,7 +77,7 @@ pub(crate) fn replace_derive_with_manual_impl(
|
||||||
let found_traits = items_locator::items_with_name(
|
let found_traits = items_locator::items_with_name(
|
||||||
&ctx.sema,
|
&ctx.sema,
|
||||||
current_crate,
|
current_crate,
|
||||||
NameToImport::exact_case_sensitive(trait_path.segments().last()?.to_string()),
|
NameToImport::exact_case_sensitive(path.segments().last()?.to_string()),
|
||||||
items_locator::AssocItemSearch::Exclude,
|
items_locator::AssocItemSearch::Exclude,
|
||||||
Some(items_locator::DEFAULT_QUERY_SEARCH_LIMIT.inner()),
|
Some(items_locator::DEFAULT_QUERY_SEARCH_LIMIT.inner()),
|
||||||
)
|
)
|
||||||
|
@ -83,8 +94,6 @@ pub(crate) fn replace_derive_with_manual_impl(
|
||||||
});
|
});
|
||||||
|
|
||||||
let mut no_traits_found = true;
|
let mut no_traits_found = true;
|
||||||
let current_derives = parse_tt_as_comma_sep_paths(args.clone())?;
|
|
||||||
let current_derives = current_derives.as_slice();
|
|
||||||
for (replace_trait_path, trait_) in found_traits.inspect(|_| no_traits_found = false) {
|
for (replace_trait_path, trait_) in found_traits.inspect(|_| no_traits_found = false) {
|
||||||
add_assist(
|
add_assist(
|
||||||
acc,
|
acc,
|
||||||
|
@ -92,14 +101,14 @@ pub(crate) fn replace_derive_with_manual_impl(
|
||||||
&attr,
|
&attr,
|
||||||
¤t_derives,
|
¤t_derives,
|
||||||
&args,
|
&args,
|
||||||
&trait_path,
|
&path,
|
||||||
&replace_trait_path,
|
&replace_trait_path,
|
||||||
Some(trait_),
|
Some(trait_),
|
||||||
&adt,
|
&adt,
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
if no_traits_found {
|
if no_traits_found {
|
||||||
add_assist(acc, ctx, &attr, ¤t_derives, &args, &trait_path, &trait_path, None, &adt)?;
|
add_assist(acc, ctx, &attr, ¤t_derives, &args, &path, &path, None, &adt)?;
|
||||||
}
|
}
|
||||||
Some(())
|
Some(())
|
||||||
}
|
}
|
||||||
|
@ -128,7 +137,7 @@ fn add_assist(
|
||||||
let impl_def_with_items =
|
let impl_def_with_items =
|
||||||
impl_def_from_trait(&ctx.sema, adt, &annotated_name, trait_, replace_trait_path);
|
impl_def_from_trait(&ctx.sema, adt, &annotated_name, trait_, replace_trait_path);
|
||||||
update_attribute(builder, old_derives, old_tree, old_trait_path, attr);
|
update_attribute(builder, old_derives, old_tree, old_trait_path, attr);
|
||||||
let trait_path = format!("{}", replace_trait_path);
|
let trait_path = replace_trait_path.to_string();
|
||||||
match (ctx.config.snippet_cap, impl_def_with_items) {
|
match (ctx.config.snippet_cap, impl_def_with_items) {
|
||||||
(None, _) => {
|
(None, _) => {
|
||||||
builder.insert(insert_pos, generate_trait_impl_text(adt, &trait_path, ""))
|
builder.insert(insert_pos, generate_trait_impl_text(adt, &trait_path, ""))
|
||||||
|
@ -258,7 +267,7 @@ mod tests {
|
||||||
check_assist(
|
check_assist(
|
||||||
replace_derive_with_manual_impl,
|
replace_derive_with_manual_impl,
|
||||||
r#"
|
r#"
|
||||||
//- minicore: fmt
|
//- minicore: fmt, derive
|
||||||
#[derive(Debu$0g)]
|
#[derive(Debu$0g)]
|
||||||
struct Foo {
|
struct Foo {
|
||||||
bar: String,
|
bar: String,
|
||||||
|
@ -282,7 +291,7 @@ impl core::fmt::Debug for Foo {
|
||||||
check_assist(
|
check_assist(
|
||||||
replace_derive_with_manual_impl,
|
replace_derive_with_manual_impl,
|
||||||
r#"
|
r#"
|
||||||
//- minicore: fmt
|
//- minicore: fmt, derive
|
||||||
#[derive(Debu$0g)]
|
#[derive(Debu$0g)]
|
||||||
struct Foo(String, usize);
|
struct Foo(String, usize);
|
||||||
"#,
|
"#,
|
||||||
|
@ -301,7 +310,7 @@ impl core::fmt::Debug for Foo {
|
||||||
check_assist(
|
check_assist(
|
||||||
replace_derive_with_manual_impl,
|
replace_derive_with_manual_impl,
|
||||||
r#"
|
r#"
|
||||||
//- minicore: fmt
|
//- minicore: fmt, derive
|
||||||
#[derive(Debu$0g)]
|
#[derive(Debu$0g)]
|
||||||
struct Foo;
|
struct Foo;
|
||||||
"#,
|
"#,
|
||||||
|
@ -321,7 +330,7 @@ impl core::fmt::Debug for Foo {
|
||||||
check_assist(
|
check_assist(
|
||||||
replace_derive_with_manual_impl,
|
replace_derive_with_manual_impl,
|
||||||
r#"
|
r#"
|
||||||
//- minicore: fmt
|
//- minicore: fmt, derive
|
||||||
#[derive(Debu$0g)]
|
#[derive(Debu$0g)]
|
||||||
enum Foo {
|
enum Foo {
|
||||||
Bar,
|
Bar,
|
||||||
|
@ -351,7 +360,7 @@ impl core::fmt::Debug for Foo {
|
||||||
check_assist(
|
check_assist(
|
||||||
replace_derive_with_manual_impl,
|
replace_derive_with_manual_impl,
|
||||||
r#"
|
r#"
|
||||||
//- minicore: fmt
|
//- minicore: fmt, derive
|
||||||
#[derive(Debu$0g)]
|
#[derive(Debu$0g)]
|
||||||
enum Foo {
|
enum Foo {
|
||||||
Bar(usize, usize),
|
Bar(usize, usize),
|
||||||
|
@ -380,7 +389,7 @@ impl core::fmt::Debug for Foo {
|
||||||
check_assist(
|
check_assist(
|
||||||
replace_derive_with_manual_impl,
|
replace_derive_with_manual_impl,
|
||||||
r#"
|
r#"
|
||||||
//- minicore: fmt
|
//- minicore: fmt, derive
|
||||||
#[derive(Debu$0g)]
|
#[derive(Debu$0g)]
|
||||||
enum Foo {
|
enum Foo {
|
||||||
Bar {
|
Bar {
|
||||||
|
@ -415,7 +424,7 @@ impl core::fmt::Debug for Foo {
|
||||||
check_assist(
|
check_assist(
|
||||||
replace_derive_with_manual_impl,
|
replace_derive_with_manual_impl,
|
||||||
r#"
|
r#"
|
||||||
//- minicore: default
|
//- minicore: default, derive
|
||||||
#[derive(Defau$0lt)]
|
#[derive(Defau$0lt)]
|
||||||
struct Foo {
|
struct Foo {
|
||||||
foo: usize,
|
foo: usize,
|
||||||
|
@ -439,7 +448,7 @@ impl Default for Foo {
|
||||||
check_assist(
|
check_assist(
|
||||||
replace_derive_with_manual_impl,
|
replace_derive_with_manual_impl,
|
||||||
r#"
|
r#"
|
||||||
//- minicore: default
|
//- minicore: default, derive
|
||||||
#[derive(Defau$0lt)]
|
#[derive(Defau$0lt)]
|
||||||
struct Foo(usize);
|
struct Foo(usize);
|
||||||
"#,
|
"#,
|
||||||
|
@ -459,7 +468,7 @@ impl Default for Foo {
|
||||||
check_assist(
|
check_assist(
|
||||||
replace_derive_with_manual_impl,
|
replace_derive_with_manual_impl,
|
||||||
r#"
|
r#"
|
||||||
//- minicore: default
|
//- minicore: default, derive
|
||||||
#[derive(Defau$0lt)]
|
#[derive(Defau$0lt)]
|
||||||
struct Foo;
|
struct Foo;
|
||||||
"#,
|
"#,
|
||||||
|
@ -480,7 +489,7 @@ impl Default for Foo {
|
||||||
check_assist(
|
check_assist(
|
||||||
replace_derive_with_manual_impl,
|
replace_derive_with_manual_impl,
|
||||||
r#"
|
r#"
|
||||||
//- minicore: hash
|
//- minicore: hash, derive
|
||||||
#[derive(Has$0h)]
|
#[derive(Has$0h)]
|
||||||
struct Foo {
|
struct Foo {
|
||||||
bin: usize,
|
bin: usize,
|
||||||
|
@ -508,7 +517,7 @@ impl core::hash::Hash for Foo {
|
||||||
check_assist(
|
check_assist(
|
||||||
replace_derive_with_manual_impl,
|
replace_derive_with_manual_impl,
|
||||||
r#"
|
r#"
|
||||||
//- minicore: hash
|
//- minicore: hash, derive
|
||||||
#[derive(Has$0h)]
|
#[derive(Has$0h)]
|
||||||
struct Foo(usize, usize);
|
struct Foo(usize, usize);
|
||||||
"#,
|
"#,
|
||||||
|
@ -530,7 +539,7 @@ impl core::hash::Hash for Foo {
|
||||||
check_assist(
|
check_assist(
|
||||||
replace_derive_with_manual_impl,
|
replace_derive_with_manual_impl,
|
||||||
r#"
|
r#"
|
||||||
//- minicore: hash
|
//- minicore: hash, derive
|
||||||
#[derive(Has$0h)]
|
#[derive(Has$0h)]
|
||||||
enum Foo {
|
enum Foo {
|
||||||
Bar,
|
Bar,
|
||||||
|
@ -557,7 +566,7 @@ impl core::hash::Hash for Foo {
|
||||||
check_assist(
|
check_assist(
|
||||||
replace_derive_with_manual_impl,
|
replace_derive_with_manual_impl,
|
||||||
r#"
|
r#"
|
||||||
//- minicore: clone
|
//- minicore: clone, derive
|
||||||
#[derive(Clo$0ne)]
|
#[derive(Clo$0ne)]
|
||||||
struct Foo {
|
struct Foo {
|
||||||
bin: usize,
|
bin: usize,
|
||||||
|
@ -584,7 +593,7 @@ impl Clone for Foo {
|
||||||
check_assist(
|
check_assist(
|
||||||
replace_derive_with_manual_impl,
|
replace_derive_with_manual_impl,
|
||||||
r#"
|
r#"
|
||||||
//- minicore: clone
|
//- minicore: clone, derive
|
||||||
#[derive(Clo$0ne)]
|
#[derive(Clo$0ne)]
|
||||||
struct Foo(usize, usize);
|
struct Foo(usize, usize);
|
||||||
"#,
|
"#,
|
||||||
|
@ -605,7 +614,7 @@ impl Clone for Foo {
|
||||||
check_assist(
|
check_assist(
|
||||||
replace_derive_with_manual_impl,
|
replace_derive_with_manual_impl,
|
||||||
r#"
|
r#"
|
||||||
//- minicore: clone
|
//- minicore: clone, derive
|
||||||
#[derive(Clo$0ne)]
|
#[derive(Clo$0ne)]
|
||||||
struct Foo;
|
struct Foo;
|
||||||
"#,
|
"#,
|
||||||
|
@ -626,7 +635,7 @@ impl Clone for Foo {
|
||||||
check_assist(
|
check_assist(
|
||||||
replace_derive_with_manual_impl,
|
replace_derive_with_manual_impl,
|
||||||
r#"
|
r#"
|
||||||
//- minicore: clone
|
//- minicore: clone, derive
|
||||||
#[derive(Clo$0ne)]
|
#[derive(Clo$0ne)]
|
||||||
enum Foo {
|
enum Foo {
|
||||||
Bar,
|
Bar,
|
||||||
|
@ -656,7 +665,7 @@ impl Clone for Foo {
|
||||||
check_assist(
|
check_assist(
|
||||||
replace_derive_with_manual_impl,
|
replace_derive_with_manual_impl,
|
||||||
r#"
|
r#"
|
||||||
//- minicore: clone
|
//- minicore: clone, derive
|
||||||
#[derive(Clo$0ne)]
|
#[derive(Clo$0ne)]
|
||||||
enum Foo {
|
enum Foo {
|
||||||
Bar(String),
|
Bar(String),
|
||||||
|
@ -686,7 +695,7 @@ impl Clone for Foo {
|
||||||
check_assist(
|
check_assist(
|
||||||
replace_derive_with_manual_impl,
|
replace_derive_with_manual_impl,
|
||||||
r#"
|
r#"
|
||||||
//- minicore: clone
|
//- minicore: clone, derive
|
||||||
#[derive(Clo$0ne)]
|
#[derive(Clo$0ne)]
|
||||||
enum Foo {
|
enum Foo {
|
||||||
Bar {
|
Bar {
|
||||||
|
@ -720,7 +729,7 @@ impl Clone for Foo {
|
||||||
check_assist(
|
check_assist(
|
||||||
replace_derive_with_manual_impl,
|
replace_derive_with_manual_impl,
|
||||||
r#"
|
r#"
|
||||||
//- minicore: ord
|
//- minicore: ord, derive
|
||||||
#[derive(Partial$0Ord)]
|
#[derive(Partial$0Ord)]
|
||||||
struct Foo {
|
struct Foo {
|
||||||
bin: usize,
|
bin: usize,
|
||||||
|
@ -745,7 +754,7 @@ impl PartialOrd for Foo {
|
||||||
check_assist(
|
check_assist(
|
||||||
replace_derive_with_manual_impl,
|
replace_derive_with_manual_impl,
|
||||||
r#"
|
r#"
|
||||||
//- minicore: ord
|
//- minicore: ord, derive
|
||||||
#[derive(Partial$0Ord)]
|
#[derive(Partial$0Ord)]
|
||||||
struct Foo {
|
struct Foo {
|
||||||
bin: usize,
|
bin: usize,
|
||||||
|
@ -782,7 +791,7 @@ impl PartialOrd for Foo {
|
||||||
check_assist(
|
check_assist(
|
||||||
replace_derive_with_manual_impl,
|
replace_derive_with_manual_impl,
|
||||||
r#"
|
r#"
|
||||||
//- minicore: ord
|
//- minicore: ord, derive
|
||||||
#[derive(Partial$0Ord)]
|
#[derive(Partial$0Ord)]
|
||||||
struct Foo(usize, usize, usize);
|
struct Foo(usize, usize, usize);
|
||||||
"#,
|
"#,
|
||||||
|
@ -811,7 +820,7 @@ impl PartialOrd for Foo {
|
||||||
check_assist(
|
check_assist(
|
||||||
replace_derive_with_manual_impl,
|
replace_derive_with_manual_impl,
|
||||||
r#"
|
r#"
|
||||||
//- minicore: eq
|
//- minicore: eq, derive
|
||||||
#[derive(Partial$0Eq)]
|
#[derive(Partial$0Eq)]
|
||||||
struct Foo {
|
struct Foo {
|
||||||
bin: usize,
|
bin: usize,
|
||||||
|
@ -838,7 +847,7 @@ impl PartialEq for Foo {
|
||||||
check_assist(
|
check_assist(
|
||||||
replace_derive_with_manual_impl,
|
replace_derive_with_manual_impl,
|
||||||
r#"
|
r#"
|
||||||
//- minicore: eq
|
//- minicore: eq, derive
|
||||||
#[derive(Partial$0Eq)]
|
#[derive(Partial$0Eq)]
|
||||||
struct Foo(usize, usize);
|
struct Foo(usize, usize);
|
||||||
"#,
|
"#,
|
||||||
|
@ -859,7 +868,7 @@ impl PartialEq for Foo {
|
||||||
check_assist(
|
check_assist(
|
||||||
replace_derive_with_manual_impl,
|
replace_derive_with_manual_impl,
|
||||||
r#"
|
r#"
|
||||||
//- minicore: eq
|
//- minicore: eq, derive
|
||||||
#[derive(Partial$0Eq)]
|
#[derive(Partial$0Eq)]
|
||||||
struct Foo;
|
struct Foo;
|
||||||
"#,
|
"#,
|
||||||
|
@ -880,7 +889,7 @@ impl PartialEq for Foo {
|
||||||
check_assist(
|
check_assist(
|
||||||
replace_derive_with_manual_impl,
|
replace_derive_with_manual_impl,
|
||||||
r#"
|
r#"
|
||||||
//- minicore: eq
|
//- minicore: eq, derive
|
||||||
#[derive(Partial$0Eq)]
|
#[derive(Partial$0Eq)]
|
||||||
enum Foo {
|
enum Foo {
|
||||||
Bar,
|
Bar,
|
||||||
|
@ -907,7 +916,7 @@ impl PartialEq for Foo {
|
||||||
check_assist(
|
check_assist(
|
||||||
replace_derive_with_manual_impl,
|
replace_derive_with_manual_impl,
|
||||||
r#"
|
r#"
|
||||||
//- minicore: eq
|
//- minicore: eq, derive
|
||||||
#[derive(Partial$0Eq)]
|
#[derive(Partial$0Eq)]
|
||||||
enum Foo {
|
enum Foo {
|
||||||
Bar(String),
|
Bar(String),
|
||||||
|
@ -937,7 +946,7 @@ impl PartialEq for Foo {
|
||||||
check_assist(
|
check_assist(
|
||||||
replace_derive_with_manual_impl,
|
replace_derive_with_manual_impl,
|
||||||
r#"
|
r#"
|
||||||
//- minicore: eq
|
//- minicore: eq, derive
|
||||||
#[derive(Partial$0Eq)]
|
#[derive(Partial$0Eq)]
|
||||||
enum Foo {
|
enum Foo {
|
||||||
Bar {
|
Bar {
|
||||||
|
@ -981,6 +990,7 @@ impl PartialEq for Foo {
|
||||||
check_assist(
|
check_assist(
|
||||||
replace_derive_with_manual_impl,
|
replace_derive_with_manual_impl,
|
||||||
r#"
|
r#"
|
||||||
|
//- minicore: derive
|
||||||
mod foo {
|
mod foo {
|
||||||
pub trait Bar {
|
pub trait Bar {
|
||||||
type Qux;
|
type Qux;
|
||||||
|
@ -1026,10 +1036,11 @@ impl foo::Bar for Foo {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
#[test]
|
#[test]
|
||||||
fn add_custom_impl_for_unique_input() {
|
fn add_custom_impl_for_unique_input_unknown() {
|
||||||
check_assist(
|
check_assist(
|
||||||
replace_derive_with_manual_impl,
|
replace_derive_with_manual_impl,
|
||||||
r#"
|
r#"
|
||||||
|
//- minicore: derive
|
||||||
#[derive(Debu$0g)]
|
#[derive(Debu$0g)]
|
||||||
struct Foo {
|
struct Foo {
|
||||||
bar: String,
|
bar: String,
|
||||||
|
@ -1052,6 +1063,7 @@ impl Debug for Foo {
|
||||||
check_assist(
|
check_assist(
|
||||||
replace_derive_with_manual_impl,
|
replace_derive_with_manual_impl,
|
||||||
r#"
|
r#"
|
||||||
|
//- minicore: derive
|
||||||
#[derive(Debug$0)]
|
#[derive(Debug$0)]
|
||||||
pub struct Foo {
|
pub struct Foo {
|
||||||
bar: String,
|
bar: String,
|
||||||
|
@ -1074,6 +1086,7 @@ impl Debug for Foo {
|
||||||
check_assist(
|
check_assist(
|
||||||
replace_derive_with_manual_impl,
|
replace_derive_with_manual_impl,
|
||||||
r#"
|
r#"
|
||||||
|
//- minicore: derive
|
||||||
#[derive(Display, Debug$0, Serialize)]
|
#[derive(Display, Debug$0, Serialize)]
|
||||||
struct Foo {}
|
struct Foo {}
|
||||||
"#,
|
"#,
|
||||||
|
@ -1093,7 +1106,7 @@ impl Debug for Foo {
|
||||||
check_assist(
|
check_assist(
|
||||||
replace_derive_with_manual_impl,
|
replace_derive_with_manual_impl,
|
||||||
r#"
|
r#"
|
||||||
//- minicore: default
|
//- minicore: default, derive
|
||||||
#[derive(Defau$0lt)]
|
#[derive(Defau$0lt)]
|
||||||
struct Foo<T, U> {
|
struct Foo<T, U> {
|
||||||
foo: T,
|
foo: T,
|
||||||
|
@ -1120,7 +1133,7 @@ impl<T, U> Default for Foo<T, U> {
|
||||||
check_assist(
|
check_assist(
|
||||||
replace_derive_with_manual_impl,
|
replace_derive_with_manual_impl,
|
||||||
r#"
|
r#"
|
||||||
//- minicore: clone
|
//- minicore: clone, derive
|
||||||
#[derive(Clo$0ne)]
|
#[derive(Clo$0ne)]
|
||||||
struct Foo<T: Clone>(T, usize);
|
struct Foo<T: Clone>(T, usize);
|
||||||
"#,
|
"#,
|
||||||
|
@ -1141,6 +1154,7 @@ impl<T: Clone> Clone for Foo<T> {
|
||||||
check_assist_not_applicable(
|
check_assist_not_applicable(
|
||||||
replace_derive_with_manual_impl,
|
replace_derive_with_manual_impl,
|
||||||
r#"
|
r#"
|
||||||
|
//- minicore: derive
|
||||||
#[derive($0)]
|
#[derive($0)]
|
||||||
struct Foo {}
|
struct Foo {}
|
||||||
"#,
|
"#,
|
||||||
|
@ -1152,6 +1166,7 @@ struct Foo {}
|
||||||
check_assist_not_applicable(
|
check_assist_not_applicable(
|
||||||
replace_derive_with_manual_impl,
|
replace_derive_with_manual_impl,
|
||||||
r#"
|
r#"
|
||||||
|
//- minicore: derive, fmt
|
||||||
#[derive$0(Debug)]
|
#[derive$0(Debug)]
|
||||||
struct Foo {}
|
struct Foo {}
|
||||||
"#,
|
"#,
|
||||||
|
@ -1160,6 +1175,7 @@ struct Foo {}
|
||||||
check_assist_not_applicable(
|
check_assist_not_applicable(
|
||||||
replace_derive_with_manual_impl,
|
replace_derive_with_manual_impl,
|
||||||
r#"
|
r#"
|
||||||
|
//- minicore: derive, fmt
|
||||||
#[derive(Debug)$0]
|
#[derive(Debug)$0]
|
||||||
struct Foo {}
|
struct Foo {}
|
||||||
"#,
|
"#,
|
||||||
|
@ -1171,6 +1187,7 @@ struct Foo {}
|
||||||
check_assist_not_applicable(
|
check_assist_not_applicable(
|
||||||
replace_derive_with_manual_impl,
|
replace_derive_with_manual_impl,
|
||||||
r#"
|
r#"
|
||||||
|
//- minicore: derive
|
||||||
#[allow(non_camel_$0case_types)]
|
#[allow(non_camel_$0case_types)]
|
||||||
struct Foo {}
|
struct Foo {}
|
||||||
"#,
|
"#,
|
||||||
|
@ -1179,10 +1196,10 @@ struct Foo {}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn works_at_start_of_file() {
|
fn works_at_start_of_file() {
|
||||||
cov_mark::check!(outside_of_attr_args);
|
|
||||||
check_assist_not_applicable(
|
check_assist_not_applicable(
|
||||||
replace_derive_with_manual_impl,
|
replace_derive_with_manual_impl,
|
||||||
r#"
|
r#"
|
||||||
|
//- minicore: derive, fmt
|
||||||
$0#[derive(Debug)]
|
$0#[derive(Debug)]
|
||||||
struct S;
|
struct S;
|
||||||
"#,
|
"#,
|
||||||
|
@ -1194,7 +1211,7 @@ struct S;
|
||||||
check_assist(
|
check_assist(
|
||||||
replace_derive_with_manual_impl,
|
replace_derive_with_manual_impl,
|
||||||
r#"
|
r#"
|
||||||
//- minicore: clone
|
//- minicore: clone, derive
|
||||||
#[derive(std::fmt::Debug, Clo$0ne)]
|
#[derive(std::fmt::Debug, Clo$0ne)]
|
||||||
pub struct Foo;
|
pub struct Foo;
|
||||||
"#,
|
"#,
|
||||||
|
@ -1216,7 +1233,7 @@ impl Clone for Foo {
|
||||||
check_assist(
|
check_assist(
|
||||||
replace_derive_with_manual_impl,
|
replace_derive_with_manual_impl,
|
||||||
r#"
|
r#"
|
||||||
//- minicore: fmt
|
//- minicore: fmt, derive
|
||||||
#[derive(core::fmt::Deb$0ug, Clone)]
|
#[derive(core::fmt::Deb$0ug, Clone)]
|
||||||
pub struct Foo;
|
pub struct Foo;
|
||||||
"#,
|
"#,
|
||||||
|
|
|
@ -1766,6 +1766,7 @@ fn doctest_replace_derive_with_manual_impl() {
|
||||||
check_doc_test(
|
check_doc_test(
|
||||||
"replace_derive_with_manual_impl",
|
"replace_derive_with_manual_impl",
|
||||||
r#####"
|
r#####"
|
||||||
|
//- minicore: derive
|
||||||
trait Debug { fn fmt(&self, f: &mut Formatter) -> Result<()>; }
|
trait Debug { fn fmt(&self, f: &mut Formatter) -> Result<()>; }
|
||||||
#[derive(Deb$0ug, Display)]
|
#[derive(Deb$0ug, Display)]
|
||||||
struct S;
|
struct S;
|
||||||
|
|
|
@ -9,15 +9,14 @@ pub mod node_ext;
|
||||||
pub mod rust_doc;
|
pub mod rust_doc;
|
||||||
pub mod format_string;
|
pub mod format_string;
|
||||||
|
|
||||||
use std::{collections::VecDeque, iter};
|
use std::collections::VecDeque;
|
||||||
|
|
||||||
use base_db::FileId;
|
use base_db::FileId;
|
||||||
use hir::{ItemInNs, MacroDef, ModuleDef, Name, PathResolution, Semantics};
|
use hir::{ItemInNs, MacroDef, ModuleDef, Name, Semantics};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use syntax::{
|
use syntax::{
|
||||||
ast::{self, make, HasLoopBody},
|
ast::{self, make, HasLoopBody},
|
||||||
AstNode, AstToken, Direction, SyntaxElement, SyntaxKind, SyntaxToken, TokenAtOffset, WalkEvent,
|
AstNode, SyntaxKind, SyntaxToken, TokenAtOffset, WalkEvent, T,
|
||||||
T,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{defs::Definition, RootDatabase};
|
use crate::{defs::Definition, RootDatabase};
|
||||||
|
@ -32,49 +31,6 @@ pub fn item_name(db: &RootDatabase, item: ItemInNs) -> Option<Name> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parses and returns the derive path at the cursor position in the given attribute, if it is a derive.
|
|
||||||
/// This special case is required because the derive macro is a compiler builtin that discards the input derives.
|
|
||||||
///
|
|
||||||
/// The returned path is synthesized from TokenTree tokens and as such cannot be used with the [`Semantics`].
|
|
||||||
pub fn get_path_in_derive_attr(
|
|
||||||
sema: &hir::Semantics<RootDatabase>,
|
|
||||||
attr: &ast::Attr,
|
|
||||||
cursor: &ast::Ident,
|
|
||||||
) -> Option<ast::Path> {
|
|
||||||
let path = attr.path()?;
|
|
||||||
let tt = attr.token_tree()?;
|
|
||||||
if !tt.syntax().text_range().contains_range(cursor.syntax().text_range()) {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
let scope = sema.scope(attr.syntax());
|
|
||||||
let resolved_attr = sema.resolve_path(&path)?;
|
|
||||||
let derive = FamousDefs(sema, scope.krate()).core_macros_builtin_derive()?;
|
|
||||||
if PathResolution::Macro(derive) != resolved_attr {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
get_path_at_cursor_in_tt(cursor)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Parses the path the identifier is part of inside a token tree.
|
|
||||||
pub fn get_path_at_cursor_in_tt(cursor: &ast::Ident) -> Option<ast::Path> {
|
|
||||||
let cursor = cursor.syntax();
|
|
||||||
let first = cursor
|
|
||||||
.siblings_with_tokens(Direction::Prev)
|
|
||||||
.filter_map(SyntaxElement::into_token)
|
|
||||||
.take_while(|tok| tok.kind() != T!['('] && tok.kind() != T![,])
|
|
||||||
.last()?;
|
|
||||||
let path_tokens = first
|
|
||||||
.siblings_with_tokens(Direction::Next)
|
|
||||||
.filter_map(SyntaxElement::into_token)
|
|
||||||
.take_while(|tok| tok != cursor);
|
|
||||||
|
|
||||||
syntax::hacks::parse_expr_from_str(&path_tokens.chain(iter::once(cursor.clone())).join(""))
|
|
||||||
.and_then(|expr| match expr {
|
|
||||||
ast::Expr::PathExpr(it) => it.path(),
|
|
||||||
_ => None,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Picks the token with the highest rank returned by the passed in function.
|
/// Picks the token with the highest rank returned by the passed in function.
|
||||||
pub fn pick_best_token(
|
pub fn pick_best_token(
|
||||||
tokens: TokenAtOffset<SyntaxToken>,
|
tokens: TokenAtOffset<SyntaxToken>,
|
||||||
|
|
|
@ -8,11 +8,10 @@ use rustc_hash::FxHashSet;
|
||||||
use syntax::{
|
use syntax::{
|
||||||
ast::{self, HasName},
|
ast::{self, HasName},
|
||||||
utils::path_to_string_stripping_turbo_fish,
|
utils::path_to_string_stripping_turbo_fish,
|
||||||
AstNode, AstToken, SyntaxNode,
|
AstNode, SyntaxNode,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
helpers::get_path_in_derive_attr,
|
|
||||||
items_locator::{self, AssocItemSearch, DEFAULT_QUERY_SEARCH_LIMIT},
|
items_locator::{self, AssocItemSearch, DEFAULT_QUERY_SEARCH_LIMIT},
|
||||||
RootDatabase,
|
RootDatabase,
|
||||||
};
|
};
|
||||||
|
@ -139,23 +138,6 @@ impl ImportAssets {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn for_derive_ident(sema: &Semantics<RootDatabase>, ident: &ast::Ident) -> Option<Self> {
|
|
||||||
let attr = ident.syntax().ancestors().find_map(ast::Attr::cast)?;
|
|
||||||
let path = get_path_in_derive_attr(sema, &attr, ident)?;
|
|
||||||
|
|
||||||
if let Some(_) = path.qualifier() {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
let name = NameToImport::exact_case_sensitive(path.segment()?.name_ref()?.to_string());
|
|
||||||
let candidate_node = attr.syntax().clone();
|
|
||||||
Some(Self {
|
|
||||||
import_candidate: ImportCandidate::Path(PathImportCandidate { qualifier: None, name }),
|
|
||||||
module_with_candidate: sema.scope(&candidate_node).module()?,
|
|
||||||
candidate_node,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn for_fuzzy_path(
|
pub fn for_fuzzy_path(
|
||||||
module_with_candidate: Module,
|
module_with_candidate: Module,
|
||||||
qualifier: Option<ast::Path>,
|
qualifier: Option<ast::Path>,
|
||||||
|
|
|
@ -705,6 +705,15 @@ impl ast::RangePat {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ast::TokenTree {
|
impl ast::TokenTree {
|
||||||
|
pub fn token_trees_and_tokens(
|
||||||
|
&self,
|
||||||
|
) -> impl Iterator<Item = NodeOrToken<ast::TokenTree, SyntaxToken>> {
|
||||||
|
self.syntax().children_with_tokens().filter_map(|not| match not {
|
||||||
|
NodeOrToken::Node(node) => ast::TokenTree::cast(node).map(NodeOrToken::Node),
|
||||||
|
NodeOrToken::Token(t) => Some(NodeOrToken::Token(t)),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
pub fn left_delimiter_token(&self) -> Option<SyntaxToken> {
|
pub fn left_delimiter_token(&self) -> Option<SyntaxToken> {
|
||||||
self.syntax()
|
self.syntax()
|
||||||
.first_child_or_token()?
|
.first_child_or_token()?
|
||||||
|
|
Loading…
Reference in a new issue