diff options
author | Aleksey Kladov <[email protected]> | 2018-12-08 18:18:29 +0000 |
---|---|---|
committer | Aleksey Kladov <[email protected]> | 2018-12-08 18:18:29 +0000 |
commit | 7fd6a41127dc9a60efe703f7d588f8555b8bffc6 (patch) | |
tree | 91695d49c0dd47ce0543161b57b8986fa37eeb6b /crates | |
parent | 7a79cde107ec71abbc7c715e933f29f7a1fb2b95 (diff) |
Refactor symbol resolve API
Introduce ReferenceResolution to avoid nesting to many non-nominal
types.
Diffstat (limited to 'crates')
-rw-r--r-- | crates/ra_analysis/src/imp.rs | 27 | ||||
-rw-r--r-- | crates/ra_analysis/src/lib.rs | 26 | ||||
-rw-r--r-- | crates/ra_analysis/tests/tests.rs | 15 | ||||
-rw-r--r-- | crates/ra_lsp_server/src/main_loop/handlers.rs | 15 |
4 files changed, 59 insertions, 24 deletions
diff --git a/crates/ra_analysis/src/imp.rs b/crates/ra_analysis/src/imp.rs index 99bcf0666..03d17de0d 100644 --- a/crates/ra_analysis/src/imp.rs +++ b/crates/ra_analysis/src/imp.rs | |||
@@ -27,6 +27,7 @@ use crate::{ | |||
27 | symbol_index::{SymbolIndex, SymbolsDatabase}, | 27 | symbol_index::{SymbolIndex, SymbolsDatabase}, |
28 | AnalysisChange, Cancelable, CrateId, Diagnostic, FileId, | 28 | AnalysisChange, Cancelable, CrateId, Diagnostic, FileId, |
29 | FileSystemEdit, FilePosition, Query, SourceChange, SourceFileNodeEdit, | 29 | FileSystemEdit, FilePosition, Query, SourceChange, SourceFileNodeEdit, |
30 | ReferenceResolution, | ||
30 | }; | 31 | }; |
31 | 32 | ||
32 | #[derive(Debug, Default)] | 33 | #[derive(Debug, Default)] |
@@ -206,10 +207,11 @@ impl AnalysisImpl { | |||
206 | pub fn approximately_resolve_symbol( | 207 | pub fn approximately_resolve_symbol( |
207 | &self, | 208 | &self, |
208 | position: FilePosition, | 209 | position: FilePosition, |
209 | ) -> Cancelable<Option<(TextRange, Vec<(FileId, FileSymbol)>)>> { | 210 | ) -> Cancelable<Option<ReferenceResolution>> { |
210 | let file = self.db.source_file(position.file_id); | 211 | let file = self.db.source_file(position.file_id); |
211 | let syntax = file.syntax(); | 212 | let syntax = file.syntax(); |
212 | if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(syntax, position.offset) { | 213 | if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(syntax, position.offset) { |
214 | let mut rr = ReferenceResolution::new(name_ref.syntax().range()); | ||
213 | if let Some(fn_descr) = source_binder::function_from_child_node( | 215 | if let Some(fn_descr) = source_binder::function_from_child_node( |
214 | &*self.db, | 216 | &*self.db, |
215 | position.file_id, | 217 | position.file_id, |
@@ -218,24 +220,25 @@ impl AnalysisImpl { | |||
218 | let scope = fn_descr.scope(&*self.db); | 220 | let scope = fn_descr.scope(&*self.db); |
219 | // First try to resolve the symbol locally | 221 | // First try to resolve the symbol locally |
220 | if let Some(entry) = scope.resolve_local_name(name_ref) { | 222 | if let Some(entry) = scope.resolve_local_name(name_ref) { |
221 | let vec = vec![( | 223 | rr.add_resolution( |
222 | position.file_id, | 224 | position.file_id, |
223 | FileSymbol { | 225 | FileSymbol { |
224 | name: entry.name().clone(), | 226 | name: entry.name().clone(), |
225 | node_range: entry.ptr().range(), | 227 | node_range: entry.ptr().range(), |
226 | kind: NAME, | 228 | kind: NAME, |
227 | }, | 229 | }, |
228 | )]; | 230 | ); |
229 | return Ok(Some((name_ref.syntax().range(), vec))); | 231 | return Ok(Some(rr)); |
230 | }; | 232 | }; |
231 | } | 233 | } |
232 | // If that fails try the index based approach. | 234 | // If that fails try the index based approach. |
233 | return Ok(Some(( | 235 | for (file_id, symbol) in self.index_resolve(name_ref)? { |
234 | name_ref.syntax().range(), | 236 | rr.add_resolution(file_id, symbol); |
235 | self.index_resolve(name_ref)?, | 237 | } |
236 | ))); | 238 | return Ok(Some(rr)); |
237 | } | 239 | } |
238 | if let Some(name) = find_node_at_offset::<ast::Name>(syntax, position.offset) { | 240 | if let Some(name) = find_node_at_offset::<ast::Name>(syntax, position.offset) { |
241 | let mut rr = ReferenceResolution::new(name.syntax().range()); | ||
239 | if let Some(module) = name.syntax().parent().and_then(ast::Module::cast) { | 242 | if let Some(module) = name.syntax().parent().and_then(ast::Module::cast) { |
240 | if module.has_semi() { | 243 | if module.has_semi() { |
241 | let parent_module = | 244 | let parent_module = |
@@ -250,7 +253,8 @@ impl AnalysisImpl { | |||
250 | node_range: TextRange::offset_len(0.into(), 0.into()), | 253 | node_range: TextRange::offset_len(0.into(), 0.into()), |
251 | kind: MODULE, | 254 | kind: MODULE, |
252 | }; | 255 | }; |
253 | return Ok(Some((name.syntax().range(), vec![(file_id, symbol)]))); | 256 | rr.add_resolution(file_id, symbol); |
257 | return Ok(Some(rr)); | ||
254 | } | 258 | } |
255 | } | 259 | } |
256 | _ => (), | 260 | _ => (), |
@@ -258,10 +262,7 @@ impl AnalysisImpl { | |||
258 | } | 262 | } |
259 | } | 263 | } |
260 | } | 264 | } |
261 | let range = | 265 | Ok(None) |
262 | ctry!(ra_syntax::algo::find_leaf_at_offset(syntax, position.offset).left_biased()) | ||
263 | .range(); | ||
264 | Ok(Some((range, vec![]))) | ||
265 | } | 266 | } |
266 | 267 | ||
267 | pub fn find_all_refs(&self, position: FilePosition) -> Cancelable<Vec<(FileId, TextRange)>> { | 268 | pub fn find_all_refs(&self, position: FilePosition) -> Cancelable<Vec<(FileId, TextRange)>> { |
diff --git a/crates/ra_analysis/src/lib.rs b/crates/ra_analysis/src/lib.rs index d33f3e4ca..eaf24cb36 100644 --- a/crates/ra_analysis/src/lib.rs +++ b/crates/ra_analysis/src/lib.rs | |||
@@ -178,6 +178,30 @@ impl Query { | |||
178 | } | 178 | } |
179 | } | 179 | } |
180 | 180 | ||
181 | /// Result of "goto def" query. | ||
182 | #[derive(Debug)] | ||
183 | pub struct ReferenceResolution { | ||
184 | /// The range of the reference itself. Client does not know what constitutes | ||
185 | /// a reference, it handles us only the offset. It's helpful to tell the | ||
186 | /// client where the reference was. | ||
187 | pub reference_range: TextRange, | ||
188 | /// What this reference resolves to. | ||
189 | pub resolves_to: Vec<(FileId, FileSymbol)>, | ||
190 | } | ||
191 | |||
192 | impl ReferenceResolution { | ||
193 | fn new(reference_range: TextRange) -> ReferenceResolution { | ||
194 | ReferenceResolution { | ||
195 | reference_range, | ||
196 | resolves_to: Vec::new(), | ||
197 | } | ||
198 | } | ||
199 | |||
200 | fn add_resolution(&mut self, file_id: FileId, symbol: FileSymbol) { | ||
201 | self.resolves_to.push((file_id, symbol)) | ||
202 | } | ||
203 | } | ||
204 | |||
181 | /// Analysis is a snapshot of a world state at a moment in time. It is the main | 205 | /// Analysis is a snapshot of a world state at a moment in time. It is the main |
182 | /// entry point for asking semantic information about the world. When the world | 206 | /// entry point for asking semantic information about the world. When the world |
183 | /// state is advanced using `AnalysisHost::apply_change` method, all existing | 207 | /// state is advanced using `AnalysisHost::apply_change` method, all existing |
@@ -236,7 +260,7 @@ impl Analysis { | |||
236 | pub fn approximately_resolve_symbol( | 260 | pub fn approximately_resolve_symbol( |
237 | &self, | 261 | &self, |
238 | position: FilePosition, | 262 | position: FilePosition, |
239 | ) -> Cancelable<Option<(TextRange, Vec<(FileId, FileSymbol)>)>> { | 263 | ) -> Cancelable<Option<ReferenceResolution>> { |
240 | self.imp.approximately_resolve_symbol(position) | 264 | self.imp.approximately_resolve_symbol(position) |
241 | } | 265 | } |
242 | pub fn find_all_refs(&self, position: FilePosition) -> Cancelable<Vec<(FileId, TextRange)>> { | 266 | pub fn find_all_refs(&self, position: FilePosition) -> Cancelable<Vec<(FileId, TextRange)>> { |
diff --git a/crates/ra_analysis/tests/tests.rs b/crates/ra_analysis/tests/tests.rs index 05ad687ae..889b568b9 100644 --- a/crates/ra_analysis/tests/tests.rs +++ b/crates/ra_analysis/tests/tests.rs | |||
@@ -23,7 +23,10 @@ fn approximate_resolve_works_in_items() { | |||
23 | 23 | ||
24 | let symbols = analysis.approximately_resolve_symbol(pos).unwrap().unwrap(); | 24 | let symbols = analysis.approximately_resolve_symbol(pos).unwrap().unwrap(); |
25 | assert_eq_dbg( | 25 | assert_eq_dbg( |
26 | r#"([23; 26), [(FileId(1), FileSymbol { name: "Foo", node_range: [0; 11), kind: STRUCT_DEF })])"#, | 26 | r#"ReferenceResolution { |
27 | reference_range: [23; 26), | ||
28 | resolves_to: [(FileId(1), FileSymbol { name: "Foo", node_range: [0; 11), kind: STRUCT_DEF })] | ||
29 | }"#, | ||
27 | &symbols, | 30 | &symbols, |
28 | ); | 31 | ); |
29 | } | 32 | } |
@@ -41,7 +44,10 @@ fn test_resolve_module() { | |||
41 | 44 | ||
42 | let symbols = analysis.approximately_resolve_symbol(pos).unwrap().unwrap(); | 45 | let symbols = analysis.approximately_resolve_symbol(pos).unwrap().unwrap(); |
43 | assert_eq_dbg( | 46 | assert_eq_dbg( |
44 | r#"([4; 7), [(FileId(2), FileSymbol { name: "foo", node_range: [0; 0), kind: MODULE })])"#, | 47 | r#"ReferenceResolution { |
48 | reference_range: [4; 7), | ||
49 | resolves_to: [(FileId(2), FileSymbol { name: "foo", node_range: [0; 0), kind: MODULE })] | ||
50 | }"#, | ||
45 | &symbols, | 51 | &symbols, |
46 | ); | 52 | ); |
47 | 53 | ||
@@ -56,7 +62,10 @@ fn test_resolve_module() { | |||
56 | 62 | ||
57 | let symbols = analysis.approximately_resolve_symbol(pos).unwrap().unwrap(); | 63 | let symbols = analysis.approximately_resolve_symbol(pos).unwrap().unwrap(); |
58 | assert_eq_dbg( | 64 | assert_eq_dbg( |
59 | r#"([4; 7), [(FileId(2), FileSymbol { name: "foo", node_range: [0; 0), kind: MODULE })])"#, | 65 | r#"ReferenceResolution { |
66 | reference_range: [4; 7), | ||
67 | resolves_to: [(FileId(2), FileSymbol { name: "foo", node_range: [0; 0), kind: MODULE })] | ||
68 | }"#, | ||
60 | &symbols, | 69 | &symbols, |
61 | ); | 70 | ); |
62 | } | 71 | } |
diff --git a/crates/ra_lsp_server/src/main_loop/handlers.rs b/crates/ra_lsp_server/src/main_loop/handlers.rs index f18a1305d..92e92f836 100644 --- a/crates/ra_lsp_server/src/main_loop/handlers.rs +++ b/crates/ra_lsp_server/src/main_loop/handlers.rs | |||
@@ -203,11 +203,12 @@ pub fn handle_goto_definition( | |||
203 | params: req::TextDocumentPositionParams, | 203 | params: req::TextDocumentPositionParams, |
204 | ) -> Result<Option<req::GotoDefinitionResponse>> { | 204 | ) -> Result<Option<req::GotoDefinitionResponse>> { |
205 | let position = params.try_conv_with(&world)?; | 205 | let position = params.try_conv_with(&world)?; |
206 | let mut res = Vec::new(); | 206 | let rr = match world.analysis().approximately_resolve_symbol(position)? { |
207 | for (file_id, symbol) in match world.analysis().approximately_resolve_symbol(position)? { | ||
208 | None => return Ok(None), | 207 | None => return Ok(None), |
209 | Some(it) => it.1, | 208 | Some(it) => it, |
210 | } { | 209 | }; |
210 | let mut res = Vec::new(); | ||
211 | for (file_id, symbol) in rr.resolves_to { | ||
211 | let line_index = world.analysis().file_line_index(file_id); | 212 | let line_index = world.analysis().file_line_index(file_id); |
212 | let location = to_location(file_id, symbol.node_range, &world, &line_index)?; | 213 | let location = to_location(file_id, symbol.node_range, &world, &line_index)?; |
213 | res.push(location) | 214 | res.push(location) |
@@ -510,17 +511,17 @@ pub fn handle_hover( | |||
510 | // TODO: Cut down on number of allocations | 511 | // TODO: Cut down on number of allocations |
511 | let position = params.try_conv_with(&world)?; | 512 | let position = params.try_conv_with(&world)?; |
512 | let line_index = world.analysis().file_line_index(position.file_id); | 513 | let line_index = world.analysis().file_line_index(position.file_id); |
513 | let (range, resolved) = match world.analysis().approximately_resolve_symbol(position)? { | 514 | let rr = match world.analysis().approximately_resolve_symbol(position)? { |
514 | None => return Ok(None), | 515 | None => return Ok(None), |
515 | Some(it) => it, | 516 | Some(it) => it, |
516 | }; | 517 | }; |
517 | let mut result = Vec::new(); | 518 | let mut result = Vec::new(); |
518 | for (file_id, symbol) in resolved { | 519 | for (file_id, symbol) in rr.resolves_to { |
519 | if let Some(docs) = world.analysis().doc_text_for(file_id, symbol)? { | 520 | if let Some(docs) = world.analysis().doc_text_for(file_id, symbol)? { |
520 | result.push(docs); | 521 | result.push(docs); |
521 | } | 522 | } |
522 | } | 523 | } |
523 | let range = range.conv_with(&line_index); | 524 | let range = rr.reference_range.conv_with(&line_index); |
524 | if result.len() > 0 { | 525 | if result.len() > 0 { |
525 | return Ok(Some(Hover { | 526 | return Ok(Some(Hover { |
526 | contents: HoverContents::Scalar(MarkedString::String(result.join("\n\n---\n"))), | 527 | contents: HoverContents::Scalar(MarkedString::String(result.join("\n\n---\n"))), |