@@ -15,7 +15,7 @@ use ide_db::{
1515 FxIndexSet , RootDatabase ,
1616} ;
1717use itertools:: Itertools ;
18- use syntax:: { ast, match_ast , AstNode , SyntaxKind :: * , SyntaxNode , SyntaxToken , T } ;
18+ use syntax:: { ast, AstNode , SyntaxKind :: * , SyntaxNode , T } ;
1919
2020use crate :: {
2121 doc_links:: token_as_doc_comment,
@@ -86,30 +86,38 @@ pub struct HoverResult {
8686// image::https://user-images.githubusercontent.com/48062697/113020658-b5f98b80-917a-11eb-9f88-3dbc27320c95.gif[]
8787pub ( crate ) fn hover (
8888 db : & RootDatabase ,
89- file_range : FileRange ,
89+ frange @ FileRange { file_id , range } : FileRange ,
9090 config : & HoverConfig ,
9191) -> Option < RangeInfo < HoverResult > > {
9292 let sema = & hir:: Semantics :: new ( db) ;
93- let mut res = hover_impl ( sema, file_range, config) ?;
93+ let file = sema. parse ( file_id) . syntax ( ) . clone ( ) ;
94+ let mut res = if range. is_empty ( ) {
95+ hover_simple ( sema, FilePosition { file_id, offset : range. start ( ) } , file, config)
96+ } else {
97+ hover_ranged ( sema, frange, file, config)
98+ } ?;
99+
94100 if let HoverDocFormat :: PlainText = config. format {
95101 res. info . markup = remove_markdown ( res. info . markup . as_str ( ) ) . into ( ) ;
96102 }
97103 Some ( res)
98104}
99105
100- fn hover_impl (
106+ fn hover_simple (
101107 sema : & Semantics < ' _ , RootDatabase > ,
102- FileRange { file_id, range } : FileRange ,
108+ FilePosition { file_id, offset } : FilePosition ,
109+ file : SyntaxNode ,
103110 config : & HoverConfig ,
104111) -> Option < RangeInfo < HoverResult > > {
105- let file = sema. parse ( file_id) . syntax ( ) . clone ( ) ;
106- if !range. is_empty ( ) {
107- return hover_ranged ( & file, range, sema, config) ;
108- }
109- let offset = range. start ( ) ;
110-
111112 let original_token = pick_best_token ( file. token_at_offset ( offset) , |kind| match kind {
112- IDENT | INT_NUMBER | LIFETIME_IDENT | T ! [ self ] | T ! [ super ] | T ! [ crate ] | T ! [ Self ] => 4 ,
113+ IDENT
114+ | INT_NUMBER
115+ | LIFETIME_IDENT
116+ | T ! [ self ]
117+ | T ! [ super ]
118+ | T ! [ crate ]
119+ | T ! [ Self ]
120+ | T ! [ _] => 4 ,
113121 // index and prefix ops
114122 T ! [ '[' ] | T ! [ ']' ] | T ! [ ?] | T ! [ * ] | T ! [ -] | T ! [ !] => 3 ,
115123 kind if kind. is_keyword ( ) => 2 ,
@@ -142,19 +150,18 @@ fn hover_impl(
142150 } else {
143151 sema. descend_into_macros_with_same_text ( original_token. clone ( ) )
144152 } ;
153+ let descended = || descended. iter ( ) ;
145154
146- // try lint hover
147- let result = descended
148- . iter ( )
155+ let result = descended ( )
156+ // try lint hover
149157 . find_map ( |token| {
150158 // FIXME: Definition should include known lints and the like instead of having this special case here
151159 let attr = token. parent_ancestors ( ) . find_map ( ast:: Attr :: cast) ?;
152160 render:: try_for_lint ( & attr, token)
153161 } )
154- // try item definitions
162+ // try definitions
155163 . or_else ( || {
156- descended
157- . iter ( )
164+ descended ( )
158165 . filter_map ( |token| {
159166 let node = token. parent ( ) ?;
160167 let class = IdentClass :: classify_token ( sema, token) ?;
@@ -175,10 +182,12 @@ fn hover_impl(
175182 } )
176183 } )
177184 // try keywords
178- . or_else ( || descended. iter ( ) . find_map ( |token| render:: keyword ( sema, config, token) ) )
179- // try rest item hover
185+ . or_else ( || descended ( ) . find_map ( |token| render:: keyword ( sema, config, token) ) )
186+ // try _ hovers
187+ . or_else ( || descended ( ) . find_map ( |token| render:: underscore ( sema, config, token) ) )
188+ // try rest pattern hover
180189 . or_else ( || {
181- descended. iter ( ) . find_map ( |token| {
190+ descended ( ) . find_map ( |token| {
182191 if token. kind ( ) != DOT2 {
183192 return None ;
184193 }
@@ -194,51 +203,24 @@ fn hover_impl(
194203 } )
195204 } ) ;
196205
197- result
198- . map ( |mut res : HoverResult | {
199- res. actions = dedupe_or_merge_hover_actions ( res. actions ) ;
200- RangeInfo :: new ( original_token. text_range ( ) , res)
201- } )
202- // fallback to type hover if there aren't any other suggestions
203- // this finds its own range instead of using the closest token's range
204- . or_else ( || {
205- descended. iter ( ) . find_map ( |token| hover_type_fallback ( sema, config, token, token) )
206- } )
207- }
208-
209- pub ( crate ) fn hover_for_definition (
210- sema : & Semantics < ' _ , RootDatabase > ,
211- file_id : FileId ,
212- definition : Definition ,
213- node : & SyntaxNode ,
214- config : & HoverConfig ,
215- ) -> Option < HoverResult > {
216- let famous_defs = match & definition {
217- Definition :: BuiltinType ( _) => Some ( FamousDefs ( sema, sema. scope ( node) ?. krate ( ) ) ) ,
218- _ => None ,
219- } ;
220- render:: definition ( sema. db , definition, famous_defs. as_ref ( ) , config) . map ( |markup| {
221- HoverResult {
222- markup : render:: process_markup ( sema. db , definition, & markup, config) ,
223- actions : show_implementations_action ( sema. db , definition)
224- . into_iter ( )
225- . chain ( show_fn_references_action ( sema. db , definition) )
226- . chain ( runnable_action ( sema, definition, file_id) )
227- . chain ( goto_type_action_for_def ( sema. db , definition) )
228- . collect ( ) ,
229- }
206+ result. map ( |mut res : HoverResult | {
207+ res. actions = dedupe_or_merge_hover_actions ( res. actions ) ;
208+ RangeInfo :: new ( original_token. text_range ( ) , res)
230209 } )
231210}
232211
233212fn hover_ranged (
234- file : & SyntaxNode ,
235- range : syntax:: TextRange ,
236213 sema : & Semantics < ' _ , RootDatabase > ,
214+ FileRange { range, .. } : FileRange ,
215+ file : SyntaxNode ,
237216 config : & HoverConfig ,
238217) -> Option < RangeInfo < HoverResult > > {
239218 // FIXME: make this work in attributes
240- let expr_or_pat =
241- file. covering_element ( range) . ancestors ( ) . find_map ( Either :: < ast:: Expr , ast:: Pat > :: cast) ?;
219+ let expr_or_pat = file
220+ . covering_element ( range)
221+ . ancestors ( )
222+ . take_while ( |it| ast:: MacroCall :: can_cast ( it. kind ( ) ) || !ast:: Item :: can_cast ( it. kind ( ) ) )
223+ . find_map ( Either :: < ast:: Expr , ast:: Pat > :: cast) ?;
242224 let res = match & expr_or_pat {
243225 Either :: Left ( ast:: Expr :: TryExpr ( try_expr) ) => render:: try_expr ( sema, config, try_expr) ,
244226 Either :: Left ( ast:: Expr :: PrefixExpr ( prefix_expr) )
@@ -248,7 +230,7 @@ fn hover_ranged(
248230 }
249231 _ => None ,
250232 } ;
251- let res = res. or_else ( || render:: type_info ( sema, config, & expr_or_pat) ) ;
233+ let res = res. or_else ( || render:: type_info_of ( sema, config, & expr_or_pat) ) ;
252234 res. map ( |it| {
253235 let range = match expr_or_pat {
254236 Either :: Left ( it) => it. syntax ( ) . text_range ( ) ,
@@ -258,37 +240,31 @@ fn hover_ranged(
258240 } )
259241}
260242
261- fn hover_type_fallback (
243+ pub ( crate ) fn hover_for_definition (
262244 sema : & Semantics < ' _ , RootDatabase > ,
245+ file_id : FileId ,
246+ definition : Definition ,
247+ node : & SyntaxNode ,
263248 config : & HoverConfig ,
264- token : & SyntaxToken ,
265- original_token : & SyntaxToken ,
266- ) -> Option < RangeInfo < HoverResult > > {
267- let node =
268- token. parent_ancestors ( ) . take_while ( |it| !ast:: Item :: can_cast ( it. kind ( ) ) ) . find ( |n| {
269- ast:: Expr :: can_cast ( n. kind ( ) )
270- || ast:: Pat :: can_cast ( n. kind ( ) )
271- || ast:: Type :: can_cast ( n. kind ( ) )
272- } ) ?;
273-
274- let expr_or_pat = match_ast ! {
275- match node {
276- ast:: Expr ( it) => Either :: Left ( it) ,
277- ast:: Pat ( it) => Either :: Right ( it) ,
278- // If this node is a MACRO_CALL, it means that `descend_into_macros_many` failed to resolve.
279- // (e.g expanding a builtin macro). So we give up here.
280- ast:: MacroCall ( _it) => return None ,
281- _ => return None ,
282- }
249+ ) -> Option < HoverResult > {
250+ let famous_defs = match & definition {
251+ Definition :: BuiltinType ( _) => Some ( FamousDefs ( sema, sema. scope ( node) ?. krate ( ) ) ) ,
252+ _ => None ,
283253 } ;
284-
285- let res = render:: type_info ( sema, config, & expr_or_pat) ?;
286-
287- let range = sema
288- . original_range_opt ( & node)
289- . map ( |frange| frange. range )
290- . unwrap_or_else ( || original_token. text_range ( ) ) ;
291- Some ( RangeInfo :: new ( range, res) )
254+ render:: definition ( sema. db , definition, famous_defs. as_ref ( ) , config) . map ( |markup| {
255+ HoverResult {
256+ markup : render:: process_markup ( sema. db , definition, & markup, config) ,
257+ actions : [
258+ show_implementations_action ( sema. db , definition) ,
259+ show_fn_references_action ( sema. db , definition) ,
260+ runnable_action ( sema, definition, file_id) ,
261+ goto_type_action_for_def ( sema. db , definition) ,
262+ ]
263+ . into_iter ( )
264+ . flatten ( )
265+ . collect ( ) ,
266+ }
267+ } )
292268}
293269
294270fn show_implementations_action ( db : & RootDatabase , def : Definition ) -> Option < HoverAction > {
0 commit comments