//! Completes references after dot (fields and method calls).
use either::Either;
-use hir::ScopeDef;
use rustc_hash::FxHashSet;
use crate::{context::CompletionContext, patterns::ImmediateLocation, Completions};
if !ctx.is_trivial_path() || ctx.is_path_disallowed() || !ctx.expects_expression() {
return;
}
- ctx.scope.process_all_names(&mut |name, def| {
- if let ScopeDef::Local(local) = &def {
- if local.is_self(ctx.db) {
- let ty = local.ty(ctx.db);
- complete_fields(ctx, &ty, |field, ty| match field {
- either::Either::Left(field) => {
- acc.add_field(ctx, Some(name.clone()), field, &ty)
- }
- either::Either::Right(tuple_idx) => {
- acc.add_tuple_field(ctx, Some(name.clone()), tuple_idx, &ty)
- }
- });
- complete_methods(ctx, &ty, |func| {
- acc.add_method(ctx, func, Some(name.clone()), None)
- });
- }
+ if let Some(func) = ctx.function_def.as_ref().and_then(|fn_| ctx.sema.to_def(fn_)) {
+ if let Some(self_) = func.self_param(ctx.db) {
+ let ty = self_.ty(ctx.db);
+ complete_fields(ctx, &ty, |field, ty| match field {
+ either::Either::Left(field) => {
+ acc.add_field(ctx, Some(hir::known::SELF_PARAM), field, &ty)
+ }
+ either::Either::Right(tuple_idx) => {
+ acc.add_tuple_field(ctx, Some(hir::known::SELF_PARAM), tuple_idx, &ty)
+ }
+ });
+ complete_methods(ctx, &ty, |func| {
+ acc.add_method(ctx, func, Some(hir::known::SELF_PARAM), None)
+ });
}
- });
+ }
}
fn complete_fields(
) {
for receiver in receiver.autoderef(ctx.db) {
for (field, ty) in receiver.fields(ctx.db) {
- if !ctx.is_visible(&field) {
- continue;
- }
f(Either::Left(field), ty);
}
for (i, ty) in receiver.tuple_fields(ctx.db).into_iter().enumerate() {
) {
if let Some(krate) = ctx.krate {
let mut seen_methods = FxHashSet::default();
- let traits_in_scope = ctx.scope.traits_in_scope();
- receiver.iterate_method_candidates(ctx.db, krate, &traits_in_scope, None, |_ty, func| {
- if func.self_param(ctx.db).is_some()
- && ctx.is_visible(&func)
- && seen_methods.insert(func.name(ctx.db))
- {
- f(func);
- }
- None::<()>
- });
+ 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,
+ ctx.module,
+ None,
+ |_ty, func| {
+ if func.self_param(ctx.db).is_some() && seen_methods.insert(func.name(ctx.db)) {
+ f(func);
+ }
+ None::<()>
+ },
+ );
}
}
mod tests {
use expect_test::{expect, Expect};
- use crate::{
- tests::{check_edit, filtered_completion_list},
- CompletionKind,
- };
+ use crate::tests::{check_edit, completion_list_no_kw};
fn check(ra_fixture: &str, expect: Expect) {
- let actual = filtered_completion_list(ra_fixture, CompletionKind::Reference);
+ let actual = completion_list_no_kw(ra_fixture);
expect.assert_eq(&actual);
}
struct A { the_field: u32 }
fn foo(a: A) { a.$0() }
"#,
- expect![[""]],
+ expect![[r#""#]],
);
}
);
}
+ #[test]
+ fn test_local_impls() {
+ check(
+ r#"
+//- /lib.rs crate:lib
+pub struct A {}
+mod m {
+ impl super::A {
+ pub fn pub_module_method(&self) {}
+ }
+ fn f() {
+ impl super::A {
+ pub fn pub_foreign_local_method(&self) {}
+ }
+ }
+}
+//- /main.rs crate:main deps:lib
+fn foo(a: lib::A) {
+ impl lib::A {
+ fn local_method(&self) {}
+ }
+ a.$0
+}
+"#,
+ expect![[r#"
+ me local_method() fn(&self)
+ me pub_module_method() fn(&self)
+ "#]],
+ );
+ }
+
#[test]
fn test_doc_hidden_filtering() {
check(
a.$0
}
"#,
- expect![[""]],
+ expect![[r#""#]],
);
}
lc self &Foo
sp Self
st Foo
+ bt u32
fd self.field i32
me self.foo() fn(&self)
"#]],
lc self &mut Foo
sp Self
st Foo
+ bt u32
fd self.0 i32
me self.foo() fn(&mut self)
"#]],
"#]],
);
}
+
+ #[test]
+ fn completes_method_call_when_receiver_type_has_errors_issue_10297() {
+ check(
+ r#"
+//- minicore: iterator, sized
+struct Vec<T>;
+impl<T> IntoIterator for Vec<T> {
+ type Item = ();
+ type IntoIter = ();
+ fn into_iter(self);
+}
+fn main() {
+ let x: Vec<_>;
+ x.$0;
+}
+"#,
+ expect![[r#"
+ me into_iter() (as IntoIterator) fn(self) -> <Self as IntoIterator>::IntoIter
+ "#]],
+ )
+ }
+
+ #[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);
+}
+",
+ )
+ }
}