1
1
use ide_db:: { base_db:: Upcast , helpers:: pick_best_token, RootDatabase } ;
2
- use syntax:: { ast, match_ast, AstNode , SyntaxKind :: * , SyntaxToken , T } ;
2
+ use syntax:: { ast, match_ast, AstNode , SyntaxKind :: * , SyntaxToken , TextRange , T } ;
3
3
4
4
use crate :: { display:: TryToNav , FilePosition , NavigationTarget , RangeInfo } ;
5
5
@@ -27,32 +27,6 @@ pub(crate) fn goto_type_definition(
27
27
kind if kind. is_trivia ( ) => 0 ,
28
28
_ => 1 ,
29
29
} ) ?;
30
- let token: SyntaxToken = sema. descend_into_macros_single ( token) ;
31
-
32
- let ( ty, node) = sema. token_ancestors_with_macros ( token) . find_map ( |node| {
33
- let ty = match_ast ! {
34
- match node {
35
- ast:: Expr ( it) => sema. type_of_expr( & it) ?. original,
36
- ast:: Pat ( it) => sema. type_of_pat( & it) ?. original,
37
- ast:: SelfParam ( it) => sema. type_of_self( & it) ?,
38
- ast:: Type ( it) => sema. resolve_type( & it) ?,
39
- ast:: RecordField ( it) => sema. to_def( & it) . map( |d| d. ty( db. upcast( ) ) ) ?,
40
- // can't match on RecordExprField directly as `ast::Expr` will match an iteration too early otherwise
41
- ast:: NameRef ( it) => {
42
- if let Some ( record_field) = ast:: RecordExprField :: for_name_ref( & it) {
43
- let ( _, _, ty) = sema. resolve_record_field( & record_field) ?;
44
- ty
45
- } else {
46
- let record_field = ast:: RecordPatField :: for_field_name_ref( & it) ?;
47
- sema. resolve_record_pat_field( & record_field) ?. ty( db)
48
- }
49
- } ,
50
- _ => return None ,
51
- }
52
- } ;
53
-
54
- Some ( ( ty, node) )
55
- } ) ?;
56
30
57
31
let mut res = Vec :: new ( ) ;
58
32
let mut push = |def : hir:: ModuleDef | {
@@ -63,20 +37,60 @@ pub(crate) fn goto_type_definition(
63
37
}
64
38
} ;
65
39
66
- let ty = ty. strip_references ( ) ;
67
- ty. walk ( db, |t| {
68
- if let Some ( adt) = t. as_adt ( ) {
69
- push ( adt. into ( ) ) ;
70
- } else if let Some ( trait_) = t. as_dyn_trait ( ) {
71
- push ( trait_. into ( ) ) ;
72
- } else if let Some ( traits) = t. as_impl_traits ( db) {
73
- traits. into_iter ( ) . for_each ( |it| push ( it. into ( ) ) ) ;
74
- } else if let Some ( trait_) = t. as_associated_type_parent_trait ( db) {
75
- push ( trait_. into ( ) ) ;
76
- }
77
- } ) ;
40
+ // TODO this became pretty baroque after refactoring for `descend_into_macros(_many)`
41
+ let range = sema
42
+ . descend_into_macros ( token)
43
+ . iter ( )
44
+ . filter_map ( |token| {
45
+ let ty_range = sema. token_ancestors_with_macros ( token. clone ( ) ) . find_map ( |node| {
46
+ let ty = match_ast ! {
47
+ match node {
48
+ ast:: Expr ( it) => sema. type_of_expr( & it) ?. original,
49
+ ast:: Pat ( it) => sema. type_of_pat( & it) ?. original,
50
+ ast:: SelfParam ( it) => sema. type_of_self( & it) ?,
51
+ ast:: Type ( it) => sema. resolve_type( & it) ?,
52
+ ast:: RecordField ( it) => sema. to_def( & it) . map( |d| d. ty( db. upcast( ) ) ) ?,
53
+ // can't match on RecordExprField directly as `ast::Expr` will match an iteration too early otherwise
54
+ ast:: NameRef ( it) => {
55
+ if let Some ( record_field) = ast:: RecordExprField :: for_name_ref( & it) {
56
+ let ( _, _, ty) = sema. resolve_record_field( & record_field) ?;
57
+ ty
58
+ } else {
59
+ let record_field = ast:: RecordPatField :: for_field_name_ref( & it) ?;
60
+ sema. resolve_record_pat_field( & record_field) ?. ty( db)
61
+ }
62
+ } ,
63
+ _ => return None ,
64
+ }
65
+ } ;
66
+
67
+ let range = node. text_range ( ) ;
68
+ Some ( ( ty, range. start ( ) , range. end ( ) ) )
69
+ } ) ;
70
+ ty_range
71
+ } )
72
+ . inspect ( |( ty, _range_start, _range_end) | {
73
+ // collect from each `ty` into the `res` result vec
74
+ let ty = ty. strip_references ( ) ;
75
+ ty. walk ( db, |t| {
76
+ if let Some ( adt) = t. as_adt ( ) {
77
+ push ( adt. into ( ) ) ;
78
+ } else if let Some ( trait_) = t. as_dyn_trait ( ) {
79
+ push ( trait_. into ( ) ) ;
80
+ } else if let Some ( traits) = t. as_impl_traits ( db) {
81
+ traits. into_iter ( ) . for_each ( |it| push ( it. into ( ) ) ) ;
82
+ } else if let Some ( trait_) = t. as_associated_type_parent_trait ( db) {
83
+ push ( trait_. into ( ) ) ;
84
+ }
85
+ } ) ;
86
+ } ) // reduce all ranges into a single umbrella span (TODO fishy?)
87
+ . map ( |( _, range_start, range_end) | ( range_start, range_end) )
88
+ . reduce ( |( start_acc, end_acc) , ( start_cur, end_cur) | {
89
+ ( start_acc. min ( start_cur) , end_acc. max ( end_cur) )
90
+ } )
91
+ . map ( |( range_start, range_end) | TextRange :: new ( range_start, range_end) ) ?; // TODO easy to miss `?` bail
78
92
79
- Some ( RangeInfo :: new ( node . text_range ( ) , res) )
93
+ Some ( RangeInfo :: new ( range , res) )
80
94
}
81
95
82
96
#[ cfg( test) ]
0 commit comments