about summary refs log tree commit diff
diff options
context:
space:
mode:
authorLukas Wirth <lukastw97@gmail.com>2021-12-22 02:25:38 +0100
committerLukas Wirth <lukastw97@gmail.com>2021-12-22 02:25:38 +0100
commit5360c9bd22f36865db50bb69d9bfce6f3d4fec38 (patch)
tree7ff0a3b63140ebb30eeb2640003065ad1b669c0b
parent276687a6eeefbbc0721ded81980f88edd2178ebe (diff)
downloadrust-5360c9bd22f36865db50bb69d9bfce6f3d4fec38.tar.gz
rust-5360c9bd22f36865db50bb69d9bfce6f3d4fec38.zip
fix: Do not complete `Drop::drop`, complete `std::mem::drop` instead
-rw-r--r--crates/ide_completion/src/completions/attribute/derive.rs4
-rw-r--r--crates/ide_completion/src/completions/dot.rs39
-rw-r--r--crates/ide_completion/src/completions/postfix.rs22
-rw-r--r--crates/ide_completion/src/completions/record.rs4
-rw-r--r--crates/ide_completion/src/context.rs5
-rw-r--r--crates/ide_completion/src/render.rs1
-rw-r--r--crates/ide_db/src/helpers/famous_defs.rs4
-rw-r--r--crates/test_utils/src/minicore.rs19
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>(T);
+impl<T> Drop for Vec<T> {
+    fn drop(&mut self) {}
+}
+fn main() {
+    let x = Vec(0u32)
+    x.$0;
+}
+"#,
+            r"
+struct Vec<T>(T);
+impl<T> Drop for Vec<T> {
+    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 hir::{Local, Name, ScopeDef, Semantics, SemanticsScope, Type, TypeInfo};
 use ide_db::{
     active_parameter::ActiveParameter,
     base_db::{FilePosition, SourceDatabase},
+    helpers::FamousDefs,
     RootDatabase,
 };
 use syntax::{
@@ -150,6 +151,10 @@ impl<'a> CompletionContext<'a> {
         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 @@ impl<'a> RenderContext<'a> {
                 .unwrap_or(false)
     }
 
+    // FIXME: remove this
     fn docs(&self, def: impl HasAttrs) -> Option<hir::Documentation> {
         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 @@ impl FamousDefs<'_, '_> {
         self.find_enum("core:ops:ControlFlow")
     }
 
+    pub fn core_ops_Drop(&self) -> Option<Trait> {
+        self.find_trait("core:ops:Drop")
+    }
+
     pub fn core_marker_Copy(&self) -> Option<Trait> {
         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 mod clone {
 }
 // endregion:clone
 
-
 pub mod convert {
     // region:from
     pub trait From<T>: Sized {
@@ -195,6 +195,13 @@ pub mod ops {
     };
     // 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 @@ pub mod ops {
     pub use self::index::{Index, IndexMut};
     // endregion:index
 
+    // region:drop
+    pub mod mem {
+        pub fn drop<T>(_x: T) {}
+    }
+    // endregion:drop
+
     // region:range
     mod range {
         #[lang = "RangeFull"]
@@ -620,13 +633,15 @@ pub mod prelude {
             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