@@ -5,7 +5,7 @@ use hir::{AsAssocItem, InFile, ModuleDef, Semantics};
55use ide_db:: {
66 base_db:: { AnchoredPath , FileId , FileLoader } ,
77 defs:: { Definition , NameClass , NameRefClass } ,
8- helpers:: pick_best_token,
8+ helpers:: { pick_best_token, try_resolve_derive_input_at } ,
99 RootDatabase ,
1010} ;
1111use syntax:: { ast, match_ast, AstNode , AstToken , SyntaxKind :: * , SyntaxToken , TextRange , T } ;
@@ -78,38 +78,49 @@ pub(crate) fn goto_definition(
7878 } else {
7979 reference_definition( & sema, Either :: Left ( & lt) )
8080 } ,
81- ast:: TokenTree ( tt) => try_lookup_include_path ( sema. db , tt, token, position. file_id) ?,
81+ ast:: TokenTree ( tt) => try_lookup_include_path_or_derive ( & sema, tt, token, position. file_id) ?,
8282 _ => return None ,
8383 }
8484 } ;
8585
8686 Some ( RangeInfo :: new ( original_token. text_range ( ) , navs) )
8787}
8888
89- fn try_lookup_include_path (
90- db : & RootDatabase ,
89+ fn try_lookup_include_path_or_derive (
90+ sema : & Semantics < RootDatabase > ,
9191 tt : ast:: TokenTree ,
9292 token : SyntaxToken ,
9393 file_id : FileId ,
9494) -> Option < Vec < NavigationTarget > > {
95- let path = ast:: String :: cast ( token) ?. value ( ) ?. into_owned ( ) ;
96- let macro_call = tt. syntax ( ) . parent ( ) . and_then ( ast:: MacroCall :: cast) ?;
97- let name = macro_call. path ( ) ?. segment ( ) ?. name_ref ( ) ?;
98- if !matches ! ( & * name. text( ) , "include" | "include_str" | "include_bytes" ) {
99- return None ;
100- }
101- let file_id = db. resolve_path ( AnchoredPath { anchor : file_id, path : & path } ) ?;
102- let size = db. file_text ( file_id) . len ( ) . try_into ( ) . ok ( ) ?;
103- Some ( vec ! [ NavigationTarget {
104- file_id,
105- full_range: TextRange :: new( 0 . into( ) , size) ,
106- name: path. into( ) ,
107- focus_range: None ,
108- kind: None ,
109- container_name: None ,
110- description: None ,
111- docs: None ,
112- } ] )
95+ match ast:: String :: cast ( token. clone ( ) ) {
96+ Some ( token) => {
97+ let path = token. value ( ) ?. into_owned ( ) ;
98+ let macro_call = tt. syntax ( ) . parent ( ) . and_then ( ast:: MacroCall :: cast) ?;
99+ let name = macro_call. path ( ) ?. segment ( ) ?. name_ref ( ) ?;
100+ if !matches ! ( & * name. text( ) , "include" | "include_str" | "include_bytes" ) {
101+ return None ;
102+ }
103+ let file_id = sema. db . resolve_path ( AnchoredPath { anchor : file_id, path : & path } ) ?;
104+ let size = sema. db . file_text ( file_id) . len ( ) . try_into ( ) . ok ( ) ?;
105+ Some ( vec ! [ NavigationTarget {
106+ file_id,
107+ full_range: TextRange :: new( 0 . into( ) , size) ,
108+ name: path. into( ) ,
109+ focus_range: None ,
110+ kind: None ,
111+ container_name: None ,
112+ description: None ,
113+ docs: None ,
114+ } ] )
115+ }
116+ None => try_resolve_derive_input_at (
117+ sema,
118+ & tt. syntax ( ) . ancestors ( ) . nth ( 2 ) . and_then ( ast:: Attr :: cast) ?,
119+ & token,
120+ )
121+ . and_then ( |it| it. try_to_nav ( sema. db ) )
122+ . map ( |it| vec ! [ it] ) ,
123+ }
113124}
114125
115126/// finds the trait definition of an impl'd item
@@ -1383,4 +1394,28 @@ impl Twait for Stwuct {
13831394"# ,
13841395 ) ;
13851396 }
1397+
1398+ #[ test]
1399+ fn goto_def_derive_input ( ) {
1400+ check (
1401+ r#"
1402+ #[rustc_builtin_macro]
1403+ pub macro Copy {}
1404+ // ^^^^
1405+ #[derive(Copy$0)]
1406+ struct Foo;
1407+ "# ,
1408+ ) ;
1409+ check (
1410+ r#"
1411+ mod foo {
1412+ #[rustc_builtin_macro]
1413+ pub macro Copy {}
1414+ // ^^^^
1415+ }
1416+ #[derive(foo::Copy$0)]
1417+ struct Foo;
1418+ "# ,
1419+ ) ;
1420+ }
13861421}
0 commit comments