aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/ra_analysis/src/imp.rs27
-rw-r--r--crates/ra_analysis/src/lib.rs26
-rw-r--r--crates/ra_analysis/tests/tests.rs15
-rw-r--r--crates/ra_lsp_server/src/main_loop/handlers.rs15
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)]
183pub 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
192impl 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"))),