diff options
author | bors[bot] <bors[bot]@users.noreply.github.com> | 2018-10-07 18:01:57 +0100 |
---|---|---|
committer | bors[bot] <bors[bot]@users.noreply.github.com> | 2018-10-07 18:01:57 +0100 |
commit | e4fdfd15012c983e4555996aa466b57d787e4385 (patch) | |
tree | 33b5209f553bf29cc409d3d8e71107f841af89ba /crates/ra_editor | |
parent | f53c8aee065fac2816b50964d4b7544c84d67837 (diff) | |
parent | ff1b2da50280ef40988ce79f8bb5e82aff7e68c5 (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.rs | 10 | ||||
-rw-r--r-- | crates/ra_editor/src/scope/fn_scope.rs | 74 | ||||
-rw-r--r-- | crates/ra_editor/src/scope/mod.rs | 2 |
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; | |||
19 | mod test_utils; | 19 | mod test_utils; |
20 | 20 | ||
21 | use ra_syntax::{ | 21 | use 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 | ||
167 | pub 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)] |
168 | mod tests { | 176 | mod 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 | ||
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 | ||