diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2020-07-10 13:47:23 +0100 |
---|---|---|
committer | GitHub <[email protected]> | 2020-07-10 13:47:23 +0100 |
commit | 0f7770ae43dd0d97686eb85fccb38801ff30117b (patch) | |
tree | 754d726b02595db4dcc4594712e30ca97a336988 /crates/ra_ide/src | |
parent | 5fa8f8e3761363098c80e11842682dffcee171d8 (diff) | |
parent | 075380dd56439cdaf1967b7298e10b96b995fc07 (diff) |
Merge #5292
5292: Goto type definition improvements r=matklad a=matklad
bors r+
🤖
Co-authored-by: Aleksey Kladov <[email protected]>
Diffstat (limited to 'crates/ra_ide/src')
-rw-r--r-- | crates/ra_ide/src/goto_definition.rs | 10 | ||||
-rw-r--r-- | crates/ra_ide/src/goto_type_definition.rs | 132 |
2 files changed, 76 insertions, 66 deletions
diff --git a/crates/ra_ide/src/goto_definition.rs b/crates/ra_ide/src/goto_definition.rs index 4c78fa214..8fc33d031 100644 --- a/crates/ra_ide/src/goto_definition.rs +++ b/crates/ra_ide/src/goto_definition.rs | |||
@@ -7,7 +7,7 @@ use ra_syntax::{ | |||
7 | ast::{self}, | 7 | ast::{self}, |
8 | match_ast, AstNode, | 8 | match_ast, AstNode, |
9 | SyntaxKind::*, | 9 | SyntaxKind::*, |
10 | SyntaxToken, TokenAtOffset, | 10 | SyntaxToken, TokenAtOffset, T, |
11 | }; | 11 | }; |
12 | 12 | ||
13 | use crate::{ | 13 | use crate::{ |
@@ -32,9 +32,10 @@ pub(crate) fn goto_definition( | |||
32 | let file = sema.parse(position.file_id).syntax().clone(); | 32 | let file = sema.parse(position.file_id).syntax().clone(); |
33 | let original_token = pick_best(file.token_at_offset(position.offset))?; | 33 | let original_token = pick_best(file.token_at_offset(position.offset))?; |
34 | let token = sema.descend_into_macros(original_token.clone()); | 34 | let token = sema.descend_into_macros(original_token.clone()); |
35 | let parent = token.parent(); | ||
35 | 36 | ||
36 | let nav_targets = match_ast! { | 37 | let nav_targets = match_ast! { |
37 | match (token.parent()) { | 38 | match parent { |
38 | ast::NameRef(name_ref) => { | 39 | ast::NameRef(name_ref) => { |
39 | reference_definition(&sema, &name_ref).to_vec() | 40 | reference_definition(&sema, &name_ref).to_vec() |
40 | }, | 41 | }, |
@@ -57,7 +58,7 @@ fn pick_best(tokens: TokenAtOffset<SyntaxToken>) -> Option<SyntaxToken> { | |||
57 | return tokens.max_by_key(priority); | 58 | return tokens.max_by_key(priority); |
58 | fn priority(n: &SyntaxToken) -> usize { | 59 | fn priority(n: &SyntaxToken) -> usize { |
59 | match n.kind() { | 60 | match n.kind() { |
60 | IDENT | INT_NUMBER => 2, | 61 | IDENT | INT_NUMBER | T![self] => 2, |
61 | kind if kind.is_trivia() => 0, | 62 | kind if kind.is_trivia() => 0, |
62 | _ => 1, | 63 | _ => 1, |
63 | } | 64 | } |
@@ -121,7 +122,8 @@ mod tests { | |||
121 | data => panic!("bad data: {}", data), | 122 | data => panic!("bad data: {}", data), |
122 | } | 123 | } |
123 | 124 | ||
124 | let mut navs = analysis.goto_definition(position).unwrap().unwrap().info; | 125 | let mut navs = |
126 | analysis.goto_definition(position).unwrap().expect("no definition found").info; | ||
125 | if navs.len() == 0 { | 127 | if navs.len() == 0 { |
126 | panic!("unresolved reference") | 128 | panic!("unresolved reference") |
127 | } | 129 | } |
diff --git a/crates/ra_ide/src/goto_type_definition.rs b/crates/ra_ide/src/goto_type_definition.rs index 7eb40d637..069cb283e 100644 --- a/crates/ra_ide/src/goto_type_definition.rs +++ b/crates/ra_ide/src/goto_type_definition.rs | |||
@@ -1,5 +1,5 @@ | |||
1 | use ra_ide_db::RootDatabase; | 1 | use ra_ide_db::RootDatabase; |
2 | use ra_syntax::{ast, match_ast, AstNode, SyntaxKind::*, SyntaxToken, TokenAtOffset}; | 2 | use ra_syntax::{ast, match_ast, AstNode, SyntaxKind::*, SyntaxToken, TokenAtOffset, T}; |
3 | 3 | ||
4 | use crate::{display::ToNav, FilePosition, NavigationTarget, RangeInfo}; | 4 | use crate::{display::ToNav, FilePosition, NavigationTarget, RangeInfo}; |
5 | 5 | ||
@@ -25,8 +25,9 @@ pub(crate) fn goto_type_definition( | |||
25 | let (ty, node) = sema.ancestors_with_macros(token.parent()).find_map(|node| { | 25 | let (ty, node) = sema.ancestors_with_macros(token.parent()).find_map(|node| { |
26 | let ty = match_ast! { | 26 | let ty = match_ast! { |
27 | match node { | 27 | match node { |
28 | ast::Expr(expr) => sema.type_of_expr(&expr)?, | 28 | ast::Expr(it) => sema.type_of_expr(&it)?, |
29 | ast::Pat(pat) => sema.type_of_pat(&pat)?, | 29 | ast::Pat(it) => sema.type_of_pat(&it)?, |
30 | ast::SelfParam(it) => sema.type_of_self(&it)?, | ||
30 | _ => return None, | 31 | _ => return None, |
31 | } | 32 | } |
32 | }; | 33 | }; |
@@ -34,7 +35,7 @@ pub(crate) fn goto_type_definition( | |||
34 | Some((ty, node)) | 35 | Some((ty, node)) |
35 | })?; | 36 | })?; |
36 | 37 | ||
37 | let adt_def = ty.autoderef(db).find_map(|ty| ty.as_adt())?; | 38 | let adt_def = ty.autoderef(db).filter_map(|ty| ty.as_adt()).last()?; |
38 | 39 | ||
39 | let nav = adt_def.to_nav(db); | 40 | let nav = adt_def.to_nav(db); |
40 | Some(RangeInfo::new(node.text_range(), vec![nav])) | 41 | Some(RangeInfo::new(node.text_range(), vec![nav])) |
@@ -44,7 +45,7 @@ fn pick_best(tokens: TokenAtOffset<SyntaxToken>) -> Option<SyntaxToken> { | |||
44 | return tokens.max_by_key(priority); | 45 | return tokens.max_by_key(priority); |
45 | fn priority(n: &SyntaxToken) -> usize { | 46 | fn priority(n: &SyntaxToken) -> usize { |
46 | match n.kind() { | 47 | match n.kind() { |
47 | IDENT | INT_NUMBER => 2, | 48 | IDENT | INT_NUMBER | T![self] => 2, |
48 | kind if kind.is_trivia() => 0, | 49 | kind if kind.is_trivia() => 0, |
49 | _ => 1, | 50 | _ => 1, |
50 | } | 51 | } |
@@ -53,91 +54,98 @@ fn pick_best(tokens: TokenAtOffset<SyntaxToken>) -> Option<SyntaxToken> { | |||
53 | 54 | ||
54 | #[cfg(test)] | 55 | #[cfg(test)] |
55 | mod tests { | 56 | mod tests { |
56 | use crate::mock_analysis::analysis_and_position; | 57 | use ra_db::FileRange; |
57 | 58 | ||
58 | fn check_goto(ra_fixture: &str, expected: &str) { | 59 | use crate::mock_analysis::MockAnalysis; |
59 | let (analysis, pos) = analysis_and_position(ra_fixture); | ||
60 | 60 | ||
61 | let mut navs = analysis.goto_type_definition(pos).unwrap().unwrap().info; | 61 | fn check(ra_fixture: &str) { |
62 | let (mock, position) = MockAnalysis::with_files_and_position(ra_fixture); | ||
63 | let (expected, data) = mock.annotation(); | ||
64 | assert!(data.is_empty()); | ||
65 | let analysis = mock.analysis(); | ||
66 | |||
67 | let mut navs = analysis.goto_type_definition(position).unwrap().unwrap().info; | ||
62 | assert_eq!(navs.len(), 1); | 68 | assert_eq!(navs.len(), 1); |
63 | let nav = navs.pop().unwrap(); | 69 | let nav = navs.pop().unwrap(); |
64 | nav.assert_match(expected); | 70 | assert_eq!(expected, FileRange { file_id: nav.file_id(), range: nav.range() }); |
65 | } | 71 | } |
66 | 72 | ||
67 | #[test] | 73 | #[test] |
68 | fn goto_type_definition_works_simple() { | 74 | fn goto_type_definition_works_simple() { |
69 | check_goto( | 75 | check( |
70 | r" | 76 | r#" |
71 | //- /lib.rs | 77 | struct Foo; |
72 | struct Foo; | 78 | //^^^ |
73 | fn foo() { | 79 | fn foo() { |
74 | let f: Foo; | 80 | let f: Foo; f<|> |
75 | f<|> | 81 | } |
76 | } | 82 | "#, |
77 | ", | ||
78 | "Foo STRUCT_DEF FileId(1) 0..11 7..10", | ||
79 | ); | 83 | ); |
80 | } | 84 | } |
81 | 85 | ||
82 | #[test] | 86 | #[test] |
83 | fn goto_type_definition_works_simple_ref() { | 87 | fn goto_type_definition_works_simple_ref() { |
84 | check_goto( | 88 | check( |
85 | r" | 89 | r#" |
86 | //- /lib.rs | 90 | struct Foo; |
87 | struct Foo; | 91 | //^^^ |
88 | fn foo() { | 92 | fn foo() { |
89 | let f: &Foo; | 93 | let f: &Foo; f<|> |
90 | f<|> | 94 | } |
91 | } | 95 | "#, |
92 | ", | ||
93 | "Foo STRUCT_DEF FileId(1) 0..11 7..10", | ||
94 | ); | 96 | ); |
95 | } | 97 | } |
96 | 98 | ||
97 | #[test] | 99 | #[test] |
98 | fn goto_type_definition_works_through_macro() { | 100 | fn goto_type_definition_works_through_macro() { |
99 | check_goto( | 101 | check( |
100 | r" | 102 | r#" |
101 | //- /lib.rs | 103 | macro_rules! id { ($($tt:tt)*) => { $($tt)* } } |
102 | macro_rules! id { | 104 | struct Foo {} |
103 | ($($tt:tt)*) => { $($tt)* } | 105 | //^^^ |
104 | } | 106 | id! { |
105 | struct Foo {} | 107 | fn bar() { let f<|> = Foo {}; } |
106 | id! { | 108 | } |
107 | fn bar() { | 109 | "#, |
108 | let f<|> = Foo {}; | ||
109 | } | ||
110 | } | ||
111 | ", | ||
112 | "Foo STRUCT_DEF FileId(1) 52..65 59..62", | ||
113 | ); | 110 | ); |
114 | } | 111 | } |
115 | 112 | ||
116 | #[test] | 113 | #[test] |
117 | fn goto_type_definition_for_param() { | 114 | fn goto_type_definition_for_param() { |
118 | check_goto( | 115 | check( |
119 | r" | 116 | r#" |
120 | //- /lib.rs | 117 | struct Foo; |
121 | struct Foo; | 118 | //^^^ |
122 | fn foo(<|>f: Foo) {} | 119 | fn foo(<|>f: Foo) {} |
123 | ", | 120 | "#, |
124 | "Foo STRUCT_DEF FileId(1) 0..11 7..10", | ||
125 | ); | 121 | ); |
126 | } | 122 | } |
127 | 123 | ||
128 | #[test] | 124 | #[test] |
129 | fn goto_type_definition_for_tuple_field() { | 125 | fn goto_type_definition_for_tuple_field() { |
130 | check_goto( | 126 | check( |
131 | r" | 127 | r#" |
132 | //- /lib.rs | 128 | struct Foo; |
133 | struct Foo; | 129 | //^^^ |
134 | struct Bar(Foo); | 130 | struct Bar(Foo); |
135 | fn foo() { | 131 | fn foo() { |
136 | let bar = Bar(Foo); | 132 | let bar = Bar(Foo); |
137 | bar.<|>0; | 133 | bar.<|>0; |
138 | } | 134 | } |
139 | ", | 135 | "#, |
140 | "Foo STRUCT_DEF FileId(1) 0..11 7..10", | ||
141 | ); | 136 | ); |
142 | } | 137 | } |
138 | |||
139 | #[test] | ||
140 | fn goto_def_for_self_param() { | ||
141 | check( | ||
142 | r#" | ||
143 | struct Foo; | ||
144 | //^^^ | ||
145 | impl Foo { | ||
146 | fn f(&self<|>) {} | ||
147 | } | ||
148 | "#, | ||
149 | ) | ||
150 | } | ||
143 | } | 151 | } |