aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_editor/src/scope
diff options
context:
space:
mode:
authorJeremy A. Kolb <[email protected]>2018-10-05 15:53:17 +0100
committerJeremy A. Kolb <[email protected]>2018-10-05 15:53:17 +0100
commit91312a9ff98d1f82313c42a2387df49fbdf09ac6 (patch)
treeb09d89eb522394be12c5b522e7b96f3882f9db82 /crates/ra_editor/src/scope
parent81bf190f7aca4cadec5394c397bd7c084b53b9f5 (diff)
Add resolve_local_name to resolve names in a function scope
Diffstat (limited to 'crates/ra_editor/src/scope')
-rw-r--r--crates/ra_editor/src/scope/fn_scope.rs81
1 files changed, 79 insertions, 2 deletions
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 {
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<ast::Name<'a>> {
245 use std::collections::HashSet;
246
247 let mut shadowed = HashSet::new();
248 let names = 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 names.ast().name()
254}
255
244#[cfg(test)] 256#[cfg(test)]
245mod tests { 257mod tests {
246 use super::*; 258 use super::*;
@@ -265,7 +277,7 @@ mod tests {
265 .flat_map(|scope| scopes.entries(scope)) 277 .flat_map(|scope| scopes.entries(scope))
266 .map(|it| it.name()) 278 .map(|it| it.name())
267 .collect::<Vec<_>>(); 279 .collect::<Vec<_>>();
268 assert_eq!(expected, actual.as_slice()); 280 assert_eq!(actual.as_slice(), expected);
269 } 281 }
270 282
271 #[test] 283 #[test]
@@ -326,4 +338,69 @@ mod tests {
326 &["x"], 338 &["x"],
327 ); 339 );
328 } 340 }
329} 341
342 #[test]
343 fn test_shadow_variable() {
344 do_check(r"
345 fn foo(x: String) {
346 let x : &str = &x<|>;
347 }",
348 &["x"],
349 );
350 }
351
352 fn do_check_local_name(code: &str, expected_offset: u32) {
353 let (off, code) = extract_offset(code);
354 let code = {
355 let mut buf = String::new();
356 let off = u32::from(off) as usize;
357 buf.push_str(&code[..off]);
358 buf.push_str(&code[off..]);
359 buf
360 };
361
362 let file = File::parse(&code);
363 let fn_def: ast::FnDef = find_node_at_offset(file.syntax(), off).unwrap();
364 let name_ref: ast::NameRef = find_node_at_offset(file.syntax(), off).unwrap();
365
366 let scopes = FnScopes::new(fn_def);
367
368 let local_name = resolve_local_name(name_ref, &scopes).unwrap();
369
370 let expected_name = find_node_at_offset::<ast::Name>(file.syntax(), expected_offset.into()).unwrap();
371 assert_eq!(local_name.syntax().range(), expected_name.syntax().range());
372 }
373
374 #[test]
375 fn test_resolve_local_name() {
376 do_check_local_name(r#"
377 fn foo(x: i32, y: u32) {
378 {
379 let z = x * 2;
380 }
381 {
382 let t = x<|> * 3;
383 }
384 }"#,
385 21);
386 }
387
388 #[test]
389 fn test_resolve_local_name_declaration() {
390 do_check_local_name(r#"
391 fn foo(x: String) {
392 let x : &str = &x<|>;
393 }"#,
394 21);
395 }
396
397 #[test]
398 fn test_resolve_local_name_shadow() {
399 do_check_local_name(r"
400 fn foo(x: String) {
401 let x : &str = &x;
402 x<|>
403 }",
404 46);
405 }
406} \ No newline at end of file