aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_editor
diff options
context:
space:
mode:
authorbors[bot] <bors[bot]@users.noreply.github.com>2018-10-07 18:01:57 +0100
committerbors[bot] <bors[bot]@users.noreply.github.com>2018-10-07 18:01:57 +0100
commite4fdfd15012c983e4555996aa466b57d787e4385 (patch)
tree33b5209f553bf29cc409d3d8e71107f841af89ba /crates/ra_editor
parentf53c8aee065fac2816b50964d4b7544c84d67837 (diff)
parentff1b2da50280ef40988ce79f8bb5e82aff7e68c5 (diff)
Merge #98
98: WIP: Add resolve_local_name to resolve names in a function scope r=kjeremy a=kjeremy First step to resolving #80 Co-authored-by: Jeremy A. Kolb <[email protected]>
Diffstat (limited to 'crates/ra_editor')
-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
3 files changed, 81 insertions, 5 deletions
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