Skip to content

Commit 7f9c4a5

Browse files
bors[bot]Veykril
andauthored
Merge #9130
9130: Prefix/suffix parameter inlay hint hiding heuristic is more strict r=Veykril a=Veykril Instead of just plainly checking prefix/suffix of the argument string to the parameter name we only check for prefixes and suffixes if they are split apart via an underscore meaning, with the argument `foo`, it will be hidden for the parameter name `foo_bar` but not for `foobar`. bors r+ Closes #8878 Co-authored-by: Lukas Wirth <[email protected]>
2 parents 1dbdac8 + cc762c3 commit 7f9c4a5

File tree

1 file changed

+57
-70
lines changed

1 file changed

+57
-70
lines changed

crates/ide/src/inlay_hints.rs

Lines changed: 57 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -150,17 +150,11 @@ fn get_param_name_hints(
150150
return None;
151151
}
152152

153-
let args = match &expr {
154-
ast::Expr::CallExpr(expr) => expr.arg_list()?.args(),
155-
ast::Expr::MethodCallExpr(expr) => expr.arg_list()?.args(),
156-
_ => return None,
157-
};
158-
159-
let callable = get_callable(sema, &expr)?;
153+
let (callable, arg_list) = get_callable(sema, &expr)?;
160154
let hints = callable
161155
.params(sema.db)
162156
.into_iter()
163-
.zip(args)
157+
.zip(arg_list.args())
164158
.filter_map(|((param, _ty), arg)| {
165159
let param_name = match param? {
166160
Either::Left(_) => "self".to_string(),
@@ -171,7 +165,7 @@ fn get_param_name_hints(
171165
};
172166
Some((param_name, arg))
173167
})
174-
.filter(|(param_name, arg)| should_show_param_name_hint(sema, &callable, param_name, &arg))
168+
.filter(|(param_name, arg)| !should_hide_param_name_hint(sema, &callable, param_name, &arg))
175169
.map(|(param_name, arg)| InlayHint {
176170
range: arg.syntax().text_range(),
177171
kind: InlayKind::ParameterHint,
@@ -289,15 +283,9 @@ fn should_not_display_type_hint(
289283
for node in bind_pat.syntax().ancestors() {
290284
match_ast! {
291285
match node {
292-
ast::LetStmt(it) => {
293-
return it.ty().is_some()
294-
},
295-
ast::Param(it) => {
296-
return it.ty().is_some()
297-
},
298-
ast::MatchArm(_it) => {
299-
return pat_is_enum_variant(db, bind_pat, pat_ty);
300-
},
286+
ast::LetStmt(it) => return it.ty().is_some(),
287+
ast::Param(it) => return it.ty().is_some(),
288+
ast::MatchArm(_it) => return pat_is_enum_variant(db, bind_pat, pat_ty),
301289
ast::IfExpr(it) => {
302290
return it.condition().and_then(|condition| condition.pat()).is_some()
303291
&& pat_is_enum_variant(db, bind_pat, pat_ty);
@@ -322,76 +310,66 @@ fn should_not_display_type_hint(
322310
false
323311
}
324312

325-
fn should_show_param_name_hint(
313+
fn should_hide_param_name_hint(
326314
sema: &Semantics<RootDatabase>,
327315
callable: &hir::Callable,
328316
param_name: &str,
329317
argument: &ast::Expr,
330318
) -> bool {
319+
// hide when:
320+
// - the parameter name is a suffix of the function's name
321+
// - the argument is an enum whose name is equal to the parameter
322+
// - exact argument<->parameter match(ignoring leading underscore) or argument is a prefix/suffix
323+
// of parameter with _ splitting it off
324+
// - param starts with `ra_fixture`
325+
// - param is a well known name in an unary function
326+
331327
let param_name = param_name.trim_start_matches('_');
328+
if param_name.is_empty() {
329+
return true;
330+
}
331+
332332
let fn_name = match callable.kind() {
333333
hir::CallableKind::Function(it) => Some(it.name(sema.db).to_string()),
334-
hir::CallableKind::TupleStruct(_)
335-
| hir::CallableKind::TupleEnumVariant(_)
336-
| hir::CallableKind::Closure => None,
334+
_ => None,
337335
};
338-
339-
if param_name.is_empty()
340-
|| Some(param_name) == fn_name.as_ref().map(|s| s.trim_start_matches('_'))
341-
|| is_argument_similar_to_param_name(sema, argument, param_name)
342-
|| is_param_name_similar_to_fn_name(param_name, callable, fn_name.as_ref())
336+
let fn_name = fn_name.as_deref();
337+
is_param_name_suffix_of_fn_name(param_name, callable, fn_name)
338+
|| is_enum_name_similar_to_param_name(sema, argument, param_name)
339+
|| is_argument_similar_to_param_name(argument, param_name)
343340
|| param_name.starts_with("ra_fixture")
344-
{
345-
return false;
346-
}
347-
348-
// avoid displaying hints for common functions like map, filter, etc.
349-
// or other obvious words used in std
350-
!(callable.n_params() == 1 && is_obvious_param(param_name))
341+
|| (callable.n_params() == 1 && is_obvious_param(param_name))
351342
}
352343

353-
fn is_argument_similar_to_param_name(
354-
sema: &Semantics<RootDatabase>,
355-
argument: &ast::Expr,
356-
param_name: &str,
357-
) -> bool {
358-
if is_enum_name_similar_to_param_name(sema, argument, param_name) {
359-
return true;
360-
}
344+
fn is_argument_similar_to_param_name(argument: &ast::Expr, param_name: &str) -> bool {
361345
match get_string_representation(argument) {
362346
None => false,
363-
Some(argument_string) => {
364-
let num_leading_underscores =
365-
argument_string.bytes().take_while(|&c| c == b'_').count();
366-
367-
// Does the argument name begin with the parameter name? Ignore leading underscores.
368-
let mut arg_bytes = argument_string.bytes().skip(num_leading_underscores);
369-
let starts_with_pattern = param_name.bytes().all(
370-
|expected| matches!(arg_bytes.next(), Some(actual) if expected.eq_ignore_ascii_case(&actual)),
371-
);
372-
373-
if starts_with_pattern {
374-
return true;
347+
Some(argument) => {
348+
let mut res = false;
349+
if let Some(first) = argument.bytes().skip_while(|&c| c == b'_').position(|c| c == b'_')
350+
{
351+
res |= param_name == argument[..first].trim_start_matches('_');
375352
}
376-
377-
// Does the argument name end with the parameter name?
378-
let mut arg_bytes = argument_string.bytes().skip(num_leading_underscores);
379-
param_name.bytes().rev().all(
380-
|expected| matches!(arg_bytes.next_back(), Some(actual) if expected.eq_ignore_ascii_case(&actual)),
381-
)
353+
if let Some(last) =
354+
argument.bytes().rev().skip_while(|&c| c == b'_').position(|c| c == b'_')
355+
{
356+
res |= param_name == argument[last..].trim_end_matches('_');
357+
}
358+
res |= argument == param_name;
359+
res
382360
}
383361
}
384362
}
385363

386-
fn is_param_name_similar_to_fn_name(
364+
/// Hide the parameter name of an unary function if it is a `_` - prefixed suffix of the function's name, or equal.
365+
///
366+
/// `fn strip_suffix(suffix)` will be hidden.
367+
/// `fn stripsuffix(suffix)` will not be hidden.
368+
fn is_param_name_suffix_of_fn_name(
387369
param_name: &str,
388370
callable: &Callable,
389-
fn_name: Option<&String>,
371+
fn_name: Option<&str>,
390372
) -> bool {
391-
// if it's the only parameter, don't show it if:
392-
// - is the same as the function name, or
393-
// - the function ends with '_' + param_name
394-
395373
match (callable.n_params(), fn_name) {
396374
(1, Some(function)) => {
397375
function == param_name
@@ -424,23 +402,32 @@ fn get_string_representation(expr: &ast::Expr) -> Option<String> {
424402
}
425403
}
426404
ast::Expr::FieldExpr(field_expr) => Some(field_expr.name_ref()?.to_string()),
427-
ast::Expr::PathExpr(path_expr) => Some(path_expr.to_string()),
405+
ast::Expr::PathExpr(path_expr) => Some(path_expr.path()?.segment()?.to_string()),
428406
ast::Expr::PrefixExpr(prefix_expr) => get_string_representation(&prefix_expr.expr()?),
429407
ast::Expr::RefExpr(ref_expr) => get_string_representation(&ref_expr.expr()?),
430408
_ => None,
431409
}
432410
}
433411

434412
fn is_obvious_param(param_name: &str) -> bool {
413+
// avoid displaying hints for common functions like map, filter, etc.
414+
// or other obvious words used in std
435415
let is_obvious_param_name =
436416
matches!(param_name, "predicate" | "value" | "pat" | "rhs" | "other");
437417
param_name.len() == 1 || is_obvious_param_name
438418
}
439419

440-
fn get_callable(sema: &Semantics<RootDatabase>, expr: &ast::Expr) -> Option<hir::Callable> {
420+
fn get_callable(
421+
sema: &Semantics<RootDatabase>,
422+
expr: &ast::Expr,
423+
) -> Option<(hir::Callable, ast::ArgList)> {
441424
match expr {
442-
ast::Expr::CallExpr(expr) => sema.type_of_expr(&expr.expr()?)?.as_callable(sema.db),
443-
ast::Expr::MethodCallExpr(expr) => sema.resolve_method_call_as_callable(expr),
425+
ast::Expr::CallExpr(expr) => {
426+
sema.type_of_expr(&expr.expr()?)?.as_callable(sema.db).zip(expr.arg_list())
427+
}
428+
ast::Expr::MethodCallExpr(expr) => {
429+
sema.resolve_method_call_as_callable(expr).zip(expr.arg_list())
430+
}
444431
_ => None,
445432
}
446433
}

0 commit comments

Comments
 (0)