This commit is contained in:
Lukas Wirth 2021-12-20 14:38:22 +01:00
parent a574434c3f
commit f609efff87
2 changed files with 58 additions and 52 deletions

View File

@ -1,6 +1,5 @@
//! Extensions for `Builder` structure required for item rendering. //! Extensions for `Builder` structure required for item rendering.
use either::Either;
use itertools::Itertools; use itertools::Itertools;
use syntax::ast::{self, HasName}; use syntax::ast::{self, HasName};
@ -8,14 +7,14 @@ use crate::{context::PathKind, item::Builder, patterns::ImmediateLocation, Compl
#[derive(Debug)] #[derive(Debug)]
pub(super) enum Params { pub(super) enum Params {
Named(Vec<(Either<ast::SelfParam, ast::Param>, hir::Param)>), Named(Option<ast::SelfParam>, Vec<(ast::Param, hir::Param)>),
Anonymous(usize), Anonymous(usize),
} }
impl Params { impl Params {
pub(super) fn len(&self) -> usize { pub(super) fn len(&self) -> usize {
match self { match self {
Params::Named(xs) => xs.len(), Params::Named(selv, params) => params.len() + if selv.is_some() { 1 } else { 0 },
Params::Anonymous(len) => *len, Params::Anonymous(len) => *len,
} }
} }
@ -77,24 +76,15 @@ impl Builder {
} else { } else {
self.trigger_call_info(); self.trigger_call_info();
let snippet = match (ctx.config.add_call_argument_snippets, params) { let snippet = match (ctx.config.add_call_argument_snippets, params) {
(true, Params::Named(params)) => { (true, Params::Named(self_param, params)) => {
let offset = if self_param.is_some() { 2 } else { 1 };
let function_params_snippet = params.iter().enumerate().format_with( let function_params_snippet = params.iter().enumerate().format_with(
", ", ", ",
|(index, (param_source, param)), f| { |(index, (param_source, param)), f| {
let name; let name;
let text; let text;
let (ref_, name) = match param_source {
Either::Left(self_param) => (
match self_param.kind() {
ast::SelfParamKind::Owned => "",
ast::SelfParamKind::Ref => "&",
ast::SelfParamKind::MutRef => "&mut ",
},
"self",
),
Either::Right(it) => {
let n = (|| { let n = (|| {
let mut pat = it.pat()?; let mut pat = param_source.pat()?;
loop { loop {
match pat { match pat {
ast::Pat::IdentPat(pat) => break pat.name(), ast::Pat::IdentPat(pat) => break pat.name(),
@ -103,7 +93,7 @@ impl Builder {
} }
} }
})(); })();
match n { let (ref_, name) = match n {
Some(n) => { Some(n) => {
name = n; name = n;
text = name.text(); text = name.text();
@ -112,14 +102,31 @@ impl Builder {
(ref_, text) (ref_, text)
} }
None => ("", "_"), None => ("", "_"),
}
}
}; };
f(&format_args!("${{{}:{}{}}}", index + 1, ref_, name))
f(&format_args!("${{{}:{}{}}}", index + offset, ref_, name))
}, },
); );
match self_param {
Some(self_param) => {
let prefix = match self_param.kind() {
ast::SelfParamKind::Owned => "",
ast::SelfParamKind::Ref => "&",
ast::SelfParamKind::MutRef => "&mut ",
};
format!(
"{}(${{1:{}self}}{}{})$0",
name,
prefix,
if params.is_empty() { "" } else { ", " },
function_params_snippet
)
}
None => {
format!("{}({})$0", name, function_params_snippet) format!("{}({})$0", name, function_params_snippet)
} }
}
}
_ => { _ => {
cov_mark::hit!(suppress_arg_snippets); cov_mark::hit!(suppress_arg_snippets);
format!("{}($0)", name) format!("{}($0)", name)

View File

@ -1,6 +1,5 @@
//! Renderer for function calls. //! Renderer for function calls.
use either::Either;
use hir::{AsAssocItem, HasSource, HirDisplay}; use hir::{AsAssocItem, HasSource, HirDisplay};
use ide_db::SymbolKind; use ide_db::SymbolKind;
use itertools::Itertools; use itertools::Itertools;
@ -56,7 +55,7 @@ struct FunctionRender<'a> {
/// ///
/// It seems that just using `ast` is the best choice -- most of parses /// It seems that just using `ast` is the best choice -- most of parses
/// should be cached anyway. /// should be cached anyway.
ast_node: ast::Fn, param_list: Option<ast::ParamList>,
is_method: bool, is_method: bool,
} }
@ -69,9 +68,9 @@ impl<'a> FunctionRender<'a> {
is_method: bool, is_method: bool,
) -> Option<FunctionRender<'a>> { ) -> Option<FunctionRender<'a>> {
let name = local_name.unwrap_or_else(|| fn_.name(ctx.db())); let name = local_name.unwrap_or_else(|| fn_.name(ctx.db()));
let ast_node = fn_.source(ctx.db())?.value; let param_list = fn_.source(ctx.db())?.value.param_list();
Some(FunctionRender { ctx, name, receiver, func: fn_, ast_node, is_method }) Some(FunctionRender { ctx, name, receiver, func: fn_, param_list, is_method })
} }
fn render(self, import_to_add: Option<ImportEdit>) -> CompletionItem { fn render(self, import_to_add: Option<ImportEdit>) -> CompletionItem {
@ -152,25 +151,25 @@ impl<'a> FunctionRender<'a> {
} }
fn params(&self) -> Params { fn params(&self) -> Params {
let ast_params = match self.ast_node.param_list() { let ast_params = match &self.param_list {
Some(it) => it, Some(it) => it,
None => return Params::Named(Vec::new()), None => return Params::Named(None, Vec::new()),
}; };
let params = ast_params.params().map(Either::Right); let params = ast_params.params();
let params = if self.ctx.completion.has_dot_receiver() || self.receiver.is_some() { let (params, self_param) = if self.ctx.completion.has_dot_receiver()
params.zip(self.func.method_params(self.ctx.db()).unwrap_or_default()).collect() || self.receiver.is_some()
{
(params.zip(self.func.method_params(self.ctx.db()).unwrap_or_default()).collect(), None)
} else { } else {
ast_params let mut assoc_params = self.func.assoc_fn_params(self.ctx.db());
.self_param() if self.func.self_param(self.ctx.db()).is_some() {
.map(Either::Left) assoc_params.remove(0);
.into_iter() }
.chain(params) (params.zip(assoc_params).collect(), ast_params.self_param())
.zip(self.func.assoc_fn_params(self.ctx.db()))
.collect()
}; };
Params::Named(params) Params::Named(self_param, params)
} }
fn kind(&self) -> CompletionItemKind { fn kind(&self) -> CompletionItemKind {