@@ -239,22 +239,18 @@ pub(super) fn keyword(
239
239
}
240
240
let parent = token. parent ( ) ?;
241
241
let famous_defs = FamousDefs ( sema, sema. scope ( & parent) . krate ( ) ) ;
242
- let keyword_mod = if token. kind ( ) == T ! [ fn ] && ast:: FnPtrType :: cast ( parent) . is_some ( ) {
243
- // treat fn keyword inside function pointer type as primitive
244
- format ! ( "prim_{}" , token. text( ) )
245
- } else {
246
- // std exposes {}_keyword modules with docstrings on the root to document keywords
247
- format ! ( "{}_keyword" , token. text( ) )
248
- } ;
242
+
243
+ let KeywordHint { description, keyword_mod, actions } = keyword_hints ( sema, token, parent) ;
244
+
249
245
let doc_owner = find_std_module ( & famous_defs, & keyword_mod) ?;
250
246
let docs = doc_owner. attrs ( sema. db ) . docs ( ) ?;
251
247
let markup = process_markup (
252
248
sema. db ,
253
249
Definition :: Module ( doc_owner) ,
254
- & markup ( Some ( docs. into ( ) ) , token . text ( ) . into ( ) , None ) ?,
250
+ & markup ( Some ( docs. into ( ) ) , description , None ) ?,
255
251
config,
256
252
) ;
257
- Some ( HoverResult { markup, actions : Default :: default ( ) } )
253
+ Some ( HoverResult { markup, actions } )
258
254
}
259
255
260
256
pub ( super ) fn try_for_lint ( attr : & ast:: Attr , token : & SyntaxToken ) -> Option < HoverResult > {
@@ -500,3 +496,65 @@ fn local(db: &RootDatabase, it: hir::Local) -> Option<Markup> {
500
496
} ;
501
497
markup ( None , desc, None )
502
498
}
499
+
500
+ struct KeywordHint {
501
+ description : String ,
502
+ keyword_mod : String ,
503
+ actions : Vec < HoverAction > ,
504
+ }
505
+
506
+ impl KeywordHint {
507
+ fn new ( description : String , keyword_mod : String ) -> Self {
508
+ Self { description, keyword_mod, actions : Vec :: default ( ) }
509
+ }
510
+ }
511
+
512
+ fn keyword_hints (
513
+ sema : & Semantics < RootDatabase > ,
514
+ token : & SyntaxToken ,
515
+ parent : syntax:: SyntaxNode ,
516
+ ) -> KeywordHint {
517
+ match token. kind ( ) {
518
+ T ! [ await ] | T ! [ loop ] | T ! [ match ] | T ! [ unsafe ] | T ! [ as ] | T ! [ try] | T ! [ if ] | T ! [ else] => {
519
+ let keyword_mod = format ! ( "{}_keyword" , token. text( ) ) ;
520
+
521
+ match ast:: Expr :: cast ( parent) . and_then ( |site| sema. type_of_expr ( & site) ) {
522
+ // ignore the unit type ()
523
+ Some ( ty) if !ty. adjusted . as_ref ( ) . unwrap_or ( & ty. original ) . is_unit ( ) => {
524
+ let mut targets: Vec < hir:: ModuleDef > = Vec :: new ( ) ;
525
+ let mut push_new_def = |item : hir:: ModuleDef | {
526
+ if !targets. contains ( & item) {
527
+ targets. push ( item) ;
528
+ }
529
+ } ;
530
+ walk_and_push_ty ( sema. db , & ty. original , & mut push_new_def) ;
531
+
532
+ let ty = ty. adjusted ( ) ;
533
+ let description = format ! ( "{}: {}" , token. text( ) , ty. display( sema. db) ) ;
534
+
535
+ KeywordHint {
536
+ description,
537
+ keyword_mod,
538
+ actions : vec ! [ HoverAction :: goto_type_from_targets( sema. db, targets) ] ,
539
+ }
540
+ }
541
+ _ => KeywordHint {
542
+ description : token. text ( ) . to_string ( ) ,
543
+ keyword_mod,
544
+ actions : Vec :: new ( ) ,
545
+ } ,
546
+ }
547
+ }
548
+
549
+ T ! [ fn ] => {
550
+ let module = match ast:: FnPtrType :: cast ( parent) {
551
+ // treat fn keyword inside function pointer type as primitive
552
+ Some ( _) => format ! ( "prim_{}" , token. text( ) ) ,
553
+ None => format ! ( "{}_keyword" , token. text( ) ) ,
554
+ } ;
555
+ KeywordHint :: new ( token. text ( ) . to_string ( ) , module)
556
+ }
557
+
558
+ _ => KeywordHint :: new ( token. text ( ) . to_string ( ) , format ! ( "{}_keyword" , token. text( ) ) ) ,
559
+ }
560
+ }
0 commit comments