From 91312a9ff98d1f82313c42a2387df49fbdf09ac6 Mon Sep 17 00:00:00 2001 From: "Jeremy A. Kolb" Date: Fri, 5 Oct 2018 10:53:17 -0400 Subject: Add resolve_local_name to resolve names in a function scope --- crates/ra_editor/src/scope/fn_scope.rs | 81 +++++++++++++++++++++++++++++++++- 1 file changed, 79 insertions(+), 2 deletions(-) (limited to 'crates/ra_editor/src') diff --git a/crates/ra_editor/src/scope/fn_scope.rs b/crates/ra_editor/src/scope/fn_scope.rs index eddd87495..03f9df094 100644 --- a/crates/ra_editor/src/scope/fn_scope.rs +++ b/crates/ra_editor/src/scope/fn_scope.rs @@ -241,6 +241,18 @@ struct ScopeData { entries: Vec } +pub fn resolve_local_name<'a>(name_ref: ast::NameRef, scopes: &'a FnScopes) -> Option> { + use std::collections::HashSet; + + let mut shadowed = HashSet::new(); + let names = scopes.scope_chain(name_ref.syntax()) + .flat_map(|scope| scopes.entries(scope).iter()) + .filter(|entry| shadowed.insert(entry.name())) + .filter(|entry| entry.name() == name_ref.text()) + .nth(0)?; + names.ast().name() +} + #[cfg(test)] mod tests { use super::*; @@ -265,7 +277,7 @@ mod tests { .flat_map(|scope| scopes.entries(scope)) .map(|it| it.name()) .collect::>(); - assert_eq!(expected, actual.as_slice()); + assert_eq!(actual.as_slice(), expected); } #[test] @@ -326,4 +338,69 @@ mod tests { &["x"], ); } -} + + #[test] + fn test_shadow_variable() { + do_check(r" + fn foo(x: String) { + let x : &str = &x<|>; + }", + &["x"], + ); + } + + fn do_check_local_name(code: &str, expected_offset: u32) { + let (off, code) = extract_offset(code); + let code = { + let mut buf = String::new(); + let off = u32::from(off) as usize; + buf.push_str(&code[..off]); + buf.push_str(&code[off..]); + buf + }; + + let file = File::parse(&code); + let fn_def: ast::FnDef = find_node_at_offset(file.syntax(), off).unwrap(); + let name_ref: ast::NameRef = find_node_at_offset(file.syntax(), off).unwrap(); + + let scopes = FnScopes::new(fn_def); + + let local_name = resolve_local_name(name_ref, &scopes).unwrap(); + + let expected_name = find_node_at_offset::(file.syntax(), expected_offset.into()).unwrap(); + assert_eq!(local_name.syntax().range(), expected_name.syntax().range()); + } + + #[test] + fn test_resolve_local_name() { + do_check_local_name(r#" + fn foo(x: i32, y: u32) { + { + let z = x * 2; + } + { + let t = x<|> * 3; + } + }"#, + 21); + } + + #[test] + fn test_resolve_local_name_declaration() { + do_check_local_name(r#" + fn foo(x: String) { + let x : &str = &x<|>; + }"#, + 21); + } + + #[test] + fn test_resolve_local_name_shadow() { + do_check_local_name(r" + fn foo(x: String) { + let x : &str = &x; + x<|> + }", + 46); + } +} \ No newline at end of file -- cgit v1.2.3