internal: Lift out IdentContext from CompletionContext

This commit is contained in:
Lukas Wirth 2022-06-20 17:41:04 +02:00
parent bcf10cde13
commit 6e9c963348
21 changed files with 456 additions and 351 deletions

View file

@ -8,8 +8,7 @@ use syntax::SmolStr;
use crate::{
context::{
CompletionContext, DotAccess, DotAccessKind, IdentContext, NameRefContext, NameRefKind,
PathCompletionCtx, PathKind, Qualified,
CompletionContext, DotAccess, DotAccessKind, PathCompletionCtx, PathKind, Qualified,
},
item::{Builder, CompletionItem, CompletionItemKind, CompletionRelevance},
render::{compute_exact_name_match, compute_ref_match, compute_type_match, RenderContext},
@ -23,21 +22,54 @@ enum FuncKind {
pub(crate) fn render_fn(
ctx: RenderContext<'_>,
path_ctx: &PathCompletionCtx,
local_name: Option<hir::Name>,
func: hir::Function,
) -> Builder {
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(
ctx: RenderContext<'_>,
dot_access: &DotAccess,
receiver: Option<hir::Name>,
local_name: Option<hir::Name>,
func: hir::Function,
) -> Builder {
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(
@ -45,6 +77,8 @@ fn render(
local_name: Option<hir::Name>,
func: hir::Function,
func_kind: FuncKind,
params: Option<(Option<hir::SelfParam>, Vec<hir::Param>)>,
qualified_path: bool,
) -> Builder {
let db = completion.db;
@ -80,16 +114,6 @@ fn render(
// FIXME For now we don't properly calculate the edits for ref match
// completions on methods or qualified paths, so we've disabled them.
// 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 {
item.ref_match(ref_match);
}
@ -100,11 +124,9 @@ fn render(
.detail(detail(db, func))
.lookup_by(name.to_smol_str());
match completion.config.snippet_cap {
Some(cap) => {
if let Some((self_param, params)) = params(completion, func, &func_kind) {
add_call_parens(&mut item, completion, cap, call, self_param, params);
}
match completion.config.snippet_cap.zip(params) {
Some((cap, (self_param, params))) => {
add_call_parens(&mut item, completion, cap, call, self_param, params);
}
_ => (),
}
@ -254,37 +276,12 @@ fn params(
ctx: &CompletionContext<'_>,
func: hir::Function,
func_kind: &FuncKind,
has_dot_receiver: bool,
) -> Option<(Option<hir::SelfParam>, Vec<hir::Param>)> {
if ctx.config.callable.is_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.
if let Some(ty) = &ctx.expected_type {
// FIXME: check signature matches?

View file

@ -4,9 +4,7 @@ use hir::{db::HirDatabase, Documentation, HasAttrs, StructKind};
use ide_db::SymbolKind;
use crate::{
context::{
CompletionContext, IdentContext, NameRefContext, NameRefKind, PathCompletionCtx, PathKind,
},
context::{CompletionContext, PathCompletionCtx, PathKind},
item::{Builder, CompletionItem},
render::{
compute_ref_match, compute_type_match,
@ -21,6 +19,7 @@ use crate::{
pub(crate) fn render_variant_lit(
ctx: RenderContext<'_>,
path_ctx: &PathCompletionCtx,
local_name: Option<hir::Name>,
variant: hir::Variant,
path: Option<hir::ModPath>,
@ -29,11 +28,12 @@ pub(crate) fn render_variant_lit(
let db = ctx.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(
ctx: RenderContext<'_>,
path_ctx: &PathCompletionCtx,
strukt: hir::Struct,
path: Option<hir::ModPath>,
local_name: Option<hir::Name>,
@ -42,29 +42,21 @@ pub(crate) fn render_struct_literal(
let db = ctx.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(
ctx @ RenderContext { completion, .. }: RenderContext<'_>,
path_ctx: &PathCompletionCtx,
thing: Variant,
name: hir::Name,
path: Option<hir::ModPath>,
) -> Option<Builder> {
let db = completion.db;
let mut kind = thing.kind(db);
let should_add_parens = match &completion.ident_ctx {
IdentContext::NameRef(NameRefContext {
kind: NameRefKind::Path(PathCompletionCtx { has_call_parens: true, .. }),
..
}) => false,
IdentContext::NameRef(NameRefContext {
kind:
NameRefKind::Path(PathCompletionCtx {
kind: PathKind::Use | PathKind::Type { .. }, ..
}),
..
}) => false,
let should_add_parens = match &path_ctx {
PathCompletionCtx { has_call_parens: true, .. } => false,
PathCompletionCtx { kind: PathKind::Use | PathKind::Type { .. }, .. } => false,
_ => true,
};

View file

@ -5,18 +5,24 @@ use ide_db::SymbolKind;
use syntax::SmolStr;
use crate::{
context::{IdentContext, NameRefContext, NameRefKind, PathCompletionCtx, PathKind},
context::{PathCompletionCtx, PathKind},
item::{Builder, CompletionItem},
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");
render(ctx, name, macro_)
render(ctx, path_ctx, name, macro_)
}
fn render(
ctx @ RenderContext { completion, .. }: RenderContext<'_>,
PathCompletionCtx { kind, has_macro_bang, has_call_parens, .. }: &PathCompletionCtx,
name: hir::Name,
macro_: hir::Macro,
) -> Builder {
@ -33,13 +39,7 @@ fn render(
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 needs_bang = match &completion.ident_ctx {
IdentContext::NameRef(NameRefContext {
kind: NameRefKind::Path(PathCompletionCtx { kind, has_macro_bang, .. }),
..
}) => is_fn_like && *kind != PathKind::Use && !has_macro_bang,
_ => is_fn_like,
};
let needs_bang = is_fn_like && *kind != PathKind::Use && !has_macro_bang;
let mut item = CompletionItem::new(
SymbolKind::from(macro_.kind(completion.db)),
@ -53,7 +53,7 @@ fn render(
let name = &*name;
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 lookup = banged_name(name);
item.insert_snippet(cap, snippet).lookup_by(lookup);

View file

@ -6,16 +6,14 @@ use itertools::Itertools;
use syntax::SmolStr;
use crate::{
context::{
IdentContext, NameContext, NameKind, NameRefContext, NameRefKind, ParamKind,
PathCompletionCtx, PathKind, PatternContext,
},
context::{ParamKind, PatternContext},
render::{variant::visible_fields, RenderContext},
CompletionItem, CompletionItemKind,
};
pub(crate) fn render_struct_pat(
ctx: RenderContext<'_>,
pattern_ctx: &PatternContext,
strukt: hir::Struct,
local_name: Option<Name>,
) -> 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 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))
}
pub(crate) fn render_variant_pat(
ctx: RenderContext<'_>,
pattern_ctx: &PatternContext,
variant: hir::Variant,
local_name: Option<Name>,
path: Option<&hir::ModPath>,
@ -50,7 +56,14 @@ pub(crate) fn render_variant_pat(
Some(path) => path.to_string().into(),
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))
}
@ -75,49 +88,28 @@ fn build_completion(
fn render_pat(
ctx: &RenderContext<'_>,
pattern_ctx: &PatternContext,
name: &str,
kind: StructKind,
fields: &[hir::Field],
fields_omitted: bool,
) -> 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 {
StructKind::Tuple if !has_call_parens => {
render_tuple_as_pat(ctx.snippet_cap(), fields, name, fields_omitted)
}
StructKind::Record if !has_call_parens => {
StructKind::Tuple => render_tuple_as_pat(ctx.snippet_cap(), fields, name, fields_omitted),
StructKind::Record => {
render_record_as_pat(ctx.db(), ctx.snippet_cap(), fields, name, fields_omitted)
}
StructKind::Unit => return None,
_ => name.to_owned(),
};
let needs_ascription = !has_call_parens
&& matches!(
&ctx.completion.ident_ctx,
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(_))),
has_type_ascription: false,
..
})
);
let needs_ascription = matches!(
pattern_ctx,
PatternContext {
param_ctx: Some((.., ParamKind::Function(_))),
has_type_ascription: false,
..
}
);
if needs_ascription {
pat.push(':');
pat.push(' ');