diff options
Diffstat (limited to 'crates/ra_ide')
-rw-r--r-- | crates/ra_ide/src/display/navigation_target.rs | 10 | ||||
-rw-r--r-- | crates/ra_ide/src/goto_implementation.rs | 193 | ||||
-rw-r--r-- | crates/ra_ide/src/mock_analysis.rs | 20 |
3 files changed, 119 insertions, 104 deletions
diff --git a/crates/ra_ide/src/display/navigation_target.rs b/crates/ra_ide/src/display/navigation_target.rs index 02f55e5ba..f8a466304 100644 --- a/crates/ra_ide/src/display/navigation_target.rs +++ b/crates/ra_ide/src/display/navigation_target.rs | |||
@@ -279,13 +279,17 @@ impl ToNav for hir::Module { | |||
279 | impl ToNav for hir::ImplDef { | 279 | impl ToNav for hir::ImplDef { |
280 | fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { | 280 | fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { |
281 | let src = self.source(db); | 281 | let src = self.source(db); |
282 | let frange = if let Some(item) = self.is_builtin_derive(db) { | 282 | let derive_attr = self.is_builtin_derive(db); |
283 | let frange = if let Some(item) = &derive_attr { | ||
283 | original_range(db, item.syntax()) | 284 | original_range(db, item.syntax()) |
284 | } else { | 285 | } else { |
285 | original_range(db, src.as_ref().map(|it| it.syntax())) | 286 | original_range(db, src.as_ref().map(|it| it.syntax())) |
286 | }; | 287 | }; |
287 | let focus_range = | 288 | let focus_range = if derive_attr.is_some() { |
288 | src.value.target_type().map(|ty| original_range(db, src.with_value(ty.syntax())).range); | 289 | None |
290 | } else { | ||
291 | src.value.target_type().map(|ty| original_range(db, src.with_value(ty.syntax())).range) | ||
292 | }; | ||
289 | 293 | ||
290 | NavigationTarget::from_syntax( | 294 | NavigationTarget::from_syntax( |
291 | frange.file_id, | 295 | frange.file_id, |
diff --git a/crates/ra_ide/src/goto_implementation.rs b/crates/ra_ide/src/goto_implementation.rs index 0cec0657e..1882789c4 100644 --- a/crates/ra_ide/src/goto_implementation.rs +++ b/crates/ra_ide/src/goto_implementation.rs | |||
@@ -74,135 +74,152 @@ fn impls_for_trait( | |||
74 | 74 | ||
75 | #[cfg(test)] | 75 | #[cfg(test)] |
76 | mod tests { | 76 | mod tests { |
77 | use crate::mock_analysis::analysis_and_position; | 77 | use ra_db::FileRange; |
78 | 78 | ||
79 | fn check_goto(fixture: &str, expected: &[&str]) { | 79 | use crate::mock_analysis::{analysis_and_position, MockAnalysis}; |
80 | let (analysis, pos) = analysis_and_position(fixture); | ||
81 | 80 | ||
82 | let mut navs = analysis.goto_implementation(pos).unwrap().unwrap().info; | 81 | fn check(ra_fixture: &str) { |
83 | assert_eq!(navs.len(), expected.len()); | 82 | let (mock, position) = MockAnalysis::with_files_and_position(ra_fixture); |
84 | navs.sort_by_key(|nav| (nav.file_id(), nav.full_range().start())); | 83 | let annotations = mock.annotations(); |
85 | navs.into_iter().enumerate().for_each(|(i, nav)| nav.assert_match(expected[i])); | 84 | let analysis = mock.analysis(); |
85 | |||
86 | let navs = analysis.goto_implementation(position).unwrap().unwrap().info; | ||
87 | |||
88 | let key = |frange: &FileRange| (frange.file_id, frange.range.start()); | ||
89 | |||
90 | let mut expected = annotations | ||
91 | .into_iter() | ||
92 | .map(|(range, data)| { | ||
93 | assert!(data.is_empty()); | ||
94 | range | ||
95 | }) | ||
96 | .collect::<Vec<_>>(); | ||
97 | expected.sort_by_key(key); | ||
98 | |||
99 | let mut actual = navs | ||
100 | .into_iter() | ||
101 | .map(|nav| FileRange { file_id: nav.file_id(), range: nav.range() }) | ||
102 | .collect::<Vec<_>>(); | ||
103 | actual.sort_by_key(key); | ||
104 | |||
105 | assert_eq!(expected, actual); | ||
86 | } | 106 | } |
87 | 107 | ||
88 | #[test] | 108 | #[test] |
89 | fn goto_implementation_works() { | 109 | fn goto_implementation_works() { |
90 | check_goto( | 110 | check( |
91 | " | 111 | r#" |
92 | //- /lib.rs | 112 | struct Foo<|>; |
93 | struct Foo<|>; | 113 | impl Foo {} |
94 | impl Foo {} | 114 | //^^^ |
95 | ", | 115 | "#, |
96 | &["impl IMPL_DEF FileId(1) 12..23"], | ||
97 | ); | 116 | ); |
98 | } | 117 | } |
99 | 118 | ||
100 | #[test] | 119 | #[test] |
101 | fn goto_implementation_works_multiple_blocks() { | 120 | fn goto_implementation_works_multiple_blocks() { |
102 | check_goto( | 121 | check( |
103 | " | 122 | r#" |
104 | //- /lib.rs | 123 | struct Foo<|>; |
105 | struct Foo<|>; | 124 | impl Foo {} |
106 | impl Foo {} | 125 | //^^^ |
107 | impl Foo {} | 126 | impl Foo {} |
108 | ", | 127 | //^^^ |
109 | &["impl IMPL_DEF FileId(1) 12..23", "impl IMPL_DEF FileId(1) 24..35"], | 128 | "#, |
110 | ); | 129 | ); |
111 | } | 130 | } |
112 | 131 | ||
113 | #[test] | 132 | #[test] |
114 | fn goto_implementation_works_multiple_mods() { | 133 | fn goto_implementation_works_multiple_mods() { |
115 | check_goto( | 134 | check( |
116 | " | 135 | r#" |
117 | //- /lib.rs | 136 | struct Foo<|>; |
118 | struct Foo<|>; | 137 | mod a { |
119 | mod a { | 138 | impl super::Foo {} |
120 | impl super::Foo {} | 139 | //^^^^^^^^^^ |
121 | } | 140 | } |
122 | mod b { | 141 | mod b { |
123 | impl super::Foo {} | 142 | impl super::Foo {} |
124 | } | 143 | //^^^^^^^^^^ |
125 | ", | 144 | } |
126 | &["impl IMPL_DEF FileId(1) 24..42", "impl IMPL_DEF FileId(1) 57..75"], | 145 | "#, |
127 | ); | 146 | ); |
128 | } | 147 | } |
129 | 148 | ||
130 | #[test] | 149 | #[test] |
131 | fn goto_implementation_works_multiple_files() { | 150 | fn goto_implementation_works_multiple_files() { |
132 | check_goto( | 151 | check( |
133 | " | 152 | r#" |
134 | //- /lib.rs | 153 | //- /lib.rs |
135 | struct Foo<|>; | 154 | struct Foo<|>; |
136 | mod a; | 155 | mod a; |
137 | mod b; | 156 | mod b; |
138 | //- /a.rs | 157 | //- /a.rs |
139 | impl crate::Foo {} | 158 | impl crate::Foo {} |
140 | //- /b.rs | 159 | //^^^^^^^^^^ |
141 | impl crate::Foo {} | 160 | //- /b.rs |
142 | ", | 161 | impl crate::Foo {} |
143 | &["impl IMPL_DEF FileId(2) 0..18", "impl IMPL_DEF FileId(3) 0..18"], | 162 | //^^^^^^^^^^ |
163 | "#, | ||
144 | ); | 164 | ); |
145 | } | 165 | } |
146 | 166 | ||
147 | #[test] | 167 | #[test] |
148 | fn goto_implementation_for_trait() { | 168 | fn goto_implementation_for_trait() { |
149 | check_goto( | 169 | check( |
150 | " | 170 | r#" |
151 | //- /lib.rs | 171 | trait T<|> {} |
152 | trait T<|> {} | 172 | struct Foo; |
153 | struct Foo; | 173 | impl T for Foo {} |
154 | impl T for Foo {} | 174 | //^^^ |
155 | ", | 175 | "#, |
156 | &["impl IMPL_DEF FileId(1) 23..40"], | ||
157 | ); | 176 | ); |
158 | } | 177 | } |
159 | 178 | ||
160 | #[test] | 179 | #[test] |
161 | fn goto_implementation_for_trait_multiple_files() { | 180 | fn goto_implementation_for_trait_multiple_files() { |
162 | check_goto( | 181 | check( |
163 | " | 182 | r#" |
164 | //- /lib.rs | 183 | //- /lib.rs |
165 | trait T<|> {}; | 184 | trait T<|> {}; |
166 | struct Foo; | 185 | struct Foo; |
167 | mod a; | 186 | mod a; |
168 | mod b; | 187 | mod b; |
169 | //- /a.rs | 188 | //- /a.rs |
170 | impl crate::T for crate::Foo {} | 189 | impl crate::T for crate::Foo {} |
171 | //- /b.rs | 190 | //^^^^^^^^^^ |
172 | impl crate::T for crate::Foo {} | 191 | //- /b.rs |
173 | ", | 192 | impl crate::T for crate::Foo {} |
174 | &["impl IMPL_DEF FileId(2) 0..31", "impl IMPL_DEF FileId(3) 0..31"], | 193 | //^^^^^^^^^^ |
194 | "#, | ||
175 | ); | 195 | ); |
176 | } | 196 | } |
177 | 197 | ||
178 | #[test] | 198 | #[test] |
179 | fn goto_implementation_all_impls() { | 199 | fn goto_implementation_all_impls() { |
180 | check_goto( | 200 | check( |
181 | " | 201 | r#" |
182 | //- /lib.rs | 202 | //- /lib.rs |
183 | trait T {} | 203 | trait T {} |
184 | struct Foo<|>; | 204 | struct Foo<|>; |
185 | impl Foo {} | 205 | impl Foo {} |
186 | impl T for Foo {} | 206 | //^^^ |
187 | impl T for &Foo {} | 207 | impl T for Foo {} |
188 | ", | 208 | //^^^ |
189 | &[ | 209 | impl T for &Foo {} |
190 | "impl IMPL_DEF FileId(1) 23..34", | 210 | //^^^^ |
191 | "impl IMPL_DEF FileId(1) 35..52", | 211 | "#, |
192 | "impl IMPL_DEF FileId(1) 53..71", | ||
193 | ], | ||
194 | ); | 212 | ); |
195 | } | 213 | } |
196 | 214 | ||
197 | #[test] | 215 | #[test] |
198 | fn goto_implementation_to_builtin_derive() { | 216 | fn goto_implementation_to_builtin_derive() { |
199 | check_goto( | 217 | check( |
200 | " | 218 | r#" |
201 | //- /lib.rs | 219 | #[derive(Copy)] |
202 | #[derive(Copy)] | 220 | //^^^^^^^^^^^^^^^ |
203 | struct Foo<|>; | 221 | struct Foo<|>; |
204 | ", | 222 | "#, |
205 | &["impl IMPL_DEF FileId(1) 0..15"], | ||
206 | ); | 223 | ); |
207 | } | 224 | } |
208 | } | 225 | } |
diff --git a/crates/ra_ide/src/mock_analysis.rs b/crates/ra_ide/src/mock_analysis.rs index 120d29aa0..db6d50694 100644 --- a/crates/ra_ide/src/mock_analysis.rs +++ b/crates/ra_ide/src/mock_analysis.rs | |||
@@ -10,8 +10,6 @@ use test_utils::{ | |||
10 | use crate::{ | 10 | use crate::{ |
11 | Analysis, AnalysisChange, AnalysisHost, CrateGraph, Edition, FileId, FilePosition, FileRange, | 11 | Analysis, AnalysisChange, AnalysisHost, CrateGraph, Edition, FileId, FilePosition, FileRange, |
12 | }; | 12 | }; |
13 | use ra_syntax::TextRange; | ||
14 | use rustc_hash::FxHashMap; | ||
15 | 13 | ||
16 | /// Mock analysis is used in test to bootstrap an AnalysisHost/Analysis | 14 | /// Mock analysis is used in test to bootstrap an AnalysisHost/Analysis |
17 | /// from a set of in-memory files. | 15 | /// from a set of in-memory files. |
@@ -81,27 +79,23 @@ impl MockAnalysis { | |||
81 | .expect("no file in this mock"); | 79 | .expect("no file in this mock"); |
82 | FileId(idx as u32 + 1) | 80 | FileId(idx as u32 + 1) |
83 | } | 81 | } |
84 | pub fn annotations(&self) -> FxHashMap<FileId, Vec<(TextRange, String)>> { | 82 | pub fn annotations(&self) -> Vec<(FileRange, String)> { |
85 | self.files | 83 | self.files |
86 | .iter() | 84 | .iter() |
87 | .enumerate() | 85 | .enumerate() |
88 | .filter_map(|(idx, fixture)| { | 86 | .flat_map(|(idx, fixture)| { |
89 | let file_id = FileId(idx as u32 + 1); | 87 | let file_id = FileId(idx as u32 + 1); |
90 | let annotations = extract_annotations(&fixture.text); | 88 | let annotations = extract_annotations(&fixture.text); |
91 | if annotations.is_empty() { | 89 | annotations |
92 | return None; | 90 | .into_iter() |
93 | } | 91 | .map(move |(range, data)| (FileRange { file_id, range }, data)) |
94 | Some((file_id, annotations)) | ||
95 | }) | 92 | }) |
96 | .collect() | 93 | .collect() |
97 | } | 94 | } |
98 | pub fn annotation(&self) -> (FileRange, String) { | 95 | pub fn annotation(&self) -> (FileRange, String) { |
99 | let all = self.annotations(); | 96 | let mut all = self.annotations(); |
100 | assert_eq!(all.len(), 1); | 97 | assert_eq!(all.len(), 1); |
101 | let (file_id, mut for_file) = all.into_iter().next().unwrap(); | 98 | all.pop().unwrap() |
102 | assert_eq!(for_file.len(), 1); | ||
103 | let (range, data) = for_file.pop().unwrap(); | ||
104 | (FileRange { file_id, range}, data) | ||
105 | } | 99 | } |
106 | pub fn analysis_host(self) -> AnalysisHost { | 100 | pub fn analysis_host(self) -> AnalysisHost { |
107 | let mut host = AnalysisHost::default(); | 101 | let mut host = AnalysisHost::default(); |