@@ -15,7 +15,7 @@ use ide_db::{
15
15
FxIndexSet , RootDatabase ,
16
16
} ;
17
17
use itertools:: Itertools ;
18
- use syntax:: { ast, match_ast , AstNode , SyntaxKind :: * , SyntaxNode , SyntaxToken , T } ;
18
+ use syntax:: { ast, AstNode , SyntaxKind :: * , SyntaxNode , T } ;
19
19
20
20
use crate :: {
21
21
doc_links:: token_as_doc_comment,
@@ -86,30 +86,38 @@ pub struct HoverResult {
86
86
// image::https://user-images.githubusercontent.com/48062697/113020658-b5f98b80-917a-11eb-9f88-3dbc27320c95.gif[]
87
87
pub ( crate ) fn hover (
88
88
db : & RootDatabase ,
89
- file_range : FileRange ,
89
+ frange @ FileRange { file_id , range } : FileRange ,
90
90
config : & HoverConfig ,
91
91
) -> Option < RangeInfo < HoverResult > > {
92
92
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
+
94
100
if let HoverDocFormat :: PlainText = config. format {
95
101
res. info . markup = remove_markdown ( res. info . markup . as_str ( ) ) . into ( ) ;
96
102
}
97
103
Some ( res)
98
104
}
99
105
100
- fn hover_impl (
106
+ fn hover_simple (
101
107
sema : & Semantics < ' _ , RootDatabase > ,
102
- FileRange { file_id, range } : FileRange ,
108
+ FilePosition { file_id, offset } : FilePosition ,
109
+ file : SyntaxNode ,
103
110
config : & HoverConfig ,
104
111
) -> 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
-
111
112
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 ,
113
121
// index and prefix ops
114
122
T ! [ '[' ] | T ! [ ']' ] | T ! [ ?] | T ! [ * ] | T ! [ -] | T ! [ !] => 3 ,
115
123
kind if kind. is_keyword ( ) => 2 ,
@@ -142,19 +150,18 @@ fn hover_impl(
142
150
} else {
143
151
sema. descend_into_macros_with_same_text ( original_token. clone ( ) )
144
152
} ;
153
+ let descended = || descended. iter ( ) ;
145
154
146
- // try lint hover
147
- let result = descended
148
- . iter ( )
155
+ let result = descended ( )
156
+ // try lint hover
149
157
. find_map ( |token| {
150
158
// FIXME: Definition should include known lints and the like instead of having this special case here
151
159
let attr = token. parent_ancestors ( ) . find_map ( ast:: Attr :: cast) ?;
152
160
render:: try_for_lint ( & attr, token)
153
161
} )
154
- // try item definitions
162
+ // try definitions
155
163
. or_else ( || {
156
- descended
157
- . iter ( )
164
+ descended ( )
158
165
. filter_map ( |token| {
159
166
let node = token. parent ( ) ?;
160
167
let class = IdentClass :: classify_token ( sema, token) ?;
@@ -175,10 +182,12 @@ fn hover_impl(
175
182
} )
176
183
} )
177
184
// 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
180
189
. or_else ( || {
181
- descended. iter ( ) . find_map ( |token| {
190
+ descended ( ) . find_map ( |token| {
182
191
if token. kind ( ) != DOT2 {
183
192
return None ;
184
193
}
@@ -194,51 +203,24 @@ fn hover_impl(
194
203
} )
195
204
} ) ;
196
205
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)
230
209
} )
231
210
}
232
211
233
212
fn hover_ranged (
234
- file : & SyntaxNode ,
235
- range : syntax:: TextRange ,
236
213
sema : & Semantics < ' _ , RootDatabase > ,
214
+ FileRange { range, .. } : FileRange ,
215
+ file : SyntaxNode ,
237
216
config : & HoverConfig ,
238
217
) -> Option < RangeInfo < HoverResult > > {
239
218
// 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) ?;
242
224
let res = match & expr_or_pat {
243
225
Either :: Left ( ast:: Expr :: TryExpr ( try_expr) ) => render:: try_expr ( sema, config, try_expr) ,
244
226
Either :: Left ( ast:: Expr :: PrefixExpr ( prefix_expr) )
@@ -248,7 +230,7 @@ fn hover_ranged(
248
230
}
249
231
_ => None ,
250
232
} ;
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) ) ;
252
234
res. map ( |it| {
253
235
let range = match expr_or_pat {
254
236
Either :: Left ( it) => it. syntax ( ) . text_range ( ) ,
@@ -258,37 +240,31 @@ fn hover_ranged(
258
240
} )
259
241
}
260
242
261
- fn hover_type_fallback (
243
+ pub ( crate ) fn hover_for_definition (
262
244
sema : & Semantics < ' _ , RootDatabase > ,
245
+ file_id : FileId ,
246
+ definition : Definition ,
247
+ node : & SyntaxNode ,
263
248
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 ,
283
253
} ;
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
+ } )
292
268
}
293
269
294
270
fn show_implementations_action ( db : & RootDatabase , def : Definition ) -> Option < HoverAction > {
0 commit comments