aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
Diffstat (limited to 'crates')
-rw-r--r--crates/ra_analysis/src/imp.rs18
-rw-r--r--crates/ra_editor/src/lib.rs10
-rw-r--r--crates/ra_editor/src/scope/fn_scope.rs74
-rw-r--r--crates/ra_editor/src/scope/mod.rs2
4 files changed, 97 insertions, 7 deletions
diff --git a/crates/ra_analysis/src/imp.rs b/crates/ra_analysis/src/imp.rs
index 90184a4b9..517867e86 100644
--- a/crates/ra_analysis/src/imp.rs
+++ b/crates/ra_analysis/src/imp.rs
@@ -9,7 +9,7 @@ use std::{
9}; 9};
10 10
11use relative_path::RelativePath; 11use relative_path::RelativePath;
12use ra_editor::{self, FileSymbol, LineIndex, find_node_at_offset, LocalEdit}; 12use ra_editor::{self, FileSymbol, LineIndex, find_node_at_offset, LocalEdit, resolve_local_name};
13use ra_syntax::{ 13use ra_syntax::{
14 TextUnit, TextRange, SmolStr, File, AstNode, 14 TextUnit, TextRange, SmolStr, File, AstNode,
15 SyntaxKind::*, 15 SyntaxKind::*,
@@ -197,7 +197,21 @@ impl AnalysisImpl {
197 let file = root.syntax(file_id); 197 let file = root.syntax(file_id);
198 let syntax = file.syntax(); 198 let syntax = file.syntax();
199 if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(syntax, offset) { 199 if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(syntax, offset) {
200 return self.index_resolve(name_ref, token); 200
201 // First try to resolve the symbol locally
202 if let Some((name, range)) = resolve_local_name(&file, offset, name_ref) {
203 let mut vec = vec![];
204 vec.push((file_id, FileSymbol {
205 name,
206 node_range: range,
207 kind : NAME
208 }));
209
210 return vec;
211 } else {
212 // If that fails try the index based approach.
213 return self.index_resolve(name_ref, token);
214 }
201 } 215 }
202 if let Some(name) = find_node_at_offset::<ast::Name>(syntax, offset) { 216 if let Some(name) = find_node_at_offset::<ast::Name>(syntax, offset) {
203 if let Some(module) = name.syntax().parent().and_then(ast::Module::cast) { 217 if let Some(module) = name.syntax().parent().and_then(ast::Module::cast) {
diff --git a/crates/ra_editor/src/lib.rs b/crates/ra_editor/src/lib.rs
index a93924e00..2a801f7da 100644
--- a/crates/ra_editor/src/lib.rs
+++ b/crates/ra_editor/src/lib.rs
@@ -19,7 +19,7 @@ mod scope;
19mod test_utils; 19mod test_utils;
20 20
21use ra_syntax::{ 21use ra_syntax::{
22 File, TextUnit, TextRange, SyntaxNodeRef, 22 File, TextUnit, TextRange, SmolStr, SyntaxNodeRef,
23 ast::{self, AstNode, NameOwner}, 23 ast::{self, AstNode, NameOwner},
24 algo::find_leaf_at_offset, 24 algo::find_leaf_at_offset,
25 SyntaxKind::{self, *}, 25 SyntaxKind::{self, *},
@@ -164,6 +164,14 @@ pub fn find_node_at_offset<'a, N: AstNode<'a>>(
164 .next() 164 .next()
165} 165}
166 166
167pub fn resolve_local_name(file: &File, offset: TextUnit, name_ref: ast::NameRef) -> Option<(SmolStr, TextRange)> {
168 let fn_def = find_node_at_offset::<ast::FnDef>(file.syntax(), offset)?;
169 let scopes = scope::FnScopes::new(fn_def);
170 let scope_entry = scope::resolve_local_name(name_ref, &scopes)?;
171 let name = scope_entry.ast().name()?;
172 Some((scope_entry.name(), name.syntax().range()))
173}
174
167#[cfg(test)] 175#[cfg(test)]
168mod tests { 176mod tests {
169 use super::*; 177 use super::*;
diff --git a/crates/ra_editor/src/scope/fn_scope.rs b/crates/ra_editor/src/scope/fn_scope.rs
index eddd87495..a99bd1822 100644
--- a/crates/ra_editor/src/scope/fn_scope.rs
+++ b/crates/ra_editor/src/scope/fn_scope.rs
@@ -89,7 +89,7 @@ impl ScopeEntry {
89 .unwrap() 89 .unwrap()
90 .text() 90 .text()
91 } 91 }
92 fn ast(&self) -> ast::BindPat { 92 pub fn ast(&self) -> ast::BindPat {
93 ast::BindPat::cast(self.syntax.borrowed()) 93 ast::BindPat::cast(self.syntax.borrowed())
94 .unwrap() 94 .unwrap()
95 } 95 }
@@ -241,6 +241,17 @@ struct ScopeData {
241 entries: Vec<ScopeEntry> 241 entries: Vec<ScopeEntry>
242} 242}
243 243
244pub fn resolve_local_name<'a>(name_ref: ast::NameRef, scopes: &'a FnScopes) -> Option<&'a ScopeEntry> {
245 use std::collections::HashSet;
246
247 let mut shadowed = HashSet::new();
248 scopes.scope_chain(name_ref.syntax())
249 .flat_map(|scope| scopes.entries(scope).iter())
250 .filter(|entry| shadowed.insert(entry.name()))
251 .filter(|entry| entry.name() == name_ref.text())
252 .nth(0)
253}
254
244#[cfg(test)] 255#[cfg(test)]
245mod tests { 256mod tests {
246 use super::*; 257 use super::*;
@@ -265,7 +276,7 @@ mod tests {
265 .flat_map(|scope| scopes.entries(scope)) 276 .flat_map(|scope| scopes.entries(scope))
266 .map(|it| it.name()) 277 .map(|it| it.name())
267 .collect::<Vec<_>>(); 278 .collect::<Vec<_>>();
268 assert_eq!(expected, actual.as_slice()); 279 assert_eq!(actual.as_slice(), expected);
269 } 280 }
270 281
271 #[test] 282 #[test]
@@ -326,4 +337,61 @@ mod tests {
326 &["x"], 337 &["x"],
327 ); 338 );
328 } 339 }
329} 340
341 #[test]
342 fn test_shadow_variable() {
343 do_check(r"
344 fn foo(x: String) {
345 let x : &str = &x<|>;
346 }",
347 &["x"],
348 );
349 }
350
351 fn do_check_local_name(code: &str, expected_offset: u32) {
352 let (off, code) = extract_offset(code);
353 let file = File::parse(&code);
354 let fn_def: ast::FnDef = find_node_at_offset(file.syntax(), off).unwrap();
355 let name_ref: ast::NameRef = find_node_at_offset(file.syntax(), off).unwrap();
356
357 let scopes = FnScopes::new(fn_def);
358
359 let local_name = resolve_local_name(name_ref, &scopes).unwrap().ast().name().unwrap();
360
361 let expected_name = find_node_at_offset::<ast::Name>(file.syntax(), expected_offset.into()).unwrap();
362 assert_eq!(local_name.syntax().range(), expected_name.syntax().range());
363 }
364
365 #[test]
366 fn test_resolve_local_name() {
367 do_check_local_name(r#"
368 fn foo(x: i32, y: u32) {
369 {
370 let z = x * 2;
371 }
372 {
373 let t = x<|> * 3;
374 }
375 }"#,
376 21);
377 }
378
379 #[test]
380 fn test_resolve_local_name_declaration() {
381 do_check_local_name(r#"
382 fn foo(x: String) {
383 let x : &str = &x<|>;
384 }"#,
385 21);
386 }
387
388 #[test]
389 fn test_resolve_local_name_shadow() {
390 do_check_local_name(r"
391 fn foo(x: String) {
392 let x : &str = &x;
393 x<|>
394 }",
395 46);
396 }
397} \ No newline at end of file
diff --git a/crates/ra_editor/src/scope/mod.rs b/crates/ra_editor/src/scope/mod.rs
index 2f25230f8..7d6d530f7 100644
--- a/crates/ra_editor/src/scope/mod.rs
+++ b/crates/ra_editor/src/scope/mod.rs
@@ -2,7 +2,7 @@ mod fn_scope;
2mod mod_scope; 2mod mod_scope;
3 3
4pub use self::{ 4pub use self::{
5 fn_scope::FnScopes, 5 fn_scope::{FnScopes, resolve_local_name},
6 mod_scope::ModuleScope, 6 mod_scope::ModuleScope,
7}; 7};
8 8