aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_editor/src/scope/fn_scope.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_editor/src/scope/fn_scope.rs')
-rw-r--r--crates/ra_editor/src/scope/fn_scope.rs74
1 files changed, 71 insertions, 3 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
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