1- use std:: fmt;
1+ use std:: {
2+ fmt:: { self , Write } ,
3+ mem:: take,
4+ } ;
25
36use either:: Either ;
4- use hir:: { known, HasVisibility , HirDisplay , Semantics } ;
7+ use hir:: { known, HasVisibility , HirDisplay , HirWrite , ModuleDef , ModuleDefId , Semantics } ;
58use ide_db:: { base_db:: FileRange , famous_defs:: FamousDefs , RootDatabase } ;
69use itertools:: Itertools ;
10+ use stdx:: never;
711use syntax:: {
812 ast:: { self , AstNode } ,
913 match_ast, NodeOrToken , SyntaxNode , TextRange , TextSize ,
1014} ;
1115
12- use crate :: FileId ;
16+ use crate :: { navigation_target :: TryToNav , FileId } ;
1317
1418mod closing_brace;
1519mod implicit_static;
@@ -89,6 +93,7 @@ pub enum InlayTooltip {
8993 HoverOffset ( FileId , TextSize ) ,
9094}
9195
96+ #[ derive( Default ) ]
9297pub struct InlayHintLabel {
9398 pub parts : Vec < InlayHintLabelPart > ,
9499}
@@ -172,6 +177,96 @@ impl fmt::Debug for InlayHintLabelPart {
172177 }
173178}
174179
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+
175270// Feature: Inlay Hints
176271//
177272// rust-analyzer shows additional information inline with the source code.
@@ -224,7 +319,7 @@ pub(crate) fn inlay_hints(
224319
225320fn hints (
226321 hints : & mut Vec < InlayHint > ,
227- famous_defs @ FamousDefs ( sema, _) : & FamousDefs < ' _ , ' _ > ,
322+ FamousDefs ( sema, _) : & FamousDefs < ' _ , ' _ > ,
228323 config : & InlayHintsConfig ,
229324 file_id : FileId ,
230325 node : SyntaxNode ,
@@ -233,14 +328,14 @@ fn hints(
233328 match_ast ! {
234329 match node {
235330 ast:: Expr ( expr) => {
236- chaining:: hints( hints, sema, & famous_defs , config, file_id, & expr) ;
331+ chaining:: hints( hints, sema, config, file_id, & expr) ;
237332 adjustment:: hints( hints, sema, config, & expr) ;
238333 match expr {
239334 ast:: Expr :: CallExpr ( it) => param_name:: hints( hints, sema, config, ast:: Expr :: from( it) ) ,
240335 ast:: Expr :: MethodCallExpr ( it) => {
241336 param_name:: hints( hints, sema, config, ast:: Expr :: from( it) )
242337 }
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) ,
244339 // We could show reborrows for all expressions, but usually that is just noise to the user
245340 // and the main point here is to show why "moving" a mutable reference doesn't necessarily move it
246341 // ast::Expr::PathExpr(_) => reborrow_hints(hints, sema, config, &expr),
@@ -270,13 +365,12 @@ fn hints(
270365 } ;
271366}
272367
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 .
274369fn hint_iterator (
275370 sema : & Semantics < ' _ , RootDatabase > ,
276371 famous_defs : & FamousDefs < ' _ , ' _ > ,
277- config : & InlayHintsConfig ,
278372 ty : & hir:: Type ,
279- ) -> Option < String > {
373+ ) -> Option < hir :: Type > {
280374 let db = sema. db ;
281375 let strukt = ty. strip_references ( ) . as_adt ( ) ?;
282376 let krate = strukt. module ( db) . krate ( ) ;
@@ -299,21 +393,7 @@ fn hint_iterator(
299393 _ => None ,
300394 } ) ?;
301395 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) ;
317397 }
318398 }
319399
0 commit comments