Skip to content

Commit a31bc66

Browse files
committed
Hide generic constructors if appropriate
1 parent 992b464 commit a31bc66

File tree

1 file changed

+60
-29
lines changed

1 file changed

+60
-29
lines changed

crates/ide/src/inlay_hints.rs

Lines changed: 60 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use either::Either;
22
use hir::{known, Callable, HasVisibility, HirDisplay, Semantics, TypeInfo};
33
use ide_db::RootDatabase;
44
use ide_db::{base_db::FileRange, helpers::FamousDefs};
5+
use itertools::Itertools;
56
use stdx::to_lower_snake_case;
67
use syntax::{
78
ast::{self, AstNode, HasArgList, HasName},
@@ -211,11 +212,11 @@ fn get_bind_pat_hints(
211212
let label = match label {
212213
Some(label) => label,
213214
None => {
214-
let ty = ty.display_truncated(sema.db, config.max_length).to_string();
215-
if Some(&*ty) == get_constructor_name(sema, pat).as_deref() {
215+
let ty_name = ty.display_truncated(sema.db, config.max_length).to_string();
216+
if is_named_constructor(sema, pat, &ty_name).is_some() {
216217
return None;
217218
}
218-
ty.into()
219+
ty_name.into()
219220
}
220221
};
221222

@@ -231,34 +232,60 @@ fn get_bind_pat_hints(
231232
Some(())
232233
}
233234

234-
fn get_constructor_name(sema: &Semantics<RootDatabase>, pat: &ast::IdentPat) -> Option<String> {
235-
let it = pat.syntax().parent()?;
235+
fn is_named_constructor(
236+
sema: &Semantics<RootDatabase>,
237+
pat: &ast::IdentPat,
238+
ty_name: &str,
239+
) -> Option<()> {
240+
let let_node = pat.syntax().parent()?;
236241
let expr = match_ast! {
237-
match it {
242+
match let_node {
238243
ast::LetStmt(it) => it.initializer(),
239244
ast::Condition(it) => it.expr(),
240245
_ => None,
241246
}
247+
}?;
248+
249+
let expr = sema.descend_node_into_attributes(expr.clone()).pop().unwrap_or(expr);
250+
// unwrap postfix expressions
251+
let expr = match expr {
252+
ast::Expr::TryExpr(it) => it.expr(),
253+
ast::Expr::AwaitExpr(it) => it.expr(),
254+
expr => Some(expr),
255+
}?;
256+
let expr = match expr {
257+
ast::Expr::CallExpr(call) => match call.expr()? {
258+
ast::Expr::PathExpr(p) => p,
259+
_ => return None,
260+
},
261+
_ => return None,
242262
};
263+
let path = expr.path()?;
243264

244-
if let Some(expr) = expr {
245-
let expr = sema.descend_node_into_attributes(expr.clone()).pop().unwrap_or(expr);
246-
let expr = match expr {
247-
ast::Expr::TryExpr(it) => it.expr(),
248-
ast::Expr::AwaitExpr(it) => it.expr(),
249-
expr => Some(expr),
250-
}?;
251-
let path = match expr {
252-
ast::Expr::CallExpr(call) => match call.expr()? {
253-
ast::Expr::PathExpr(p) => p.path(),
254-
_ => None,
255-
},
256-
_ => None,
257-
}?;
258-
let seg = path.qualifier()?.segment()?;
259-
return Some(seg.to_string());
265+
// Check for tuple-struct or tuple-variant in which case we can check the last segment
266+
let callable = sema.type_of_expr(&ast::Expr::PathExpr(expr))?.original.as_callable(sema.db);
267+
let callable_kind = callable.map(|it| it.kind());
268+
if let Some(hir::CallableKind::TupleStruct(_) | hir::CallableKind::TupleEnumVariant(_)) =
269+
callable_kind
270+
{
271+
if let Some(ctor) = path.segment() {
272+
return (&ctor.to_string() == ty_name).then(|| ());
273+
}
260274
}
261-
None
275+
276+
// otherwise use the qualifying segment as the constructor name
277+
let qual_seg = path.qualifier()?.segment()?;
278+
let ctor_name = match qual_seg.kind()? {
279+
ast::PathSegmentKind::Name(name_ref) => {
280+
match qual_seg.generic_arg_list().map(|it| it.generic_args()) {
281+
Some(generics) => format!("{}<{}>", name_ref, generics.format(", ")),
282+
None => name_ref.to_string(),
283+
}
284+
}
285+
ast::PathSegmentKind::Type { type_ref: Some(ty), trait_ref: None } => ty.to_string(),
286+
_ => return None,
287+
};
288+
(&ctor_name == ty_name).then(|| ())
262289
}
263290

264291
/// Checks if the type is an Iterator from std::iter and replaces its hint with an `impl Iterator<Item = Ty>`.
@@ -511,10 +538,12 @@ mod tests {
511538
max_length: None,
512539
};
513540

541+
#[track_caller]
514542
fn check(ra_fixture: &str) {
515543
check_with_config(TEST_CONFIG, ra_fixture);
516544
}
517545

546+
#[track_caller]
518547
fn check_params(ra_fixture: &str) {
519548
check_with_config(
520549
InlayHintsConfig {
@@ -527,6 +556,7 @@ mod tests {
527556
);
528557
}
529558

559+
#[track_caller]
530560
fn check_types(ra_fixture: &str) {
531561
check_with_config(
532562
InlayHintsConfig {
@@ -539,6 +569,7 @@ mod tests {
539569
);
540570
}
541571

572+
#[track_caller]
542573
fn check_chains(ra_fixture: &str) {
543574
check_with_config(
544575
InlayHintsConfig {
@@ -551,6 +582,7 @@ mod tests {
551582
);
552583
}
553584

585+
#[track_caller]
554586
fn check_with_config(config: InlayHintsConfig, ra_fixture: &str) {
555587
let (analysis, file_id) = fixture::file(&ra_fixture);
556588
let expected = extract_annotations(&*analysis.file_text(file_id).unwrap());
@@ -560,6 +592,7 @@ mod tests {
560592
assert_eq!(expected, actual, "\nExpected:\n{:#?}\n\nActual:\n{:#?}", expected, actual);
561593
}
562594

595+
#[track_caller]
563596
fn check_expect(config: InlayHintsConfig, ra_fixture: &str, expect: Expect) {
564597
let (analysis, file_id) = fixture::file(&ra_fixture);
565598
let inlay_hints = analysis.inlay_hints(&config, file_id).unwrap();
@@ -1232,11 +1265,12 @@ trait Display {}
12321265
trait Sync {}
12331266
12341267
fn main() {
1235-
let _v = Vec::<Box<&(dyn Display + Sync)>>::new();
1268+
// The block expression wrapping disables the constructor hint hiding logic
1269+
let _v = { Vec::<Box<&(dyn Display + Sync)>>::new() };
12361270
//^^ Vec<Box<&(dyn Display + Sync)>>
1237-
let _v = Vec::<Box<*const (dyn Display + Sync)>>::new();
1271+
let _v = { Vec::<Box<*const (dyn Display + Sync)>>::new() };
12381272
//^^ Vec<Box<*const (dyn Display + Sync)>>
1239-
let _v = Vec::<Box<dyn Display + Sync>>::new();
1273+
let _v = { Vec::<Box<dyn Display + Sync>>::new() };
12401274
//^^ Vec<Box<dyn Display + Sync>>
12411275
}
12421276
"#,
@@ -1304,13 +1338,10 @@ impl Generic<i32> {
13041338
fn main() {
13051339
let strukt = Struct::new();
13061340
let tuple_struct = TupleStruct();
1307-
// ^^^^^^^^^^^^ TupleStruct
13081341
let generic0 = Generic::new();
13091342
// ^^^^^^^^ Generic<i32>
13101343
let generic1 = Generic::<i32>::new();
1311-
// ^^^^^^^^ Generic<i32>
13121344
let generic2 = <Generic<i32>>::new();
1313-
// ^^^^^^^^ Generic<i32>
13141345
}
13151346
13161347
fn fallible() -> ControlFlow<()> {

0 commit comments

Comments
 (0)