From 5360c9bd22f36865db50bb69d9bfce6f3d4fec38 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Wed, 22 Dec 2021 02:25:38 +0100 Subject: [PATCH] fix: Do not complete `Drop::drop`, complete `std::mem::drop` instead --- .../src/completions/attribute/derive.rs | 4 +- crates/ide_completion/src/completions/dot.rs | 39 ++++++++++++++++++- .../ide_completion/src/completions/postfix.rs | 22 +++++++++-- .../ide_completion/src/completions/record.rs | 4 +- crates/ide_completion/src/context.rs | 5 +++ crates/ide_completion/src/render.rs | 1 + crates/ide_db/src/helpers/famous_defs.rs | 4 ++ crates/test_utils/src/minicore.rs | 19 ++++++++- 8 files changed, 88 insertions(+), 10 deletions(-) diff --git a/crates/ide_completion/src/completions/attribute/derive.rs b/crates/ide_completion/src/completions/attribute/derive.rs index 0daf1147882..3cab1918f3e 100644 --- a/crates/ide_completion/src/completions/attribute/derive.rs +++ b/crates/ide_completion/src/completions/attribute/derive.rs @@ -1,7 +1,7 @@ //! Completion for derives use hir::{HasAttrs, MacroDef, MacroKind}; use ide_db::{ - helpers::{import_assets::ImportAssets, insert_use::ImportScope, FamousDefs}, + helpers::{import_assets::ImportAssets, insert_use::ImportScope}, SymbolKind, }; use itertools::Itertools; @@ -18,7 +18,7 @@ pub(super) fn complete_derive( ctx: &CompletionContext, existing_derives: &[ast::Path], ) { - let core = FamousDefs(&ctx.sema, ctx.krate).core(); + let core = ctx.famous_defs().core(); let existing_derives: FxHashSet<_> = existing_derives .into_iter() .filter_map(|path| ctx.scope.speculative_resolve_as_mac(&path)) diff --git a/crates/ide_completion/src/completions/dot.rs b/crates/ide_completion/src/completions/dot.rs index e08a70ac7eb..539b423cb30 100644 --- a/crates/ide_completion/src/completions/dot.rs +++ b/crates/ide_completion/src/completions/dot.rs @@ -76,7 +76,14 @@ fn complete_methods( ) { if let Some(krate) = ctx.krate { let mut seen_methods = FxHashSet::default(); - let traits_in_scope = ctx.scope.visible_traits(); + let mut traits_in_scope = ctx.scope.visible_traits(); + + // Remove drop from the environment as calling `Drop::drop` is not allowed + if let Some(drop_trait) = ctx.famous_defs().core_ops_Drop() { + cov_mark::hit!(dot_remove_drop_trait); + traits_in_scope.remove(&drop_trait.into()); + } + receiver.iterate_method_candidates(ctx.db, krate, &traits_in_scope, None, |_ty, func| { if func.self_param(ctx.db).is_some() && seen_methods.insert(func.name(ctx.db)) { f(func); @@ -709,4 +716,34 @@ fn main() { "#]], ) } + + #[test] + fn postfix_drop_completion() { + cov_mark::check!(dot_remove_drop_trait); + cov_mark::check!(postfix_drop_completion); + check_edit( + "drop", + r#" +//- minicore: drop +struct Vec(T); +impl Drop for Vec { + fn drop(&mut self) {} +} +fn main() { + let x = Vec(0u32) + x.$0; +} +"#, + r" +struct Vec(T); +impl Drop for Vec { + fn drop(&mut self) {} +} +fn main() { + let x = Vec(0u32) + drop($0x); +} +", + ) + } } diff --git a/crates/ide_completion/src/completions/postfix.rs b/crates/ide_completion/src/completions/postfix.rs index 8a25da7ddb7..a212a98461f 100644 --- a/crates/ide_completion/src/completions/postfix.rs +++ b/crates/ide_completion/src/completions/postfix.rs @@ -2,9 +2,9 @@ mod format_like; -use hir::Documentation; +use hir::{Documentation, HasAttrs}; use ide_db::{ - helpers::{insert_use::ImportScope, FamousDefs, SnippetCap}, + helpers::{insert_use::ImportScope, SnippetCap}, ty_filter::TryEnum, }; use syntax::{ @@ -59,6 +59,22 @@ pub(crate) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) { None => return, }; + if let Some(drop_trait) = ctx.famous_defs().core_ops_Drop() { + if receiver_ty.impls_trait(ctx.db, drop_trait, &[]) { + if let &[hir::AssocItem::Function(drop_fn)] = &*drop_trait.items(ctx.db) { + cov_mark::hit!(postfix_drop_completion); + // FIXME: check that `drop` is in scope, use fully qualified path if it isn't/if shadowed + let mut item = postfix_snippet( + "drop", + "fn drop(&mut self)", + &format!("drop($0{})", receiver_text), + ); + item.set_documentation(drop_fn.docs(ctx.db)); + item.add_to(acc); + } + } + } + if !ctx.config.snippets.is_empty() { add_custom_postfix_completions(acc, ctx, &postfix_snippet, &receiver_text); } @@ -107,7 +123,7 @@ pub(crate) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) { ) .add_to(acc); postfix_snippet("not", "!expr", &format!("!{}", receiver_text)).add_to(acc); - } else if let Some(trait_) = FamousDefs(&ctx.sema, ctx.krate).core_iter_IntoIterator() { + } else if let Some(trait_) = ctx.famous_defs().core_iter_IntoIterator() { if receiver_ty.impls_trait(ctx.db, trait_, &[]) { postfix_snippet( "for", diff --git a/crates/ide_completion/src/completions/record.rs b/crates/ide_completion/src/completions/record.rs index d50f889ee47..b066a46065d 100644 --- a/crates/ide_completion/src/completions/record.rs +++ b/crates/ide_completion/src/completions/record.rs @@ -1,5 +1,5 @@ //! Complete fields in record literals and patterns. -use ide_db::{helpers::FamousDefs, SymbolKind}; +use ide_db::SymbolKind; use syntax::{ast::Expr, T}; use crate::{ @@ -13,7 +13,7 @@ pub(crate) fn complete_record(acc: &mut Completions, ctx: &CompletionContext) -> | ImmediateLocation::RecordExprUpdate(record_expr), ) => { let ty = ctx.sema.type_of_expr(&Expr::RecordExpr(record_expr.clone())); - let default_trait = FamousDefs(&ctx.sema, ctx.krate).core_default_Default(); + let default_trait = ctx.famous_defs().core_default_Default(); let impl_default_trait = default_trait.zip(ty).map_or(false, |(default_trait, ty)| { ty.original.impls_trait(ctx.db, default_trait, &[]) }); diff --git a/crates/ide_completion/src/context.rs b/crates/ide_completion/src/context.rs index d0ed9889898..d29e181bacc 100644 --- a/crates/ide_completion/src/context.rs +++ b/crates/ide_completion/src/context.rs @@ -5,6 +5,7 @@ use ide_db::{ active_parameter::ActiveParameter, base_db::{FilePosition, SourceDatabase}, + helpers::FamousDefs, RootDatabase, }; use syntax::{ @@ -150,6 +151,10 @@ pub(crate) fn previous_token_is(&self, kind: SyntaxKind) -> bool { self.previous_token.as_ref().map_or(false, |tok| tok.kind() == kind) } + pub(crate) fn famous_defs(&self) -> FamousDefs { + FamousDefs(&self.sema, self.krate) + } + pub(crate) fn dot_receiver(&self) -> Option<&ast::Expr> { match &self.completion_location { Some( diff --git a/crates/ide_completion/src/render.rs b/crates/ide_completion/src/render.rs index 404a2fa9d33..4fa5aa04dea 100644 --- a/crates/ide_completion/src/render.rs +++ b/crates/ide_completion/src/render.rs @@ -71,6 +71,7 @@ fn is_deprecated_assoc_item(&self, as_assoc_item: impl AsAssocItem) -> bool { .unwrap_or(false) } + // FIXME: remove this fn docs(&self, def: impl HasAttrs) -> Option { def.docs(self.db()) } diff --git a/crates/ide_db/src/helpers/famous_defs.rs b/crates/ide_db/src/helpers/famous_defs.rs index fd92c64f174..ee7bf9540bc 100644 --- a/crates/ide_db/src/helpers/famous_defs.rs +++ b/crates/ide_db/src/helpers/famous_defs.rs @@ -76,6 +76,10 @@ pub fn core_ops_ControlFlow(&self) -> Option { self.find_enum("core:ops:ControlFlow") } + pub fn core_ops_Drop(&self) -> Option { + self.find_trait("core:ops:Drop") + } + pub fn core_marker_Copy(&self) -> Option { self.find_trait("core:marker:Copy") } diff --git a/crates/test_utils/src/minicore.rs b/crates/test_utils/src/minicore.rs index 8801567fa5d..5c63e27879d 100644 --- a/crates/test_utils/src/minicore.rs +++ b/crates/test_utils/src/minicore.rs @@ -36,6 +36,7 @@ //! bool_impl: option, fn //! add: //! as_ref: sized +//! drop: pub mod marker { // region:sized @@ -118,7 +119,6 @@ pub trait Clone: Sized { } // endregion:clone - pub mod convert { // region:from pub trait From: Sized { @@ -195,6 +195,13 @@ pub trait DerefMut: Deref { }; // endregion:deref + // region:drop + #[lang = "drop"] + pub trait Drop { + fn drop(&mut self); + } + // endregion:drop + // region:index mod index { #[lang = "index"] @@ -237,6 +244,12 @@ unsafe impl SliceIndex<[T]> for usize { pub use self::index::{Index, IndexMut}; // endregion:index + // region:drop + pub mod mem { + pub fn drop(_x: T) {} + } + // endregion:drop + // region:range mod range { #[lang = "RangeFull"] @@ -620,13 +633,15 @@ pub mod v1 { clone::Clone, // :clone cmp::{Eq, PartialEq}, // :eq cmp::{Ord, PartialOrd}, // :ord - convert::{From, Into}, // :from convert::AsRef, // :as_ref + convert::{From, Into}, // :from default::Default, // :default iter::{IntoIterator, Iterator}, // :iterator macros::builtin::derive, // :derive marker::Copy, // :copy marker::Sized, // :sized + mem::drop, // :drop + ops::Drop, // :drop ops::{Fn, FnMut, FnOnce}, // :fn option::Option::{self, None, Some}, // :option result::Result::{self, Err, Ok}, // :result -- 2.44.0