diff options
Diffstat (limited to 'crates/ra_editor/src/scope')
-rw-r--r-- | crates/ra_editor/src/scope/fn_scope.rs | 74 | ||||
-rw-r--r-- | crates/ra_editor/src/scope/mod.rs | 2 |
2 files changed, 72 insertions, 4 deletions
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 | ||
244 | pub 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)] |
245 | mod tests { | 256 | mod 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; | |||
2 | mod mod_scope; | 2 | mod mod_scope; |
3 | 3 | ||
4 | pub use self::{ | 4 | pub 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 | ||