mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-28 04:44:57 +00:00
fix: Do not complete Drop::drop
, complete std::mem::drop
instead
This commit is contained in:
parent
276687a6ee
commit
5360c9bd22
8 changed files with 88 additions and 10 deletions
|
@ -1,7 +1,7 @@
|
||||||
//! Completion for derives
|
//! Completion for derives
|
||||||
use hir::{HasAttrs, MacroDef, MacroKind};
|
use hir::{HasAttrs, MacroDef, MacroKind};
|
||||||
use ide_db::{
|
use ide_db::{
|
||||||
helpers::{import_assets::ImportAssets, insert_use::ImportScope, FamousDefs},
|
helpers::{import_assets::ImportAssets, insert_use::ImportScope},
|
||||||
SymbolKind,
|
SymbolKind,
|
||||||
};
|
};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
|
@ -18,7 +18,7 @@ pub(super) fn complete_derive(
|
||||||
ctx: &CompletionContext,
|
ctx: &CompletionContext,
|
||||||
existing_derives: &[ast::Path],
|
existing_derives: &[ast::Path],
|
||||||
) {
|
) {
|
||||||
let core = FamousDefs(&ctx.sema, ctx.krate).core();
|
let core = ctx.famous_defs().core();
|
||||||
let existing_derives: FxHashSet<_> = existing_derives
|
let existing_derives: FxHashSet<_> = existing_derives
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter_map(|path| ctx.scope.speculative_resolve_as_mac(&path))
|
.filter_map(|path| ctx.scope.speculative_resolve_as_mac(&path))
|
||||||
|
|
|
@ -76,7 +76,14 @@ fn complete_methods(
|
||||||
) {
|
) {
|
||||||
if let Some(krate) = ctx.krate {
|
if let Some(krate) = ctx.krate {
|
||||||
let mut seen_methods = FxHashSet::default();
|
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| {
|
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)) {
|
if func.self_param(ctx.db).is_some() && seen_methods.insert(func.name(ctx.db)) {
|
||||||
f(func);
|
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);
|
||||||
|
}
|
||||||
|
",
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,9 +2,9 @@
|
||||||
|
|
||||||
mod format_like;
|
mod format_like;
|
||||||
|
|
||||||
use hir::Documentation;
|
use hir::{Documentation, HasAttrs};
|
||||||
use ide_db::{
|
use ide_db::{
|
||||||
helpers::{insert_use::ImportScope, FamousDefs, SnippetCap},
|
helpers::{insert_use::ImportScope, SnippetCap},
|
||||||
ty_filter::TryEnum,
|
ty_filter::TryEnum,
|
||||||
};
|
};
|
||||||
use syntax::{
|
use syntax::{
|
||||||
|
@ -59,6 +59,22 @@ pub(crate) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) {
|
||||||
None => return,
|
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() {
|
if !ctx.config.snippets.is_empty() {
|
||||||
add_custom_postfix_completions(acc, ctx, &postfix_snippet, &receiver_text);
|
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);
|
.add_to(acc);
|
||||||
postfix_snippet("not", "!expr", &format!("!{}", receiver_text)).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_, &[]) {
|
if receiver_ty.impls_trait(ctx.db, trait_, &[]) {
|
||||||
postfix_snippet(
|
postfix_snippet(
|
||||||
"for",
|
"for",
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
//! Complete fields in record literals and patterns.
|
//! Complete fields in record literals and patterns.
|
||||||
use ide_db::{helpers::FamousDefs, SymbolKind};
|
use ide_db::SymbolKind;
|
||||||
use syntax::{ast::Expr, T};
|
use syntax::{ast::Expr, T};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
@ -13,7 +13,7 @@ pub(crate) fn complete_record(acc: &mut Completions, ctx: &CompletionContext) ->
|
||||||
| ImmediateLocation::RecordExprUpdate(record_expr),
|
| ImmediateLocation::RecordExprUpdate(record_expr),
|
||||||
) => {
|
) => {
|
||||||
let ty = ctx.sema.type_of_expr(&Expr::RecordExpr(record_expr.clone()));
|
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)| {
|
let impl_default_trait = default_trait.zip(ty).map_or(false, |(default_trait, ty)| {
|
||||||
ty.original.impls_trait(ctx.db, default_trait, &[])
|
ty.original.impls_trait(ctx.db, default_trait, &[])
|
||||||
});
|
});
|
||||||
|
|
|
@ -5,6 +5,7 @@ use hir::{Local, Name, ScopeDef, Semantics, SemanticsScope, Type, TypeInfo};
|
||||||
use ide_db::{
|
use ide_db::{
|
||||||
active_parameter::ActiveParameter,
|
active_parameter::ActiveParameter,
|
||||||
base_db::{FilePosition, SourceDatabase},
|
base_db::{FilePosition, SourceDatabase},
|
||||||
|
helpers::FamousDefs,
|
||||||
RootDatabase,
|
RootDatabase,
|
||||||
};
|
};
|
||||||
use syntax::{
|
use syntax::{
|
||||||
|
@ -150,6 +151,10 @@ impl<'a> CompletionContext<'a> {
|
||||||
self.previous_token.as_ref().map_or(false, |tok| tok.kind() == kind)
|
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> {
|
pub(crate) fn dot_receiver(&self) -> Option<&ast::Expr> {
|
||||||
match &self.completion_location {
|
match &self.completion_location {
|
||||||
Some(
|
Some(
|
||||||
|
|
|
@ -71,6 +71,7 @@ impl<'a> RenderContext<'a> {
|
||||||
.unwrap_or(false)
|
.unwrap_or(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME: remove this
|
||||||
fn docs(&self, def: impl HasAttrs) -> Option<hir::Documentation> {
|
fn docs(&self, def: impl HasAttrs) -> Option<hir::Documentation> {
|
||||||
def.docs(self.db())
|
def.docs(self.db())
|
||||||
}
|
}
|
||||||
|
|
|
@ -76,6 +76,10 @@ impl FamousDefs<'_, '_> {
|
||||||
self.find_enum("core:ops:ControlFlow")
|
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> {
|
pub fn core_marker_Copy(&self) -> Option<Trait> {
|
||||||
self.find_trait("core:marker:Copy")
|
self.find_trait("core:marker:Copy")
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,6 +36,7 @@
|
||||||
//! bool_impl: option, fn
|
//! bool_impl: option, fn
|
||||||
//! add:
|
//! add:
|
||||||
//! as_ref: sized
|
//! as_ref: sized
|
||||||
|
//! drop:
|
||||||
|
|
||||||
pub mod marker {
|
pub mod marker {
|
||||||
// region:sized
|
// region:sized
|
||||||
|
@ -118,7 +119,6 @@ pub mod clone {
|
||||||
}
|
}
|
||||||
// endregion:clone
|
// endregion:clone
|
||||||
|
|
||||||
|
|
||||||
pub mod convert {
|
pub mod convert {
|
||||||
// region:from
|
// region:from
|
||||||
pub trait From<T>: Sized {
|
pub trait From<T>: Sized {
|
||||||
|
@ -195,6 +195,13 @@ pub mod ops {
|
||||||
};
|
};
|
||||||
// endregion:deref
|
// endregion:deref
|
||||||
|
|
||||||
|
// region:drop
|
||||||
|
#[lang = "drop"]
|
||||||
|
pub trait Drop {
|
||||||
|
fn drop(&mut self);
|
||||||
|
}
|
||||||
|
// endregion:drop
|
||||||
|
|
||||||
// region:index
|
// region:index
|
||||||
mod index {
|
mod index {
|
||||||
#[lang = "index"]
|
#[lang = "index"]
|
||||||
|
@ -237,6 +244,12 @@ pub mod ops {
|
||||||
pub use self::index::{Index, IndexMut};
|
pub use self::index::{Index, IndexMut};
|
||||||
// endregion:index
|
// endregion:index
|
||||||
|
|
||||||
|
// region:drop
|
||||||
|
pub mod mem {
|
||||||
|
pub fn drop<T>(_x: T) {}
|
||||||
|
}
|
||||||
|
// endregion:drop
|
||||||
|
|
||||||
// region:range
|
// region:range
|
||||||
mod range {
|
mod range {
|
||||||
#[lang = "RangeFull"]
|
#[lang = "RangeFull"]
|
||||||
|
@ -620,13 +633,15 @@ pub mod prelude {
|
||||||
clone::Clone, // :clone
|
clone::Clone, // :clone
|
||||||
cmp::{Eq, PartialEq}, // :eq
|
cmp::{Eq, PartialEq}, // :eq
|
||||||
cmp::{Ord, PartialOrd}, // :ord
|
cmp::{Ord, PartialOrd}, // :ord
|
||||||
convert::{From, Into}, // :from
|
|
||||||
convert::AsRef, // :as_ref
|
convert::AsRef, // :as_ref
|
||||||
|
convert::{From, Into}, // :from
|
||||||
default::Default, // :default
|
default::Default, // :default
|
||||||
iter::{IntoIterator, Iterator}, // :iterator
|
iter::{IntoIterator, Iterator}, // :iterator
|
||||||
macros::builtin::derive, // :derive
|
macros::builtin::derive, // :derive
|
||||||
marker::Copy, // :copy
|
marker::Copy, // :copy
|
||||||
marker::Sized, // :sized
|
marker::Sized, // :sized
|
||||||
|
mem::drop, // :drop
|
||||||
|
ops::Drop, // :drop
|
||||||
ops::{Fn, FnMut, FnOnce}, // :fn
|
ops::{Fn, FnMut, FnOnce}, // :fn
|
||||||
option::Option::{self, None, Some}, // :option
|
option::Option::{self, None, Some}, // :option
|
||||||
result::Result::{self, Err, Ok}, // :result
|
result::Result::{self, Err, Ok}, // :result
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue