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 <lukastw97@gmail.com>
This commit is contained in:
bors[bot] 2021-12-22 01:48:31 +00:00 committed by GitHub
commit 578269e613
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 127 additions and 42 deletions

View file

@ -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",
},
],
),
]
"#]],
},
],
),
]
"#]],
);
}

View file

@ -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))

View file

@ -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);
}
",
)
}
}

View file

@ -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",

View file

@ -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, &[])
});

View file

@ -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(

View file

@ -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<hir::Documentation> {
def.docs(self.db())
}

View file

@ -76,6 +76,10 @@ pub fn core_ops_ControlFlow(&self) -> Option<Enum> {
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")
}

View file

@ -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<T>: 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<T> SliceIndex<[T]> for usize {
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 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