Skip to content

Commit 492e66c

Browse files
committed
feat: suggest name in let_stmt and fn_param
1 parent b207e57 commit 492e66c

File tree

5 files changed

+53
-2
lines changed

5 files changed

+53
-2
lines changed

crates/ide-completion/src/completions.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -617,6 +617,16 @@ impl Completions {
617617
}
618618
self.add_opt(render_struct_pat(RenderContext::new(ctx), pattern_ctx, strukt, local_name));
619619
}
620+
621+
pub(crate) fn suggest_name(&mut self, ctx: &CompletionContext<'_>, name: &str) {
622+
let item = CompletionItem::new(
623+
CompletionItemKind::Binding,
624+
ctx.source_range(),
625+
SmolStr::from(name),
626+
ctx.edition,
627+
);
628+
item.add_to(self, ctx.db);
629+
}
620630
}
621631

622632
/// Calls the callback for each variant of the provided enum with the path to the variant.

crates/ide-completion/src/completions/pattern.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
//! Completes constants and paths in unqualified patterns.
22
33
use hir::{db::DefDatabase, AssocItem, ScopeDef};
4+
use ide_db::syntax_helpers::suggest_name;
45
use syntax::ast::Pat;
56

67
use crate::{
@@ -45,6 +46,18 @@ pub(crate) fn complete_pattern(
4546
return;
4647
}
4748

49+
// Suggest name only in let-stmt and fn param
50+
if pattern_ctx.should_suggest_name {
51+
if let Some(suggested) = ctx
52+
.expected_type
53+
.as_ref()
54+
.map(|ty| ty.strip_references())
55+
.and_then(|ty| suggest_name::for_type(&ty, ctx.db, ctx.edition))
56+
{
57+
acc.suggest_name(ctx, &suggested);
58+
}
59+
}
60+
4861
let refutable = pattern_ctx.refutability == PatternRefutability::Refutable;
4962
let single_variant_enum = |enum_: hir::Enum| ctx.db.enum_data(enum_.into()).variants.len() == 1;
5063

crates/ide-completion/src/context.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,7 @@ pub(crate) struct PatternContext {
264264
pub(crate) refutability: PatternRefutability,
265265
pub(crate) param_ctx: Option<ParamContext>,
266266
pub(crate) has_type_ascription: bool,
267+
pub(crate) should_suggest_name: bool,
267268
pub(crate) parent_pat: Option<ast::Pat>,
268269
pub(crate) ref_token: Option<SyntaxToken>,
269270
pub(crate) mut_token: Option<SyntaxToken>,

crates/ide-completion/src/context/analysis.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1430,10 +1430,23 @@ fn pattern_context_for(
14301430
_ => (None, None),
14311431
};
14321432

1433+
// Only suggest name in let-stmt or fn param
1434+
let should_suggest_name = matches!(
1435+
&pat,
1436+
ast::Pat::IdentPat(it)
1437+
if it.syntax()
1438+
.parent()
1439+
.map_or(false, |node| {
1440+
let kind = node.kind();
1441+
ast::LetStmt::can_cast(kind) || ast::Param::can_cast(kind)
1442+
})
1443+
);
1444+
14331445
PatternContext {
14341446
refutability,
14351447
param_ctx,
14361448
has_type_ascription,
1449+
should_suggest_name,
14371450
parent_pat: pat.syntax().parent().and_then(ast::Pat::cast),
14381451
mut_token,
14391452
ref_token,

crates/ide-db/src/syntax_helpers/suggest_name.rs

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,21 @@ const USELESS_METHODS: &[&str] = &[
6060
"into_future",
6161
];
6262

63+
/// Suggest a name for given type.
64+
///
65+
/// The function will strip references first, and suggest name from the inner type.
66+
///
67+
/// - If `ty` is an ADT, it will suggest the name of the ADT.
68+
/// + If `ty` is wrapped in `Box`, `Option` or `Result`, it will suggest the name from the inner type.
69+
/// - If `ty` is a trait, it will suggest the name of the trait.
70+
/// - If `ty` is an `impl Trait`, it will suggest the name of the first trait.
71+
///
72+
/// If the suggested name conflicts with reserved keywords, it will return `None`.
73+
pub fn for_type(ty: &hir::Type, db: &RootDatabase, edition: Edition) -> Option<String> {
74+
let ty = ty.strip_references();
75+
name_of_type(&ty, db, edition)
76+
}
77+
6378
/// Suggest a unique name for generic parameter.
6479
///
6580
/// `existing_params` is used to check if the name conflicts with existing
@@ -269,10 +284,9 @@ fn var_name_from_pat(pat: &ast::Pat) -> Option<ast::Name> {
269284

270285
fn from_type(expr: &ast::Expr, sema: &Semantics<'_, RootDatabase>) -> Option<String> {
271286
let ty = sema.type_of_expr(expr)?.adjusted();
272-
let ty = ty.remove_ref().unwrap_or(ty);
273287
let edition = sema.scope(expr.syntax())?.krate().edition(sema.db);
274288

275-
name_of_type(&ty, sema.db, edition)
289+
for_type(&ty, sema.db, edition)
276290
}
277291

278292
fn name_of_type(ty: &hir::Type, db: &RootDatabase, edition: Edition) -> Option<String> {

0 commit comments

Comments
 (0)