mirror of
https://github.com/rust-lang/rust-analyzer
synced 2025-01-16 07:03:57 +00:00
internal: Lift out IdentContext from CompletionContext
This commit is contained in:
parent
bcf10cde13
commit
6e9c963348
21 changed files with 456 additions and 351 deletions
|
@ -23,13 +23,13 @@ pub(crate) mod vis;
|
||||||
use std::iter;
|
use std::iter;
|
||||||
|
|
||||||
use hir::{known, ScopeDef};
|
use hir::{known, ScopeDef};
|
||||||
use ide_db::SymbolKind;
|
use ide_db::{imports::import_assets::LocatedImport, SymbolKind};
|
||||||
use syntax::ast;
|
use syntax::ast;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
context::{
|
context::{
|
||||||
ItemListKind, NameContext, NameKind, NameRefContext, NameRefKind, PathKind, PatternContext,
|
DotAccess, ItemListKind, NameContext, NameKind, NameRefContext, NameRefKind,
|
||||||
TypeLocation, Visible,
|
PathCompletionCtx, PathKind, PatternContext, TypeLocation, Visible,
|
||||||
},
|
},
|
||||||
item::Builder,
|
item::Builder,
|
||||||
render::{
|
render::{
|
||||||
|
@ -38,7 +38,7 @@ use crate::{
|
||||||
literal::{render_struct_literal, render_variant_lit},
|
literal::{render_struct_literal, render_variant_lit},
|
||||||
macro_::render_macro,
|
macro_::render_macro,
|
||||||
pattern::{render_struct_pat, render_variant_pat},
|
pattern::{render_struct_pat, render_variant_pat},
|
||||||
render_field, render_resolution, render_resolution_simple, render_tuple_field,
|
render_field, render_path_resolution, render_resolution_simple, render_tuple_field,
|
||||||
type_alias::{render_type_alias, render_type_alias_with_eq},
|
type_alias::{render_type_alias, render_type_alias_with_eq},
|
||||||
union_literal::render_union_literal,
|
union_literal::render_union_literal,
|
||||||
RenderContext,
|
RenderContext,
|
||||||
|
@ -137,15 +137,16 @@ impl Completions {
|
||||||
pub(crate) fn add_crate_roots(&mut self, ctx: &CompletionContext) {
|
pub(crate) fn add_crate_roots(&mut self, ctx: &CompletionContext) {
|
||||||
ctx.process_all_names(&mut |name, res| match res {
|
ctx.process_all_names(&mut |name, res| match res {
|
||||||
ScopeDef::ModuleDef(hir::ModuleDef::Module(m)) if m.is_crate_root(ctx.db) => {
|
ScopeDef::ModuleDef(hir::ModuleDef::Module(m)) if m.is_crate_root(ctx.db) => {
|
||||||
self.add_resolution(ctx, name, res);
|
self.add_module(ctx, m, name);
|
||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn add_resolution(
|
pub(crate) fn add_path_resolution(
|
||||||
&mut self,
|
&mut self,
|
||||||
ctx: &CompletionContext,
|
ctx: &CompletionContext,
|
||||||
|
path_ctx: &PathCompletionCtx,
|
||||||
local_name: hir::Name,
|
local_name: hir::Name,
|
||||||
resolution: hir::ScopeDef,
|
resolution: hir::ScopeDef,
|
||||||
) {
|
) {
|
||||||
|
@ -153,7 +154,10 @@ impl Completions {
|
||||||
cov_mark::hit!(qualified_path_doc_hidden);
|
cov_mark::hit!(qualified_path_doc_hidden);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
self.add(render_resolution(RenderContext::new(ctx), local_name, resolution).build());
|
self.add(
|
||||||
|
render_path_resolution(RenderContext::new(ctx), path_ctx, local_name, resolution)
|
||||||
|
.build(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn add_resolution_simple(
|
pub(crate) fn add_resolution_simple(
|
||||||
|
@ -174,12 +178,13 @@ impl Completions {
|
||||||
module: hir::Module,
|
module: hir::Module,
|
||||||
local_name: hir::Name,
|
local_name: hir::Name,
|
||||||
) {
|
) {
|
||||||
self.add_resolution(ctx, local_name, hir::ScopeDef::ModuleDef(module.into()));
|
self.add_resolution_simple(ctx, local_name, hir::ScopeDef::ModuleDef(module.into()));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn add_macro(
|
pub(crate) fn add_macro(
|
||||||
&mut self,
|
&mut self,
|
||||||
ctx: &CompletionContext,
|
ctx: &CompletionContext,
|
||||||
|
path_ctx: &PathCompletionCtx,
|
||||||
mac: hir::Macro,
|
mac: hir::Macro,
|
||||||
local_name: hir::Name,
|
local_name: hir::Name,
|
||||||
) {
|
) {
|
||||||
|
@ -191,6 +196,7 @@ impl Completions {
|
||||||
self.add(
|
self.add(
|
||||||
render_macro(
|
render_macro(
|
||||||
RenderContext::new(ctx).private_editable(is_private_editable),
|
RenderContext::new(ctx).private_editable(is_private_editable),
|
||||||
|
path_ctx,
|
||||||
local_name,
|
local_name,
|
||||||
mac,
|
mac,
|
||||||
)
|
)
|
||||||
|
@ -201,6 +207,7 @@ impl Completions {
|
||||||
pub(crate) fn add_function(
|
pub(crate) fn add_function(
|
||||||
&mut self,
|
&mut self,
|
||||||
ctx: &CompletionContext,
|
ctx: &CompletionContext,
|
||||||
|
path_ctx: &PathCompletionCtx,
|
||||||
func: hir::Function,
|
func: hir::Function,
|
||||||
local_name: Option<hir::Name>,
|
local_name: Option<hir::Name>,
|
||||||
) {
|
) {
|
||||||
|
@ -212,6 +219,7 @@ impl Completions {
|
||||||
self.add(
|
self.add(
|
||||||
render_fn(
|
render_fn(
|
||||||
RenderContext::new(ctx).private_editable(is_private_editable),
|
RenderContext::new(ctx).private_editable(is_private_editable),
|
||||||
|
path_ctx,
|
||||||
local_name,
|
local_name,
|
||||||
func,
|
func,
|
||||||
)
|
)
|
||||||
|
@ -222,6 +230,7 @@ impl Completions {
|
||||||
pub(crate) fn add_method(
|
pub(crate) fn add_method(
|
||||||
&mut self,
|
&mut self,
|
||||||
ctx: &CompletionContext,
|
ctx: &CompletionContext,
|
||||||
|
dot_access: &DotAccess,
|
||||||
func: hir::Function,
|
func: hir::Function,
|
||||||
receiver: Option<hir::Name>,
|
receiver: Option<hir::Name>,
|
||||||
local_name: Option<hir::Name>,
|
local_name: Option<hir::Name>,
|
||||||
|
@ -234,6 +243,7 @@ impl Completions {
|
||||||
self.add(
|
self.add(
|
||||||
render_method(
|
render_method(
|
||||||
RenderContext::new(ctx).private_editable(is_private_editable),
|
RenderContext::new(ctx).private_editable(is_private_editable),
|
||||||
|
dot_access,
|
||||||
receiver,
|
receiver,
|
||||||
local_name,
|
local_name,
|
||||||
func,
|
func,
|
||||||
|
@ -242,6 +252,32 @@ impl Completions {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn add_method_with_import(
|
||||||
|
&mut self,
|
||||||
|
ctx: &CompletionContext,
|
||||||
|
dot_access: &DotAccess,
|
||||||
|
func: hir::Function,
|
||||||
|
import: LocatedImport,
|
||||||
|
) {
|
||||||
|
let is_private_editable = match ctx.is_visible(&func) {
|
||||||
|
Visible::Yes => false,
|
||||||
|
Visible::Editable => true,
|
||||||
|
Visible::No => return,
|
||||||
|
};
|
||||||
|
self.add(
|
||||||
|
render_method(
|
||||||
|
RenderContext::new(ctx)
|
||||||
|
.private_editable(is_private_editable)
|
||||||
|
.import_to_add(Some(import)),
|
||||||
|
dot_access,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
func,
|
||||||
|
)
|
||||||
|
.build(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn add_const(&mut self, ctx: &CompletionContext, konst: hir::Const) {
|
pub(crate) fn add_const(&mut self, ctx: &CompletionContext, konst: hir::Const) {
|
||||||
let is_private_editable = match ctx.is_visible(&konst) {
|
let is_private_editable = match ctx.is_visible(&konst) {
|
||||||
Visible::Yes => false,
|
Visible::Yes => false,
|
||||||
|
@ -277,11 +313,12 @@ impl Completions {
|
||||||
pub(crate) fn add_qualified_enum_variant(
|
pub(crate) fn add_qualified_enum_variant(
|
||||||
&mut self,
|
&mut self,
|
||||||
ctx: &CompletionContext,
|
ctx: &CompletionContext,
|
||||||
|
path_ctx: &PathCompletionCtx,
|
||||||
variant: hir::Variant,
|
variant: hir::Variant,
|
||||||
path: hir::ModPath,
|
path: hir::ModPath,
|
||||||
) {
|
) {
|
||||||
if let Some(builder) =
|
if let Some(builder) =
|
||||||
render_variant_lit(RenderContext::new(ctx), None, variant, Some(path))
|
render_variant_lit(RenderContext::new(ctx), path_ctx, None, variant, Some(path))
|
||||||
{
|
{
|
||||||
self.add(builder.build());
|
self.add(builder.build());
|
||||||
}
|
}
|
||||||
|
@ -290,11 +327,12 @@ impl Completions {
|
||||||
pub(crate) fn add_enum_variant(
|
pub(crate) fn add_enum_variant(
|
||||||
&mut self,
|
&mut self,
|
||||||
ctx: &CompletionContext,
|
ctx: &CompletionContext,
|
||||||
|
path_ctx: &PathCompletionCtx,
|
||||||
variant: hir::Variant,
|
variant: hir::Variant,
|
||||||
local_name: Option<hir::Name>,
|
local_name: Option<hir::Name>,
|
||||||
) {
|
) {
|
||||||
if let Some(builder) =
|
if let Some(builder) =
|
||||||
render_variant_lit(RenderContext::new(ctx), local_name, variant, None)
|
render_variant_lit(RenderContext::new(ctx), path_ctx, local_name, variant, None)
|
||||||
{
|
{
|
||||||
self.add(builder.build());
|
self.add(builder.build());
|
||||||
}
|
}
|
||||||
|
@ -324,12 +362,13 @@ impl Completions {
|
||||||
pub(crate) fn add_struct_literal(
|
pub(crate) fn add_struct_literal(
|
||||||
&mut self,
|
&mut self,
|
||||||
ctx: &CompletionContext,
|
ctx: &CompletionContext,
|
||||||
|
path_ctx: &PathCompletionCtx,
|
||||||
strukt: hir::Struct,
|
strukt: hir::Struct,
|
||||||
path: Option<hir::ModPath>,
|
path: Option<hir::ModPath>,
|
||||||
local_name: Option<hir::Name>,
|
local_name: Option<hir::Name>,
|
||||||
) {
|
) {
|
||||||
if let Some(builder) =
|
if let Some(builder) =
|
||||||
render_struct_literal(RenderContext::new(ctx), strukt, path, local_name)
|
render_struct_literal(RenderContext::new(ctx), path_ctx, strukt, path, local_name)
|
||||||
{
|
{
|
||||||
self.add(builder.build());
|
self.add(builder.build());
|
||||||
}
|
}
|
||||||
|
@ -369,11 +408,13 @@ impl Completions {
|
||||||
pub(crate) fn add_variant_pat(
|
pub(crate) fn add_variant_pat(
|
||||||
&mut self,
|
&mut self,
|
||||||
ctx: &CompletionContext,
|
ctx: &CompletionContext,
|
||||||
|
pattern_ctx: &PatternContext,
|
||||||
variant: hir::Variant,
|
variant: hir::Variant,
|
||||||
local_name: Option<hir::Name>,
|
local_name: Option<hir::Name>,
|
||||||
) {
|
) {
|
||||||
self.add_opt(render_variant_pat(
|
self.add_opt(render_variant_pat(
|
||||||
RenderContext::new(ctx),
|
RenderContext::new(ctx),
|
||||||
|
pattern_ctx,
|
||||||
variant,
|
variant,
|
||||||
local_name.clone(),
|
local_name.clone(),
|
||||||
None,
|
None,
|
||||||
|
@ -383,20 +424,22 @@ impl Completions {
|
||||||
pub(crate) fn add_qualified_variant_pat(
|
pub(crate) fn add_qualified_variant_pat(
|
||||||
&mut self,
|
&mut self,
|
||||||
ctx: &CompletionContext,
|
ctx: &CompletionContext,
|
||||||
|
pattern_ctx: &PatternContext,
|
||||||
variant: hir::Variant,
|
variant: hir::Variant,
|
||||||
path: hir::ModPath,
|
path: hir::ModPath,
|
||||||
) {
|
) {
|
||||||
let path = Some(&path);
|
let path = Some(&path);
|
||||||
self.add_opt(render_variant_pat(RenderContext::new(ctx), variant, None, path));
|
self.add_opt(render_variant_pat(RenderContext::new(ctx), pattern_ctx, variant, None, path));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn add_struct_pat(
|
pub(crate) fn add_struct_pat(
|
||||||
&mut self,
|
&mut self,
|
||||||
ctx: &CompletionContext,
|
ctx: &CompletionContext,
|
||||||
|
pattern_ctx: &PatternContext,
|
||||||
strukt: hir::Struct,
|
strukt: hir::Struct,
|
||||||
local_name: Option<hir::Name>,
|
local_name: Option<hir::Name>,
|
||||||
) {
|
) {
|
||||||
self.add_opt(render_struct_pat(RenderContext::new(ctx), strukt, local_name));
|
self.add_opt(render_struct_pat(RenderContext::new(ctx), pattern_ctx, strukt, local_name));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -74,7 +74,7 @@ pub(crate) fn complete_known_attribute_input(
|
||||||
pub(crate) fn complete_attribute_path(
|
pub(crate) fn complete_attribute_path(
|
||||||
acc: &mut Completions,
|
acc: &mut Completions,
|
||||||
ctx: &CompletionContext,
|
ctx: &CompletionContext,
|
||||||
PathCompletionCtx { qualified, .. }: &PathCompletionCtx,
|
path_ctx @ PathCompletionCtx { qualified, .. }: &PathCompletionCtx,
|
||||||
&AttrCtx { kind, annotated_item_kind }: &AttrCtx,
|
&AttrCtx { kind, annotated_item_kind }: &AttrCtx,
|
||||||
) {
|
) {
|
||||||
let is_inner = kind == AttrKind::Inner;
|
let is_inner = kind == AttrKind::Inner;
|
||||||
|
@ -92,7 +92,7 @@ pub(crate) fn complete_attribute_path(
|
||||||
for (name, def) in module.scope(ctx.db, Some(ctx.module)) {
|
for (name, def) in module.scope(ctx.db, Some(ctx.module)) {
|
||||||
match def {
|
match def {
|
||||||
hir::ScopeDef::ModuleDef(hir::ModuleDef::Macro(m)) if m.is_attr(ctx.db) => {
|
hir::ScopeDef::ModuleDef(hir::ModuleDef::Macro(m)) if m.is_attr(ctx.db) => {
|
||||||
acc.add_macro(ctx, m, name)
|
acc.add_macro(ctx, path_ctx, m, name)
|
||||||
}
|
}
|
||||||
hir::ScopeDef::ModuleDef(hir::ModuleDef::Module(m)) => {
|
hir::ScopeDef::ModuleDef(hir::ModuleDef::Module(m)) => {
|
||||||
acc.add_module(ctx, m, name)
|
acc.add_module(ctx, m, name)
|
||||||
|
@ -108,7 +108,7 @@ pub(crate) fn complete_attribute_path(
|
||||||
Qualified::No => {
|
Qualified::No => {
|
||||||
ctx.process_all_names(&mut |name, def| match def {
|
ctx.process_all_names(&mut |name, def| match def {
|
||||||
hir::ScopeDef::ModuleDef(hir::ModuleDef::Macro(m)) if m.is_attr(ctx.db) => {
|
hir::ScopeDef::ModuleDef(hir::ModuleDef::Macro(m)) if m.is_attr(ctx.db) => {
|
||||||
acc.add_macro(ctx, m, name)
|
acc.add_macro(ctx, path_ctx, m, name)
|
||||||
}
|
}
|
||||||
hir::ScopeDef::ModuleDef(hir::ModuleDef::Module(m)) => acc.add_module(ctx, m, name),
|
hir::ScopeDef::ModuleDef(hir::ModuleDef::Module(m)) => acc.add_module(ctx, m, name),
|
||||||
_ => (),
|
_ => (),
|
||||||
|
|
|
@ -13,7 +13,7 @@ use crate::{
|
||||||
pub(crate) fn complete_derive_path(
|
pub(crate) fn complete_derive_path(
|
||||||
acc: &mut Completions,
|
acc: &mut Completions,
|
||||||
ctx: &CompletionContext,
|
ctx: &CompletionContext,
|
||||||
PathCompletionCtx { qualified, .. }: &PathCompletionCtx,
|
path_ctx @ PathCompletionCtx { qualified, .. }: &PathCompletionCtx,
|
||||||
existing_derives: &ExistingDerives,
|
existing_derives: &ExistingDerives,
|
||||||
) {
|
) {
|
||||||
let core = ctx.famous_defs().core();
|
let core = ctx.famous_defs().core();
|
||||||
|
@ -33,7 +33,7 @@ pub(crate) fn complete_derive_path(
|
||||||
ScopeDef::ModuleDef(hir::ModuleDef::Macro(mac))
|
ScopeDef::ModuleDef(hir::ModuleDef::Macro(mac))
|
||||||
if !existing_derives.contains(&mac) && mac.is_derive(ctx.db) =>
|
if !existing_derives.contains(&mac) && mac.is_derive(ctx.db) =>
|
||||||
{
|
{
|
||||||
acc.add_macro(ctx, mac, name)
|
acc.add_macro(ctx, path_ctx, mac, name)
|
||||||
}
|
}
|
||||||
ScopeDef::ModuleDef(hir::ModuleDef::Module(m)) => acc.add_module(ctx, m, name),
|
ScopeDef::ModuleDef(hir::ModuleDef::Module(m)) => acc.add_module(ctx, m, name),
|
||||||
_ => (),
|
_ => (),
|
||||||
|
@ -59,7 +59,7 @@ pub(crate) fn complete_derive_path(
|
||||||
match (core, mac.module(ctx.db).krate()) {
|
match (core, mac.module(ctx.db).krate()) {
|
||||||
// show derive dependencies for `core`/`std` derives
|
// show derive dependencies for `core`/`std` derives
|
||||||
(Some(core), mac_krate) if core == mac_krate => {}
|
(Some(core), mac_krate) if core == mac_krate => {}
|
||||||
_ => return acc.add_macro(ctx, mac, name),
|
_ => return acc.add_macro(ctx, path_ctx, mac, name),
|
||||||
};
|
};
|
||||||
|
|
||||||
let name_ = name.to_smol_str();
|
let name_ = name.to_smol_str();
|
||||||
|
@ -92,7 +92,7 @@ pub(crate) fn complete_derive_path(
|
||||||
item.lookup_by(lookup);
|
item.lookup_by(lookup);
|
||||||
item.add_to(acc);
|
item.add_to(acc);
|
||||||
}
|
}
|
||||||
None => acc.add_macro(ctx, mac, name),
|
None => acc.add_macro(ctx, path_ctx, mac, name),
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
acc.add_nameref_keywords_with_colon(ctx);
|
acc.add_nameref_keywords_with_colon(ctx);
|
||||||
|
|
|
@ -33,7 +33,7 @@ pub(crate) fn complete_dot(acc: &mut Completions, ctx: &CompletionContext, dot_a
|
||||||
|acc, field, ty| acc.add_tuple_field(ctx, None, field, &ty),
|
|acc, field, ty| acc.add_tuple_field(ctx, None, field, &ty),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
complete_methods(ctx, &receiver_ty, |func| acc.add_method(ctx, func, None, None));
|
complete_methods(ctx, &receiver_ty, |func| acc.add_method(ctx, dot_access, func, None, None));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn complete_undotted_self(
|
pub(crate) fn complete_undotted_self(
|
||||||
|
@ -68,7 +68,17 @@ pub(crate) fn complete_undotted_self(
|
||||||
|acc, field, ty| acc.add_tuple_field(ctx, Some(hir::known::SELF_PARAM), field, &ty),
|
|acc, field, ty| acc.add_tuple_field(ctx, Some(hir::known::SELF_PARAM), field, &ty),
|
||||||
);
|
);
|
||||||
complete_methods(ctx, &ty, |func| {
|
complete_methods(ctx, &ty, |func| {
|
||||||
acc.add_method(ctx, func, Some(hir::known::SELF_PARAM), None)
|
acc.add_method(
|
||||||
|
ctx,
|
||||||
|
&DotAccess {
|
||||||
|
receiver: None,
|
||||||
|
receiver_ty: None,
|
||||||
|
kind: DotAccessKind::Method { has_parens: false },
|
||||||
|
},
|
||||||
|
func,
|
||||||
|
Some(hir::known::SELF_PARAM),
|
||||||
|
None,
|
||||||
|
)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@ use crate::{
|
||||||
pub(crate) fn complete_expr_path(
|
pub(crate) fn complete_expr_path(
|
||||||
acc: &mut Completions,
|
acc: &mut Completions,
|
||||||
ctx: &CompletionContext,
|
ctx: &CompletionContext,
|
||||||
PathCompletionCtx { qualified, .. }: &PathCompletionCtx,
|
path_ctx @ PathCompletionCtx { qualified, .. }: &PathCompletionCtx,
|
||||||
&ExprCtx {
|
&ExprCtx {
|
||||||
in_block_expr,
|
in_block_expr,
|
||||||
in_loop_body,
|
in_loop_body,
|
||||||
|
@ -34,11 +34,12 @@ pub(crate) fn complete_expr_path(
|
||||||
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| {
|
||||||
use hir::{GenericParam::*, ModuleDef::*};
|
|
||||||
match def {
|
match def {
|
||||||
ScopeDef::GenericParam(LifetimeParam(_)) | ScopeDef::Label(_) => false,
|
ScopeDef::GenericParam(hir::GenericParam::LifetimeParam(_)) | ScopeDef::Label(_) => {
|
||||||
|
false
|
||||||
|
}
|
||||||
// Don't suggest attribute macros and derives.
|
// Don't suggest attribute macros and derives.
|
||||||
ScopeDef::ModuleDef(Macro(mac)) => mac.is_fn_like(ctx.db),
|
ScopeDef::ModuleDef(hir::ModuleDef::Macro(mac)) => mac.is_fn_like(ctx.db),
|
||||||
_ => true,
|
_ => true,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -49,7 +50,7 @@ pub(crate) fn complete_expr_path(
|
||||||
.0
|
.0
|
||||||
.into_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, ctx, 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`.
|
||||||
|
@ -62,7 +63,7 @@ pub(crate) fn complete_expr_path(
|
||||||
let module_scope = module.scope(ctx.db, Some(ctx.module));
|
let module_scope = module.scope(ctx.db, Some(ctx.module));
|
||||||
for (name, def) in module_scope {
|
for (name, def) in module_scope {
|
||||||
if scope_def_applicable(def) {
|
if scope_def_applicable(def) {
|
||||||
acc.add_resolution(ctx, name, def);
|
acc.add_path_resolution(ctx, path_ctx, name, def);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -73,7 +74,7 @@ pub(crate) fn complete_expr_path(
|
||||||
| hir::ModuleDef::BuiltinType(_)),
|
| hir::ModuleDef::BuiltinType(_)),
|
||||||
) => {
|
) => {
|
||||||
if let &hir::ModuleDef::Adt(hir::Adt::Enum(e)) = def {
|
if let &hir::ModuleDef::Adt(hir::Adt::Enum(e)) = def {
|
||||||
add_enum_variants(acc, ctx, e);
|
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),
|
||||||
|
@ -81,7 +82,7 @@ pub(crate) fn complete_expr_path(
|
||||||
let ty = a.ty(ctx.db);
|
let ty = a.ty(ctx.db);
|
||||||
if let Some(hir::Adt::Enum(e)) = ty.as_adt() {
|
if let Some(hir::Adt::Enum(e)) = ty.as_adt() {
|
||||||
cov_mark::hit!(completes_variant_through_alias);
|
cov_mark::hit!(completes_variant_through_alias);
|
||||||
add_enum_variants(acc, ctx, e);
|
add_enum_variants(acc, ctx, path_ctx, e);
|
||||||
}
|
}
|
||||||
ty
|
ty
|
||||||
}
|
}
|
||||||
|
@ -102,7 +103,7 @@ pub(crate) fn complete_expr_path(
|
||||||
Some(ctx.module),
|
Some(ctx.module),
|
||||||
None,
|
None,
|
||||||
|item| {
|
|item| {
|
||||||
add_assoc_item(acc, ctx, item);
|
add_assoc_item(acc, ctx, path_ctx, item);
|
||||||
None::<()>
|
None::<()>
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
@ -118,7 +119,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, item);
|
add_assoc_item(acc, ctx, path_ctx, item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
hir::PathResolution::TypeParam(_) | hir::PathResolution::SelfType(_) => {
|
hir::PathResolution::TypeParam(_) | hir::PathResolution::SelfType(_) => {
|
||||||
|
@ -129,7 +130,7 @@ 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, e);
|
add_enum_variants(acc, ctx, path_ctx, e);
|
||||||
}
|
}
|
||||||
let mut seen = FxHashSet::default();
|
let mut seen = FxHashSet::default();
|
||||||
ty.iterate_path_candidates(
|
ty.iterate_path_candidates(
|
||||||
|
@ -142,7 +143,7 @@ pub(crate) fn complete_expr_path(
|
||||||
// We might iterate candidates of a trait multiple times here, so deduplicate
|
// We might iterate candidates of a trait multiple times here, so deduplicate
|
||||||
// them.
|
// them.
|
||||||
if seen.insert(item) {
|
if seen.insert(item) {
|
||||||
add_assoc_item(acc, ctx, item);
|
add_assoc_item(acc, ctx, path_ctx, item);
|
||||||
}
|
}
|
||||||
None::<()>
|
None::<()>
|
||||||
},
|
},
|
||||||
|
@ -167,10 +168,16 @@ pub(crate) fn complete_expr_path(
|
||||||
.find_use_path(ctx.db, hir::ModuleDef::from(strukt))
|
.find_use_path(ctx.db, hir::ModuleDef::from(strukt))
|
||||||
.filter(|it| it.len() > 1);
|
.filter(|it| it.len() > 1);
|
||||||
|
|
||||||
acc.add_struct_literal(ctx, strukt, path, None);
|
acc.add_struct_literal(ctx, path_ctx, strukt, path, None);
|
||||||
|
|
||||||
if complete_self {
|
if complete_self {
|
||||||
acc.add_struct_literal(ctx, strukt, None, Some(hir::known::SELF_TYPE));
|
acc.add_struct_literal(
|
||||||
|
ctx,
|
||||||
|
path_ctx,
|
||||||
|
strukt,
|
||||||
|
None,
|
||||||
|
Some(hir::known::SELF_TYPE),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
hir::Adt::Union(un) => {
|
hir::Adt::Union(un) => {
|
||||||
|
@ -191,7 +198,7 @@ pub(crate) fn complete_expr_path(
|
||||||
e,
|
e,
|
||||||
impl_,
|
impl_,
|
||||||
|acc, ctx, variant, path| {
|
|acc, ctx, variant, path| {
|
||||||
acc.add_qualified_enum_variant(ctx, variant, path)
|
acc.add_qualified_enum_variant(ctx, path_ctx, variant, path)
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -199,7 +206,7 @@ pub(crate) fn complete_expr_path(
|
||||||
}
|
}
|
||||||
ctx.process_all_names(&mut |name, def| {
|
ctx.process_all_names(&mut |name, def| {
|
||||||
if scope_def_applicable(def) {
|
if scope_def_applicable(def) {
|
||||||
acc.add_resolution(ctx, name, def);
|
acc.add_path_resolution(ctx, path_ctx, name, def);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -259,14 +266,26 @@ pub(crate) fn complete_expr_path(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_assoc_item(acc: &mut Completions, ctx: &CompletionContext, item: hir::AssocItem) {
|
fn add_assoc_item(
|
||||||
|
acc: &mut Completions,
|
||||||
|
ctx: &CompletionContext,
|
||||||
|
path_ctx: &PathCompletionCtx,
|
||||||
|
item: hir::AssocItem,
|
||||||
|
) {
|
||||||
match item {
|
match item {
|
||||||
hir::AssocItem::Function(func) => acc.add_function(ctx, func, None),
|
hir::AssocItem::Function(func) => acc.add_function(ctx, path_ctx, func, None),
|
||||||
hir::AssocItem::Const(ct) => acc.add_const(ctx, ct),
|
hir::AssocItem::Const(ct) => acc.add_const(ctx, ct),
|
||||||
hir::AssocItem::TypeAlias(ty) => acc.add_type_alias(ctx, ty),
|
hir::AssocItem::TypeAlias(ty) => acc.add_type_alias(ctx, ty),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_enum_variants(acc: &mut Completions, ctx: &CompletionContext, e: hir::Enum) {
|
fn add_enum_variants(
|
||||||
e.variants(ctx.db).into_iter().for_each(|variant| acc.add_enum_variant(ctx, variant, None));
|
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));
|
||||||
}
|
}
|
||||||
|
|
|
@ -116,17 +116,17 @@ pub(crate) fn import_on_the_fly_path(
|
||||||
if !ctx.config.enable_imports_on_the_fly {
|
if !ctx.config.enable_imports_on_the_fly {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
let (kind, qualified) = match path_ctx {
|
let qualified = match path_ctx {
|
||||||
PathCompletionCtx {
|
PathCompletionCtx {
|
||||||
kind:
|
kind:
|
||||||
kind @ (PathKind::Expr { .. }
|
PathKind::Expr { .. }
|
||||||
| PathKind::Type { .. }
|
| PathKind::Type { .. }
|
||||||
| PathKind::Attr { .. }
|
| PathKind::Attr { .. }
|
||||||
| PathKind::Derive { .. }
|
| PathKind::Derive { .. }
|
||||||
| PathKind::Pat { .. }),
|
| PathKind::Pat { .. },
|
||||||
qualified,
|
qualified,
|
||||||
..
|
..
|
||||||
} => (Some(kind), qualified),
|
} => qualified,
|
||||||
_ => return None,
|
_ => return None,
|
||||||
};
|
};
|
||||||
let potential_import_name = import_name(ctx);
|
let potential_import_name = import_name(ctx);
|
||||||
|
@ -139,13 +139,46 @@ pub(crate) fn import_on_the_fly_path(
|
||||||
import_on_the_fly(
|
import_on_the_fly(
|
||||||
acc,
|
acc,
|
||||||
ctx,
|
ctx,
|
||||||
kind,
|
path_ctx,
|
||||||
import_assets,
|
import_assets,
|
||||||
qualifier.map(|it| it.syntax().clone()).or_else(|| ctx.original_token.parent())?,
|
qualifier.map(|it| it.syntax().clone()).or_else(|| ctx.original_token.parent())?,
|
||||||
potential_import_name,
|
potential_import_name,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn import_on_the_fly_pat(
|
||||||
|
acc: &mut Completions,
|
||||||
|
ctx: &CompletionContext,
|
||||||
|
pat_ctx: &PatternContext,
|
||||||
|
) -> Option<()> {
|
||||||
|
if !ctx.config.enable_imports_on_the_fly {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
if let PatternContext { record_pat: Some(_), .. } = pat_ctx {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let potential_import_name = import_name(ctx);
|
||||||
|
let import_assets = import_assets_for_path(ctx, &potential_import_name, None)?;
|
||||||
|
|
||||||
|
import_on_the_fly(
|
||||||
|
acc,
|
||||||
|
ctx,
|
||||||
|
&PathCompletionCtx {
|
||||||
|
has_call_parens: false,
|
||||||
|
has_macro_bang: false,
|
||||||
|
qualified: Qualified::No,
|
||||||
|
parent: None,
|
||||||
|
kind: crate::context::PathKind::Pat { pat_ctx: pat_ctx.clone() },
|
||||||
|
has_type_args: false,
|
||||||
|
use_tree_parent: false,
|
||||||
|
},
|
||||||
|
import_assets,
|
||||||
|
ctx.original_token.parent()?,
|
||||||
|
potential_import_name,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn import_on_the_fly_dot(
|
pub(crate) fn import_on_the_fly_dot(
|
||||||
acc: &mut Completions,
|
acc: &mut Completions,
|
||||||
ctx: &CompletionContext,
|
ctx: &CompletionContext,
|
||||||
|
@ -164,46 +197,20 @@ pub(crate) fn import_on_the_fly_dot(
|
||||||
receiver.syntax().clone(),
|
receiver.syntax().clone(),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
import_on_the_fly(
|
import_on_the_fly_method(
|
||||||
acc,
|
acc,
|
||||||
ctx,
|
ctx,
|
||||||
None,
|
dot_access,
|
||||||
import_assets,
|
import_assets,
|
||||||
receiver.syntax().clone(),
|
receiver.syntax().clone(),
|
||||||
potential_import_name,
|
potential_import_name,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn import_on_the_fly_pat(
|
|
||||||
acc: &mut Completions,
|
|
||||||
ctx: &CompletionContext,
|
|
||||||
pat_ctx: &PatternContext,
|
|
||||||
) -> Option<()> {
|
|
||||||
if !ctx.config.enable_imports_on_the_fly {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
let kind = match pat_ctx {
|
|
||||||
PatternContext { record_pat: None, .. } => PathKind::Pat { pat_ctx: pat_ctx.clone() },
|
|
||||||
_ => return None,
|
|
||||||
};
|
|
||||||
|
|
||||||
let potential_import_name = import_name(ctx);
|
|
||||||
let import_assets = import_assets_for_path(ctx, &potential_import_name, None)?;
|
|
||||||
|
|
||||||
import_on_the_fly(
|
|
||||||
acc,
|
|
||||||
ctx,
|
|
||||||
Some(&kind),
|
|
||||||
import_assets,
|
|
||||||
ctx.original_token.parent()?,
|
|
||||||
potential_import_name,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn import_on_the_fly(
|
fn import_on_the_fly(
|
||||||
acc: &mut Completions,
|
acc: &mut Completions,
|
||||||
ctx: &CompletionContext,
|
ctx: &CompletionContext,
|
||||||
path_kind: Option<&PathKind>,
|
path_ctx @ PathCompletionCtx { kind, .. }: &PathCompletionCtx,
|
||||||
import_assets: ImportAssets,
|
import_assets: ImportAssets,
|
||||||
position: SyntaxNode,
|
position: SyntaxNode,
|
||||||
potential_import_name: String,
|
potential_import_name: String,
|
||||||
|
@ -215,11 +222,7 @@ fn import_on_the_fly(
|
||||||
}
|
}
|
||||||
|
|
||||||
let ns_filter = |import: &LocatedImport| {
|
let ns_filter = |import: &LocatedImport| {
|
||||||
let path_kind = match path_kind {
|
match (kind, import.original_item) {
|
||||||
Some(it) => it,
|
|
||||||
None => return true,
|
|
||||||
};
|
|
||||||
match (path_kind, import.original_item) {
|
|
||||||
// Aren't handled in flyimport
|
// Aren't handled in flyimport
|
||||||
(PathKind::Vis { .. } | PathKind::Use, _) => false,
|
(PathKind::Vis { .. } | PathKind::Use, _) => false,
|
||||||
// modules are always fair game
|
// modules are always fair game
|
||||||
|
@ -276,12 +279,49 @@ fn import_on_the_fly(
|
||||||
&user_input_lowercased,
|
&user_input_lowercased,
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
.filter_map(|import| render_resolution_with_import(RenderContext::new(ctx), import))
|
.filter_map(|import| {
|
||||||
|
render_resolution_with_import(RenderContext::new(ctx), path_ctx, import)
|
||||||
|
})
|
||||||
.map(|builder| builder.build()),
|
.map(|builder| builder.build()),
|
||||||
);
|
);
|
||||||
Some(())
|
Some(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn import_on_the_fly_method(
|
||||||
|
acc: &mut Completions,
|
||||||
|
ctx: &CompletionContext,
|
||||||
|
dot_access: &DotAccess,
|
||||||
|
import_assets: ImportAssets,
|
||||||
|
position: SyntaxNode,
|
||||||
|
potential_import_name: String,
|
||||||
|
) -> Option<()> {
|
||||||
|
let _p = profile::span("import_on_the_fly").detail(|| potential_import_name.clone());
|
||||||
|
|
||||||
|
if ImportScope::find_insert_use_container(&position, &ctx.sema).is_none() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let user_input_lowercased = potential_import_name.to_lowercase();
|
||||||
|
|
||||||
|
import_assets
|
||||||
|
.search_for_imports(&ctx.sema, ctx.config.insert_use.prefix_kind)
|
||||||
|
.into_iter()
|
||||||
|
.filter(|import| {
|
||||||
|
!ctx.is_item_hidden(&import.item_to_import)
|
||||||
|
&& !ctx.is_item_hidden(&import.original_item)
|
||||||
|
})
|
||||||
|
.sorted_by_key(|located_import| {
|
||||||
|
compute_fuzzy_completion_order_key(&located_import.import_path, &user_input_lowercased)
|
||||||
|
})
|
||||||
|
.for_each(|import| match import.original_item {
|
||||||
|
ItemInNs::Values(hir::ModuleDef::Function(f)) => {
|
||||||
|
acc.add_method_with_import(ctx, dot_access, f, import);
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
});
|
||||||
|
Some(())
|
||||||
|
}
|
||||||
|
|
||||||
fn import_name(ctx: &CompletionContext) -> String {
|
fn import_name(ctx: &CompletionContext) -> String {
|
||||||
let token_kind = ctx.token.kind();
|
let token_kind = ctx.token.kind();
|
||||||
if matches!(token_kind, T![.] | T![::]) {
|
if matches!(token_kind, T![.] | T![::]) {
|
||||||
|
|
|
@ -42,7 +42,7 @@ pub(crate) fn complete_item_list(
|
||||||
for (name, def) in module.scope(ctx.db, Some(ctx.module)) {
|
for (name, def) in module.scope(ctx.db, Some(ctx.module)) {
|
||||||
match def {
|
match def {
|
||||||
hir::ScopeDef::ModuleDef(hir::ModuleDef::Macro(m)) if m.is_fn_like(ctx.db) => {
|
hir::ScopeDef::ModuleDef(hir::ModuleDef::Macro(m)) if m.is_fn_like(ctx.db) => {
|
||||||
acc.add_macro(ctx, m, name)
|
acc.add_macro(ctx, path_ctx, m, name)
|
||||||
}
|
}
|
||||||
hir::ScopeDef::ModuleDef(hir::ModuleDef::Module(m)) => {
|
hir::ScopeDef::ModuleDef(hir::ModuleDef::Module(m)) => {
|
||||||
acc.add_module(ctx, m, name)
|
acc.add_module(ctx, m, name)
|
||||||
|
@ -59,7 +59,7 @@ pub(crate) fn complete_item_list(
|
||||||
Qualified::No if ctx.qualifier_ctx.none() => {
|
Qualified::No if ctx.qualifier_ctx.none() => {
|
||||||
ctx.process_all_names(&mut |name, def| match def {
|
ctx.process_all_names(&mut |name, def| match def {
|
||||||
hir::ScopeDef::ModuleDef(hir::ModuleDef::Macro(m)) if m.is_fn_like(ctx.db) => {
|
hir::ScopeDef::ModuleDef(hir::ModuleDef::Macro(m)) if m.is_fn_like(ctx.db) => {
|
||||||
acc.add_macro(ctx, m, name)
|
acc.add_macro(ctx, path_ctx, m, name)
|
||||||
}
|
}
|
||||||
hir::ScopeDef::ModuleDef(hir::ModuleDef::Module(m)) => acc.add_module(ctx, m, name),
|
hir::ScopeDef::ModuleDef(hir::ModuleDef::Module(m)) => acc.add_module(ctx, m, name),
|
||||||
_ => (),
|
_ => (),
|
||||||
|
|
|
@ -13,9 +13,9 @@ use crate::{
|
||||||
pub(crate) fn complete_pattern(
|
pub(crate) fn complete_pattern(
|
||||||
acc: &mut Completions,
|
acc: &mut Completions,
|
||||||
ctx: &CompletionContext,
|
ctx: &CompletionContext,
|
||||||
patctx: &PatternContext,
|
pattern_ctx: &PatternContext,
|
||||||
) {
|
) {
|
||||||
match patctx.parent_pat.as_ref() {
|
match pattern_ctx.parent_pat.as_ref() {
|
||||||
Some(Pat::RangePat(_) | Pat::BoxPat(_)) => (),
|
Some(Pat::RangePat(_) | Pat::BoxPat(_)) => (),
|
||||||
Some(Pat::RefPat(r)) => {
|
Some(Pat::RefPat(r)) => {
|
||||||
if r.mut_token().is_none() {
|
if r.mut_token().is_none() {
|
||||||
|
@ -24,7 +24,7 @@ pub(crate) fn complete_pattern(
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
let tok = ctx.token.text_range().start();
|
let tok = ctx.token.text_range().start();
|
||||||
match (patctx.ref_token.as_ref(), patctx.mut_token.as_ref()) {
|
match (pattern_ctx.ref_token.as_ref(), pattern_ctx.mut_token.as_ref()) {
|
||||||
(None, None) => {
|
(None, None) => {
|
||||||
acc.add_keyword(ctx, "ref");
|
acc.add_keyword(ctx, "ref");
|
||||||
acc.add_keyword(ctx, "mut");
|
acc.add_keyword(ctx, "mut");
|
||||||
|
@ -40,11 +40,11 @@ pub(crate) fn complete_pattern(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if patctx.record_pat.is_some() {
|
if pattern_ctx.record_pat.is_some() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let refutable = patctx.refutability == PatternRefutability::Refutable;
|
let refutable = pattern_ctx.refutability == PatternRefutability::Refutable;
|
||||||
let single_variant_enum = |enum_: hir::Enum| ctx.db.enum_data(enum_.into()).variants.len() == 1;
|
let single_variant_enum = |enum_: hir::Enum| ctx.db.enum_data(enum_.into()).variants.len() == 1;
|
||||||
|
|
||||||
if let Some(hir::Adt::Enum(e)) =
|
if let Some(hir::Adt::Enum(e)) =
|
||||||
|
@ -55,9 +55,9 @@ pub(crate) fn complete_pattern(
|
||||||
acc,
|
acc,
|
||||||
ctx,
|
ctx,
|
||||||
e,
|
e,
|
||||||
&patctx.impl_,
|
&pattern_ctx.impl_,
|
||||||
|acc, ctx, variant, path| {
|
|acc, ctx, variant, path| {
|
||||||
acc.add_qualified_variant_pat(ctx, variant, path);
|
acc.add_qualified_variant_pat(ctx, pattern_ctx, variant, path);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -69,26 +69,39 @@ pub(crate) fn complete_pattern(
|
||||||
let add_simple_path = match res {
|
let add_simple_path = match res {
|
||||||
hir::ScopeDef::ModuleDef(def) => match def {
|
hir::ScopeDef::ModuleDef(def) => match def {
|
||||||
hir::ModuleDef::Adt(hir::Adt::Struct(strukt)) => {
|
hir::ModuleDef::Adt(hir::Adt::Struct(strukt)) => {
|
||||||
acc.add_struct_pat(ctx, strukt, Some(name.clone()));
|
acc.add_struct_pat(ctx, pattern_ctx, strukt, Some(name.clone()));
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
hir::ModuleDef::Variant(variant)
|
hir::ModuleDef::Variant(variant)
|
||||||
if refutable || single_variant_enum(variant.parent_enum(ctx.db)) =>
|
if refutable || single_variant_enum(variant.parent_enum(ctx.db)) =>
|
||||||
{
|
{
|
||||||
acc.add_variant_pat(ctx, variant, Some(name.clone()));
|
acc.add_variant_pat(ctx, pattern_ctx, variant, Some(name.clone()));
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
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) if mac.is_fn_like(ctx.db) => {
|
||||||
return acc.add_macro(ctx, mac, name)
|
return acc.add_macro(
|
||||||
|
ctx,
|
||||||
|
&PathCompletionCtx {
|
||||||
|
has_call_parens: false,
|
||||||
|
has_macro_bang: false,
|
||||||
|
qualified: Qualified::No,
|
||||||
|
parent: None,
|
||||||
|
kind: crate::context::PathKind::Pat { pat_ctx: pattern_ctx.clone() },
|
||||||
|
has_type_args: false,
|
||||||
|
use_tree_parent: false,
|
||||||
|
},
|
||||||
|
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() {
|
||||||
Some(hir::Adt::Struct(strukt)) => {
|
Some(hir::Adt::Struct(strukt)) => {
|
||||||
acc.add_struct_pat(ctx, strukt, Some(name.clone()));
|
acc.add_struct_pat(ctx, pattern_ctx, strukt, Some(name.clone()));
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
Some(hir::Adt::Enum(e)) => refutable || single_variant_enum(e),
|
Some(hir::Adt::Enum(e)) => refutable || single_variant_enum(e),
|
||||||
|
@ -111,7 +124,7 @@ pub(crate) fn complete_pattern(
|
||||||
pub(crate) fn complete_pattern_path(
|
pub(crate) fn complete_pattern_path(
|
||||||
acc: &mut Completions,
|
acc: &mut Completions,
|
||||||
ctx: &CompletionContext,
|
ctx: &CompletionContext,
|
||||||
PathCompletionCtx { qualified, .. }: &PathCompletionCtx,
|
path_ctx @ PathCompletionCtx { qualified, .. }: &PathCompletionCtx,
|
||||||
) {
|
) {
|
||||||
match qualified {
|
match qualified {
|
||||||
Qualified::With { resolution: Some(resolution), is_super_chain, .. } => {
|
Qualified::With { resolution: Some(resolution), is_super_chain, .. } => {
|
||||||
|
@ -132,7 +145,7 @@ pub(crate) fn complete_pattern_path(
|
||||||
};
|
};
|
||||||
|
|
||||||
if add_resolution {
|
if add_resolution {
|
||||||
acc.add_resolution(ctx, name, def);
|
acc.add_path_resolution(ctx, path_ctx, name, def);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -150,9 +163,9 @@ pub(crate) fn complete_pattern_path(
|
||||||
}
|
}
|
||||||
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);
|
cov_mark::hit!(enum_plain_qualified_use_tree);
|
||||||
e.variants(ctx.db)
|
e.variants(ctx.db).into_iter().for_each(|variant| {
|
||||||
.into_iter()
|
acc.add_enum_variant(ctx, path_ctx, variant, None)
|
||||||
.for_each(|variant| acc.add_enum_variant(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))) => {
|
||||||
|
@ -197,7 +210,7 @@ pub(crate) fn complete_pattern_path(
|
||||||
ctx.process_all_names(&mut |name, res| {
|
ctx.process_all_names(&mut |name, res| {
|
||||||
// FIXME: properly filter here
|
// FIXME: properly filter here
|
||||||
if let ScopeDef::ModuleDef(_) = res {
|
if let ScopeDef::ModuleDef(_) = res {
|
||||||
acc.add_resolution(ctx, name, res);
|
acc.add_path_resolution(ctx, path_ctx, name, res);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,7 @@ use crate::{
|
||||||
pub(crate) fn complete_type_path(
|
pub(crate) fn complete_type_path(
|
||||||
acc: &mut Completions,
|
acc: &mut Completions,
|
||||||
ctx: &CompletionContext,
|
ctx: &CompletionContext,
|
||||||
PathCompletionCtx { qualified, .. }: &PathCompletionCtx,
|
path_ctx @ PathCompletionCtx { qualified, .. }: &PathCompletionCtx,
|
||||||
location: &TypeLocation,
|
location: &TypeLocation,
|
||||||
) {
|
) {
|
||||||
let _p = profile::span("complete_type_path");
|
let _p = profile::span("complete_type_path");
|
||||||
|
@ -69,7 +69,7 @@ pub(crate) fn complete_type_path(
|
||||||
let module_scope = module.scope(ctx.db, Some(ctx.module));
|
let module_scope = module.scope(ctx.db, Some(ctx.module));
|
||||||
for (name, def) in module_scope {
|
for (name, def) in module_scope {
|
||||||
if scope_def_applicable(def) {
|
if scope_def_applicable(def) {
|
||||||
acc.add_resolution(ctx, name, def);
|
acc.add_path_resolution(ctx, path_ctx, name, def);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -154,7 +154,7 @@ pub(crate) fn complete_type_path(
|
||||||
_ => false,
|
_ => false,
|
||||||
};
|
};
|
||||||
if add_resolution {
|
if add_resolution {
|
||||||
acc.add_resolution(ctx, name, res);
|
acc.add_path_resolution(ctx, path_ctx, name, res);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
|
@ -178,7 +178,7 @@ pub(crate) fn complete_type_path(
|
||||||
}
|
}
|
||||||
ctx.process_all_names(&mut |name, def| {
|
ctx.process_all_names(&mut |name, def| {
|
||||||
if scope_def_applicable(def) {
|
if scope_def_applicable(def) {
|
||||||
acc.add_resolution(ctx, name, def);
|
acc.add_path_resolution(ctx, path_ctx, name, def);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,7 @@ use crate::{
|
||||||
pub(crate) fn complete_use_path(
|
pub(crate) fn complete_use_path(
|
||||||
acc: &mut Completions,
|
acc: &mut Completions,
|
||||||
ctx: &CompletionContext,
|
ctx: &CompletionContext,
|
||||||
PathCompletionCtx { qualified, use_tree_parent, .. }: &PathCompletionCtx,
|
path_ctx @ PathCompletionCtx { qualified, use_tree_parent, .. }: &PathCompletionCtx,
|
||||||
name_ref: &Option<ast::NameRef>,
|
name_ref: &Option<ast::NameRef>,
|
||||||
) {
|
) {
|
||||||
match qualified {
|
match qualified {
|
||||||
|
@ -68,7 +68,7 @@ pub(crate) fn complete_use_path(
|
||||||
};
|
};
|
||||||
|
|
||||||
if add_resolution {
|
if add_resolution {
|
||||||
let mut builder = Builder::from_resolution(ctx, name, def);
|
let mut builder = Builder::from_resolution(ctx, path_ctx, name, def);
|
||||||
builder.set_relevance(CompletionRelevance {
|
builder.set_relevance(CompletionRelevance {
|
||||||
is_name_already_imported,
|
is_name_already_imported,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
|
@ -81,7 +81,7 @@ pub(crate) fn complete_use_path(
|
||||||
cov_mark::hit!(enum_plain_qualified_use_tree);
|
cov_mark::hit!(enum_plain_qualified_use_tree);
|
||||||
e.variants(ctx.db)
|
e.variants(ctx.db)
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.for_each(|variant| acc.add_enum_variant(ctx, variant, None));
|
.for_each(|variant| acc.add_enum_variant(ctx, path_ctx, variant, None));
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
|
@ -269,7 +269,7 @@ pub(super) enum NameRefKind {
|
||||||
|
|
||||||
/// The identifier we are currently completing.
|
/// The identifier we are currently completing.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(super) enum IdentContext {
|
pub(super) enum CompletionAnalysis {
|
||||||
Name(NameContext),
|
Name(NameContext),
|
||||||
NameRef(NameRefContext),
|
NameRef(NameRefContext),
|
||||||
Lifetime(LifetimeContext),
|
Lifetime(LifetimeContext),
|
||||||
|
@ -338,8 +338,6 @@ pub(crate) struct CompletionContext<'a> {
|
||||||
/// The expected type of what we are completing.
|
/// The expected type of what we are completing.
|
||||||
pub(super) expected_type: Option<Type>,
|
pub(super) expected_type: Option<Type>,
|
||||||
|
|
||||||
// We might wanna split these out of CompletionContext
|
|
||||||
pub(super) ident_ctx: IdentContext,
|
|
||||||
pub(super) qualifier_ctx: QualifierCtx,
|
pub(super) qualifier_ctx: QualifierCtx,
|
||||||
|
|
||||||
pub(super) locals: FxHashMap<Name, Local>,
|
pub(super) locals: FxHashMap<Name, Local>,
|
||||||
|
@ -461,7 +459,7 @@ impl<'a> CompletionContext<'a> {
|
||||||
db: &'a RootDatabase,
|
db: &'a RootDatabase,
|
||||||
position @ FilePosition { file_id, offset }: FilePosition,
|
position @ FilePosition { file_id, offset }: FilePosition,
|
||||||
config: &'a CompletionConfig,
|
config: &'a CompletionConfig,
|
||||||
) -> Option<CompletionContext<'a>> {
|
) -> Option<(CompletionContext<'a>, CompletionAnalysis)> {
|
||||||
let _p = profile::span("CompletionContext::new");
|
let _p = profile::span("CompletionContext::new");
|
||||||
let sema = Semantics::new(db);
|
let sema = Semantics::new(db);
|
||||||
|
|
||||||
|
@ -503,21 +501,16 @@ impl<'a> CompletionContext<'a> {
|
||||||
module,
|
module,
|
||||||
expected_name: None,
|
expected_name: None,
|
||||||
expected_type: None,
|
expected_type: None,
|
||||||
// dummy value, will be overwritten
|
|
||||||
ident_ctx: IdentContext::UnexpandedAttrTT {
|
|
||||||
fake_attribute_under_caret: None,
|
|
||||||
colon_prefix: false,
|
|
||||||
},
|
|
||||||
qualifier_ctx: Default::default(),
|
qualifier_ctx: Default::default(),
|
||||||
locals,
|
locals,
|
||||||
};
|
};
|
||||||
ctx.expand_and_fill(
|
let ident_ctx = ctx.expand_and_analyze(
|
||||||
original_file.syntax().clone(),
|
original_file.syntax().clone(),
|
||||||
file_with_fake_ident.syntax().clone(),
|
file_with_fake_ident.syntax().clone(),
|
||||||
offset,
|
offset,
|
||||||
fake_ident_token,
|
fake_ident_token,
|
||||||
)?;
|
)?;
|
||||||
Some(ctx)
|
Some((ctx, ident_ctx))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,23 +11,23 @@ use syntax::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::context::{
|
use crate::context::{
|
||||||
AttrCtx, CompletionContext, DotAccess, DotAccessKind, ExprCtx, IdentContext, ItemListKind,
|
AttrCtx, CompletionAnalysis, CompletionContext, DotAccess, DotAccessKind, ExprCtx,
|
||||||
LifetimeContext, LifetimeKind, NameContext, NameKind, NameRefContext, NameRefKind, ParamKind,
|
ItemListKind, LifetimeContext, LifetimeKind, NameContext, NameKind, NameRefContext,
|
||||||
PathCompletionCtx, PathKind, PatternContext, PatternRefutability, Qualified, QualifierCtx,
|
NameRefKind, ParamKind, PathCompletionCtx, PathKind, PatternContext, PatternRefutability,
|
||||||
TypeAscriptionTarget, TypeLocation, COMPLETION_MARKER,
|
Qualified, QualifierCtx, TypeAscriptionTarget, TypeLocation, COMPLETION_MARKER,
|
||||||
};
|
};
|
||||||
|
|
||||||
impl<'a> CompletionContext<'a> {
|
impl<'a> CompletionContext<'a> {
|
||||||
/// Expand attributes and macro calls at the current cursor position for both the original file
|
/// Expand attributes and macro calls at the current cursor position for both the original file
|
||||||
/// and fake file repeatedly. As soon as one of the two expansions fail we stop so the original
|
/// and fake file repeatedly. As soon as one of the two expansions fail we stop so the original
|
||||||
/// and speculative states stay in sync.
|
/// and speculative states stay in sync.
|
||||||
pub(super) fn expand_and_fill(
|
pub(super) fn expand_and_analyze(
|
||||||
&mut self,
|
&mut self,
|
||||||
mut original_file: SyntaxNode,
|
mut original_file: SyntaxNode,
|
||||||
mut speculative_file: SyntaxNode,
|
mut speculative_file: SyntaxNode,
|
||||||
mut offset: TextSize,
|
mut offset: TextSize,
|
||||||
mut fake_ident_token: SyntaxToken,
|
mut fake_ident_token: SyntaxToken,
|
||||||
) -> Option<()> {
|
) -> Option<CompletionAnalysis> {
|
||||||
let _p = profile::span("CompletionContext::expand_and_fill");
|
let _p = profile::span("CompletionContext::expand_and_fill");
|
||||||
let mut derive_ctx = None;
|
let mut derive_ctx = None;
|
||||||
|
|
||||||
|
@ -157,7 +157,7 @@ impl<'a> CompletionContext<'a> {
|
||||||
break 'expansion;
|
break 'expansion;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.fill(&original_file, speculative_file, offset, derive_ctx)
|
self.analyze(&original_file, speculative_file, offset, derive_ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Calculate the expected type and name of the cursor position.
|
/// Calculate the expected type and name of the cursor position.
|
||||||
|
@ -311,13 +311,13 @@ impl<'a> CompletionContext<'a> {
|
||||||
|
|
||||||
/// Fill the completion context, this is what does semantic reasoning about the surrounding context
|
/// Fill the completion context, this is what does semantic reasoning about the surrounding context
|
||||||
/// of the completion location.
|
/// of the completion location.
|
||||||
fn fill(
|
fn analyze(
|
||||||
&mut self,
|
&mut self,
|
||||||
original_file: &SyntaxNode,
|
original_file: &SyntaxNode,
|
||||||
file_with_fake_ident: SyntaxNode,
|
file_with_fake_ident: SyntaxNode,
|
||||||
offset: TextSize,
|
offset: TextSize,
|
||||||
derive_ctx: Option<(SyntaxNode, SyntaxNode, TextSize, ast::Attr)>,
|
derive_ctx: Option<(SyntaxNode, SyntaxNode, TextSize, ast::Attr)>,
|
||||||
) -> Option<()> {
|
) -> Option<CompletionAnalysis> {
|
||||||
let fake_ident_token = file_with_fake_ident.token_at_offset(offset).right_biased()?;
|
let fake_ident_token = file_with_fake_ident.token_at_offset(offset).right_biased()?;
|
||||||
let syntax_element = NodeOrToken::Token(fake_ident_token);
|
let syntax_element = NodeOrToken::Token(fake_ident_token);
|
||||||
if is_in_token_of_for_loop(syntax_element.clone()) {
|
if is_in_token_of_for_loop(syntax_element.clone()) {
|
||||||
|
@ -350,8 +350,7 @@ impl<'a> CompletionContext<'a> {
|
||||||
.collect(),
|
.collect(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
self.ident_ctx = IdentContext::NameRef(nameref_ctx);
|
return Some(CompletionAnalysis::NameRef(nameref_ctx));
|
||||||
return Some(());
|
|
||||||
}
|
}
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
@ -359,11 +358,12 @@ impl<'a> CompletionContext<'a> {
|
||||||
let name_like = match find_node_at_offset(&file_with_fake_ident, offset) {
|
let name_like = match find_node_at_offset(&file_with_fake_ident, offset) {
|
||||||
Some(it) => it,
|
Some(it) => it,
|
||||||
None => {
|
None => {
|
||||||
|
let analysis =
|
||||||
if let Some(original) = ast::String::cast(self.original_token.clone()) {
|
if let Some(original) = ast::String::cast(self.original_token.clone()) {
|
||||||
self.ident_ctx = IdentContext::String {
|
CompletionAnalysis::String {
|
||||||
original,
|
original,
|
||||||
expanded: ast::String::cast(self.token.clone()),
|
expanded: ast::String::cast(self.token.clone()),
|
||||||
};
|
}
|
||||||
} else {
|
} else {
|
||||||
// Fix up trailing whitespace problem
|
// Fix up trailing whitespace problem
|
||||||
// #[attr(foo = $0
|
// #[attr(foo = $0
|
||||||
|
@ -375,42 +375,37 @@ impl<'a> CompletionContext<'a> {
|
||||||
{
|
{
|
||||||
let colon_prefix = previous_non_trivia_token(self.token.clone())
|
let colon_prefix = previous_non_trivia_token(self.token.clone())
|
||||||
.map_or(false, |it| T![:] == it.kind());
|
.map_or(false, |it| T![:] == it.kind());
|
||||||
self.ident_ctx = IdentContext::UnexpandedAttrTT {
|
CompletionAnalysis::UnexpandedAttrTT {
|
||||||
fake_attribute_under_caret: syntax_element
|
fake_attribute_under_caret: syntax_element
|
||||||
.ancestors()
|
.ancestors()
|
||||||
.find_map(ast::Attr::cast),
|
.find_map(ast::Attr::cast),
|
||||||
colon_prefix,
|
colon_prefix,
|
||||||
};
|
}
|
||||||
} else {
|
} else {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
return Some(());
|
return Some(analysis);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
let analysis = match name_like {
|
||||||
match name_like {
|
ast::NameLike::Lifetime(lifetime) => CompletionAnalysis::Lifetime(
|
||||||
ast::NameLike::Lifetime(lifetime) => {
|
Self::classify_lifetime(&self.sema, original_file, lifetime)?,
|
||||||
self.ident_ctx = IdentContext::Lifetime(Self::classify_lifetime(
|
),
|
||||||
&self.sema,
|
|
||||||
original_file,
|
|
||||||
lifetime,
|
|
||||||
)?);
|
|
||||||
}
|
|
||||||
ast::NameLike::NameRef(name_ref) => {
|
ast::NameLike::NameRef(name_ref) => {
|
||||||
let parent = name_ref.syntax().parent()?;
|
let parent = name_ref.syntax().parent()?;
|
||||||
let (nameref_ctx, qualifier_ctx) =
|
let (nameref_ctx, qualifier_ctx) =
|
||||||
Self::classify_name_ref(&self.sema, &original_file, name_ref, parent.clone())?;
|
Self::classify_name_ref(&self.sema, &original_file, name_ref, parent.clone())?;
|
||||||
|
|
||||||
self.qualifier_ctx = qualifier_ctx;
|
self.qualifier_ctx = qualifier_ctx;
|
||||||
self.ident_ctx = IdentContext::NameRef(nameref_ctx);
|
CompletionAnalysis::NameRef(nameref_ctx)
|
||||||
}
|
}
|
||||||
ast::NameLike::Name(name) => {
|
ast::NameLike::Name(name) => {
|
||||||
let name_ctx = Self::classify_name(&self.sema, original_file, name)?;
|
let name_ctx = Self::classify_name(&self.sema, original_file, name)?;
|
||||||
self.ident_ctx = IdentContext::Name(name_ctx);
|
CompletionAnalysis::Name(name_ctx)
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
Some(())
|
Some(analysis)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn classify_lifetime(
|
fn classify_lifetime(
|
||||||
|
|
|
@ -9,7 +9,7 @@ use crate::{
|
||||||
fn check_expected_type_and_name(ra_fixture: &str, expect: Expect) {
|
fn check_expected_type_and_name(ra_fixture: &str, expect: Expect) {
|
||||||
let (db, pos) = position(ra_fixture);
|
let (db, pos) = position(ra_fixture);
|
||||||
let config = TEST_CONFIG;
|
let config = TEST_CONFIG;
|
||||||
let completion_context = CompletionContext::new(&db, pos, &config).unwrap();
|
let (completion_context, _analysis) = CompletionContext::new(&db, pos, &config).unwrap();
|
||||||
|
|
||||||
let ty = completion_context
|
let ty = completion_context
|
||||||
.expected_type
|
.expected_type
|
||||||
|
|
|
@ -10,8 +10,8 @@ use syntax::{SmolStr, TextRange};
|
||||||
use text_edit::TextEdit;
|
use text_edit::TextEdit;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
context::CompletionContext,
|
context::{CompletionContext, PathCompletionCtx},
|
||||||
render::{render_resolution, RenderContext},
|
render::{render_path_resolution, RenderContext},
|
||||||
};
|
};
|
||||||
|
|
||||||
/// `CompletionItem` describes a single completion variant in the editor pop-up.
|
/// `CompletionItem` describes a single completion variant in the editor pop-up.
|
||||||
|
@ -434,10 +434,11 @@ pub(crate) struct Builder {
|
||||||
impl Builder {
|
impl Builder {
|
||||||
pub(crate) fn from_resolution(
|
pub(crate) fn from_resolution(
|
||||||
ctx: &CompletionContext,
|
ctx: &CompletionContext,
|
||||||
|
path_ctx: &PathCompletionCtx,
|
||||||
local_name: hir::Name,
|
local_name: hir::Name,
|
||||||
resolution: hir::ScopeDef,
|
resolution: hir::ScopeDef,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
render_resolution(RenderContext::new(ctx), local_name, resolution)
|
render_path_resolution(RenderContext::new(ctx), path_ctx, local_name, resolution)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn build(self) -> CompletionItem {
|
pub(crate) fn build(self) -> CompletionItem {
|
||||||
|
|
|
@ -25,7 +25,8 @@ use text_edit::TextEdit;
|
||||||
use crate::{
|
use crate::{
|
||||||
completions::Completions,
|
completions::Completions,
|
||||||
context::{
|
context::{
|
||||||
CompletionContext, IdentContext, NameRefContext, NameRefKind, PathCompletionCtx, PathKind,
|
CompletionAnalysis, CompletionContext, NameRefContext, NameRefKind, PathCompletionCtx,
|
||||||
|
PathKind,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -148,12 +149,12 @@ pub fn completions(
|
||||||
position: FilePosition,
|
position: FilePosition,
|
||||||
trigger_character: Option<char>,
|
trigger_character: Option<char>,
|
||||||
) -> Option<Completions> {
|
) -> Option<Completions> {
|
||||||
let ctx = &CompletionContext::new(db, position, config)?;
|
let (ctx, analysis) = &CompletionContext::new(db, position, config)?;
|
||||||
let mut completions = Completions::default();
|
let mut completions = Completions::default();
|
||||||
|
|
||||||
// prevent `(` from triggering unwanted completion noise
|
// prevent `(` from triggering unwanted completion noise
|
||||||
if trigger_character == Some('(') {
|
if trigger_character == Some('(') {
|
||||||
if let IdentContext::NameRef(NameRefContext { kind, .. }) = &ctx.ident_ctx {
|
if let CompletionAnalysis::NameRef(NameRefContext { kind, .. }) = &analysis {
|
||||||
if let NameRefKind::Path(
|
if let NameRefKind::Path(
|
||||||
path_ctx @ PathCompletionCtx { kind: PathKind::Vis { has_in_token }, .. },
|
path_ctx @ PathCompletionCtx { kind: PathKind::Vis { has_in_token }, .. },
|
||||||
) = kind
|
) = kind
|
||||||
|
@ -168,20 +169,20 @@ pub fn completions(
|
||||||
{
|
{
|
||||||
let acc = &mut completions;
|
let acc = &mut completions;
|
||||||
|
|
||||||
match &ctx.ident_ctx {
|
match &analysis {
|
||||||
IdentContext::Name(name_ctx) => completions::complete_name(acc, ctx, name_ctx),
|
CompletionAnalysis::Name(name_ctx) => completions::complete_name(acc, ctx, name_ctx),
|
||||||
IdentContext::NameRef(name_ref_ctx) => {
|
CompletionAnalysis::NameRef(name_ref_ctx) => {
|
||||||
completions::complete_name_ref(acc, ctx, name_ref_ctx)
|
completions::complete_name_ref(acc, ctx, name_ref_ctx)
|
||||||
}
|
}
|
||||||
IdentContext::Lifetime(lifetime_ctx) => {
|
CompletionAnalysis::Lifetime(lifetime_ctx) => {
|
||||||
completions::lifetime::complete_label(acc, ctx, lifetime_ctx);
|
completions::lifetime::complete_label(acc, ctx, lifetime_ctx);
|
||||||
completions::lifetime::complete_lifetime(acc, ctx, lifetime_ctx);
|
completions::lifetime::complete_lifetime(acc, ctx, lifetime_ctx);
|
||||||
}
|
}
|
||||||
IdentContext::String { original, expanded: Some(expanded) } => {
|
CompletionAnalysis::String { original, expanded: Some(expanded) } => {
|
||||||
completions::extern_abi::complete_extern_abi(acc, ctx, expanded);
|
completions::extern_abi::complete_extern_abi(acc, ctx, expanded);
|
||||||
completions::format_string::format_string(acc, ctx, original, expanded);
|
completions::format_string::format_string(acc, ctx, original, expanded);
|
||||||
}
|
}
|
||||||
IdentContext::UnexpandedAttrTT {
|
CompletionAnalysis::UnexpandedAttrTT {
|
||||||
colon_prefix,
|
colon_prefix,
|
||||||
fake_attribute_under_caret: Some(attr),
|
fake_attribute_under_caret: Some(attr),
|
||||||
} => {
|
} => {
|
||||||
|
@ -192,7 +193,7 @@ pub fn completions(
|
||||||
attr,
|
attr,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
IdentContext::UnexpandedAttrTT { .. } | IdentContext::String { .. } => (),
|
CompletionAnalysis::UnexpandedAttrTT { .. } | CompletionAnalysis::String { .. } => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -204,22 +205,26 @@ pub fn completions(
|
||||||
pub fn resolve_completion_edits(
|
pub fn resolve_completion_edits(
|
||||||
db: &RootDatabase,
|
db: &RootDatabase,
|
||||||
config: &CompletionConfig,
|
config: &CompletionConfig,
|
||||||
position: FilePosition,
|
FilePosition { file_id, offset }: FilePosition,
|
||||||
imports: impl IntoIterator<Item = (String, String)>,
|
imports: impl IntoIterator<Item = (String, String)>,
|
||||||
) -> Option<Vec<TextEdit>> {
|
) -> Option<Vec<TextEdit>> {
|
||||||
let _p = profile::span("resolve_completion_edits");
|
let _p = profile::span("resolve_completion_edits");
|
||||||
let ctx = CompletionContext::new(db, position, config)?;
|
let sema = hir::Semantics::new(db);
|
||||||
let position_for_import = &ctx.original_token.parent()?;
|
|
||||||
let scope = ImportScope::find_insert_use_container(position_for_import, &ctx.sema)?;
|
|
||||||
|
|
||||||
let current_module = ctx.sema.scope(position_for_import)?.module();
|
let original_file = sema.parse(file_id);
|
||||||
|
let original_token =
|
||||||
|
syntax::AstNode::syntax(&original_file).token_at_offset(offset).left_biased()?;
|
||||||
|
let position_for_import = &original_token.parent()?;
|
||||||
|
let scope = ImportScope::find_insert_use_container(position_for_import, &sema)?;
|
||||||
|
|
||||||
|
let current_module = sema.scope(position_for_import)?.module();
|
||||||
let current_crate = current_module.krate();
|
let current_crate = current_module.krate();
|
||||||
let new_ast = scope.clone_for_update();
|
let new_ast = scope.clone_for_update();
|
||||||
let mut import_insert = TextEdit::builder();
|
let mut import_insert = TextEdit::builder();
|
||||||
|
|
||||||
imports.into_iter().for_each(|(full_import_path, imported_name)| {
|
imports.into_iter().for_each(|(full_import_path, imported_name)| {
|
||||||
let items_with_name = items_locator::items_with_name(
|
let items_with_name = items_locator::items_with_name(
|
||||||
&ctx.sema,
|
&sema,
|
||||||
current_crate,
|
current_crate,
|
||||||
NameToImport::exact_case_sensitive(imported_name),
|
NameToImport::exact_case_sensitive(imported_name),
|
||||||
items_locator::AssocItemSearch::Include,
|
items_locator::AssocItemSearch::Include,
|
||||||
|
|
|
@ -17,7 +17,7 @@ use ide_db::{
|
||||||
use syntax::{SmolStr, SyntaxKind, TextRange};
|
use syntax::{SmolStr, SyntaxKind, TextRange};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
context::{IdentContext, NameRefContext, NameRefKind, PathCompletionCtx, PathKind},
|
context::{PathCompletionCtx, PathKind},
|
||||||
item::{Builder, CompletionRelevanceTypeMatch},
|
item::{Builder, CompletionRelevanceTypeMatch},
|
||||||
render::{function::render_fn, literal::render_variant_lit, macro_::render_macro},
|
render::{function::render_fn, literal::render_variant_lit, macro_::render_macro},
|
||||||
CompletionContext, CompletionItem, CompletionItemKind, CompletionRelevance,
|
CompletionContext, CompletionItem, CompletionItemKind, CompletionRelevance,
|
||||||
|
@ -74,16 +74,6 @@ impl<'a> RenderContext<'a> {
|
||||||
.map_or(false, |it| it.kind() == SyntaxKind::MACRO_CALL)
|
.map_or(false, |it| it.kind() == SyntaxKind::MACRO_CALL)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn path_is_call(&self) -> bool {
|
|
||||||
matches!(
|
|
||||||
self.completion.ident_ctx,
|
|
||||||
IdentContext::NameRef(NameRefContext {
|
|
||||||
kind: NameRefKind::Path(PathCompletionCtx { has_call_parens: true, .. }),
|
|
||||||
..
|
|
||||||
})
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_deprecated(&self, def: impl HasAttrs) -> bool {
|
fn is_deprecated(&self, def: impl HasAttrs) -> bool {
|
||||||
let attrs = def.attrs(self.db());
|
let attrs = def.attrs(self.db());
|
||||||
attrs.by_key("deprecated").exists()
|
attrs.by_key("deprecated").exists()
|
||||||
|
@ -163,12 +153,13 @@ pub(crate) fn render_tuple_field(
|
||||||
item.build()
|
item.build()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn render_resolution(
|
pub(crate) fn render_path_resolution(
|
||||||
ctx: RenderContext<'_>,
|
ctx: RenderContext<'_>,
|
||||||
|
path_ctx: &PathCompletionCtx,
|
||||||
local_name: hir::Name,
|
local_name: hir::Name,
|
||||||
resolution: ScopeDef,
|
resolution: ScopeDef,
|
||||||
) -> Builder {
|
) -> Builder {
|
||||||
render_resolution_(ctx, local_name, None, resolution)
|
render_resolution_(ctx, path_ctx, local_name, None, resolution)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn render_resolution_simple(
|
pub(crate) fn render_resolution_simple(
|
||||||
|
@ -181,6 +172,7 @@ pub(crate) fn render_resolution_simple(
|
||||||
|
|
||||||
pub(crate) fn render_resolution_with_import(
|
pub(crate) fn render_resolution_with_import(
|
||||||
ctx: RenderContext<'_>,
|
ctx: RenderContext<'_>,
|
||||||
|
path_ctx: &PathCompletionCtx,
|
||||||
import_edit: LocatedImport,
|
import_edit: LocatedImport,
|
||||||
) -> Option<Builder> {
|
) -> Option<Builder> {
|
||||||
let resolution = ScopeDef::from(import_edit.original_item);
|
let resolution = ScopeDef::from(import_edit.original_item);
|
||||||
|
@ -190,7 +182,7 @@ pub(crate) fn render_resolution_with_import(
|
||||||
ScopeDef::ModuleDef(hir::ModuleDef::TypeAlias(t)) => t.name(ctx.completion.db),
|
ScopeDef::ModuleDef(hir::ModuleDef::TypeAlias(t)) => t.name(ctx.completion.db),
|
||||||
_ => item_name(ctx.db(), import_edit.original_item)?,
|
_ => item_name(ctx.db(), import_edit.original_item)?,
|
||||||
};
|
};
|
||||||
Some(render_resolution_(ctx, local_name, Some(import_edit), resolution))
|
Some(render_resolution_(ctx, path_ctx, local_name, Some(import_edit), resolution))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn render_type_inference(ty_string: String, ctx: &CompletionContext) -> CompletionItem {
|
pub(crate) fn render_type_inference(ty_string: String, ctx: &CompletionContext) -> CompletionItem {
|
||||||
|
@ -202,6 +194,7 @@ pub(crate) fn render_type_inference(ty_string: String, ctx: &CompletionContext)
|
||||||
|
|
||||||
fn render_resolution_(
|
fn render_resolution_(
|
||||||
ctx: RenderContext<'_>,
|
ctx: RenderContext<'_>,
|
||||||
|
path_ctx: &PathCompletionCtx,
|
||||||
local_name: hir::Name,
|
local_name: hir::Name,
|
||||||
import_to_add: Option<LocatedImport>,
|
import_to_add: Option<LocatedImport>,
|
||||||
resolution: ScopeDef,
|
resolution: ScopeDef,
|
||||||
|
@ -212,21 +205,61 @@ fn render_resolution_(
|
||||||
match resolution {
|
match resolution {
|
||||||
ScopeDef::ModuleDef(Macro(mac)) => {
|
ScopeDef::ModuleDef(Macro(mac)) => {
|
||||||
let ctx = ctx.import_to_add(import_to_add);
|
let ctx = ctx.import_to_add(import_to_add);
|
||||||
return render_macro(ctx, local_name, mac);
|
return render_macro(ctx, path_ctx, local_name, mac);
|
||||||
}
|
}
|
||||||
ScopeDef::ModuleDef(Function(func)) => {
|
ScopeDef::ModuleDef(Function(func)) => {
|
||||||
let ctx = ctx.import_to_add(import_to_add);
|
let ctx = ctx.import_to_add(import_to_add);
|
||||||
return render_fn(ctx, Some(local_name), func);
|
return render_fn(ctx, path_ctx, Some(local_name), func);
|
||||||
}
|
}
|
||||||
ScopeDef::ModuleDef(Variant(var)) => {
|
ScopeDef::ModuleDef(Variant(var)) => {
|
||||||
let ctx = ctx.clone().import_to_add(import_to_add.clone());
|
let ctx = ctx.clone().import_to_add(import_to_add.clone());
|
||||||
if let Some(item) = render_variant_lit(ctx, Some(local_name.clone()), var, None) {
|
if let Some(item) =
|
||||||
|
render_variant_lit(ctx, path_ctx, Some(local_name.clone()), var, None)
|
||||||
|
{
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
render_resolution_simple_(ctx, local_name, import_to_add, resolution)
|
render_resolution_simple_type(ctx, path_ctx, local_name, import_to_add, resolution)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn render_resolution_simple_type(
|
||||||
|
ctx: RenderContext<'_>,
|
||||||
|
path_ctx: &PathCompletionCtx,
|
||||||
|
local_name: hir::Name,
|
||||||
|
import_to_add: Option<LocatedImport>,
|
||||||
|
resolution: ScopeDef,
|
||||||
|
) -> Builder {
|
||||||
|
let cap = ctx.snippet_cap();
|
||||||
|
let db = ctx.completion.db;
|
||||||
|
let config = ctx.completion.config;
|
||||||
|
let name = local_name.to_smol_str();
|
||||||
|
let mut item = render_resolution_simple_(ctx, local_name, import_to_add, resolution);
|
||||||
|
// Add `<>` for generic types
|
||||||
|
let type_path_no_ty_args = matches!(
|
||||||
|
path_ctx,
|
||||||
|
PathCompletionCtx { kind: PathKind::Type { .. }, has_type_args: false, .. }
|
||||||
|
) && config.callable.is_some();
|
||||||
|
if type_path_no_ty_args {
|
||||||
|
if let Some(cap) = cap {
|
||||||
|
let has_non_default_type_params = match resolution {
|
||||||
|
ScopeDef::ModuleDef(hir::ModuleDef::Adt(it)) => it.has_non_default_type_params(db),
|
||||||
|
ScopeDef::ModuleDef(hir::ModuleDef::TypeAlias(it)) => {
|
||||||
|
it.has_non_default_type_params(db)
|
||||||
|
}
|
||||||
|
_ => false,
|
||||||
|
};
|
||||||
|
if has_non_default_type_params {
|
||||||
|
cov_mark::hit!(inserts_angle_brackets_for_generics);
|
||||||
|
item.lookup_by(name.clone())
|
||||||
|
.label(SmolStr::from_iter([&name, "<…>"]))
|
||||||
|
.trigger_call_info()
|
||||||
|
.insert_snippet(cap, format!("{}<$0>", name));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
item
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_resolution_simple_(
|
fn render_resolution_simple_(
|
||||||
|
@ -289,34 +322,6 @@ fn render_resolution_simple_(
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Add `<>` for generic types
|
|
||||||
let type_path_no_ty_args = matches!(
|
|
||||||
ctx.completion.ident_ctx,
|
|
||||||
IdentContext::NameRef(NameRefContext {
|
|
||||||
kind: NameRefKind::Path(PathCompletionCtx {
|
|
||||||
kind: PathKind::Type { .. },
|
|
||||||
has_type_args: false,
|
|
||||||
..
|
|
||||||
}),
|
|
||||||
..
|
|
||||||
})
|
|
||||||
) && ctx.completion.config.callable.is_some();
|
|
||||||
if type_path_no_ty_args {
|
|
||||||
if let Some(cap) = ctx.snippet_cap() {
|
|
||||||
let has_non_default_type_params = match resolution {
|
|
||||||
ScopeDef::ModuleDef(Adt(it)) => it.has_non_default_type_params(db),
|
|
||||||
ScopeDef::ModuleDef(TypeAlias(it)) => it.has_non_default_type_params(db),
|
|
||||||
_ => false,
|
|
||||||
};
|
|
||||||
if has_non_default_type_params {
|
|
||||||
cov_mark::hit!(inserts_angle_brackets_for_generics);
|
|
||||||
item.lookup_by(local_name.clone())
|
|
||||||
.label(SmolStr::from_iter([&local_name, "<…>"]))
|
|
||||||
.trigger_call_info()
|
|
||||||
.insert_snippet(cap, format!("{}<$0>", local_name));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
item.set_documentation(scope_def_docs(db, resolution))
|
item.set_documentation(scope_def_docs(db, resolution))
|
||||||
.set_deprecated(scope_def_is_deprecated(&ctx, resolution));
|
.set_deprecated(scope_def_is_deprecated(&ctx, resolution));
|
||||||
|
|
||||||
|
|
|
@ -8,8 +8,7 @@ use syntax::SmolStr;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
context::{
|
context::{
|
||||||
CompletionContext, DotAccess, DotAccessKind, IdentContext, NameRefContext, NameRefKind,
|
CompletionContext, DotAccess, DotAccessKind, PathCompletionCtx, PathKind, Qualified,
|
||||||
PathCompletionCtx, PathKind, Qualified,
|
|
||||||
},
|
},
|
||||||
item::{Builder, CompletionItem, CompletionItemKind, CompletionRelevance},
|
item::{Builder, CompletionItem, CompletionItemKind, CompletionRelevance},
|
||||||
render::{compute_exact_name_match, compute_ref_match, compute_type_match, RenderContext},
|
render::{compute_exact_name_match, compute_ref_match, compute_type_match, RenderContext},
|
||||||
|
@ -23,21 +22,54 @@ enum FuncKind {
|
||||||
|
|
||||||
pub(crate) fn render_fn(
|
pub(crate) fn render_fn(
|
||||||
ctx: RenderContext<'_>,
|
ctx: RenderContext<'_>,
|
||||||
|
path_ctx: &PathCompletionCtx,
|
||||||
local_name: Option<hir::Name>,
|
local_name: Option<hir::Name>,
|
||||||
func: hir::Function,
|
func: hir::Function,
|
||||||
) -> Builder {
|
) -> Builder {
|
||||||
let _p = profile::span("render_fn");
|
let _p = profile::span("render_fn");
|
||||||
render(ctx, local_name, func, FuncKind::Function)
|
let func_kind = FuncKind::Function;
|
||||||
|
let params = match ctx.completion.config.snippet_cap {
|
||||||
|
Some(_) => {
|
||||||
|
if !matches!(
|
||||||
|
path_ctx,
|
||||||
|
PathCompletionCtx { kind: PathKind::Expr { .. }, has_call_parens: true, .. }
|
||||||
|
| PathCompletionCtx { kind: PathKind::Use | PathKind::Type { .. }, .. }
|
||||||
|
) {
|
||||||
|
params(ctx.completion, func, &func_kind, false)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
};
|
||||||
|
render(
|
||||||
|
ctx,
|
||||||
|
local_name,
|
||||||
|
func,
|
||||||
|
func_kind,
|
||||||
|
params,
|
||||||
|
matches!(path_ctx.qualified, Qualified::With { .. }),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn render_method(
|
pub(crate) fn render_method(
|
||||||
ctx: RenderContext<'_>,
|
ctx: RenderContext<'_>,
|
||||||
|
dot_access: &DotAccess,
|
||||||
receiver: Option<hir::Name>,
|
receiver: Option<hir::Name>,
|
||||||
local_name: Option<hir::Name>,
|
local_name: Option<hir::Name>,
|
||||||
func: hir::Function,
|
func: hir::Function,
|
||||||
) -> Builder {
|
) -> Builder {
|
||||||
let _p = profile::span("render_method");
|
let _p = profile::span("render_method");
|
||||||
render(ctx, local_name, func, FuncKind::Method(receiver))
|
let func_kind = FuncKind::Method(receiver);
|
||||||
|
let params = match ctx.completion.config.snippet_cap {
|
||||||
|
Some(_) => match dot_access {
|
||||||
|
DotAccess { kind: DotAccessKind::Method { has_parens: true }, .. } => None,
|
||||||
|
_ => params(ctx.completion, func, &func_kind, true),
|
||||||
|
},
|
||||||
|
_ => None,
|
||||||
|
};
|
||||||
|
|
||||||
|
render(ctx, local_name, func, func_kind, params, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render(
|
fn render(
|
||||||
|
@ -45,6 +77,8 @@ fn render(
|
||||||
local_name: Option<hir::Name>,
|
local_name: Option<hir::Name>,
|
||||||
func: hir::Function,
|
func: hir::Function,
|
||||||
func_kind: FuncKind,
|
func_kind: FuncKind,
|
||||||
|
params: Option<(Option<hir::SelfParam>, Vec<hir::Param>)>,
|
||||||
|
qualified_path: bool,
|
||||||
) -> Builder {
|
) -> Builder {
|
||||||
let db = completion.db;
|
let db = completion.db;
|
||||||
|
|
||||||
|
@ -80,16 +114,6 @@ fn render(
|
||||||
// FIXME For now we don't properly calculate the edits for ref match
|
// FIXME For now we don't properly calculate the edits for ref match
|
||||||
// completions on methods or qualified paths, so we've disabled them.
|
// completions on methods or qualified paths, so we've disabled them.
|
||||||
// See #8058.
|
// See #8058.
|
||||||
let qualified_path = matches!(
|
|
||||||
ctx.completion.ident_ctx,
|
|
||||||
IdentContext::NameRef(NameRefContext {
|
|
||||||
kind: NameRefKind::Path(PathCompletionCtx {
|
|
||||||
qualified: Qualified::With { .. },
|
|
||||||
..
|
|
||||||
}),
|
|
||||||
..
|
|
||||||
})
|
|
||||||
);
|
|
||||||
if matches!(func_kind, FuncKind::Function) && !qualified_path {
|
if matches!(func_kind, FuncKind::Function) && !qualified_path {
|
||||||
item.ref_match(ref_match);
|
item.ref_match(ref_match);
|
||||||
}
|
}
|
||||||
|
@ -100,12 +124,10 @@ fn render(
|
||||||
.detail(detail(db, func))
|
.detail(detail(db, func))
|
||||||
.lookup_by(name.to_smol_str());
|
.lookup_by(name.to_smol_str());
|
||||||
|
|
||||||
match completion.config.snippet_cap {
|
match completion.config.snippet_cap.zip(params) {
|
||||||
Some(cap) => {
|
Some((cap, (self_param, params))) => {
|
||||||
if let Some((self_param, params)) = params(completion, func, &func_kind) {
|
|
||||||
add_call_parens(&mut item, completion, cap, call, self_param, params);
|
add_call_parens(&mut item, completion, cap, call, self_param, params);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -254,37 +276,12 @@ fn params(
|
||||||
ctx: &CompletionContext<'_>,
|
ctx: &CompletionContext<'_>,
|
||||||
func: hir::Function,
|
func: hir::Function,
|
||||||
func_kind: &FuncKind,
|
func_kind: &FuncKind,
|
||||||
|
has_dot_receiver: bool,
|
||||||
) -> Option<(Option<hir::SelfParam>, Vec<hir::Param>)> {
|
) -> Option<(Option<hir::SelfParam>, Vec<hir::Param>)> {
|
||||||
if ctx.config.callable.is_none() {
|
if ctx.config.callable.is_none() {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
let has_dot_receiver = match ctx.ident_ctx {
|
|
||||||
IdentContext::NameRef(NameRefContext {
|
|
||||||
kind:
|
|
||||||
NameRefKind::DotAccess(DotAccess {
|
|
||||||
kind: DotAccessKind::Method { has_parens: true },
|
|
||||||
..
|
|
||||||
}),
|
|
||||||
..
|
|
||||||
}) => return None,
|
|
||||||
IdentContext::NameRef(NameRefContext {
|
|
||||||
kind: NameRefKind::DotAccess(DotAccess { .. }),
|
|
||||||
..
|
|
||||||
}) => true,
|
|
||||||
IdentContext::NameRef(NameRefContext {
|
|
||||||
kind:
|
|
||||||
NameRefKind::Path(
|
|
||||||
PathCompletionCtx {
|
|
||||||
kind: PathKind::Expr { .. }, has_call_parens: true, ..
|
|
||||||
}
|
|
||||||
| PathCompletionCtx { kind: PathKind::Use | PathKind::Type { .. }, .. },
|
|
||||||
),
|
|
||||||
..
|
|
||||||
}) => return None,
|
|
||||||
_ => false,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Don't add parentheses if the expected type is some function reference.
|
// Don't add parentheses if the expected type is some function reference.
|
||||||
if let Some(ty) = &ctx.expected_type {
|
if let Some(ty) = &ctx.expected_type {
|
||||||
// FIXME: check signature matches?
|
// FIXME: check signature matches?
|
||||||
|
|
|
@ -4,9 +4,7 @@ use hir::{db::HirDatabase, Documentation, HasAttrs, StructKind};
|
||||||
use ide_db::SymbolKind;
|
use ide_db::SymbolKind;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
context::{
|
context::{CompletionContext, PathCompletionCtx, PathKind},
|
||||||
CompletionContext, IdentContext, NameRefContext, NameRefKind, PathCompletionCtx, PathKind,
|
|
||||||
},
|
|
||||||
item::{Builder, CompletionItem},
|
item::{Builder, CompletionItem},
|
||||||
render::{
|
render::{
|
||||||
compute_ref_match, compute_type_match,
|
compute_ref_match, compute_type_match,
|
||||||
|
@ -21,6 +19,7 @@ use crate::{
|
||||||
|
|
||||||
pub(crate) fn render_variant_lit(
|
pub(crate) fn render_variant_lit(
|
||||||
ctx: RenderContext<'_>,
|
ctx: RenderContext<'_>,
|
||||||
|
path_ctx: &PathCompletionCtx,
|
||||||
local_name: Option<hir::Name>,
|
local_name: Option<hir::Name>,
|
||||||
variant: hir::Variant,
|
variant: hir::Variant,
|
||||||
path: Option<hir::ModPath>,
|
path: Option<hir::ModPath>,
|
||||||
|
@ -29,11 +28,12 @@ pub(crate) fn render_variant_lit(
|
||||||
let db = ctx.db();
|
let db = ctx.db();
|
||||||
|
|
||||||
let name = local_name.unwrap_or_else(|| variant.name(db));
|
let name = local_name.unwrap_or_else(|| variant.name(db));
|
||||||
render(ctx, Variant::EnumVariant(variant), name, path)
|
render(ctx, path_ctx, Variant::EnumVariant(variant), name, path)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn render_struct_literal(
|
pub(crate) fn render_struct_literal(
|
||||||
ctx: RenderContext<'_>,
|
ctx: RenderContext<'_>,
|
||||||
|
path_ctx: &PathCompletionCtx,
|
||||||
strukt: hir::Struct,
|
strukt: hir::Struct,
|
||||||
path: Option<hir::ModPath>,
|
path: Option<hir::ModPath>,
|
||||||
local_name: Option<hir::Name>,
|
local_name: Option<hir::Name>,
|
||||||
|
@ -42,29 +42,21 @@ pub(crate) fn render_struct_literal(
|
||||||
let db = ctx.db();
|
let db = ctx.db();
|
||||||
|
|
||||||
let name = local_name.unwrap_or_else(|| strukt.name(db));
|
let name = local_name.unwrap_or_else(|| strukt.name(db));
|
||||||
render(ctx, Variant::Struct(strukt), name, path)
|
render(ctx, path_ctx, Variant::Struct(strukt), name, path)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render(
|
fn render(
|
||||||
ctx @ RenderContext { completion, .. }: RenderContext<'_>,
|
ctx @ RenderContext { completion, .. }: RenderContext<'_>,
|
||||||
|
path_ctx: &PathCompletionCtx,
|
||||||
thing: Variant,
|
thing: Variant,
|
||||||
name: hir::Name,
|
name: hir::Name,
|
||||||
path: Option<hir::ModPath>,
|
path: Option<hir::ModPath>,
|
||||||
) -> Option<Builder> {
|
) -> Option<Builder> {
|
||||||
let db = completion.db;
|
let db = completion.db;
|
||||||
let mut kind = thing.kind(db);
|
let mut kind = thing.kind(db);
|
||||||
let should_add_parens = match &completion.ident_ctx {
|
let should_add_parens = match &path_ctx {
|
||||||
IdentContext::NameRef(NameRefContext {
|
PathCompletionCtx { has_call_parens: true, .. } => false,
|
||||||
kind: NameRefKind::Path(PathCompletionCtx { has_call_parens: true, .. }),
|
PathCompletionCtx { kind: PathKind::Use | PathKind::Type { .. }, .. } => false,
|
||||||
..
|
|
||||||
}) => false,
|
|
||||||
IdentContext::NameRef(NameRefContext {
|
|
||||||
kind:
|
|
||||||
NameRefKind::Path(PathCompletionCtx {
|
|
||||||
kind: PathKind::Use | PathKind::Type { .. }, ..
|
|
||||||
}),
|
|
||||||
..
|
|
||||||
}) => false,
|
|
||||||
_ => true,
|
_ => true,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -5,18 +5,24 @@ use ide_db::SymbolKind;
|
||||||
use syntax::SmolStr;
|
use syntax::SmolStr;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
context::{IdentContext, NameRefContext, NameRefKind, PathCompletionCtx, PathKind},
|
context::{PathCompletionCtx, PathKind},
|
||||||
item::{Builder, CompletionItem},
|
item::{Builder, CompletionItem},
|
||||||
render::RenderContext,
|
render::RenderContext,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub(crate) fn render_macro(ctx: RenderContext<'_>, name: hir::Name, macro_: hir::Macro) -> Builder {
|
pub(crate) fn render_macro(
|
||||||
|
ctx: RenderContext<'_>,
|
||||||
|
path_ctx: &PathCompletionCtx,
|
||||||
|
name: hir::Name,
|
||||||
|
macro_: hir::Macro,
|
||||||
|
) -> Builder {
|
||||||
let _p = profile::span("render_macro");
|
let _p = profile::span("render_macro");
|
||||||
render(ctx, name, macro_)
|
render(ctx, path_ctx, name, macro_)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render(
|
fn render(
|
||||||
ctx @ RenderContext { completion, .. }: RenderContext<'_>,
|
ctx @ RenderContext { completion, .. }: RenderContext<'_>,
|
||||||
|
PathCompletionCtx { kind, has_macro_bang, has_call_parens, .. }: &PathCompletionCtx,
|
||||||
name: hir::Name,
|
name: hir::Name,
|
||||||
macro_: hir::Macro,
|
macro_: hir::Macro,
|
||||||
) -> Builder {
|
) -> Builder {
|
||||||
|
@ -33,13 +39,7 @@ fn render(
|
||||||
let is_fn_like = macro_.is_fn_like(completion.db);
|
let is_fn_like = macro_.is_fn_like(completion.db);
|
||||||
let (bra, ket) = if is_fn_like { guess_macro_braces(&name, docs_str) } else { ("", "") };
|
let (bra, ket) = if is_fn_like { guess_macro_braces(&name, docs_str) } else { ("", "") };
|
||||||
|
|
||||||
let needs_bang = match &completion.ident_ctx {
|
let needs_bang = is_fn_like && *kind != PathKind::Use && !has_macro_bang;
|
||||||
IdentContext::NameRef(NameRefContext {
|
|
||||||
kind: NameRefKind::Path(PathCompletionCtx { kind, has_macro_bang, .. }),
|
|
||||||
..
|
|
||||||
}) => is_fn_like && *kind != PathKind::Use && !has_macro_bang,
|
|
||||||
_ => is_fn_like,
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut item = CompletionItem::new(
|
let mut item = CompletionItem::new(
|
||||||
SymbolKind::from(macro_.kind(completion.db)),
|
SymbolKind::from(macro_.kind(completion.db)),
|
||||||
|
@ -53,7 +53,7 @@ fn render(
|
||||||
|
|
||||||
let name = &*name;
|
let name = &*name;
|
||||||
match ctx.snippet_cap() {
|
match ctx.snippet_cap() {
|
||||||
Some(cap) if needs_bang && !ctx.path_is_call() => {
|
Some(cap) if needs_bang && !has_call_parens => {
|
||||||
let snippet = format!("{}!{}$0{}", name, bra, ket);
|
let snippet = format!("{}!{}$0{}", name, bra, ket);
|
||||||
let lookup = banged_name(name);
|
let lookup = banged_name(name);
|
||||||
item.insert_snippet(cap, snippet).lookup_by(lookup);
|
item.insert_snippet(cap, snippet).lookup_by(lookup);
|
||||||
|
|
|
@ -6,16 +6,14 @@ use itertools::Itertools;
|
||||||
use syntax::SmolStr;
|
use syntax::SmolStr;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
context::{
|
context::{ParamKind, PatternContext},
|
||||||
IdentContext, NameContext, NameKind, NameRefContext, NameRefKind, ParamKind,
|
|
||||||
PathCompletionCtx, PathKind, PatternContext,
|
|
||||||
},
|
|
||||||
render::{variant::visible_fields, RenderContext},
|
render::{variant::visible_fields, RenderContext},
|
||||||
CompletionItem, CompletionItemKind,
|
CompletionItem, CompletionItemKind,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub(crate) fn render_struct_pat(
|
pub(crate) fn render_struct_pat(
|
||||||
ctx: RenderContext<'_>,
|
ctx: RenderContext<'_>,
|
||||||
|
pattern_ctx: &PatternContext,
|
||||||
strukt: hir::Struct,
|
strukt: hir::Struct,
|
||||||
local_name: Option<Name>,
|
local_name: Option<Name>,
|
||||||
) -> Option<CompletionItem> {
|
) -> Option<CompletionItem> {
|
||||||
|
@ -30,13 +28,21 @@ pub(crate) fn render_struct_pat(
|
||||||
}
|
}
|
||||||
|
|
||||||
let name = local_name.unwrap_or_else(|| strukt.name(ctx.db())).to_smol_str();
|
let name = local_name.unwrap_or_else(|| strukt.name(ctx.db())).to_smol_str();
|
||||||
let pat = render_pat(&ctx, &name, strukt.kind(ctx.db()), &visible_fields, fields_omitted)?;
|
let pat = render_pat(
|
||||||
|
&ctx,
|
||||||
|
pattern_ctx,
|
||||||
|
&name,
|
||||||
|
strukt.kind(ctx.db()),
|
||||||
|
&visible_fields,
|
||||||
|
fields_omitted,
|
||||||
|
)?;
|
||||||
|
|
||||||
Some(build_completion(ctx, name, pat, strukt))
|
Some(build_completion(ctx, name, pat, strukt))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn render_variant_pat(
|
pub(crate) fn render_variant_pat(
|
||||||
ctx: RenderContext<'_>,
|
ctx: RenderContext<'_>,
|
||||||
|
pattern_ctx: &PatternContext,
|
||||||
variant: hir::Variant,
|
variant: hir::Variant,
|
||||||
local_name: Option<Name>,
|
local_name: Option<Name>,
|
||||||
path: Option<&hir::ModPath>,
|
path: Option<&hir::ModPath>,
|
||||||
|
@ -50,7 +56,14 @@ pub(crate) fn render_variant_pat(
|
||||||
Some(path) => path.to_string().into(),
|
Some(path) => path.to_string().into(),
|
||||||
None => local_name.unwrap_or_else(|| variant.name(ctx.db())).to_smol_str(),
|
None => local_name.unwrap_or_else(|| variant.name(ctx.db())).to_smol_str(),
|
||||||
};
|
};
|
||||||
let pat = render_pat(&ctx, &name, variant.kind(ctx.db()), &visible_fields, fields_omitted)?;
|
let pat = render_pat(
|
||||||
|
&ctx,
|
||||||
|
pattern_ctx,
|
||||||
|
&name,
|
||||||
|
variant.kind(ctx.db()),
|
||||||
|
&visible_fields,
|
||||||
|
fields_omitted,
|
||||||
|
)?;
|
||||||
|
|
||||||
Some(build_completion(ctx, name, pat, variant))
|
Some(build_completion(ctx, name, pat, variant))
|
||||||
}
|
}
|
||||||
|
@ -75,48 +88,27 @@ fn build_completion(
|
||||||
|
|
||||||
fn render_pat(
|
fn render_pat(
|
||||||
ctx: &RenderContext<'_>,
|
ctx: &RenderContext<'_>,
|
||||||
|
pattern_ctx: &PatternContext,
|
||||||
name: &str,
|
name: &str,
|
||||||
kind: StructKind,
|
kind: StructKind,
|
||||||
fields: &[hir::Field],
|
fields: &[hir::Field],
|
||||||
fields_omitted: bool,
|
fields_omitted: bool,
|
||||||
) -> Option<String> {
|
) -> Option<String> {
|
||||||
let has_call_parens = matches!(
|
|
||||||
ctx.completion.ident_ctx,
|
|
||||||
IdentContext::NameRef(NameRefContext {
|
|
||||||
kind: NameRefKind::Path(PathCompletionCtx { has_call_parens: true, .. }),
|
|
||||||
..
|
|
||||||
})
|
|
||||||
);
|
|
||||||
let mut pat = match kind {
|
let mut pat = match kind {
|
||||||
StructKind::Tuple if !has_call_parens => {
|
StructKind::Tuple => render_tuple_as_pat(ctx.snippet_cap(), fields, name, fields_omitted),
|
||||||
render_tuple_as_pat(ctx.snippet_cap(), fields, name, fields_omitted)
|
StructKind::Record => {
|
||||||
}
|
|
||||||
StructKind::Record if !has_call_parens => {
|
|
||||||
render_record_as_pat(ctx.db(), ctx.snippet_cap(), fields, name, fields_omitted)
|
render_record_as_pat(ctx.db(), ctx.snippet_cap(), fields, name, fields_omitted)
|
||||||
}
|
}
|
||||||
StructKind::Unit => return None,
|
StructKind::Unit => return None,
|
||||||
_ => name.to_owned(),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let needs_ascription = !has_call_parens
|
let needs_ascription = matches!(
|
||||||
&& matches!(
|
pattern_ctx,
|
||||||
&ctx.completion.ident_ctx,
|
PatternContext {
|
||||||
IdentContext::NameRef(NameRefContext {
|
|
||||||
kind: NameRefKind::Path(PathCompletionCtx {
|
|
||||||
kind: PathKind::Pat {
|
|
||||||
pat_ctx
|
|
||||||
},
|
|
||||||
..
|
|
||||||
}),
|
|
||||||
..
|
|
||||||
}) | IdentContext::Name(NameContext {
|
|
||||||
kind: NameKind::IdentPat(pat_ctx), ..}
|
|
||||||
)
|
|
||||||
if matches!(pat_ctx, PatternContext {
|
|
||||||
param_ctx: Some((.., ParamKind::Function(_))),
|
param_ctx: Some((.., ParamKind::Function(_))),
|
||||||
has_type_ascription: false,
|
has_type_ascription: false,
|
||||||
..
|
..
|
||||||
})
|
}
|
||||||
);
|
);
|
||||||
if needs_ascription {
|
if needs_ascription {
|
||||||
pat.push(':');
|
pat.push(':');
|
||||||
|
|
|
@ -1,22 +1,22 @@
|
||||||
use expect_test::{expect, Expect};
|
use expect_test::{expect, Expect};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
context::{IdentContext, NameContext, NameKind, NameRefKind},
|
context::{CompletionAnalysis, NameContext, NameKind, NameRefKind},
|
||||||
tests::{check_edit, check_edit_with_config, TEST_CONFIG},
|
tests::{check_edit, check_edit_with_config, TEST_CONFIG},
|
||||||
};
|
};
|
||||||
|
|
||||||
fn check(ra_fixture: &str, expect: Expect) {
|
fn check(ra_fixture: &str, expect: Expect) {
|
||||||
let config = TEST_CONFIG;
|
let config = TEST_CONFIG;
|
||||||
let (db, position) = crate::tests::position(ra_fixture);
|
let (db, position) = crate::tests::position(ra_fixture);
|
||||||
let ctx = crate::context::CompletionContext::new(&db, position, &config).unwrap();
|
let (ctx, analysis) = crate::context::CompletionContext::new(&db, position, &config).unwrap();
|
||||||
|
|
||||||
let mut acc = crate::completions::Completions::default();
|
let mut acc = crate::completions::Completions::default();
|
||||||
if let IdentContext::Name(NameContext { kind: NameKind::IdentPat(pat_ctx), .. }) =
|
if let CompletionAnalysis::Name(NameContext { kind: NameKind::IdentPat(pat_ctx), .. }) =
|
||||||
&ctx.ident_ctx
|
&analysis
|
||||||
{
|
{
|
||||||
crate::completions::flyimport::import_on_the_fly_pat(&mut acc, &ctx, pat_ctx);
|
crate::completions::flyimport::import_on_the_fly_pat(&mut acc, &ctx, pat_ctx);
|
||||||
}
|
}
|
||||||
if let IdentContext::NameRef(name_ref_ctx) = &ctx.ident_ctx {
|
if let CompletionAnalysis::NameRef(name_ref_ctx) = &analysis {
|
||||||
match &name_ref_ctx.kind {
|
match &name_ref_ctx.kind {
|
||||||
NameRefKind::Path(path) => {
|
NameRefKind::Path(path) => {
|
||||||
crate::completions::flyimport::import_on_the_fly_path(&mut acc, &ctx, path);
|
crate::completions::flyimport::import_on_the_fly_path(&mut acc, &ctx, path);
|
||||||
|
|
Loading…
Reference in a new issue