Unnamed repository; edit this file 'description' to name the repository.
Merge #11093
11093: fix: Do not complete `Drop::drop`, complete `std::mem::drop` instead r=Veykril a=Veykril Fixes https://github.com/rust-analyzer/rust-analyzer/issues/5005 bors r+ Co-authored-by: Lukas Wirth <[email protected]>
bors[bot] 2021-12-22
parent d4c5bf7 · parent 85ed5a3 · commit 578269e
-rw-r--r--crates/ide/src/hover/tests.rs71
-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
9 files changed, 127 insertions, 42 deletions
diff --git a/crates/ide/src/hover/tests.rs b/crates/ide/src/hover/tests.rs
index 19a0e2c261..842643cb97 100644
--- a/crates/ide/src/hover/tests.rs
+++ b/crates/ide/src/hover/tests.rs
@@ -2361,46 +2361,53 @@ fn foo(ar$0g: &impl Foo + Bar<S>) {}
fn test_hover_async_block_impl_trait_has_goto_type_action() {
check_actions(
r#"
-//- minicore: future
+//- /main.rs crate:main deps:core
+// we don't use minicore here so that this test doesn't randomly fail
+// when someone edits minicore
struct S;
fn foo() {
let fo$0o = async { S };
}
+//- /core.rs crate:core
+pub mod future {
+ #[lang = "future_trait"]
+ pub trait Future {}
+}
"#,
expect![[r#"
- [
- GoToType(
- [
- HoverGotoTypeData {
- mod_path: "core::future::Future",
- nav: NavigationTarget {
- file_id: FileId(
- 1,
- ),
- full_range: 276..458,
- focus_range: 315..321,
- name: "Future",
- kind: Trait,
- description: "pub trait Future",
- },
+ [
+ GoToType(
+ [
+ HoverGotoTypeData {
+ mod_path: "core::future::Future",
+ nav: NavigationTarget {
+ file_id: FileId(
+ 1,
+ ),
+ full_range: 21..69,
+ focus_range: 60..66,
+ name: "Future",
+ kind: Trait,
+ description: "pub trait Future",
},
- HoverGotoTypeData {
- mod_path: "test::S",
- nav: NavigationTarget {
- file_id: FileId(
- 0,
- ),
- full_range: 0..9,
- focus_range: 7..8,
- name: "S",
- kind: Struct,
- description: "struct S",
- },
+ },
+ HoverGotoTypeData {
+ mod_path: "main::S",
+ nav: NavigationTarget {
+ file_id: FileId(
+ 0,
+ ),
+ full_range: 0..110,
+ focus_range: 108..109,
+ name: "S",
+ kind: Struct,
+ description: "struct S",
},
- ],
- ),
- ]
- "#]],
+ },
+ ],
+ ),
+ ]
+ "#]],
);
}
diff --git a/crates/ide_completion/src/completions/attribute/derive.rs b/crates/ide_completion/src/completions/attribute/derive.rs
index 0daf114788..3cab1918f3 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 e08a70ac7e..539b423cb3 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 8a25da7ddb..a212a98461 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 d50f889ee4..b066a46065 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 2a1891c76b..de67d68cdb 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 404a2fa9d3..4fa5aa04de 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 fd92c64f17..ee7bf9540b 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 8801567fa5..5c63e27879 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