@@ -5,10 +5,11 @@ use crate::{
5
5
navigation_target:: { self , ToNav } ,
6
6
FilePosition , NavigationTarget , RangeInfo , TryToNav , UpmappingResult ,
7
7
} ;
8
- use hir:: { AsAssocItem , AssocItem , FileRange , InFile , MacroFileIdExt , ModuleDef , Semantics } ;
8
+ use hir:: { AsAssocItem , AssocItem , FileRange , Impl , InFile , MacroFileIdExt , ModuleDef , Semantics } ;
9
9
use ide_db:: {
10
10
base_db:: { AnchoredPath , FileLoader , SourceDatabase } ,
11
11
defs:: { Definition , IdentClass } ,
12
+ famous_defs:: FamousDefs ,
12
13
helpers:: pick_best_token,
13
14
RootDatabase , SymbolKind ,
14
15
} ;
@@ -81,6 +82,10 @@ pub(crate) fn goto_definition(
81
82
return Some ( RangeInfo :: new ( original_token. text_range ( ) , navs) ) ;
82
83
}
83
84
85
+ if let Some ( navs) = find_from_definition ( file_id, & original_token, sema) {
86
+ return Some ( RangeInfo :: new ( original_token. text_range ( ) , navs) ) ;
87
+ }
88
+
84
89
let navs = sema
85
90
. descend_into_macros_no_opaque ( original_token. clone ( ) )
86
91
. into_iter ( )
@@ -125,6 +130,62 @@ pub(crate) fn goto_definition(
125
130
Some ( RangeInfo :: new ( original_token. text_range ( ) , navs) )
126
131
}
127
132
133
+ // If the token is into(), try_into(), parse(), search the definition of From, TryFrom, FromStr.
134
+ fn find_from_definition (
135
+ file_id : FileId ,
136
+ original_token : & SyntaxToken ,
137
+ sema : & Semantics < ' _ , RootDatabase > ,
138
+ ) -> Option < Vec < NavigationTarget > > {
139
+ let db = sema. db ;
140
+ let krate = sema. file_to_module_def ( file_id) ?. krate ( ) ;
141
+
142
+ // e.g. if the method call is let b = a.into(),
143
+ // - receiver_type is A (type of a)
144
+ // - return_type is B (type of b)
145
+ // We will find the definition of B::from(a: A).
146
+ let method_call = ast:: MethodCallExpr :: cast ( original_token. parent ( ) ?. parent ( ) ?) ?;
147
+ let receiver_type = sema. type_of_expr ( & method_call. receiver ( ) ?) ?. original ( ) ;
148
+ let return_type = sema. type_of_expr ( & method_call. clone ( ) . into ( ) ) ?. original ( ) ;
149
+
150
+ let ( search_method, search_trait, return_type) = match method_call. name_ref ( ) ?. text ( ) . as_str ( ) {
151
+ "into" => ( "from" , FamousDefs ( sema, krate) . core_convert_From ( ) ?, return_type) ,
152
+ // If the mthod is try_into() or parse(), return_type is Result<T, Error>.
153
+ // Get T from type arguments of Result<T, Error>.
154
+ "try_into" => (
155
+ "try_from" ,
156
+ FamousDefs ( sema, krate) . core_convert_TryFrom ( ) ?,
157
+ return_type. type_arguments ( ) . next ( ) ?,
158
+ ) ,
159
+ "parse" => (
160
+ "from_str" ,
161
+ FamousDefs ( sema, krate) . core_str_FromStr ( ) ?,
162
+ return_type. type_arguments ( ) . next ( ) ?,
163
+ ) ,
164
+ _ => return None ,
165
+ } ;
166
+
167
+ let from_impls = Impl :: all_for_type ( db, return_type)
168
+ . into_iter ( )
169
+ . filter ( |impl_| impl_. trait_ ( db) . is_some_and ( |trait_| trait_ == search_trait) ) ;
170
+ let from_methods = from_impls. flat_map ( |impl_| impl_. items ( db) ) . filter_map ( |item| match item {
171
+ AssocItem :: Function ( function) if function. name ( db) . as_str ( ) == search_method => {
172
+ Some ( function)
173
+ }
174
+ _ => None ,
175
+ } ) ;
176
+ let target_method = from_methods. into_iter ( ) . find ( |method| {
177
+ let args = method. assoc_fn_params ( db) ;
178
+
179
+ // FIXME: This condition does not work for complicated cases such as
180
+ // receiver_type: Vec<i64>
181
+ // arg.ty(): T: IntoIterator<Item = i64>
182
+ args. get ( 0 ) . is_some_and ( |arg| receiver_type. could_coerce_to ( db, arg. ty ( ) ) )
183
+ } ) ?;
184
+
185
+ let def = Definition :: from ( target_method) ;
186
+ Some ( def_to_nav ( db, def) )
187
+ }
188
+
128
189
fn try_lookup_include_path (
129
190
sema : & Semantics < ' _ , RootDatabase > ,
130
191
token : ast:: String ,
@@ -3022,4 +3083,27 @@ fn foo() {
3022
3083
"# ,
3023
3084
) ;
3024
3085
}
3086
+ #[ test]
3087
+ fn into_call_to_from_definition ( ) {
3088
+ check (
3089
+ r#"
3090
+ //- minicore: from
3091
+ struct A;
3092
+
3093
+ struct B;
3094
+
3095
+ impl From<A> for B {
3096
+ fn from(value: A) -> Self {
3097
+ //^^^^
3098
+ B
3099
+ }
3100
+ }
3101
+
3102
+ fn f() {
3103
+ let a = A;
3104
+ let b: B = a.into$0();
3105
+ }
3106
+ "# ,
3107
+ ) ;
3108
+ }
3025
3109
}
0 commit comments