2020-11-01 04:48:42 -06:00
|
|
|
//! Renderer for function calls.
|
|
|
|
|
2021-12-21 07:51:06 -06:00
|
|
|
use hir::{db::HirDatabase, AsAssocItem, HirDisplay};
|
2022-03-12 09:10:30 -06:00
|
|
|
use ide_db::{SnippetCap, SymbolKind};
|
2021-03-06 18:56:07 -06:00
|
|
|
use itertools::Itertools;
|
2022-04-04 07:51:51 -05:00
|
|
|
use stdx::{format_to, to_lower_snake_case};
|
2022-03-12 09:10:30 -06:00
|
|
|
use syntax::SmolStr;
|
2020-11-01 03:35:04 -06:00
|
|
|
|
|
|
|
use crate::{
|
2022-05-23 10:40:41 -05:00
|
|
|
context::{
|
2022-06-17 16:36:39 -05:00
|
|
|
CompletionContext, DotAccess, DotAccessKind, IdentContext, NameRefContext, NameRefKind,
|
2022-06-17 17:47:28 -05:00
|
|
|
PathCompletionCtx, PathKind, Qualified,
|
2022-05-23 10:40:41 -05:00
|
|
|
},
|
2022-03-16 10:27:55 -05:00
|
|
|
item::{Builder, CompletionItem, CompletionItemKind, CompletionRelevance},
|
2022-03-12 09:10:30 -06:00
|
|
|
render::{compute_exact_name_match, compute_ref_match, compute_type_match, RenderContext},
|
2022-05-13 12:52:44 -05:00
|
|
|
CallableSnippets,
|
2020-11-01 03:35:04 -06:00
|
|
|
};
|
|
|
|
|
2022-03-12 09:10:30 -06:00
|
|
|
enum FuncKind {
|
2021-12-21 07:51:06 -06:00
|
|
|
Function,
|
|
|
|
Method(Option<hir::Name>),
|
|
|
|
}
|
|
|
|
|
2021-07-21 12:50:28 -05:00
|
|
|
pub(crate) fn render_fn(
|
|
|
|
ctx: RenderContext<'_>,
|
2021-05-31 07:13:09 -05:00
|
|
|
local_name: Option<hir::Name>,
|
2021-12-21 07:51:06 -06:00
|
|
|
func: hir::Function,
|
2022-04-11 11:48:27 -05:00
|
|
|
) -> Builder {
|
2020-11-27 10:00:03 -06:00
|
|
|
let _p = profile::span("render_fn");
|
2022-03-16 10:27:55 -05:00
|
|
|
render(ctx, local_name, func, FuncKind::Function)
|
2021-03-21 19:30:56 -05:00
|
|
|
}
|
|
|
|
|
2021-07-21 12:50:28 -05:00
|
|
|
pub(crate) fn render_method(
|
|
|
|
ctx: RenderContext<'_>,
|
2021-05-28 07:38:09 -05:00
|
|
|
receiver: Option<hir::Name>,
|
2021-05-31 07:13:09 -05:00
|
|
|
local_name: Option<hir::Name>,
|
2021-12-21 07:51:06 -06:00
|
|
|
func: hir::Function,
|
2022-04-11 11:48:27 -05:00
|
|
|
) -> Builder {
|
2021-03-21 19:30:56 -05:00
|
|
|
let _p = profile::span("render_method");
|
2022-03-16 10:27:55 -05:00
|
|
|
render(ctx, local_name, func, FuncKind::Method(receiver))
|
2020-11-03 01:33:13 -06:00
|
|
|
}
|
|
|
|
|
2021-12-21 07:51:06 -06:00
|
|
|
fn render(
|
2022-02-01 19:05:49 -06:00
|
|
|
ctx @ RenderContext { completion, .. }: RenderContext<'_>,
|
2021-12-21 07:51:06 -06:00
|
|
|
local_name: Option<hir::Name>,
|
2020-12-01 04:53:12 -06:00
|
|
|
func: hir::Function,
|
2022-03-12 09:10:30 -06:00
|
|
|
func_kind: FuncKind,
|
2022-04-11 11:48:27 -05:00
|
|
|
) -> Builder {
|
2021-12-21 07:51:06 -06:00
|
|
|
let db = completion.db;
|
2020-11-01 03:35:04 -06:00
|
|
|
|
2021-12-21 07:51:06 -06:00
|
|
|
let name = local_name.unwrap_or_else(|| func.name(db));
|
2021-07-03 15:29:47 -05:00
|
|
|
|
2022-03-12 09:10:30 -06:00
|
|
|
let call = match &func_kind {
|
|
|
|
FuncKind::Method(Some(receiver)) => format!("{}.{}", receiver, &name).into(),
|
2021-12-21 09:57:16 -06:00
|
|
|
_ => name.to_smol_str(),
|
2021-12-21 07:51:06 -06:00
|
|
|
};
|
|
|
|
let mut item = CompletionItem::new(
|
|
|
|
if func.self_param(db).is_some() {
|
|
|
|
CompletionItemKind::Method
|
|
|
|
} else {
|
|
|
|
CompletionItemKind::SymbolKind(SymbolKind::Function)
|
|
|
|
},
|
|
|
|
ctx.source_range(),
|
|
|
|
call.clone(),
|
|
|
|
);
|
|
|
|
|
|
|
|
let ret_type = func.ret_type(db);
|
2022-02-01 05:33:55 -06:00
|
|
|
let is_op_method = func
|
|
|
|
.as_assoc_item(ctx.db())
|
|
|
|
.and_then(|trait_| trait_.containing_trait_or_trait_impl(ctx.db()))
|
|
|
|
.map_or(false, |trait_| completion.is_ops_trait(trait_));
|
2021-12-21 07:51:06 -06:00
|
|
|
item.set_relevance(CompletionRelevance {
|
|
|
|
type_match: compute_type_match(completion, &ret_type),
|
|
|
|
exact_name_match: compute_exact_name_match(completion, &call),
|
2022-02-01 05:33:55 -06:00
|
|
|
is_op_method,
|
2022-02-01 19:05:49 -06:00
|
|
|
..ctx.completion_relevance()
|
2021-12-21 07:51:06 -06:00
|
|
|
});
|
|
|
|
|
|
|
|
if let Some(ref_match) = compute_ref_match(completion, &ret_type) {
|
2022-03-27 05:50:16 -05:00
|
|
|
// 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.
|
2022-06-17 17:47:28 -05:00
|
|
|
let qualified_path = matches!(
|
|
|
|
ctx.completion.ident_ctx,
|
|
|
|
IdentContext::NameRef(NameRefContext {
|
2022-06-18 01:58:47 -05:00
|
|
|
kind: NameRefKind::Path(PathCompletionCtx {
|
2022-06-17 17:47:28 -05:00
|
|
|
qualified: Qualified::With { .. },
|
|
|
|
..
|
2022-06-18 01:58:47 -05:00
|
|
|
}),
|
2022-06-17 17:47:28 -05:00
|
|
|
..
|
|
|
|
})
|
|
|
|
);
|
|
|
|
if matches!(func_kind, FuncKind::Function) && !qualified_path {
|
2021-12-21 07:51:06 -06:00
|
|
|
item.ref_match(ref_match);
|
2021-11-24 09:01:33 -06:00
|
|
|
}
|
2021-03-12 15:46:40 -06:00
|
|
|
}
|
|
|
|
|
2021-12-21 09:57:16 -06:00
|
|
|
item.set_documentation(ctx.docs(func))
|
|
|
|
.set_deprecated(ctx.is_deprecated(func) || ctx.is_deprecated_assoc_item(func))
|
|
|
|
.detail(detail(db, func))
|
2022-03-12 09:10:30 -06:00
|
|
|
.lookup_by(name.to_smol_str());
|
|
|
|
|
|
|
|
match completion.config.snippet_cap {
|
2022-06-17 16:36:39 -05:00
|
|
|
Some(cap) => {
|
|
|
|
if let Some((self_param, params)) = params(completion, func, &func_kind) {
|
|
|
|
add_call_parens(&mut item, completion, cap, call, self_param, params);
|
|
|
|
}
|
2022-03-12 09:10:30 -06:00
|
|
|
}
|
|
|
|
_ => (),
|
|
|
|
}
|
2021-12-21 09:57:16 -06:00
|
|
|
|
2022-03-16 10:27:55 -05:00
|
|
|
match ctx.import_to_add {
|
|
|
|
Some(import_to_add) => {
|
|
|
|
item.add_import(import_to_add);
|
|
|
|
}
|
|
|
|
None => {
|
|
|
|
if let Some(actm) = func.as_assoc_item(db) {
|
|
|
|
if let Some(trt) = actm.containing_trait_or_trait_impl(db) {
|
|
|
|
item.trait_name(trt.name(db).to_smol_str());
|
|
|
|
}
|
2021-12-21 09:57:16 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-04-11 11:48:27 -05:00
|
|
|
item
|
2021-12-21 07:51:06 -06:00
|
|
|
}
|
2021-03-06 18:56:07 -06:00
|
|
|
|
2022-03-12 09:10:30 -06:00
|
|
|
pub(super) fn add_call_parens<'b>(
|
|
|
|
builder: &'b mut Builder,
|
|
|
|
ctx: &CompletionContext,
|
|
|
|
cap: SnippetCap,
|
|
|
|
name: SmolStr,
|
|
|
|
self_param: Option<hir::SelfParam>,
|
|
|
|
params: Vec<hir::Param>,
|
|
|
|
) -> &'b mut Builder {
|
|
|
|
cov_mark::hit!(inserts_parens_for_function_calls);
|
|
|
|
|
|
|
|
let (snippet, label_suffix) = if self_param.is_none() && params.is_empty() {
|
|
|
|
(format!("{}()$0", name), "()")
|
|
|
|
} else {
|
|
|
|
builder.trigger_call_info();
|
2022-05-13 12:52:44 -05:00
|
|
|
let snippet = if let Some(CallableSnippets::FillArguments) = ctx.config.callable {
|
2022-03-12 09:10:30 -06:00
|
|
|
let offset = if self_param.is_some() { 2 } else { 1 };
|
|
|
|
let function_params_snippet =
|
|
|
|
params.iter().enumerate().format_with(", ", |(index, param), f| {
|
|
|
|
match param.name(ctx.db) {
|
|
|
|
Some(n) => {
|
|
|
|
let smol_str = n.to_smol_str();
|
|
|
|
let text = smol_str.as_str().trim_start_matches('_');
|
|
|
|
let ref_ = ref_of_param(ctx, text, param.ty());
|
|
|
|
f(&format_args!("${{{}:{}{}}}", index + offset, ref_, text))
|
|
|
|
}
|
2022-04-04 07:51:51 -05:00
|
|
|
None => {
|
|
|
|
let name = match param.ty().as_adt() {
|
|
|
|
None => "_".to_string(),
|
2022-04-04 08:28:15 -05:00
|
|
|
Some(adt) => adt
|
|
|
|
.name(ctx.db)
|
|
|
|
.as_text()
|
2022-04-04 08:30:49 -05:00
|
|
|
.map(|s| to_lower_snake_case(s.as_str()))
|
2022-04-04 07:33:14 -05:00
|
|
|
.unwrap_or_else(|| "_".to_string()),
|
2022-04-04 07:51:51 -05:00
|
|
|
};
|
|
|
|
f(&format_args!("${{{}:{}}}", index + offset, name))
|
|
|
|
}
|
2022-03-12 09:10:30 -06:00
|
|
|
}
|
|
|
|
});
|
|
|
|
match self_param {
|
|
|
|
Some(self_param) => {
|
|
|
|
format!(
|
|
|
|
"{}(${{1:{}}}{}{})$0",
|
|
|
|
name,
|
|
|
|
self_param.display(ctx.db),
|
|
|
|
if params.is_empty() { "" } else { ", " },
|
|
|
|
function_params_snippet
|
|
|
|
)
|
|
|
|
}
|
|
|
|
None => {
|
|
|
|
format!("{}({})$0", name, function_params_snippet)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
cov_mark::hit!(suppress_arg_snippets);
|
|
|
|
format!("{}($0)", name)
|
|
|
|
};
|
|
|
|
|
|
|
|
(snippet, "(…)")
|
|
|
|
};
|
|
|
|
builder.label(SmolStr::from_iter([&name, label_suffix])).insert_snippet(cap, snippet)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn ref_of_param(ctx: &CompletionContext, arg: &str, ty: &hir::Type) -> &'static str {
|
|
|
|
if let Some(derefed_ty) = ty.remove_ref() {
|
|
|
|
for (name, local) in ctx.locals.iter() {
|
|
|
|
if name.as_text().as_deref() == Some(arg) {
|
|
|
|
return if local.ty(ctx.db) == derefed_ty {
|
|
|
|
if ty.is_mutable_reference() {
|
|
|
|
"&mut "
|
|
|
|
} else {
|
|
|
|
"&"
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
""
|
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
""
|
|
|
|
}
|
|
|
|
|
2021-12-21 07:51:06 -06:00
|
|
|
fn detail(db: &dyn HirDatabase, func: hir::Function) -> String {
|
2022-04-14 11:16:25 -05:00
|
|
|
let mut ret_ty = func.ret_type(db);
|
2022-02-08 16:48:34 -06:00
|
|
|
let mut detail = String::new();
|
|
|
|
|
|
|
|
if func.is_const(db) {
|
|
|
|
format_to!(detail, "const ");
|
|
|
|
}
|
|
|
|
if func.is_async(db) {
|
|
|
|
format_to!(detail, "async ");
|
2022-04-14 11:16:25 -05:00
|
|
|
if let Some(async_ret) = func.async_ret_type(db) {
|
|
|
|
ret_ty = async_ret;
|
|
|
|
}
|
2022-02-08 16:48:34 -06:00
|
|
|
}
|
2022-04-07 11:33:03 -05:00
|
|
|
if func.is_unsafe_to_call(db) {
|
2022-02-08 16:48:34 -06:00
|
|
|
format_to!(detail, "unsafe ");
|
|
|
|
}
|
|
|
|
|
|
|
|
format_to!(detail, "fn({})", params_display(db, func));
|
2021-12-21 07:51:06 -06:00
|
|
|
if !ret_ty.is_unit() {
|
|
|
|
format_to!(detail, " -> {}", ret_ty.display(db));
|
2021-03-12 15:46:40 -06:00
|
|
|
}
|
2021-12-21 07:51:06 -06:00
|
|
|
detail
|
|
|
|
}
|
2021-03-06 18:56:07 -06:00
|
|
|
|
2021-12-21 07:51:06 -06:00
|
|
|
fn params_display(db: &dyn HirDatabase, func: hir::Function) -> String {
|
|
|
|
if let Some(self_param) = func.self_param(db) {
|
|
|
|
let assoc_fn_params = func.assoc_fn_params(db);
|
|
|
|
let params = assoc_fn_params
|
|
|
|
.iter()
|
|
|
|
.skip(1) // skip the self param because we are manually handling that
|
|
|
|
.map(|p| p.ty().display(db));
|
|
|
|
format!(
|
|
|
|
"{}{}",
|
|
|
|
self_param.display(db),
|
|
|
|
params.format_with("", |display, f| {
|
|
|
|
f(&", ")?;
|
|
|
|
f(&display)
|
|
|
|
})
|
|
|
|
)
|
|
|
|
} else {
|
|
|
|
let assoc_fn_params = func.assoc_fn_params(db);
|
|
|
|
assoc_fn_params.iter().map(|p| p.ty().display(db)).join(", ")
|
2020-11-01 03:35:04 -06:00
|
|
|
}
|
2021-12-21 07:51:06 -06:00
|
|
|
}
|
2020-11-01 03:35:04 -06:00
|
|
|
|
2022-03-12 09:10:30 -06:00
|
|
|
fn params(
|
|
|
|
ctx: &CompletionContext<'_>,
|
|
|
|
func: hir::Function,
|
|
|
|
func_kind: &FuncKind,
|
2022-06-17 16:36:39 -05:00
|
|
|
) -> 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:
|
2022-06-18 01:58:47 -05:00
|
|
|
NameRefKind::DotAccess(DotAccess {
|
2022-06-17 16:36:39 -05:00
|
|
|
kind: DotAccessKind::Method { has_parens: true },
|
|
|
|
..
|
2022-06-18 01:58:47 -05:00
|
|
|
}),
|
2022-06-17 16:36:39 -05:00
|
|
|
..
|
|
|
|
}) => return None,
|
|
|
|
IdentContext::NameRef(NameRefContext {
|
2022-06-18 01:58:47 -05:00
|
|
|
kind: NameRefKind::DotAccess(DotAccess { .. }),
|
2022-06-17 16:36:39 -05:00
|
|
|
..
|
|
|
|
}) => true,
|
|
|
|
IdentContext::NameRef(NameRefContext {
|
|
|
|
kind:
|
2022-06-18 01:58:47 -05:00
|
|
|
NameRefKind::Path(
|
2022-06-17 16:36:39 -05:00
|
|
|
PathCompletionCtx {
|
|
|
|
kind: PathKind::Expr { .. }, has_call_parens: true, ..
|
|
|
|
}
|
|
|
|
| PathCompletionCtx { kind: PathKind::Use | PathKind::Type { .. }, .. },
|
2022-06-18 01:58:47 -05:00
|
|
|
),
|
2022-06-17 16:36:39 -05:00
|
|
|
..
|
|
|
|
}) => 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(_))) {
|
2022-03-12 09:10:30 -06:00
|
|
|
None
|
|
|
|
} else {
|
|
|
|
func.self_param(ctx.db)
|
|
|
|
};
|
2022-06-17 16:36:39 -05:00
|
|
|
Some((self_param, func.params_without_self(ctx.db)))
|
2020-11-01 03:35:04 -06:00
|
|
|
}
|
2020-11-01 04:36:30 -06:00
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
|
|
|
use crate::{
|
2021-06-16 14:45:02 -05:00
|
|
|
tests::{check_edit, check_edit_with_config, TEST_CONFIG},
|
2022-05-13 12:52:44 -05:00
|
|
|
CallableSnippets, CompletionConfig,
|
2020-11-01 04:36:30 -06:00
|
|
|
};
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn inserts_parens_for_function_calls() {
|
2021-03-08 14:19:44 -06:00
|
|
|
cov_mark::check!(inserts_parens_for_function_calls);
|
2020-11-01 04:36:30 -06:00
|
|
|
check_edit(
|
|
|
|
"no_args",
|
|
|
|
r#"
|
|
|
|
fn no_args() {}
|
2021-01-06 14:15:48 -06:00
|
|
|
fn main() { no_$0 }
|
2020-11-01 04:36:30 -06:00
|
|
|
"#,
|
|
|
|
r#"
|
|
|
|
fn no_args() {}
|
|
|
|
fn main() { no_args()$0 }
|
|
|
|
"#,
|
|
|
|
);
|
|
|
|
|
|
|
|
check_edit(
|
|
|
|
"with_args",
|
|
|
|
r#"
|
|
|
|
fn with_args(x: i32, y: String) {}
|
2021-01-06 14:15:48 -06:00
|
|
|
fn main() { with_$0 }
|
2020-11-01 04:36:30 -06:00
|
|
|
"#,
|
|
|
|
r#"
|
|
|
|
fn with_args(x: i32, y: String) {}
|
|
|
|
fn main() { with_args(${1:x}, ${2:y})$0 }
|
|
|
|
"#,
|
|
|
|
);
|
|
|
|
|
|
|
|
check_edit(
|
|
|
|
"foo",
|
|
|
|
r#"
|
|
|
|
struct S;
|
|
|
|
impl S {
|
|
|
|
fn foo(&self) {}
|
|
|
|
}
|
2021-01-06 14:15:48 -06:00
|
|
|
fn bar(s: &S) { s.f$0 }
|
2020-11-01 04:36:30 -06:00
|
|
|
"#,
|
|
|
|
r#"
|
|
|
|
struct S;
|
|
|
|
impl S {
|
|
|
|
fn foo(&self) {}
|
|
|
|
}
|
|
|
|
fn bar(s: &S) { s.foo()$0 }
|
|
|
|
"#,
|
|
|
|
);
|
|
|
|
|
|
|
|
check_edit(
|
|
|
|
"foo",
|
|
|
|
r#"
|
|
|
|
struct S {}
|
|
|
|
impl S {
|
|
|
|
fn foo(&self, x: i32) {}
|
|
|
|
}
|
|
|
|
fn bar(s: &S) {
|
2021-01-06 14:15:48 -06:00
|
|
|
s.f$0
|
2020-11-01 04:36:30 -06:00
|
|
|
}
|
|
|
|
"#,
|
|
|
|
r#"
|
|
|
|
struct S {}
|
|
|
|
impl S {
|
|
|
|
fn foo(&self, x: i32) {}
|
|
|
|
}
|
|
|
|
fn bar(s: &S) {
|
|
|
|
s.foo(${1:x})$0
|
|
|
|
}
|
2021-05-28 07:02:53 -05:00
|
|
|
"#,
|
|
|
|
);
|
|
|
|
|
|
|
|
check_edit(
|
2021-06-11 11:26:52 -05:00
|
|
|
"foo",
|
2021-05-28 07:02:53 -05:00
|
|
|
r#"
|
|
|
|
struct S {}
|
|
|
|
impl S {
|
|
|
|
fn foo(&self, x: i32) {
|
|
|
|
$0
|
|
|
|
}
|
|
|
|
}
|
|
|
|
"#,
|
|
|
|
r#"
|
|
|
|
struct S {}
|
|
|
|
impl S {
|
|
|
|
fn foo(&self, x: i32) {
|
|
|
|
self.foo(${1:x})$0
|
|
|
|
}
|
|
|
|
}
|
2020-11-01 04:36:30 -06:00
|
|
|
"#,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2020-12-01 05:23:00 -06:00
|
|
|
#[test]
|
|
|
|
fn parens_for_method_call_as_assoc_fn() {
|
|
|
|
check_edit(
|
|
|
|
"foo",
|
|
|
|
r#"
|
|
|
|
struct S;
|
|
|
|
impl S {
|
|
|
|
fn foo(&self) {}
|
|
|
|
}
|
2021-01-06 14:15:48 -06:00
|
|
|
fn main() { S::f$0 }
|
2020-12-01 05:23:00 -06:00
|
|
|
"#,
|
|
|
|
r#"
|
|
|
|
struct S;
|
|
|
|
impl S {
|
|
|
|
fn foo(&self) {}
|
|
|
|
}
|
|
|
|
fn main() { S::foo(${1:&self})$0 }
|
|
|
|
"#,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2020-11-01 04:36:30 -06:00
|
|
|
#[test]
|
|
|
|
fn suppress_arg_snippets() {
|
2021-03-08 14:19:44 -06:00
|
|
|
cov_mark::check!(suppress_arg_snippets);
|
2020-11-01 04:36:30 -06:00
|
|
|
check_edit_with_config(
|
2022-05-13 12:52:44 -05:00
|
|
|
CompletionConfig { callable: Some(CallableSnippets::AddParentheses), ..TEST_CONFIG },
|
2020-11-01 04:36:30 -06:00
|
|
|
"with_args",
|
|
|
|
r#"
|
|
|
|
fn with_args(x: i32, y: String) {}
|
2021-01-06 14:15:48 -06:00
|
|
|
fn main() { with_$0 }
|
2020-11-01 04:36:30 -06:00
|
|
|
"#,
|
|
|
|
r#"
|
|
|
|
fn with_args(x: i32, y: String) {}
|
|
|
|
fn main() { with_args($0) }
|
|
|
|
"#,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn strips_underscores_from_args() {
|
|
|
|
check_edit(
|
|
|
|
"foo",
|
|
|
|
r#"
|
|
|
|
fn foo(_foo: i32, ___bar: bool, ho_ge_: String) {}
|
2021-01-06 14:15:48 -06:00
|
|
|
fn main() { f$0 }
|
2020-11-01 04:36:30 -06:00
|
|
|
"#,
|
|
|
|
r#"
|
|
|
|
fn foo(_foo: i32, ___bar: bool, ho_ge_: String) {}
|
|
|
|
fn main() { foo(${1:foo}, ${2:bar}, ${3:ho_ge_})$0 }
|
|
|
|
"#,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn insert_ref_when_matching_local_in_scope() {
|
|
|
|
check_edit(
|
|
|
|
"ref_arg",
|
|
|
|
r#"
|
|
|
|
struct Foo {}
|
|
|
|
fn ref_arg(x: &Foo) {}
|
|
|
|
fn main() {
|
|
|
|
let x = Foo {};
|
2021-01-06 14:15:48 -06:00
|
|
|
ref_ar$0
|
2020-11-01 04:36:30 -06:00
|
|
|
}
|
|
|
|
"#,
|
|
|
|
r#"
|
|
|
|
struct Foo {}
|
|
|
|
fn ref_arg(x: &Foo) {}
|
|
|
|
fn main() {
|
|
|
|
let x = Foo {};
|
|
|
|
ref_arg(${1:&x})$0
|
|
|
|
}
|
|
|
|
"#,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn insert_mut_ref_when_matching_local_in_scope() {
|
|
|
|
check_edit(
|
|
|
|
"ref_arg",
|
|
|
|
r#"
|
|
|
|
struct Foo {}
|
|
|
|
fn ref_arg(x: &mut Foo) {}
|
|
|
|
fn main() {
|
|
|
|
let x = Foo {};
|
2021-01-06 14:15:48 -06:00
|
|
|
ref_ar$0
|
2020-11-01 04:36:30 -06:00
|
|
|
}
|
|
|
|
"#,
|
|
|
|
r#"
|
|
|
|
struct Foo {}
|
|
|
|
fn ref_arg(x: &mut Foo) {}
|
|
|
|
fn main() {
|
|
|
|
let x = Foo {};
|
|
|
|
ref_arg(${1:&mut x})$0
|
|
|
|
}
|
|
|
|
"#,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn insert_ref_when_matching_local_in_scope_for_method() {
|
|
|
|
check_edit(
|
|
|
|
"apply_foo",
|
|
|
|
r#"
|
|
|
|
struct Foo {}
|
|
|
|
struct Bar {}
|
|
|
|
impl Bar {
|
|
|
|
fn apply_foo(&self, x: &Foo) {}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn main() {
|
|
|
|
let x = Foo {};
|
|
|
|
let y = Bar {};
|
2021-01-06 14:15:48 -06:00
|
|
|
y.$0
|
2020-11-01 04:36:30 -06:00
|
|
|
}
|
|
|
|
"#,
|
|
|
|
r#"
|
|
|
|
struct Foo {}
|
|
|
|
struct Bar {}
|
|
|
|
impl Bar {
|
|
|
|
fn apply_foo(&self, x: &Foo) {}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn main() {
|
|
|
|
let x = Foo {};
|
|
|
|
let y = Bar {};
|
|
|
|
y.apply_foo(${1:&x})$0
|
|
|
|
}
|
|
|
|
"#,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn trim_mut_keyword_in_func_completion() {
|
|
|
|
check_edit(
|
|
|
|
"take_mutably",
|
|
|
|
r#"
|
|
|
|
fn take_mutably(mut x: &i32) {}
|
|
|
|
|
|
|
|
fn main() {
|
2021-01-06 14:15:48 -06:00
|
|
|
take_m$0
|
2020-11-01 04:36:30 -06:00
|
|
|
}
|
|
|
|
"#,
|
|
|
|
r#"
|
|
|
|
fn take_mutably(mut x: &i32) {}
|
|
|
|
|
|
|
|
fn main() {
|
|
|
|
take_mutably(${1:x})$0
|
|
|
|
}
|
2022-04-04 07:51:51 -05:00
|
|
|
"#,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn complete_pattern_args_with_type_name_if_adt() {
|
|
|
|
check_edit(
|
|
|
|
"qux",
|
|
|
|
r#"
|
|
|
|
struct Foo {
|
|
|
|
bar: i32
|
|
|
|
}
|
|
|
|
|
|
|
|
fn qux(Foo { bar }: Foo) {
|
|
|
|
println!("{}", bar);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn main() {
|
|
|
|
qu$0
|
|
|
|
}
|
|
|
|
"#,
|
|
|
|
r#"
|
|
|
|
struct Foo {
|
|
|
|
bar: i32
|
|
|
|
}
|
|
|
|
|
|
|
|
fn qux(Foo { bar }: Foo) {
|
|
|
|
println!("{}", bar);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn main() {
|
|
|
|
qux(${1:foo})$0
|
|
|
|
}
|
2022-04-20 03:56:20 -05:00
|
|
|
"#,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn complete_fn_param() {
|
|
|
|
// has mut kw
|
|
|
|
check_edit(
|
2022-04-27 04:54:57 -05:00
|
|
|
"mut bar: u32",
|
2022-04-20 03:56:20 -05:00
|
|
|
r#"
|
|
|
|
fn f(foo: (), mut bar: u32) {}
|
|
|
|
fn g(foo: (), mut ba$0)
|
|
|
|
"#,
|
|
|
|
r#"
|
|
|
|
fn f(foo: (), mut bar: u32) {}
|
|
|
|
fn g(foo: (), mut bar: u32)
|
|
|
|
"#,
|
|
|
|
);
|
|
|
|
|
|
|
|
// has type param
|
|
|
|
check_edit(
|
2022-04-27 04:54:57 -05:00
|
|
|
"mut bar: u32",
|
2022-04-20 03:56:20 -05:00
|
|
|
r#"
|
|
|
|
fn g(foo: (), mut ba$0: u32)
|
|
|
|
fn f(foo: (), mut bar: u32) {}
|
|
|
|
"#,
|
|
|
|
r#"
|
|
|
|
fn g(foo: (), mut bar: u32)
|
|
|
|
fn f(foo: (), mut bar: u32) {}
|
|
|
|
"#,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn complete_fn_mut_param_add_comma() {
|
|
|
|
// add leading and trailing comma
|
|
|
|
check_edit(
|
2022-04-27 04:54:57 -05:00
|
|
|
", mut bar: u32,",
|
2022-04-20 03:56:20 -05:00
|
|
|
r#"
|
|
|
|
fn f(foo: (), mut bar: u32) {}
|
|
|
|
fn g(foo: ()mut ba$0 baz: ())
|
|
|
|
"#,
|
|
|
|
r#"
|
|
|
|
fn f(foo: (), mut bar: u32) {}
|
|
|
|
fn g(foo: (), mut bar: u32, baz: ())
|
|
|
|
"#,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn complete_fn_mut_param_has_attribute() {
|
|
|
|
check_edit(
|
2022-04-27 04:54:57 -05:00
|
|
|
r#"#[baz = "qux"] mut bar: u32"#,
|
2022-04-20 03:56:20 -05:00
|
|
|
r#"
|
|
|
|
fn f(foo: (), #[baz = "qux"] mut bar: u32) {}
|
|
|
|
fn g(foo: (), mut ba$0)
|
|
|
|
"#,
|
|
|
|
r#"
|
|
|
|
fn f(foo: (), #[baz = "qux"] mut bar: u32) {}
|
|
|
|
fn g(foo: (), #[baz = "qux"] mut bar: u32)
|
|
|
|
"#,
|
|
|
|
);
|
|
|
|
|
|
|
|
check_edit(
|
2022-04-27 04:54:57 -05:00
|
|
|
r#"#[baz = "qux"] mut bar: u32"#,
|
2022-04-20 03:56:20 -05:00
|
|
|
r#"
|
|
|
|
fn f(foo: (), #[baz = "qux"] mut bar: u32) {}
|
|
|
|
fn g(foo: (), #[baz = "qux"] mut ba$0)
|
|
|
|
"#,
|
|
|
|
r#"
|
|
|
|
fn f(foo: (), #[baz = "qux"] mut bar: u32) {}
|
|
|
|
fn g(foo: (), #[baz = "qux"] mut bar: u32)
|
2022-04-21 10:07:42 -05:00
|
|
|
"#,
|
|
|
|
);
|
|
|
|
|
|
|
|
check_edit(
|
2022-04-27 04:54:57 -05:00
|
|
|
r#", #[baz = "qux"] mut bar: u32"#,
|
2022-04-21 10:07:42 -05:00
|
|
|
r#"
|
|
|
|
fn f(foo: (), #[baz = "qux"] mut bar: u32) {}
|
|
|
|
fn g(foo: ()#[baz = "qux"] mut ba$0)
|
|
|
|
"#,
|
|
|
|
r#"
|
|
|
|
fn f(foo: (), #[baz = "qux"] mut bar: u32) {}
|
|
|
|
fn g(foo: (), #[baz = "qux"] mut bar: u32)
|
2020-11-01 04:36:30 -06:00
|
|
|
"#,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|