@@ -2,6 +2,7 @@ use either::Either;
2
2
use hir:: { known, Callable , HasVisibility , HirDisplay , Semantics , TypeInfo } ;
3
3
use ide_db:: RootDatabase ;
4
4
use ide_db:: { base_db:: FileRange , helpers:: FamousDefs } ;
5
+ use itertools:: Itertools ;
5
6
use stdx:: to_lower_snake_case;
6
7
use syntax:: {
7
8
ast:: { self , AstNode , HasArgList , HasName } ,
@@ -198,28 +199,95 @@ fn get_bind_pat_hints(
198
199
199
200
let descended = sema. descend_node_into_attributes ( pat. clone ( ) ) . pop ( ) ;
200
201
let desc_pat = descended. as_ref ( ) . unwrap_or ( pat) ;
201
- let krate = sema. scope ( desc_pat. syntax ( ) ) . module ( ) . map ( |it| it. krate ( ) ) ;
202
- let famous_defs = FamousDefs ( sema, krate) ;
203
-
204
202
let ty = sema. type_of_pat ( & desc_pat. clone ( ) . into ( ) ) ?. original ;
205
203
206
204
if should_not_display_type_hint ( sema, & pat, & ty) {
207
205
return None ;
208
206
}
209
207
208
+ let krate = sema. scope ( desc_pat. syntax ( ) ) . module ( ) . map ( |it| it. krate ( ) ) ;
209
+ let famous_defs = FamousDefs ( sema, krate) ;
210
+ let label = hint_iterator ( sema, & famous_defs, config, & ty) ;
211
+
212
+ let label = match label {
213
+ Some ( label) => label,
214
+ None => {
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 ( ) {
217
+ return None ;
218
+ }
219
+ ty_name. into ( )
220
+ }
221
+ } ;
222
+
210
223
acc. push ( InlayHint {
211
224
range : match pat. name ( ) {
212
225
Some ( name) => name. syntax ( ) . text_range ( ) ,
213
226
None => pat. syntax ( ) . text_range ( ) ,
214
227
} ,
215
228
kind : InlayKind :: TypeHint ,
216
- label : hint_iterator ( sema, & famous_defs, config, & ty)
217
- . unwrap_or_else ( || ty. display_truncated ( sema. db , config. max_length ) . to_string ( ) . into ( ) ) ,
229
+ label,
218
230
} ) ;
219
231
220
232
Some ( ( ) )
221
233
}
222
234
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 ( ) ?;
241
+ let expr = match_ast ! {
242
+ match let_node {
243
+ ast:: LetStmt ( it) => it. initializer( ) ,
244
+ ast:: Condition ( it) => it. expr( ) ,
245
+ _ => None ,
246
+ }
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 ,
262
+ } ;
263
+ let path = expr. path ( ) ?;
264
+
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
+ }
274
+ }
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 ( || ( ) )
289
+ }
290
+
223
291
/// Checks if the type is an Iterator from std::iter and replaces its hint with an `impl Iterator<Item = Ty>`.
224
292
fn hint_iterator (
225
293
sema : & Semantics < RootDatabase > ,
@@ -470,10 +538,12 @@ mod tests {
470
538
max_length : None ,
471
539
} ;
472
540
541
+ #[ track_caller]
473
542
fn check ( ra_fixture : & str ) {
474
543
check_with_config ( TEST_CONFIG , ra_fixture) ;
475
544
}
476
545
546
+ #[ track_caller]
477
547
fn check_params ( ra_fixture : & str ) {
478
548
check_with_config (
479
549
InlayHintsConfig {
@@ -486,6 +556,7 @@ mod tests {
486
556
) ;
487
557
}
488
558
559
+ #[ track_caller]
489
560
fn check_types ( ra_fixture : & str ) {
490
561
check_with_config (
491
562
InlayHintsConfig {
@@ -498,6 +569,7 @@ mod tests {
498
569
) ;
499
570
}
500
571
572
+ #[ track_caller]
501
573
fn check_chains ( ra_fixture : & str ) {
502
574
check_with_config (
503
575
InlayHintsConfig {
@@ -510,6 +582,7 @@ mod tests {
510
582
) ;
511
583
}
512
584
585
+ #[ track_caller]
513
586
fn check_with_config ( config : InlayHintsConfig , ra_fixture : & str ) {
514
587
let ( analysis, file_id) = fixture:: file ( & ra_fixture) ;
515
588
let expected = extract_annotations ( & * analysis. file_text ( file_id) . unwrap ( ) ) ;
@@ -519,6 +592,7 @@ mod tests {
519
592
assert_eq ! ( expected, actual, "\n Expected:\n {:#?}\n \n Actual:\n {:#?}" , expected, actual) ;
520
593
}
521
594
595
+ #[ track_caller]
522
596
fn check_expect ( config : InlayHintsConfig , ra_fixture : & str , expect : Expect ) {
523
597
let ( analysis, file_id) = fixture:: file ( & ra_fixture) ;
524
598
let inlay_hints = analysis. inlay_hints ( & config, file_id) . unwrap ( ) ;
@@ -1191,11 +1265,12 @@ trait Display {}
1191
1265
trait Sync {}
1192
1266
1193
1267
fn main() {
1194
- 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() };
1195
1270
//^^ Vec<Box<&(dyn Display + Sync)>>
1196
- let _v = Vec::<Box<*const (dyn Display + Sync)>>::new();
1271
+ let _v = { Vec::<Box<*const (dyn Display + Sync)>>::new() } ;
1197
1272
//^^ Vec<Box<*const (dyn Display + Sync)>>
1198
- let _v = Vec::<Box<dyn Display + Sync>>::new();
1273
+ let _v = { Vec::<Box<dyn Display + Sync>>::new() } ;
1199
1274
//^^ Vec<Box<dyn Display + Sync>>
1200
1275
}
1201
1276
"# ,
@@ -1234,6 +1309,48 @@ fn main() {
1234
1309
) ;
1235
1310
}
1236
1311
1312
+ #[ test]
1313
+ fn skip_constructor_type_hints ( ) {
1314
+ check_types (
1315
+ r#"
1316
+ //- minicore: try
1317
+ use core::ops::ControlFlow;
1318
+
1319
+ struct Struct;
1320
+ struct TupleStruct();
1321
+
1322
+ impl Struct {
1323
+ fn new() -> Self {
1324
+ Struct
1325
+ }
1326
+ fn try_new() -> ControlFlow<(), Self> {
1327
+ ControlFlow::Continue(Struct)
1328
+ }
1329
+ }
1330
+
1331
+ struct Generic<T>(T);
1332
+ impl Generic<i32> {
1333
+ fn new() -> Self {
1334
+ Generic(0)
1335
+ }
1336
+ }
1337
+
1338
+ fn main() {
1339
+ let strukt = Struct::new();
1340
+ let tuple_struct = TupleStruct();
1341
+ let generic0 = Generic::new();
1342
+ // ^^^^^^^^ Generic<i32>
1343
+ let generic1 = Generic::<i32>::new();
1344
+ let generic2 = <Generic<i32>>::new();
1345
+ }
1346
+
1347
+ fn fallible() -> ControlFlow<()> {
1348
+ let strukt = Struct::try_new()?;
1349
+ }
1350
+ "# ,
1351
+ ) ;
1352
+ }
1353
+
1237
1354
#[ test]
1238
1355
fn closures ( ) {
1239
1356
check (
0 commit comments