@@ -239,22 +239,18 @@ pub(super) fn keyword(
239239 }
240240 let parent = token. parent ( ) ?;
241241 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+
249245 let doc_owner = find_std_module ( & famous_defs, & keyword_mod) ?;
250246 let docs = doc_owner. attrs ( sema. db ) . docs ( ) ?;
251247 let markup = process_markup (
252248 sema. db ,
253249 Definition :: Module ( doc_owner) ,
254- & markup ( Some ( docs. into ( ) ) , token . text ( ) . into ( ) , None ) ?,
250+ & markup ( Some ( docs. into ( ) ) , description , None ) ?,
255251 config,
256252 ) ;
257- Some ( HoverResult { markup, actions : Default :: default ( ) } )
253+ Some ( HoverResult { markup, actions } )
258254}
259255
260256pub ( 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> {
500496 } ;
501497 markup ( None , desc, None )
502498}
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