aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ide
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_ide')
-rw-r--r--crates/ra_ide/src/display/navigation_target.rs10
-rw-r--r--crates/ra_ide/src/goto_implementation.rs193
-rw-r--r--crates/ra_ide/src/mock_analysis.rs20
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 {
279impl ToNav for hir::ImplDef { 279impl 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)]
76mod tests { 76mod 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 112struct Foo<|>;
93 struct Foo<|>; 113impl 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 123struct Foo<|>;
105 struct Foo<|>; 124impl Foo {}
106 impl Foo {} 125 //^^^
107 impl Foo {} 126impl 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 136struct Foo<|>;
118 struct Foo<|>; 137mod a {
119 mod a { 138 impl super::Foo {}
120 impl super::Foo {} 139 //^^^^^^^^^^
121 } 140}
122 mod b { 141mod 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<|>; 154struct Foo<|>;
136 mod a; 155mod a;
137 mod b; 156mod b;
138 //- /a.rs 157//- /a.rs
139 impl crate::Foo {} 158impl crate::Foo {}
140 //- /b.rs 159 //^^^^^^^^^^
141 impl crate::Foo {} 160//- /b.rs
142 ", 161impl 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 171trait T<|> {}
152 trait T<|> {} 172struct Foo;
153 struct Foo; 173impl 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<|> {}; 184trait T<|> {};
166 struct Foo; 185struct Foo;
167 mod a; 186mod a;
168 mod b; 187mod b;
169 //- /a.rs 188//- /a.rs
170 impl crate::T for crate::Foo {} 189impl crate::T for crate::Foo {}
171 //- /b.rs 190 //^^^^^^^^^^
172 impl crate::T for crate::Foo {} 191//- /b.rs
173 ", 192impl 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 {} 203trait T {}
184 struct Foo<|>; 204struct Foo<|>;
185 impl Foo {} 205impl Foo {}
186 impl T for Foo {} 206 //^^^
187 impl T for &Foo {} 207impl T for Foo {}
188 ", 208 //^^^
189 &[ 209impl 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<|>; 221struct 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::{
10use crate::{ 10use crate::{
11 Analysis, AnalysisChange, AnalysisHost, CrateGraph, Edition, FileId, FilePosition, FileRange, 11 Analysis, AnalysisChange, AnalysisHost, CrateGraph, Edition, FileId, FilePosition, FileRange,
12}; 12};
13use ra_syntax::TextRange;
14use 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();