Unnamed repository; edit this file 'description' to name the repository.
Do not fill both `drop()` and `pin_drop()` in the "fill missing members" assist
I also made some changes to lang items, which turned out not needed but I think they're useful too, maybe in the future or maybe ot outside projects.
| -rw-r--r-- | crates/hir-def/src/expr_store/pretty.rs | 5 | ||||
| -rw-r--r-- | crates/hir-def/src/lang_item.rs | 19 | ||||
| -rw-r--r-- | crates/hir-def/src/resolver.rs | 9 | ||||
| -rw-r--r-- | crates/hir/src/lib.rs | 8 | ||||
| -rw-r--r-- | crates/ide-assists/src/handlers/add_missing_impl_members.rs | 63 | ||||
| -rw-r--r-- | crates/ide-db/src/traits.rs | 47 | ||||
| -rw-r--r-- | crates/intern/src/symbol/symbols.rs | 1 | ||||
| -rw-r--r-- | crates/test-utils/src/minicore.rs | 4 |
8 files changed, 136 insertions, 20 deletions
diff --git a/crates/hir-def/src/expr_store/pretty.rs b/crates/hir-def/src/expr_store/pretty.rs index 293adfc9bd..ccc08a34d7 100644 --- a/crates/hir-def/src/expr_store/pretty.rs +++ b/crates/hir-def/src/expr_store/pretty.rs @@ -14,7 +14,7 @@ use stdx::never; use syntax::ast::{HasName, RangeOp}; use crate::{ - AdtId, DefWithBodyId, FunctionId, GenericDefId, StructId, TypeParamId, VariantId, + AdtId, DefWithBodyId, FunctionId, GenericDefId, MacroId, StructId, TypeParamId, VariantId, attrs::AttrFlags, expr_store::path::{GenericArg, GenericArgs}, hir::{ @@ -1136,6 +1136,9 @@ impl Printer<'_> { LangItemTarget::TraitId(it) => write_name!(it), LangItemTarget::EnumVariantId(it) => write_name!(it), LangItemTarget::ConstId(it) => write_name!(it), + LangItemTarget::MacroId(MacroId::Macro2Id(it)) => write_name!(it), + LangItemTarget::MacroId(MacroId::MacroRulesId(it)) => write_name!(it), + LangItemTarget::MacroId(MacroId::ProcMacroId(it)) => write_name!(it), } if let Some(s) = s { diff --git a/crates/hir-def/src/lang_item.rs b/crates/hir-def/src/lang_item.rs index f9d5a843bd..04dfdb7d16 100644 --- a/crates/hir-def/src/lang_item.rs +++ b/crates/hir-def/src/lang_item.rs @@ -26,10 +26,11 @@ pub enum LangItemTarget { TraitId(TraitId), EnumVariantId(EnumVariantId), ConstId(ConstId), + MacroId(MacroId), } impl_from!( - EnumId, FunctionId, ImplId, StaticId, StructId, UnionId, TypeAliasId, TraitId, EnumVariantId, ConstId for LangItemTarget + EnumId, FunctionId, ImplId, StaticId, StructId, UnionId, TypeAliasId, TraitId, EnumVariantId, ConstId, MacroId for LangItemTarget ); /// Salsa query. This will look for lang items in a specific crate. @@ -276,7 +277,6 @@ impl LangItems { (self.BitXorAssign, &mut self.BitXorAssign_bitxor_assign, sym::bitxor_assign), (self.BitOrAssign, &mut self.BitOrAssign_bitor_assign, sym::bitor_assign), (self.BitAndAssign, &mut self.BitAndAssign_bitand_assign, sym::bitand_assign), - (self.Drop, &mut self.Drop_drop, sym::drop), (self.Debug, &mut self.Debug_fmt, sym::fmt), (self.Deref, &mut self.Deref_deref, sym::deref), (self.DerefMut, &mut self.DerefMut_deref_mut, sym::deref_mut), @@ -307,6 +307,13 @@ impl LangItems { ); Some(()) })(); + (|| { + methods( + self.Drop?, + &mut [(&mut self.Drop_drop, sym::drop), (&mut self.Drop_pin_drop, sym::pin_drop)], + ); + Some(()) + })(); } } @@ -397,11 +404,15 @@ macro_rules! language_item_table { } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] + #[allow(non_camel_case_types)] pub enum LangItemEnum { $( $(#[$attr])* $lang_item, )* + $( $non_lang_trait, )* + $( $non_lang_macro_field, )* + $( $resolve_manually, )* } impl LangItemEnum { @@ -409,6 +420,9 @@ macro_rules! language_item_table { pub fn from_lang_items(self, lang_items: &LangItems) -> Option<LangItemTarget> { match self { $( LangItemEnum::$lang_item => lang_items.$lang_item.map(Into::into), )* + $( LangItemEnum::$non_lang_trait => lang_items.$non_lang_trait.map(Into::into), )* + $( LangItemEnum::$non_lang_macro_field => lang_items.$non_lang_macro_field.map(Into::into), )* + $( LangItemEnum::$resolve_manually => lang_items.$resolve_manually.map(Into::into), )* } } @@ -716,6 +730,7 @@ language_item_table! { LangItems => PartialOrd_ge, FunctionId; PartialOrd_gt, FunctionId; Drop_drop, FunctionId; + Drop_pin_drop, FunctionId; Debug_fmt, FunctionId; Deref_deref, FunctionId; DerefMut_deref_mut, FunctionId; diff --git a/crates/hir-def/src/resolver.rs b/crates/hir-def/src/resolver.rs index 0062e6c170..c16ad9b4f2 100644 --- a/crates/hir-def/src/resolver.rs +++ b/crates/hir-def/src/resolver.rs @@ -195,7 +195,8 @@ impl<'db> Resolver<'db> { LangItemTarget::FunctionId(_) | LangItemTarget::ImplId(_) | LangItemTarget::StaticId(_) - | LangItemTarget::ConstId(_) => return None, + | LangItemTarget::ConstId(_) + | LangItemTarget::MacroId(_) => return None, }; return Some(( type_ns, @@ -343,7 +344,8 @@ impl<'db> Resolver<'db> { | LangItemTarget::ImplId(_) | LangItemTarget::TypeAliasId(_) | LangItemTarget::TraitId(_) - | LangItemTarget::EnumId(_) => return None, + | LangItemTarget::EnumId(_) + | LangItemTarget::MacroId(_) => return None, }), ResolvePathResultPrefixInfo::default(), )); @@ -359,7 +361,8 @@ impl<'db> Resolver<'db> { LangItemTarget::FunctionId(_) | LangItemTarget::ImplId(_) | LangItemTarget::StaticId(_) - | LangItemTarget::ConstId(_) => return None, + | LangItemTarget::ConstId(_) + | LangItemTarget::MacroId(_) => return None, }; // Remaining segments start from 0 because lang paths have no segments other than the remaining. return Some(( diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index d187763151..3b0fbc3e40 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -2283,6 +2283,14 @@ impl fmt::Debug for Function { } impl Function { + pub fn lang(db: &dyn HirDatabase, krate: Crate, lang_item: LangItem) -> Option<Function> { + let lang_items = hir_def::lang_item::lang_items(db, krate.id); + match lang_item.from_lang_items(lang_items)? { + LangItemTarget::FunctionId(it) => Some(it.into()), + _ => None, + } + } + pub fn module(self, db: &dyn HirDatabase) -> Module { match self.id { AnyFunctionId::FunctionId(id) => id.module(db).into(), diff --git a/crates/ide-assists/src/handlers/add_missing_impl_members.rs b/crates/ide-assists/src/handlers/add_missing_impl_members.rs index efbe3817e1..1e8fb51a3e 100644 --- a/crates/ide-assists/src/handlers/add_missing_impl_members.rs +++ b/crates/ide-assists/src/handlers/add_missing_impl_members.rs @@ -2641,4 +2641,67 @@ impl Trait for Struct { "#, ); } + + #[test] + fn drop_pin_drop() { + check_assist_not_applicable( + add_missing_impl_members, + r#" +//- minicore: drop, pin +struct Foo; +impl Drop for Foo {$0 + fn drop(&mut self) {} +} + "#, + ); + check_assist_not_applicable( + add_missing_impl_members, + r#" +//- minicore: drop, pin +struct Foo; +impl Drop for Foo {$0 + fn pin_drop(self: core::pin::Pin<&mut Self>) {} +} + "#, + ); + + check_assist_not_applicable( + add_missing_default_members, + r#" +//- minicore: drop, pin +struct Foo; +impl Drop for Foo {$0 + fn drop(&mut self) {} +} + "#, + ); + check_assist_not_applicable( + add_missing_default_members, + r#" +//- minicore: drop, pin +struct Foo; +impl Drop for Foo {$0 + fn pin_drop(self: core::pin::Pin<&mut Self>) {} +} + "#, + ); + + check_assist( + add_missing_impl_members, + r#" +//- minicore: drop, pin +struct Foo; +impl Drop for Foo {$0 +} + "#, + r#" +struct Foo; +impl Drop for Foo { + fn drop(&mut self) { + ${0:todo!()} + } +} + "#, + ); + } } diff --git a/crates/ide-db/src/traits.rs b/crates/ide-db/src/traits.rs index d38d9b6708..994427ac76 100644 --- a/crates/ide-db/src/traits.rs +++ b/crates/ide-db/src/traits.rs @@ -1,7 +1,7 @@ //! Functionality for obtaining data related to traits from the DB. use crate::{RootDatabase, defs::Definition}; -use hir::{AsAssocItem, Semantics, db::HirDatabase}; +use hir::{AsAssocItem, HasCrate, Semantics, db::HirDatabase, sym}; use rustc_hash::FxHashSet; use syntax::{AstNode, ast}; @@ -51,19 +51,38 @@ pub fn get_missing_assoc_items( } } - imp.trait_(sema.db).map_or(vec![], |target_trait| { - target_trait - .items(sema.db) - .into_iter() - .filter(|i| match i { - hir::AssocItem::Function(f) => !impl_fns_consts.contains(&f.name(sema.db)), - hir::AssocItem::TypeAlias(t) => !impl_type.contains(&t.name(sema.db)), - hir::AssocItem::Const(c) => { - c.name(sema.db).map(|n| !impl_fns_consts.contains(&n)).unwrap_or_default() - } - }) - .collect() - }) + let Some(target_trait) = imp.trait_(sema.db) else { return Vec::new() }; + + // `Drop` has two methods, `drop()` and `pin_drop()`, and you can only implement one of them, so + // we consider `pin_drop()` to not exist, unless you already implement it. + let drop_trait = hir::Trait::lang(sema.db, imp.krate(sema.db), hir::LangItem::Drop); + if let Some(drop_trait) = drop_trait + && target_trait == drop_trait + { + return if impl_fns_consts.is_empty() { + // No method implemented, return `drop()`. + let drop_drop = drop_trait.function(sema.db, sym::drop); + match drop_drop { + Some(drop_drop) => vec![hir::AssocItem::Function(drop_drop)], + None => Vec::new(), + } + } else { + // Some method is already implemented, leave it. + Vec::new() + }; + } + + target_trait + .items(sema.db) + .into_iter() + .filter(|i| match i { + hir::AssocItem::Function(f) => !impl_fns_consts.contains(&f.name(sema.db)), + hir::AssocItem::TypeAlias(t) => !impl_type.contains(&t.name(sema.db)), + hir::AssocItem::Const(c) => { + c.name(sema.db).map(|n| !impl_fns_consts.contains(&n)).unwrap_or_default() + } + }) + .collect() } /// Converts associated trait impl items to their trait definition counterpart diff --git a/crates/intern/src/symbol/symbols.rs b/crates/intern/src/symbol/symbols.rs index e5f66a202e..fe303aa0e0 100644 --- a/crates/intern/src/symbol/symbols.rs +++ b/crates/intern/src/symbol/symbols.rs @@ -295,6 +295,7 @@ define_symbols! { doc, drop_in_place, drop, + pin_drop, dyn_metadata, efiapi, eh_catch_typeinfo, diff --git a/crates/test-utils/src/minicore.rs b/crates/test-utils/src/minicore.rs index bd15dca609..c5ebc0d248 100644 --- a/crates/test-utils/src/minicore.rs +++ b/crates/test-utils/src/minicore.rs @@ -655,6 +655,10 @@ pub mod ops { #[lang = "drop"] pub trait Drop { fn drop(&mut self); + + // region:pin + fn pin_drop(self: crate::pin::Pin<&mut Self>) {} + // endregion:pin } // endregion:drop |