This commit is contained in:
Lukas Wirth 2021-07-21 18:31:12 +02:00
parent 06b0cbf607
commit 3956a5b757
9 changed files with 91 additions and 51 deletions

View File

@ -1,4 +1,6 @@
//! Completes keywords.
//! Completes keywords, except:
//! - `self`, `super` and `crate`, as these are considered part of path completions.
//! - `await`, as this is a postfix completion we handle this in the postfix completions.
use syntax::{SyntaxKind, T};
@ -25,18 +27,6 @@ pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte
return;
}
// Suggest .await syntax for types that implement Future trait
if let Some(receiver) = ctx.dot_receiver() {
if let Some(ty) = ctx.sema.type_of_expr(receiver) {
if ty.impls_future(ctx.db) {
let mut item =
CompletionItem::new(CompletionKind::Keyword, ctx.source_range(), "await");
item.kind(CompletionItemKind::Keyword).detail("expr.await");
item.add_to(acc);
}
};
}
let mut add_keyword = |kw, snippet| add_keyword(ctx, acc, kw, snippet);
let expects_assoc_item = ctx.expects_assoc_item();

View File

@ -42,6 +42,13 @@ pub(crate) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) {
None => return,
};
// Suggest .await syntax for types that implement Future trait
if receiver_ty.impls_future(ctx.db) {
let mut item = CompletionItem::new(CompletionKind::Keyword, ctx.source_range(), "await");
item.kind(CompletionItemKind::Keyword).detail("expr.await");
item.add_to(acc);
}
let cap = match ctx.config.snippet_cap {
Some(it) => it,
None => return,

View File

@ -6,10 +6,12 @@
use rustc_hash::FxHashSet;
use syntax::{ast, AstNode};
use crate::{context::PathCompletionContext, CompletionContext, Completions};
use crate::{
context::PathCompletionContext, patterns::ImmediateLocation, CompletionContext, Completions,
};
pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionContext) {
if ctx.is_path_disallowed() {
if ctx.is_path_disallowed() || ctx.has_impl_or_trait_prev_sibling() {
return;
}
let (path, use_tree_parent) = match &ctx.path_context {
@ -26,10 +28,11 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon
let context_module = ctx.scope.module();
if ctx.expects_item() || ctx.expects_assoc_item() {
if let Some(ImmediateLocation::ItemList | ImmediateLocation::Trait | ImmediateLocation::Impl) =
ctx.completion_location
{
if let hir::PathResolution::Def(hir::ModuleDef::Module(module)) = resolution {
let module_scope = module.scope(ctx.db, context_module);
for (name, def) in module_scope {
for (name, def) in module.scope(ctx.db, context_module) {
if let hir::ScopeDef::MacroDef(macro_def) = def {
if macro_def.is_fn_like() {
acc.add_macro(ctx, Some(name.clone()), macro_def);

View File

@ -12,7 +12,7 @@ pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionC
if ctx.in_use_tree() {
// only show modules in a fresh UseTree
cov_mark::hit!(only_completes_modules_in_import);
cov_mark::hit!(unqualified_path_only_modules_in_import);
ctx.scope.process_all_names(&mut |name, res| {
if let ScopeDef::ModuleDef(hir::ModuleDef::Module(_)) = res {
acc.add_resolution(ctx, name, &res);
@ -24,37 +24,39 @@ pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionC
return;
}
std::array::IntoIter::new(["self", "super", "crate"]).for_each(|kw| acc.add_keyword(ctx, kw));
if let Some(ImmediateLocation::Visibility(_)) = ctx.completion_location {
return;
}
if ctx.expects_item() || ctx.expects_assoc_item() {
// only show macros in {Assoc}ItemList
ctx.scope.process_all_names(&mut |name, res| {
if let hir::ScopeDef::MacroDef(mac) = res {
if mac.is_fn_like() {
acc.add_macro(ctx, Some(name.clone()), mac);
match &ctx.completion_location {
Some(ImmediateLocation::Visibility(_)) => return,
Some(ImmediateLocation::ItemList | ImmediateLocation::Trait | ImmediateLocation::Impl) => {
// only show macros in {Assoc}ItemList
ctx.scope.process_all_names(&mut |name, res| {
if let hir::ScopeDef::MacroDef(mac) = res {
if mac.is_fn_like() {
acc.add_macro(ctx, Some(name.clone()), mac);
}
}
}
if let hir::ScopeDef::ModuleDef(hir::ModuleDef::Module(_)) = res {
acc.add_resolution(ctx, name, &res);
}
});
return;
}
if matches!(&ctx.completion_location, Some(ImmediateLocation::TypeBound)) {
ctx.scope.process_all_names(&mut |name, res| {
let add_resolution = match res {
ScopeDef::MacroDef(mac) => mac.is_fn_like(),
ScopeDef::ModuleDef(hir::ModuleDef::Trait(_) | hir::ModuleDef::Module(_)) => true,
_ => false,
};
if add_resolution {
acc.add_resolution(ctx, name, &res);
}
});
return;
if let hir::ScopeDef::ModuleDef(hir::ModuleDef::Module(_)) = res {
acc.add_resolution(ctx, name, &res);
}
});
return;
}
Some(ImmediateLocation::TypeBound) => {
ctx.scope.process_all_names(&mut |name, res| {
let add_resolution = match res {
ScopeDef::MacroDef(mac) => mac.is_fn_like(),
ScopeDef::ModuleDef(hir::ModuleDef::Trait(_) | hir::ModuleDef::Module(_)) => {
true
}
_ => false,
};
if add_resolution {
acc.add_resolution(ctx, name, &res);
}
});
return;
}
_ => (),
}
if !ctx.expects_type() {

View File

@ -1,4 +1,8 @@
//! Patterns telling us certain facts about current syntax element, they are used in completion context
//!
//! Most logic in this module first expands the token below the cursor to a maximum node that acts similar to the token itself.
//! This means we for example expand a NameRef token to its outermost Path node, as semantically these act in the same location
//! and the completions usually query for path specific things on the Path context instead. This simplifies some location handling.
use hir::Semantics;
use ide_db::RootDatabase;

View File

@ -201,7 +201,7 @@ pub(crate) fn check_pattern_is_not_applicable(code: &str, check: fn(SyntaxElemen
pub(crate) fn get_all_items(config: CompletionConfig, code: &str) -> Vec<CompletionItem> {
let (db, position) = position(code);
crate::completions(&db, &config, position).unwrap().into()
crate::completions(&db, &config, position).map_or_else(Vec::default, Into::into)
}
fn check_no_completion(ra_fixture: &str) {

View File

@ -68,7 +68,7 @@ fn after_trait_name_in_trait_def() {
}
#[test]
fn after_trait_or_target_name_in_impl() {
fn after_target_name_in_impl() {
check(
r"impl Trait $0",
expect![[r#"
@ -76,6 +76,8 @@ fn after_trait_or_target_name_in_impl() {
kw for
"#]],
);
// FIXME: This should emit `kw where`
check(r"impl Trait for Type $0", expect![[r#""#]]);
}
#[test]

View File

@ -10,7 +10,7 @@ fn check(ra_fixture: &str, expect: Expect) {
#[test]
fn use_tree_start() {
cov_mark::check!(only_completes_modules_in_import);
cov_mark::check!(unqualified_path_only_modules_in_import);
check(
r#"
//- /lib.rs crate:main deps:other_crate

View File

@ -23,3 +23,35 @@ fn empty_pub() {
"#]],
);
}
#[test]
fn after_in_kw() {
check(
r#"
pub(in $0)
"#,
expect![[r#"
kw self
kw super
kw crate
"#]],
);
}
#[test]
fn qualified() {
// FIXME: only show parent modules
check(
r#"
mod foo {
pub(in crate::$0)
}
mod bar {}
"#,
expect![[r#"
md bar
md foo
"#]],
);
}