1
- use std:: fmt;
1
+ use std:: {
2
+ fmt:: { self , Write } ,
3
+ mem:: take,
4
+ } ;
2
5
3
6
use either:: Either ;
4
- use hir:: { known, HasVisibility , HirDisplay , Semantics } ;
7
+ use hir:: { known, HasVisibility , HirDisplay , HirWrite , ModuleDef , ModuleDefId , Semantics } ;
5
8
use ide_db:: { base_db:: FileRange , famous_defs:: FamousDefs , RootDatabase } ;
6
9
use itertools:: Itertools ;
10
+ use stdx:: never;
7
11
use syntax:: {
8
12
ast:: { self , AstNode } ,
9
13
match_ast, NodeOrToken , SyntaxNode , TextRange , TextSize ,
10
14
} ;
11
15
12
- use crate :: FileId ;
16
+ use crate :: { navigation_target :: TryToNav , FileId } ;
13
17
14
18
mod closing_brace;
15
19
mod implicit_static;
@@ -89,6 +93,7 @@ pub enum InlayTooltip {
89
93
HoverOffset ( FileId , TextSize ) ,
90
94
}
91
95
96
+ #[ derive( Default ) ]
92
97
pub struct InlayHintLabel {
93
98
pub parts : Vec < InlayHintLabelPart > ,
94
99
}
@@ -172,6 +177,96 @@ impl fmt::Debug for InlayHintLabelPart {
172
177
}
173
178
}
174
179
180
+ #[ derive( Debug ) ]
181
+ struct InlayHintLabelBuilder < ' a > {
182
+ db : & ' a RootDatabase ,
183
+ result : InlayHintLabel ,
184
+ last_part : String ,
185
+ location : Option < FileRange > ,
186
+ }
187
+
188
+ impl fmt:: Write for InlayHintLabelBuilder < ' _ > {
189
+ fn write_str ( & mut self , s : & str ) -> fmt:: Result {
190
+ self . last_part . write_str ( s)
191
+ }
192
+ }
193
+
194
+ impl HirWrite for InlayHintLabelBuilder < ' _ > {
195
+ fn start_location_link ( & mut self , def : ModuleDefId ) {
196
+ if self . location . is_some ( ) {
197
+ never ! ( "location link is already started" ) ;
198
+ }
199
+ self . make_new_part ( ) ;
200
+ let Some ( location) = ModuleDef :: from ( def) . try_to_nav ( self . db ) else { return } ;
201
+ let location =
202
+ FileRange { file_id : location. file_id , range : location. focus_or_full_range ( ) } ;
203
+ self . location = Some ( location) ;
204
+ }
205
+
206
+ fn end_location_link ( & mut self ) {
207
+ self . make_new_part ( ) ;
208
+ }
209
+ }
210
+
211
+ impl InlayHintLabelBuilder < ' _ > {
212
+ fn make_new_part ( & mut self ) {
213
+ self . result . parts . push ( InlayHintLabelPart {
214
+ text : take ( & mut self . last_part ) ,
215
+ linked_location : self . location . take ( ) ,
216
+ } ) ;
217
+ }
218
+
219
+ fn finish ( mut self ) -> InlayHintLabel {
220
+ self . make_new_part ( ) ;
221
+ self . result
222
+ }
223
+ }
224
+
225
+ fn label_of_ty (
226
+ sema : & Semantics < ' _ , RootDatabase > ,
227
+ desc_pat : & impl AstNode ,
228
+ config : & InlayHintsConfig ,
229
+ ty : hir:: Type ,
230
+ ) -> Option < InlayHintLabel > {
231
+ fn rec (
232
+ sema : & Semantics < ' _ , RootDatabase > ,
233
+ famous_defs : & FamousDefs < ' _ , ' _ > ,
234
+ mut max_length : Option < usize > ,
235
+ ty : hir:: Type ,
236
+ label_builder : & mut InlayHintLabelBuilder < ' _ > ,
237
+ ) {
238
+ let iter_item_type = hint_iterator ( sema, & famous_defs, & ty) ;
239
+ match iter_item_type {
240
+ Some ( ty) => {
241
+ const LABEL_START : & str = "impl Iterator<Item = " ;
242
+ const LABEL_END : & str = ">" ;
243
+
244
+ max_length =
245
+ max_length. map ( |len| len. saturating_sub ( LABEL_START . len ( ) + LABEL_END . len ( ) ) ) ;
246
+
247
+ label_builder. write_str ( LABEL_START ) . unwrap ( ) ;
248
+ rec ( sema, famous_defs, max_length, ty, label_builder) ;
249
+ label_builder. write_str ( LABEL_END ) . unwrap ( ) ;
250
+ }
251
+ None => {
252
+ let _ = ty. display_truncated ( sema. db , max_length) . write_to ( label_builder) ;
253
+ }
254
+ } ;
255
+ }
256
+
257
+ let krate = sema. scope ( desc_pat. syntax ( ) ) ?. krate ( ) ;
258
+ let famous_defs = FamousDefs ( sema, krate) ;
259
+ let mut label_builder = InlayHintLabelBuilder {
260
+ db : sema. db ,
261
+ last_part : String :: new ( ) ,
262
+ location : None ,
263
+ result : InlayHintLabel :: default ( ) ,
264
+ } ;
265
+ rec ( sema, & famous_defs, config. max_length , ty, & mut label_builder) ;
266
+ let r = label_builder. finish ( ) ;
267
+ Some ( r)
268
+ }
269
+
175
270
// Feature: Inlay Hints
176
271
//
177
272
// rust-analyzer shows additional information inline with the source code.
@@ -224,7 +319,7 @@ pub(crate) fn inlay_hints(
224
319
225
320
fn hints (
226
321
hints : & mut Vec < InlayHint > ,
227
- famous_defs @ FamousDefs ( sema, _) : & FamousDefs < ' _ , ' _ > ,
322
+ FamousDefs ( sema, _) : & FamousDefs < ' _ , ' _ > ,
228
323
config : & InlayHintsConfig ,
229
324
file_id : FileId ,
230
325
node : SyntaxNode ,
@@ -233,14 +328,14 @@ fn hints(
233
328
match_ast ! {
234
329
match node {
235
330
ast:: Expr ( expr) => {
236
- chaining:: hints( hints, sema, & famous_defs , config, file_id, & expr) ;
331
+ chaining:: hints( hints, sema, config, file_id, & expr) ;
237
332
adjustment:: hints( hints, sema, config, & expr) ;
238
333
match expr {
239
334
ast:: Expr :: CallExpr ( it) => param_name:: hints( hints, sema, config, ast:: Expr :: from( it) ) ,
240
335
ast:: Expr :: MethodCallExpr ( it) => {
241
336
param_name:: hints( hints, sema, config, ast:: Expr :: from( it) )
242
337
}
243
- ast:: Expr :: ClosureExpr ( it) => closure_ret:: hints( hints, sema, & famous_defs , config, file_id, it) ,
338
+ ast:: Expr :: ClosureExpr ( it) => closure_ret:: hints( hints, sema, config, file_id, it) ,
244
339
// We could show reborrows for all expressions, but usually that is just noise to the user
245
340
// and the main point here is to show why "moving" a mutable reference doesn't necessarily move it
246
341
// ast::Expr::PathExpr(_) => reborrow_hints(hints, sema, config, &expr),
@@ -270,13 +365,12 @@ fn hints(
270
365
} ;
271
366
}
272
367
273
- /// Checks if the type is an Iterator from std::iter and replaces its hint with an `impl Iterator<Item = Ty>` .
368
+ /// Checks if the type is an Iterator from std::iter and returns its item type .
274
369
fn hint_iterator (
275
370
sema : & Semantics < ' _ , RootDatabase > ,
276
371
famous_defs : & FamousDefs < ' _ , ' _ > ,
277
- config : & InlayHintsConfig ,
278
372
ty : & hir:: Type ,
279
- ) -> Option < String > {
373
+ ) -> Option < hir :: Type > {
280
374
let db = sema. db ;
281
375
let strukt = ty. strip_references ( ) . as_adt ( ) ?;
282
376
let krate = strukt. module ( db) . krate ( ) ;
@@ -299,21 +393,7 @@ fn hint_iterator(
299
393
_ => None ,
300
394
} ) ?;
301
395
if let Some ( ty) = ty. normalize_trait_assoc_type ( db, & [ ] , assoc_type_item) {
302
- const LABEL_START : & str = "impl Iterator<Item = " ;
303
- const LABEL_END : & str = ">" ;
304
-
305
- let ty_display = hint_iterator ( sema, famous_defs, config, & ty)
306
- . map ( |assoc_type_impl| assoc_type_impl. to_string ( ) )
307
- . unwrap_or_else ( || {
308
- ty. display_truncated (
309
- db,
310
- config
311
- . max_length
312
- . map ( |len| len. saturating_sub ( LABEL_START . len ( ) + LABEL_END . len ( ) ) ) ,
313
- )
314
- . to_string ( )
315
- } ) ;
316
- return Some ( format ! ( "{}{}{}" , LABEL_START , ty_display, LABEL_END ) ) ;
396
+ return Some ( ty) ;
317
397
}
318
398
}
319
399
0 commit comments