Only run completion functions if their corresponding context is active

This commit is contained in:
Lukas Wirth 2022-06-17 23:36:39 +02:00
parent d97a8ee865
commit 00fdb4a3d8
29 changed files with 562 additions and 397 deletions

View file

@ -8,7 +8,7 @@ use syntax::SmolStr;
use crate::{
context::{
CompletionContext, DotAccess, DotAccessKind, NameRefContext, NameRefKind,
CompletionContext, DotAccess, DotAccessKind, IdentContext, NameRefContext, NameRefKind,
PathCompletionCtx, PathKind,
},
item::{Builder, CompletionItem, CompletionItemKind, CompletionRelevance},
@ -91,9 +91,10 @@ fn render(
.lookup_by(name.to_smol_str());
match completion.config.snippet_cap {
Some(cap) if should_add_parens(completion) => {
let (self_param, params) = params(completion, func, &func_kind);
add_call_parens(&mut item, completion, cap, call, self_param, params);
Some(cap) => {
if let Some((self_param, params)) = params(completion, func, &func_kind) {
add_call_parens(&mut item, completion, cap, call, self_param, params);
}
}
_ => (),
}
@ -194,48 +195,6 @@ fn ref_of_param(ctx: &CompletionContext, arg: &str, ty: &hir::Type) -> &'static
""
}
fn should_add_parens(ctx: &CompletionContext) -> bool {
if ctx.config.callable.is_none() {
return false;
}
match ctx.path_context() {
Some(PathCompletionCtx { kind: PathKind::Expr { .. }, has_call_parens: true, .. }) => {
return false
}
Some(PathCompletionCtx { kind: PathKind::Use | PathKind::Type { .. }, .. }) => {
cov_mark::hit!(no_parens_in_use_item);
return false;
}
_ => {}
};
if matches!(
ctx.nameref_ctx(),
Some(NameRefContext {
kind: Some(NameRefKind::DotAccess(DotAccess {
kind: DotAccessKind::Method { has_parens: true },
..
})),
..
})
) {
return false;
}
// Don't add parentheses if the expected type is some function reference.
if let Some(ty) = &ctx.expected_type {
// FIXME: check signature matches?
if ty.is_fn() {
cov_mark::hit!(no_call_parens_if_fn_ptr_needed);
return false;
}
}
// Nothing prevents us from adding parentheses
true
}
fn detail(db: &dyn HirDatabase, func: hir::Function) -> String {
let mut ret_ty = func.ret_type(db);
let mut detail = String::new();
@ -285,13 +244,52 @@ fn params(
ctx: &CompletionContext<'_>,
func: hir::Function,
func_kind: &FuncKind,
) -> (Option<hir::SelfParam>, Vec<hir::Param>) {
let self_param = if ctx.has_dot_receiver() || matches!(func_kind, FuncKind::Method(Some(_))) {
) -> 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:
Some(NameRefKind::DotAccess(DotAccess {
kind: DotAccessKind::Method { has_parens: true },
..
})),
..
}) => return None,
IdentContext::NameRef(NameRefContext {
kind: Some(NameRefKind::DotAccess(DotAccess { .. })),
..
}) => true,
IdentContext::NameRef(NameRefContext {
kind:
Some(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?
if ty.is_fn() {
cov_mark::hit!(no_call_parens_if_fn_ptr_needed);
return None;
}
}
let self_param = if has_dot_receiver || matches!(func_kind, FuncKind::Method(Some(_))) {
None
} else {
func.self_param(ctx.db)
};
(self_param, func.params_without_self(ctx.db))
Some((self_param, func.params_without_self(ctx.db)))
}
#[cfg(test)]