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}; use syntax::{SyntaxKind, T};
@ -25,18 +27,6 @@ pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte
return; 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 mut add_keyword = |kw, snippet| add_keyword(ctx, acc, kw, snippet);
let expects_assoc_item = ctx.expects_assoc_item(); 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, 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 { let cap = match ctx.config.snippet_cap {
Some(it) => it, Some(it) => it,
None => return, None => return,

View file

@ -6,10 +6,12 @@ use hir::HasVisibility;
use rustc_hash::FxHashSet; use rustc_hash::FxHashSet;
use syntax::{ast, AstNode}; 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) { 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; return;
} }
let (path, use_tree_parent) = match &ctx.path_context { 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(); 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 { 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(ctx.db, context_module) {
for (name, def) in module_scope {
if let hir::ScopeDef::MacroDef(macro_def) = def { if let hir::ScopeDef::MacroDef(macro_def) = def {
if macro_def.is_fn_like() { if macro_def.is_fn_like() {
acc.add_macro(ctx, Some(name.clone()), macro_def); 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() { if ctx.in_use_tree() {
// only show modules in a fresh UseTree // 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| { ctx.scope.process_all_names(&mut |name, res| {
if let ScopeDef::ModuleDef(hir::ModuleDef::Module(_)) = res { if let ScopeDef::ModuleDef(hir::ModuleDef::Module(_)) = res {
acc.add_resolution(ctx, name, &res); acc.add_resolution(ctx, name, &res);
@ -24,37 +24,39 @@ pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionC
return; return;
} }
std::array::IntoIter::new(["self", "super", "crate"]).for_each(|kw| acc.add_keyword(ctx, kw)); 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() { match &ctx.completion_location {
// only show macros in {Assoc}ItemList Some(ImmediateLocation::Visibility(_)) => return,
ctx.scope.process_all_names(&mut |name, res| { Some(ImmediateLocation::ItemList | ImmediateLocation::Trait | ImmediateLocation::Impl) => {
if let hir::ScopeDef::MacroDef(mac) = res { // only show macros in {Assoc}ItemList
if mac.is_fn_like() { ctx.scope.process_all_names(&mut |name, res| {
acc.add_macro(ctx, Some(name.clone()), mac); 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 {
if let hir::ScopeDef::ModuleDef(hir::ModuleDef::Module(_)) = res { acc.add_resolution(ctx, name, &res);
acc.add_resolution(ctx, name, &res); }
} });
}); return;
return; }
} Some(ImmediateLocation::TypeBound) => {
ctx.scope.process_all_names(&mut |name, res| {
if matches!(&ctx.completion_location, Some(ImmediateLocation::TypeBound)) { let add_resolution = match res {
ctx.scope.process_all_names(&mut |name, res| { ScopeDef::MacroDef(mac) => mac.is_fn_like(),
let add_resolution = match res { ScopeDef::ModuleDef(hir::ModuleDef::Trait(_) | hir::ModuleDef::Module(_)) => {
ScopeDef::MacroDef(mac) => mac.is_fn_like(), true
ScopeDef::ModuleDef(hir::ModuleDef::Trait(_) | hir::ModuleDef::Module(_)) => true, }
_ => false, _ => false,
}; };
if add_resolution { if add_resolution {
acc.add_resolution(ctx, name, &res); acc.add_resolution(ctx, name, &res);
} }
}); });
return; return;
}
_ => (),
} }
if !ctx.expects_type() { 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 //! 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 hir::Semantics;
use ide_db::RootDatabase; 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> { pub(crate) fn get_all_items(config: CompletionConfig, code: &str) -> Vec<CompletionItem> {
let (db, position) = position(code); 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) { fn check_no_completion(ra_fixture: &str) {

View file

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

View file

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

View file

@ -23,3 +23,35 @@ pub($0)
"#]], "#]],
); );
} }
#[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
"#]],
);
}