mirror of
https://github.com/rust-lang/rust-analyzer
synced 2025-01-16 07:03:57 +00:00
internal: Simplify some completions
This commit is contained in:
parent
8b078986dc
commit
7a0774defa
11 changed files with 147 additions and 222 deletions
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
mod source_to_def;
|
mod source_to_def;
|
||||||
|
|
||||||
use std::{cell::RefCell, fmt, iter};
|
use std::{cell::RefCell, fmt, iter, ops};
|
||||||
|
|
||||||
use base_db::{FileId, FileRange};
|
use base_db::{FileId, FileRange};
|
||||||
use hir_def::{
|
use hir_def::{
|
||||||
|
@ -1449,3 +1449,11 @@ impl<'a> SemanticsScope<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct VisibleTraits(pub FxHashSet<TraitId>);
|
pub struct VisibleTraits(pub FxHashSet<TraitId>);
|
||||||
|
|
||||||
|
impl ops::Deref for VisibleTraits {
|
||||||
|
type Target = FxHashSet<TraitId>;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -36,7 +36,7 @@ use crate::{
|
||||||
const_::render_const,
|
const_::render_const,
|
||||||
function::{render_fn, render_method},
|
function::{render_fn, render_method},
|
||||||
literal::{render_struct_literal, render_variant_lit},
|
literal::{render_struct_literal, render_variant_lit},
|
||||||
macro_::{render_macro, render_macro_pat},
|
macro_::render_macro,
|
||||||
pattern::{render_struct_pat, render_variant_pat},
|
pattern::{render_struct_pat, render_variant_pat},
|
||||||
render_field, render_path_resolution, render_pattern_resolution, render_tuple_field,
|
render_field, render_path_resolution, render_pattern_resolution, render_tuple_field,
|
||||||
type_alias::{render_type_alias, render_type_alias_with_eq},
|
type_alias::{render_type_alias, render_type_alias_with_eq},
|
||||||
|
@ -101,15 +101,15 @@ impl Completions {
|
||||||
pub(crate) fn add_keyword_snippet_expr(
|
pub(crate) fn add_keyword_snippet_expr(
|
||||||
&mut self,
|
&mut self,
|
||||||
ctx: &CompletionContext,
|
ctx: &CompletionContext,
|
||||||
|
incomplete_let: bool,
|
||||||
kw: &str,
|
kw: &str,
|
||||||
snippet: &str,
|
snippet: &str,
|
||||||
incomplete_let: bool,
|
|
||||||
) {
|
) {
|
||||||
let mut item = CompletionItem::new(CompletionItemKind::Keyword, ctx.source_range(), kw);
|
let mut item = CompletionItem::new(CompletionItemKind::Keyword, ctx.source_range(), kw);
|
||||||
|
|
||||||
match ctx.config.snippet_cap {
|
match ctx.config.snippet_cap {
|
||||||
Some(cap) => {
|
Some(cap) => {
|
||||||
if snippet.ends_with('}') && incomplete_let {
|
if incomplete_let && snippet.ends_with('}') {
|
||||||
// complete block expression snippets with a trailing semicolon, if inside an incomplete let
|
// complete block expression snippets with a trailing semicolon, if inside an incomplete let
|
||||||
cov_mark::hit!(let_semi);
|
cov_mark::hit!(let_semi);
|
||||||
item.insert_snippet(cap, format!("{};", snippet));
|
item.insert_snippet(cap, format!("{};", snippet));
|
||||||
|
@ -181,6 +181,17 @@ impl Completions {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn add_enum_variants(
|
||||||
|
&mut self,
|
||||||
|
ctx: &CompletionContext,
|
||||||
|
path_ctx: &PathCompletionCtx,
|
||||||
|
e: hir::Enum,
|
||||||
|
) {
|
||||||
|
e.variants(ctx.db)
|
||||||
|
.into_iter()
|
||||||
|
.for_each(|variant| self.add_enum_variant(ctx, path_ctx, variant, None));
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn add_module(
|
pub(crate) fn add_module(
|
||||||
&mut self,
|
&mut self,
|
||||||
ctx: &CompletionContext,
|
ctx: &CompletionContext,
|
||||||
|
@ -219,29 +230,6 @@ impl Completions {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn add_macro_pat(
|
|
||||||
&mut self,
|
|
||||||
ctx: &CompletionContext,
|
|
||||||
pattern_ctx: &PatternContext,
|
|
||||||
mac: hir::Macro,
|
|
||||||
local_name: hir::Name,
|
|
||||||
) {
|
|
||||||
let is_private_editable = match ctx.is_visible(&mac) {
|
|
||||||
Visible::Yes => false,
|
|
||||||
Visible::Editable => true,
|
|
||||||
Visible::No => return,
|
|
||||||
};
|
|
||||||
self.add(
|
|
||||||
render_macro_pat(
|
|
||||||
RenderContext::new(ctx).private_editable(is_private_editable),
|
|
||||||
pattern_ctx,
|
|
||||||
local_name,
|
|
||||||
mac,
|
|
||||||
)
|
|
||||||
.build(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn add_function(
|
pub(crate) fn add_function(
|
||||||
&mut self,
|
&mut self,
|
||||||
ctx: &CompletionContext,
|
ctx: &CompletionContext,
|
||||||
|
|
|
@ -121,7 +121,7 @@ fn complete_methods(
|
||||||
receiver.iterate_method_candidates(
|
receiver.iterate_method_candidates(
|
||||||
ctx.db,
|
ctx.db,
|
||||||
&ctx.scope,
|
&ctx.scope,
|
||||||
&ctx.traits_in_scope().0,
|
&ctx.traits_in_scope(),
|
||||||
Some(ctx.module),
|
Some(ctx.module),
|
||||||
None,
|
None,
|
||||||
|func| {
|
|func| {
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
//! Completion of names from the current scope in expression position.
|
//! Completion of names from the current scope in expression position.
|
||||||
|
|
||||||
use hir::ScopeDef;
|
use hir::ScopeDef;
|
||||||
use ide_db::FxHashSet;
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
context::{ExprCtx, PathCompletionCtx, Qualified},
|
context::{ExprCtx, PathCompletionCtx, Qualified},
|
||||||
|
@ -33,24 +32,24 @@ pub(crate) fn complete_expr_path(
|
||||||
let wants_mut_token =
|
let wants_mut_token =
|
||||||
ref_expr_parent.as_ref().map(|it| it.mut_token().is_none()).unwrap_or(false);
|
ref_expr_parent.as_ref().map(|it| it.mut_token().is_none()).unwrap_or(false);
|
||||||
|
|
||||||
let scope_def_applicable = |def| {
|
let scope_def_applicable = |def| match def {
|
||||||
match def {
|
ScopeDef::GenericParam(hir::GenericParam::LifetimeParam(_)) | ScopeDef::Label(_) => false,
|
||||||
ScopeDef::GenericParam(hir::GenericParam::LifetimeParam(_)) | ScopeDef::Label(_) => {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
// Don't suggest attribute macros and derives.
|
|
||||||
ScopeDef::ModuleDef(hir::ModuleDef::Macro(mac)) => mac.is_fn_like(ctx.db),
|
ScopeDef::ModuleDef(hir::ModuleDef::Macro(mac)) => mac.is_fn_like(ctx.db),
|
||||||
_ => true,
|
_ => true,
|
||||||
}
|
};
|
||||||
|
|
||||||
|
let add_assoc_item = |acc: &mut Completions, item| match item {
|
||||||
|
hir::AssocItem::Function(func) => acc.add_function(ctx, path_ctx, func, None),
|
||||||
|
hir::AssocItem::Const(ct) => acc.add_const(ctx, ct),
|
||||||
|
hir::AssocItem::TypeAlias(ty) => acc.add_type_alias(ctx, ty),
|
||||||
};
|
};
|
||||||
|
|
||||||
match qualified {
|
match qualified {
|
||||||
Qualified::Infer => ctx
|
Qualified::Infer => ctx
|
||||||
.traits_in_scope()
|
.traits_in_scope()
|
||||||
.0
|
.iter()
|
||||||
.into_iter()
|
.flat_map(|&it| hir::Trait::from(it).items(ctx.sema.db))
|
||||||
.flat_map(|it| hir::Trait::from(it).items(ctx.sema.db))
|
.for_each(|item| add_assoc_item(acc, item)),
|
||||||
.for_each(|item| add_assoc_item(acc, ctx, path_ctx, item)),
|
|
||||||
Qualified::With { resolution: None, .. } => {}
|
Qualified::With { resolution: None, .. } => {}
|
||||||
Qualified::With { resolution: Some(resolution), .. } => {
|
Qualified::With { resolution: Some(resolution), .. } => {
|
||||||
// Add associated types on type parameters and `Self`.
|
// Add associated types on type parameters and `Self`.
|
||||||
|
@ -67,46 +66,32 @@ pub(crate) fn complete_expr_path(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
hir::PathResolution::Def(
|
hir::PathResolution::Def(
|
||||||
def @ (hir::ModuleDef::Adt(_)
|
def @ (hir::ModuleDef::Adt(_)
|
||||||
| hir::ModuleDef::TypeAlias(_)
|
| hir::ModuleDef::TypeAlias(_)
|
||||||
| hir::ModuleDef::BuiltinType(_)),
|
| hir::ModuleDef::BuiltinType(_)),
|
||||||
) => {
|
) => {
|
||||||
if let &hir::ModuleDef::Adt(hir::Adt::Enum(e)) = def {
|
|
||||||
add_enum_variants(acc, ctx, path_ctx, e);
|
|
||||||
}
|
|
||||||
let ty = match def {
|
let ty = match def {
|
||||||
hir::ModuleDef::Adt(adt) => adt.ty(ctx.db),
|
hir::ModuleDef::Adt(adt) => adt.ty(ctx.db),
|
||||||
hir::ModuleDef::TypeAlias(a) => {
|
hir::ModuleDef::TypeAlias(a) => a.ty(ctx.db),
|
||||||
let ty = a.ty(ctx.db);
|
|
||||||
if let Some(hir::Adt::Enum(e)) = ty.as_adt() {
|
|
||||||
cov_mark::hit!(completes_variant_through_alias);
|
|
||||||
add_enum_variants(acc, ctx, path_ctx, e);
|
|
||||||
}
|
|
||||||
ty
|
|
||||||
}
|
|
||||||
hir::ModuleDef::BuiltinType(builtin) => {
|
hir::ModuleDef::BuiltinType(builtin) => {
|
||||||
cov_mark::hit!(completes_primitive_assoc_const);
|
cov_mark::hit!(completes_primitive_assoc_const);
|
||||||
builtin.ty(ctx.db)
|
builtin.ty(ctx.db)
|
||||||
}
|
}
|
||||||
_ => unreachable!(),
|
_ => return,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if let Some(hir::Adt::Enum(e)) = ty.as_adt() {
|
||||||
|
cov_mark::hit!(completes_variant_through_alias);
|
||||||
|
acc.add_enum_variants(ctx, path_ctx, e);
|
||||||
|
}
|
||||||
|
|
||||||
// XXX: For parity with Rust bug #22519, this does not complete Ty::AssocType.
|
// XXX: For parity with Rust bug #22519, this does not complete Ty::AssocType.
|
||||||
// (where AssocType is defined on a trait, not an inherent impl)
|
// (where AssocType is defined on a trait, not an inherent impl)
|
||||||
|
|
||||||
ty.iterate_path_candidates(
|
ctx.iterate_path_candidates(&ty, |item| {
|
||||||
ctx.db,
|
add_assoc_item(acc, item);
|
||||||
&ctx.scope,
|
});
|
||||||
&ctx.traits_in_scope().0,
|
|
||||||
Some(ctx.module),
|
|
||||||
None,
|
|
||||||
|item| {
|
|
||||||
add_assoc_item(acc, ctx, path_ctx, item);
|
|
||||||
None::<()>
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
// Iterate assoc types separately
|
// Iterate assoc types separately
|
||||||
ty.iterate_assoc_items(ctx.db, ctx.krate, |item| {
|
ty.iterate_assoc_items(ctx.db, ctx.krate, |item| {
|
||||||
|
@ -119,7 +104,7 @@ pub(crate) fn complete_expr_path(
|
||||||
hir::PathResolution::Def(hir::ModuleDef::Trait(t)) => {
|
hir::PathResolution::Def(hir::ModuleDef::Trait(t)) => {
|
||||||
// Handles `Trait::assoc` as well as `<Ty as Trait>::assoc`.
|
// Handles `Trait::assoc` as well as `<Ty as Trait>::assoc`.
|
||||||
for item in t.items(ctx.db) {
|
for item in t.items(ctx.db) {
|
||||||
add_assoc_item(acc, ctx, path_ctx, item);
|
add_assoc_item(acc, item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
hir::PathResolution::TypeParam(_) | hir::PathResolution::SelfType(_) => {
|
hir::PathResolution::TypeParam(_) | hir::PathResolution::SelfType(_) => {
|
||||||
|
@ -130,24 +115,12 @@ pub(crate) fn complete_expr_path(
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(hir::Adt::Enum(e)) = ty.as_adt() {
|
if let Some(hir::Adt::Enum(e)) = ty.as_adt() {
|
||||||
add_enum_variants(acc, ctx, path_ctx, e);
|
acc.add_enum_variants(ctx, path_ctx, e);
|
||||||
}
|
}
|
||||||
let mut seen = FxHashSet::default();
|
|
||||||
ty.iterate_path_candidates(
|
ctx.iterate_path_candidates(&ty, |item| {
|
||||||
ctx.db,
|
add_assoc_item(acc, item);
|
||||||
&ctx.scope,
|
});
|
||||||
&ctx.traits_in_scope().0,
|
|
||||||
Some(ctx.module),
|
|
||||||
None,
|
|
||||||
|item| {
|
|
||||||
// We might iterate candidates of a trait multiple times here, so deduplicate
|
|
||||||
// them.
|
|
||||||
if seen.insert(item) {
|
|
||||||
add_assoc_item(acc, ctx, path_ctx, item);
|
|
||||||
}
|
|
||||||
None::<()>
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
|
@ -212,7 +185,7 @@ pub(crate) fn complete_expr_path(
|
||||||
|
|
||||||
if is_func_update.is_none() {
|
if is_func_update.is_none() {
|
||||||
let mut add_keyword =
|
let mut add_keyword =
|
||||||
|kw, snippet| acc.add_keyword_snippet_expr(ctx, kw, snippet, incomplete_let);
|
|kw, snippet| acc.add_keyword_snippet_expr(ctx, incomplete_let, kw, snippet);
|
||||||
|
|
||||||
if !in_block_expr {
|
if !in_block_expr {
|
||||||
add_keyword("unsafe", "unsafe {\n $0\n}");
|
add_keyword("unsafe", "unsafe {\n $0\n}");
|
||||||
|
@ -265,27 +238,3 @@ pub(crate) fn complete_expr_path(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_assoc_item(
|
|
||||||
acc: &mut Completions,
|
|
||||||
ctx: &CompletionContext,
|
|
||||||
path_ctx: &PathCompletionCtx,
|
|
||||||
item: hir::AssocItem,
|
|
||||||
) {
|
|
||||||
match item {
|
|
||||||
hir::AssocItem::Function(func) => acc.add_function(ctx, path_ctx, func, None),
|
|
||||||
hir::AssocItem::Const(ct) => acc.add_const(ctx, ct),
|
|
||||||
hir::AssocItem::TypeAlias(ty) => acc.add_type_alias(ctx, ty),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn add_enum_variants(
|
|
||||||
acc: &mut Completions,
|
|
||||||
ctx: &CompletionContext,
|
|
||||||
path_ctx: &PathCompletionCtx,
|
|
||||||
e: hir::Enum,
|
|
||||||
) {
|
|
||||||
e.variants(ctx.db)
|
|
||||||
.into_iter()
|
|
||||||
.for_each(|variant| acc.add_enum_variant(ctx, path_ctx, variant, None));
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
//! Completes constants and paths in unqualified patterns.
|
//! Completes constants and paths in unqualified patterns.
|
||||||
|
|
||||||
use hir::{db::DefDatabase, AssocItem, ScopeDef};
|
use hir::{db::DefDatabase, AssocItem, ScopeDef};
|
||||||
use ide_db::FxHashSet;
|
|
||||||
use syntax::ast::Pat;
|
use syntax::ast::Pat;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
@ -81,9 +80,7 @@ pub(crate) fn complete_pattern(
|
||||||
hir::ModuleDef::Adt(hir::Adt::Enum(e)) => refutable || single_variant_enum(e),
|
hir::ModuleDef::Adt(hir::Adt::Enum(e)) => refutable || single_variant_enum(e),
|
||||||
hir::ModuleDef::Const(..) => refutable,
|
hir::ModuleDef::Const(..) => refutable,
|
||||||
hir::ModuleDef::Module(..) => true,
|
hir::ModuleDef::Module(..) => true,
|
||||||
hir::ModuleDef::Macro(mac) if mac.is_fn_like(ctx.db) => {
|
hir::ModuleDef::Macro(mac) => mac.is_fn_like(ctx.db),
|
||||||
return acc.add_macro_pat(ctx, pattern_ctx, mac, name);
|
|
||||||
}
|
|
||||||
_ => false,
|
_ => false,
|
||||||
},
|
},
|
||||||
hir::ScopeDef::ImplSelfType(impl_) => match impl_.self_ty(ctx.db).as_adt() {
|
hir::ScopeDef::ImplSelfType(impl_) => match impl_.self_ty(ctx.db).as_adt() {
|
||||||
|
@ -136,12 +133,7 @@ pub(crate) fn complete_pattern_path(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
res @ (hir::PathResolution::TypeParam(_)
|
res => {
|
||||||
| hir::PathResolution::SelfType(_)
|
|
||||||
| hir::PathResolution::Def(hir::ModuleDef::Adt(hir::Adt::Struct(_)))
|
|
||||||
| hir::PathResolution::Def(hir::ModuleDef::Adt(hir::Adt::Enum(_)))
|
|
||||||
| hir::PathResolution::Def(hir::ModuleDef::Adt(hir::Adt::Union(_)))
|
|
||||||
| hir::PathResolution::Def(hir::ModuleDef::BuiltinType(_))) => {
|
|
||||||
let ty = match res {
|
let ty = match res {
|
||||||
hir::PathResolution::TypeParam(param) => param.ty(ctx.db),
|
hir::PathResolution::TypeParam(param) => param.ty(ctx.db),
|
||||||
hir::PathResolution::SelfType(impl_def) => impl_def.self_ty(ctx.db),
|
hir::PathResolution::SelfType(impl_def) => impl_def.self_ty(ctx.db),
|
||||||
|
@ -149,10 +141,6 @@ pub(crate) fn complete_pattern_path(
|
||||||
s.ty(ctx.db)
|
s.ty(ctx.db)
|
||||||
}
|
}
|
||||||
hir::PathResolution::Def(hir::ModuleDef::Adt(hir::Adt::Enum(e))) => {
|
hir::PathResolution::Def(hir::ModuleDef::Adt(hir::Adt::Enum(e))) => {
|
||||||
cov_mark::hit!(enum_plain_qualified_use_tree);
|
|
||||||
e.variants(ctx.db).into_iter().for_each(|variant| {
|
|
||||||
acc.add_enum_variant(ctx, path_ctx, variant, None)
|
|
||||||
});
|
|
||||||
e.ty(ctx.db)
|
e.ty(ctx.db)
|
||||||
}
|
}
|
||||||
hir::PathResolution::Def(hir::ModuleDef::Adt(hir::Adt::Union(u))) => {
|
hir::PathResolution::Def(hir::ModuleDef::Adt(hir::Adt::Union(u))) => {
|
||||||
|
@ -162,41 +150,33 @@ pub(crate) fn complete_pattern_path(
|
||||||
_ => return,
|
_ => return,
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut seen = FxHashSet::default();
|
if let Some(hir::Adt::Enum(e)) = ty.as_adt() {
|
||||||
ty.iterate_path_candidates(
|
cov_mark::hit!(enum_plain_qualified_use_tree);
|
||||||
ctx.db,
|
acc.add_enum_variants(ctx, path_ctx, e);
|
||||||
&ctx.scope,
|
|
||||||
&ctx.scope.visible_traits().0,
|
|
||||||
Some(ctx.module),
|
|
||||||
None,
|
|
||||||
|item| {
|
|
||||||
match item {
|
|
||||||
AssocItem::TypeAlias(ta) => {
|
|
||||||
// We might iterate candidates of a trait multiple times here, so deduplicate them.
|
|
||||||
if seen.insert(item) {
|
|
||||||
acc.add_type_alias(ctx, ta);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
AssocItem::Const(c) => {
|
|
||||||
if seen.insert(item) {
|
|
||||||
acc.add_const(ctx, c);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
None::<()>
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ctx.iterate_path_candidates(&ty, |item| match item {
|
||||||
|
AssocItem::TypeAlias(ta) => acc.add_type_alias(ctx, ta),
|
||||||
|
AssocItem::Const(c) => acc.add_const(ctx, c),
|
||||||
_ => {}
|
_ => {}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// qualifier can only be none here if we are in a TuplePat or RecordPat in which case special characters have to follow the path
|
|
||||||
Qualified::Absolute => acc.add_crate_roots(ctx, path_ctx),
|
Qualified::Absolute => acc.add_crate_roots(ctx, path_ctx),
|
||||||
Qualified::No => {
|
Qualified::No => {
|
||||||
|
// this will only be hit if there are brackets or braces, otherwise this will be parsed as an ident pattern
|
||||||
ctx.process_all_names(&mut |name, res| {
|
ctx.process_all_names(&mut |name, res| {
|
||||||
// FIXME: properly filter here
|
// FIXME: we should check what kind of pattern we are in and filter accordingly
|
||||||
if let ScopeDef::ModuleDef(_) = res {
|
let add_completion = match res {
|
||||||
|
ScopeDef::ModuleDef(hir::ModuleDef::Macro(mac)) => mac.is_fn_like(ctx.db),
|
||||||
|
ScopeDef::ModuleDef(hir::ModuleDef::Adt(_)) => true,
|
||||||
|
ScopeDef::ModuleDef(hir::ModuleDef::Variant(_)) => true,
|
||||||
|
ScopeDef::ModuleDef(hir::ModuleDef::Module(_)) => true,
|
||||||
|
ScopeDef::ImplSelfType(_) => true,
|
||||||
|
_ => false,
|
||||||
|
};
|
||||||
|
if add_completion {
|
||||||
acc.add_path_resolution(ctx, path_ctx, name, res);
|
acc.add_path_resolution(ctx, path_ctx, name, res);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -17,6 +17,7 @@ pub(crate) fn complete_record_pattern_fields(
|
||||||
complete_fields(acc, ctx, ctx.sema.record_pattern_missing_fields(record_pat));
|
complete_fields(acc, ctx, ctx.sema.record_pattern_missing_fields(record_pat));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn complete_record_expr_fields(
|
pub(crate) fn complete_record_expr_fields(
|
||||||
acc: &mut Completions,
|
acc: &mut Completions,
|
||||||
ctx: &CompletionContext,
|
ctx: &CompletionContext,
|
||||||
|
@ -41,7 +42,6 @@ pub(crate) fn complete_record_expr_fields(
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
let missing_fields = ctx.sema.record_literal_missing_fields(record_expr);
|
let missing_fields = ctx.sema.record_literal_missing_fields(record_expr);
|
||||||
|
|
||||||
add_default_update(acc, ctx, ty, &missing_fields);
|
add_default_update(acc, ctx, ty, &missing_fields);
|
||||||
if dot_prefix {
|
if dot_prefix {
|
||||||
let mut item =
|
let mut item =
|
||||||
|
@ -56,29 +56,7 @@ pub(crate) fn complete_record_expr_fields(
|
||||||
complete_fields(acc, ctx, missing_fields);
|
complete_fields(acc, ctx, missing_fields);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_default_update(
|
// FIXME: This should probably be part of complete_path_expr
|
||||||
acc: &mut Completions,
|
|
||||||
ctx: &CompletionContext,
|
|
||||||
ty: Option<hir::TypeInfo>,
|
|
||||||
missing_fields: &[(hir::Field, hir::Type)],
|
|
||||||
) {
|
|
||||||
let default_trait = ctx.famous_defs().core_default_Default();
|
|
||||||
let impl_default_trait = default_trait
|
|
||||||
.zip(ty.as_ref())
|
|
||||||
.map_or(false, |(default_trait, ty)| ty.original.impls_trait(ctx.db, default_trait, &[]));
|
|
||||||
if impl_default_trait && !missing_fields.is_empty() {
|
|
||||||
let completion_text = "..Default::default()";
|
|
||||||
let mut item = CompletionItem::new(SymbolKind::Field, ctx.source_range(), completion_text);
|
|
||||||
let completion_text =
|
|
||||||
completion_text.strip_prefix(ctx.token.text()).unwrap_or(completion_text);
|
|
||||||
item.insert_text(completion_text).set_relevance(CompletionRelevance {
|
|
||||||
postfix_match: Some(CompletionRelevancePostfixMatch::Exact),
|
|
||||||
..Default::default()
|
|
||||||
});
|
|
||||||
item.add_to(acc);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn complete_record_expr_func_update(
|
pub(crate) fn complete_record_expr_func_update(
|
||||||
acc: &mut Completions,
|
acc: &mut Completions,
|
||||||
ctx: &CompletionContext,
|
ctx: &CompletionContext,
|
||||||
|
@ -101,6 +79,30 @@ pub(crate) fn complete_record_expr_func_update(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn add_default_update(
|
||||||
|
acc: &mut Completions,
|
||||||
|
ctx: &CompletionContext,
|
||||||
|
ty: Option<hir::TypeInfo>,
|
||||||
|
missing_fields: &[(hir::Field, hir::Type)],
|
||||||
|
) {
|
||||||
|
let default_trait = ctx.famous_defs().core_default_Default();
|
||||||
|
let impl_default_trait = default_trait
|
||||||
|
.zip(ty.as_ref())
|
||||||
|
.map_or(false, |(default_trait, ty)| ty.original.impls_trait(ctx.db, default_trait, &[]));
|
||||||
|
if impl_default_trait && !missing_fields.is_empty() {
|
||||||
|
// FIXME: This should make use of scope_def like completions so we get all the other goodies
|
||||||
|
let completion_text = "..Default::default()";
|
||||||
|
let mut item = CompletionItem::new(SymbolKind::Field, ctx.source_range(), completion_text);
|
||||||
|
let completion_text =
|
||||||
|
completion_text.strip_prefix(ctx.token.text()).unwrap_or(completion_text);
|
||||||
|
item.insert_text(completion_text).set_relevance(CompletionRelevance {
|
||||||
|
postfix_match: Some(CompletionRelevancePostfixMatch::Exact),
|
||||||
|
..Default::default()
|
||||||
|
});
|
||||||
|
item.add_to(acc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn complete_fields(
|
fn complete_fields(
|
||||||
acc: &mut Completions,
|
acc: &mut Completions,
|
||||||
ctx: &CompletionContext,
|
ctx: &CompletionContext,
|
||||||
|
|
|
@ -9,12 +9,6 @@ use crate::{
|
||||||
CompletionContext, CompletionItem, CompletionItemKind, Completions, SnippetScope,
|
CompletionContext, CompletionItem, CompletionItemKind, Completions, SnippetScope,
|
||||||
};
|
};
|
||||||
|
|
||||||
fn snippet(ctx: &CompletionContext, cap: SnippetCap, label: &str, snippet: &str) -> Builder {
|
|
||||||
let mut item = CompletionItem::new(CompletionItemKind::Snippet, ctx.source_range(), label);
|
|
||||||
item.insert_snippet(cap, snippet);
|
|
||||||
item
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn complete_expr_snippet(
|
pub(crate) fn complete_expr_snippet(
|
||||||
acc: &mut Completions,
|
acc: &mut Completions,
|
||||||
ctx: &CompletionContext,
|
ctx: &CompletionContext,
|
||||||
|
@ -124,6 +118,12 @@ macro_rules! $1 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn snippet(ctx: &CompletionContext, cap: SnippetCap, label: &str, snippet: &str) -> Builder {
|
||||||
|
let mut item = CompletionItem::new(CompletionItemKind::Snippet, ctx.source_range(), label);
|
||||||
|
item.insert_snippet(cap, snippet);
|
||||||
|
item
|
||||||
|
}
|
||||||
|
|
||||||
fn add_custom_completions(
|
fn add_custom_completions(
|
||||||
acc: &mut Completions,
|
acc: &mut Completions,
|
||||||
ctx: &CompletionContext,
|
ctx: &CompletionContext,
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
//! Completion of names from the current scope in type position.
|
//! Completion of names from the current scope in type position.
|
||||||
|
|
||||||
use hir::{HirDisplay, ScopeDef};
|
use hir::{HirDisplay, ScopeDef};
|
||||||
use ide_db::FxHashSet;
|
|
||||||
use syntax::{ast, AstNode};
|
use syntax::{ast, AstNode};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
@ -52,9 +51,8 @@ pub(crate) fn complete_type_path(
|
||||||
match qualified {
|
match qualified {
|
||||||
Qualified::Infer => ctx
|
Qualified::Infer => ctx
|
||||||
.traits_in_scope()
|
.traits_in_scope()
|
||||||
.0
|
.iter()
|
||||||
.into_iter()
|
.flat_map(|&it| hir::Trait::from(it).items(ctx.sema.db))
|
||||||
.flat_map(|it| hir::Trait::from(it).items(ctx.sema.db))
|
|
||||||
.for_each(|item| add_assoc_item(acc, item)),
|
.for_each(|item| add_assoc_item(acc, item)),
|
||||||
Qualified::With { resolution: None, .. } => {}
|
Qualified::With { resolution: None, .. } => {}
|
||||||
Qualified::With { resolution: Some(resolution), .. } => {
|
Qualified::With { resolution: Some(resolution), .. } => {
|
||||||
|
@ -88,17 +86,9 @@ pub(crate) fn complete_type_path(
|
||||||
// XXX: For parity with Rust bug #22519, this does not complete Ty::AssocType.
|
// XXX: For parity with Rust bug #22519, this does not complete Ty::AssocType.
|
||||||
// (where AssocType is defined on a trait, not an inherent impl)
|
// (where AssocType is defined on a trait, not an inherent impl)
|
||||||
|
|
||||||
ty.iterate_path_candidates(
|
ctx.iterate_path_candidates(&ty, |item| {
|
||||||
ctx.db,
|
|
||||||
&ctx.scope,
|
|
||||||
&ctx.traits_in_scope().0,
|
|
||||||
Some(ctx.module),
|
|
||||||
None,
|
|
||||||
|item| {
|
|
||||||
add_assoc_item(acc, item);
|
add_assoc_item(acc, item);
|
||||||
None::<()>
|
});
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
// Iterate assoc types separately
|
// Iterate assoc types separately
|
||||||
ty.iterate_assoc_items(ctx.db, ctx.krate, |item| {
|
ty.iterate_assoc_items(ctx.db, ctx.krate, |item| {
|
||||||
|
@ -121,22 +111,9 @@ pub(crate) fn complete_type_path(
|
||||||
_ => return,
|
_ => return,
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut seen = FxHashSet::default();
|
ctx.iterate_path_candidates(&ty, |item| {
|
||||||
ty.iterate_path_candidates(
|
|
||||||
ctx.db,
|
|
||||||
&ctx.scope,
|
|
||||||
&ctx.traits_in_scope().0,
|
|
||||||
Some(ctx.module),
|
|
||||||
None,
|
|
||||||
|item| {
|
|
||||||
// We might iterate candidates of a trait multiple times here, so deduplicate
|
|
||||||
// them.
|
|
||||||
if seen.insert(item) {
|
|
||||||
add_assoc_item(acc, item);
|
add_assoc_item(acc, item);
|
||||||
}
|
});
|
||||||
None::<()>
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
|
|
|
@ -371,7 +371,9 @@ impl<'a> CompletionContext<'a> {
|
||||||
where
|
where
|
||||||
I: hir::HasVisibility + hir::HasAttrs + hir::HasCrate + Copy,
|
I: hir::HasVisibility + hir::HasAttrs + hir::HasCrate + Copy,
|
||||||
{
|
{
|
||||||
self.is_visible_impl(&item.visibility(self.db), &item.attrs(self.db), item.krate(self.db))
|
let vis = item.visibility(self.db);
|
||||||
|
let attrs = item.attrs(self.db);
|
||||||
|
self.is_visible_impl(&vis, &attrs, item.krate(self.db))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn is_scope_def_hidden(&self, scope_def: ScopeDef) -> bool {
|
pub(crate) fn is_scope_def_hidden(&self, scope_def: ScopeDef) -> bool {
|
||||||
|
@ -391,6 +393,7 @@ impl<'a> CompletionContext<'a> {
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Whether the given trait is an operator trait or not.
|
/// Whether the given trait is an operator trait or not.
|
||||||
pub(crate) fn is_ops_trait(&self, trait_: hir::Trait) -> bool {
|
pub(crate) fn is_ops_trait(&self, trait_: hir::Trait) -> bool {
|
||||||
match trait_.attrs(self.db).lang() {
|
match trait_.attrs(self.db).lang() {
|
||||||
|
@ -408,6 +411,29 @@ impl<'a> CompletionContext<'a> {
|
||||||
traits_in_scope
|
traits_in_scope
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn iterate_path_candidates(
|
||||||
|
&self,
|
||||||
|
ty: &hir::Type,
|
||||||
|
mut cb: impl FnMut(hir::AssocItem),
|
||||||
|
) {
|
||||||
|
let mut seen = FxHashSet::default();
|
||||||
|
ty.iterate_path_candidates(
|
||||||
|
self.db,
|
||||||
|
&self.scope,
|
||||||
|
&self.traits_in_scope(),
|
||||||
|
Some(self.module),
|
||||||
|
None,
|
||||||
|
|item| {
|
||||||
|
// We might iterate candidates of a trait multiple times here, so deduplicate
|
||||||
|
// them.
|
||||||
|
if seen.insert(item) {
|
||||||
|
cb(item)
|
||||||
|
}
|
||||||
|
None::<()>
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/// A version of [`SemanticsScope::process_all_names`] that filters out `#[doc(hidden)]` items.
|
/// A version of [`SemanticsScope::process_all_names`] that filters out `#[doc(hidden)]` items.
|
||||||
pub(crate) fn process_all_names(&self, f: &mut dyn FnMut(Name, ScopeDef)) {
|
pub(crate) fn process_all_names(&self, f: &mut dyn FnMut(Name, ScopeDef)) {
|
||||||
let _p = profile::span("CompletionContext::process_all_names");
|
let _p = profile::span("CompletionContext::process_all_names");
|
||||||
|
|
|
@ -148,7 +148,7 @@ pub fn completions(
|
||||||
config: &CompletionConfig,
|
config: &CompletionConfig,
|
||||||
position: FilePosition,
|
position: FilePosition,
|
||||||
trigger_character: Option<char>,
|
trigger_character: Option<char>,
|
||||||
) -> Option<Completions> {
|
) -> Option<Vec<CompletionItem>> {
|
||||||
let (ctx, analysis) = &CompletionContext::new(db, position, config)?;
|
let (ctx, analysis) = &CompletionContext::new(db, position, config)?;
|
||||||
let mut completions = Completions::default();
|
let mut completions = Completions::default();
|
||||||
|
|
||||||
|
@ -163,7 +163,7 @@ pub fn completions(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// prevent `(` from triggering unwanted completion noise
|
// prevent `(` from triggering unwanted completion noise
|
||||||
return Some(completions);
|
return Some(completions.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -197,7 +197,7 @@ pub fn completions(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Some(completions)
|
Some(completions.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Resolves additional completion data at the position given.
|
/// Resolves additional completion data at the position given.
|
||||||
|
|
|
@ -399,7 +399,6 @@ fn foo() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn completes_no_delims_if_existing() {
|
fn completes_no_delims_if_existing() {
|
||||||
// FIXME: We should not complete functions here
|
|
||||||
check_empty(
|
check_empty(
|
||||||
r#"
|
r#"
|
||||||
struct Bar(u32);
|
struct Bar(u32);
|
||||||
|
@ -410,9 +409,7 @@ fn foo() {
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
fn foo fn()
|
|
||||||
st Bar
|
st Bar
|
||||||
bt u32
|
|
||||||
kw crate::
|
kw crate::
|
||||||
kw self::
|
kw self::
|
||||||
kw super::
|
kw super::
|
||||||
|
@ -428,9 +425,7 @@ fn foo() {
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
fn foo fn()
|
|
||||||
st Foo
|
st Foo
|
||||||
bt u32
|
|
||||||
kw crate::
|
kw crate::
|
||||||
kw self::
|
kw self::
|
||||||
kw super::
|
kw super::
|
||||||
|
|
Loading…
Reference in a new issue