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.rs150
1 files changed, 95 insertions, 55 deletions
diff --git a/crates/ra_editor/src/scope/fn_scope.rs b/crates/ra_editor/src/scope/fn_scope.rs
index 99d698b60..9088e5a60 100644
--- a/crates/ra_editor/src/scope/fn_scope.rs
+++ b/crates/ra_editor/src/scope/fn_scope.rs
@@ -1,10 +1,11 @@
1use std::fmt; 1use std::fmt;
2
2use rustc_hash::FxHashMap; 3use rustc_hash::FxHashMap;
3 4
4use ra_syntax::{ 5use ra_syntax::{
5 SyntaxNodeRef, SyntaxNode, SmolStr, AstNode, 6 algo::generate,
6 ast::{self, NameOwner, LoopBodyOwner, ArgListOwner}, 7 ast::{self, ArgListOwner, LoopBodyOwner, NameOwner},
7 algo::{generate} 8 AstNode, SmolStr, SyntaxNode, SyntaxNodeRef,
8}; 9};
9 10
10type ScopeId = usize; 11type ScopeId = usize;
@@ -19,11 +20,12 @@ pub struct FnScopes {
19impl FnScopes { 20impl FnScopes {
20 pub fn new(fn_def: ast::FnDef) -> FnScopes { 21 pub fn new(fn_def: ast::FnDef) -> FnScopes {
21 let mut scopes = FnScopes { 22 let mut scopes = FnScopes {
22 self_param: fn_def.param_list() 23 self_param: fn_def
24 .param_list()
23 .and_then(|it| it.self_param()) 25 .and_then(|it| it.self_param())
24 .map(|it| it.syntax().owned()), 26 .map(|it| it.syntax().owned()),
25 scopes: Vec::new(), 27 scopes: Vec::new(),
26 scope_for: FxHashMap::default() 28 scope_for: FxHashMap::default(),
27 }; 29 };
28 let root = scopes.root_scope(); 30 let root = scopes.root_scope();
29 scopes.add_params_bindings(root, fn_def.param_list()); 31 scopes.add_params_bindings(root, fn_def.param_list());
@@ -35,27 +37,38 @@ impl FnScopes {
35 pub fn entries(&self, scope: ScopeId) -> &[ScopeEntry] { 37 pub fn entries(&self, scope: ScopeId) -> &[ScopeEntry] {
36 &self.scopes[scope].entries 38 &self.scopes[scope].entries
37 } 39 }
38 pub fn scope_chain<'a>(&'a self, node: SyntaxNodeRef) -> impl Iterator<Item=ScopeId> + 'a { 40 pub fn scope_chain<'a>(&'a self, node: SyntaxNodeRef) -> impl Iterator<Item = ScopeId> + 'a {
39 generate(self.scope_for(node), move |&scope| self.scopes[scope].parent) 41 generate(self.scope_for(node), move |&scope| {
42 self.scopes[scope].parent
43 })
40 } 44 }
41 fn root_scope(&mut self) -> ScopeId { 45 fn root_scope(&mut self) -> ScopeId {
42 let res = self.scopes.len(); 46 let res = self.scopes.len();
43 self.scopes.push(ScopeData { parent: None, entries: vec![] }); 47 self.scopes.push(ScopeData {
48 parent: None,
49 entries: vec![],
50 });
44 res 51 res
45 } 52 }
46 fn new_scope(&mut self, parent: ScopeId) -> ScopeId { 53 fn new_scope(&mut self, parent: ScopeId) -> ScopeId {
47 let res = self.scopes.len(); 54 let res = self.scopes.len();
48 self.scopes.push(ScopeData { parent: Some(parent), entries: vec![] }); 55 self.scopes.push(ScopeData {
56 parent: Some(parent),
57 entries: vec![],
58 });
49 res 59 res
50 } 60 }
51 fn add_bindings(&mut self, scope: ScopeId, pat: ast::Pat) { 61 fn add_bindings(&mut self, scope: ScopeId, pat: ast::Pat) {
52 let entries = pat.syntax().descendants() 62 let entries = pat
63 .syntax()
64 .descendants()
53 .filter_map(ast::BindPat::cast) 65 .filter_map(ast::BindPat::cast)
54 .filter_map(ScopeEntry::new); 66 .filter_map(ScopeEntry::new);
55 self.scopes[scope].entries.extend(entries); 67 self.scopes[scope].entries.extend(entries);
56 } 68 }
57 fn add_params_bindings(&mut self, scope: ScopeId, params: Option<ast::ParamList>) { 69 fn add_params_bindings(&mut self, scope: ScopeId, params: Option<ast::ParamList>) {
58 params.into_iter() 70 params
71 .into_iter()
59 .flat_map(|it| it.params()) 72 .flat_map(|it| it.params())
60 .filter_map(|it| it.pat()) 73 .filter_map(|it| it.pat())
61 .for_each(|it| self.add_bindings(scope, it)); 74 .for_each(|it| self.add_bindings(scope, it));
@@ -71,34 +84,33 @@ impl FnScopes {
71} 84}
72 85
73pub struct ScopeEntry { 86pub struct ScopeEntry {
74 syntax: SyntaxNode 87 syntax: SyntaxNode,
75} 88}
76 89
77impl ScopeEntry { 90impl ScopeEntry {
78 fn new(pat: ast::BindPat) -> Option<ScopeEntry> { 91 fn new(pat: ast::BindPat) -> Option<ScopeEntry> {
79 if pat.name().is_some() { 92 if pat.name().is_some() {
80 Some(ScopeEntry { syntax: pat.syntax().owned() }) 93 Some(ScopeEntry {
94 syntax: pat.syntax().owned(),
95 })
81 } else { 96 } else {
82 None 97 None
83 } 98 }
84 } 99 }
85 pub fn name(&self) -> SmolStr { 100 pub fn name(&self) -> SmolStr {
86 self.ast().name() 101 self.ast().name().unwrap().text()
87 .unwrap()
88 .text()
89 } 102 }
90 pub fn ast(&self) -> ast::BindPat { 103 pub fn ast(&self) -> ast::BindPat {
91 ast::BindPat::cast(self.syntax.borrowed()) 104 ast::BindPat::cast(self.syntax.borrowed()).unwrap()
92 .unwrap()
93 } 105 }
94} 106}
95 107
96impl fmt::Debug for ScopeEntry { 108impl fmt::Debug for ScopeEntry {
97 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 109 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
98 f.debug_struct("ScopeEntry") 110 f.debug_struct("ScopeEntry")
99 .field("name", &self.name()) 111 .field("name", &self.name())
100 .field("syntax", &self.syntax) 112 .field("syntax", &self.syntax)
101 .finish() 113 .finish()
102 } 114 }
103} 115}
104 116
@@ -132,16 +144,16 @@ fn compute_block_scopes(block: ast::Block, scopes: &mut FnScopes, mut scope: Sco
132fn compute_expr_scopes(expr: ast::Expr, scopes: &mut FnScopes, scope: ScopeId) { 144fn compute_expr_scopes(expr: ast::Expr, scopes: &mut FnScopes, scope: ScopeId) {
133 match expr { 145 match expr {
134 ast::Expr::IfExpr(e) => { 146 ast::Expr::IfExpr(e) => {
135 let cond_scope = e.condition().and_then(|cond| { 147 let cond_scope = e
136 compute_cond_scopes(cond, scopes, scope) 148 .condition()
137 }); 149 .and_then(|cond| compute_cond_scopes(cond, scopes, scope));
138 if let Some(block) = e.then_branch() { 150 if let Some(block) = e.then_branch() {
139 compute_block_scopes(block, scopes, cond_scope.unwrap_or(scope)); 151 compute_block_scopes(block, scopes, cond_scope.unwrap_or(scope));
140 } 152 }
141 if let Some(block) = e.else_branch() { 153 if let Some(block) = e.else_branch() {
142 compute_block_scopes(block, scopes, scope); 154 compute_block_scopes(block, scopes, scope);
143 } 155 }
144 }, 156 }
145 ast::Expr::BlockExpr(e) => { 157 ast::Expr::BlockExpr(e) => {
146 if let Some(block) = e.block() { 158 if let Some(block) = e.block() {
147 compute_block_scopes(block, scopes, scope); 159 compute_block_scopes(block, scopes, scope);
@@ -153,9 +165,9 @@ fn compute_expr_scopes(expr: ast::Expr, scopes: &mut FnScopes, scope: ScopeId) {
153 } 165 }
154 } 166 }
155 ast::Expr::WhileExpr(e) => { 167 ast::Expr::WhileExpr(e) => {
156 let cond_scope = e.condition().and_then(|cond| { 168 let cond_scope = e
157 compute_cond_scopes(cond, scopes, scope) 169 .condition()
158 }); 170 .and_then(|cond| compute_cond_scopes(cond, scopes, scope));
159 if let Some(block) = e.loop_body() { 171 if let Some(block) = e.loop_body() {
160 compute_block_scopes(block, scopes, cond_scope.unwrap_or(scope)); 172 compute_block_scopes(block, scopes, cond_scope.unwrap_or(scope));
161 } 173 }
@@ -201,25 +213,31 @@ fn compute_expr_scopes(expr: ast::Expr, scopes: &mut FnScopes, scope: ScopeId) {
201 } 213 }
202 } 214 }
203 } 215 }
204 _ => { 216 _ => expr
205 expr.syntax().children() 217 .syntax()
206 .filter_map(ast::Expr::cast) 218 .children()
207 .for_each(|expr| compute_expr_scopes(expr, scopes, scope)) 219 .filter_map(ast::Expr::cast)
208 } 220 .for_each(|expr| compute_expr_scopes(expr, scopes, scope)),
209 }; 221 };
210 222
211 fn compute_call_scopes( 223 fn compute_call_scopes(
212 receiver: Option<ast::Expr>, 224 receiver: Option<ast::Expr>,
213 arg_list: Option<ast::ArgList>, 225 arg_list: Option<ast::ArgList>,
214 scopes: &mut FnScopes, scope: ScopeId, 226 scopes: &mut FnScopes,
227 scope: ScopeId,
215 ) { 228 ) {
216 arg_list.into_iter() 229 arg_list
230 .into_iter()
217 .flat_map(|it| it.args()) 231 .flat_map(|it| it.args())
218 .chain(receiver) 232 .chain(receiver)
219 .for_each(|expr| compute_expr_scopes(expr, scopes, scope)); 233 .for_each(|expr| compute_expr_scopes(expr, scopes, scope));
220 } 234 }
221 235
222 fn compute_cond_scopes(cond: ast::Condition, scopes: &mut FnScopes, scope: ScopeId) -> Option<ScopeId> { 236 fn compute_cond_scopes(
237 cond: ast::Condition,
238 scopes: &mut FnScopes,
239 scope: ScopeId,
240 ) -> Option<ScopeId> {
223 if let Some(expr) = cond.expr() { 241 if let Some(expr) = cond.expr() {
224 compute_expr_scopes(expr, scopes, scope); 242 compute_expr_scopes(expr, scopes, scope);
225 } 243 }
@@ -236,14 +254,18 @@ fn compute_expr_scopes(expr: ast::Expr, scopes: &mut FnScopes, scope: ScopeId) {
236#[derive(Debug)] 254#[derive(Debug)]
237struct ScopeData { 255struct ScopeData {
238 parent: Option<ScopeId>, 256 parent: Option<ScopeId>,
239 entries: Vec<ScopeEntry> 257 entries: Vec<ScopeEntry>,
240} 258}
241 259
242pub fn resolve_local_name<'a>(name_ref: ast::NameRef, scopes: &'a FnScopes) -> Option<&'a ScopeEntry> { 260pub fn resolve_local_name<'a>(
261 name_ref: ast::NameRef,
262 scopes: &'a FnScopes,
263) -> Option<&'a ScopeEntry> {
243 use rustc_hash::FxHashSet; 264 use rustc_hash::FxHashSet;
244 265
245 let mut shadowed = FxHashSet::default(); 266 let mut shadowed = FxHashSet::default();
246 let ret = scopes.scope_chain(name_ref.syntax()) 267 let ret = scopes
268 .scope_chain(name_ref.syntax())
247 .flat_map(|scope| scopes.entries(scope).iter()) 269 .flat_map(|scope| scopes.entries(scope).iter())
248 .filter(|entry| shadowed.insert(entry.name())) 270 .filter(|entry| shadowed.insert(entry.name()))
249 .filter(|entry| entry.name() == name_ref.text()) 271 .filter(|entry| entry.name() == name_ref.text())
@@ -255,8 +277,8 @@ pub fn resolve_local_name<'a>(name_ref: ast::NameRef, scopes: &'a FnScopes) -> O
255#[cfg(test)] 277#[cfg(test)]
256mod tests { 278mod tests {
257 use super::*; 279 use super::*;
258 use ra_syntax::File;
259 use crate::{find_node_at_offset, test_utils::extract_offset}; 280 use crate::{find_node_at_offset, test_utils::extract_offset};
281 use ra_syntax::File;
260 282
261 fn do_check(code: &str, expected: &[&str]) { 283 fn do_check(code: &str, expected: &[&str]) {
262 let (off, code) = extract_offset(code); 284 let (off, code) = extract_offset(code);
@@ -272,7 +294,8 @@ mod tests {
272 let marker: ast::PathExpr = find_node_at_offset(file.syntax(), off).unwrap(); 294 let marker: ast::PathExpr = find_node_at_offset(file.syntax(), off).unwrap();
273 let fn_def: ast::FnDef = find_node_at_offset(file.syntax(), off).unwrap(); 295 let fn_def: ast::FnDef = find_node_at_offset(file.syntax(), off).unwrap();
274 let scopes = FnScopes::new(fn_def); 296 let scopes = FnScopes::new(fn_def);
275 let actual = scopes.scope_chain(marker.syntax()) 297 let actual = scopes
298 .scope_chain(marker.syntax())
276 .flat_map(|scope| scopes.entries(scope)) 299 .flat_map(|scope| scopes.entries(scope))
277 .map(|it| it.name()) 300 .map(|it| it.name())
278 .collect::<Vec<_>>(); 301 .collect::<Vec<_>>();
@@ -281,7 +304,8 @@ mod tests {
281 304
282 #[test] 305 #[test]
283 fn test_lambda_scope() { 306 fn test_lambda_scope() {
284 do_check(r" 307 do_check(
308 r"
285 fn quux(foo: i32) { 309 fn quux(foo: i32) {
286 let f = |bar, baz: i32| { 310 let f = |bar, baz: i32| {
287 <|> 311 <|>
@@ -293,7 +317,8 @@ mod tests {
293 317
294 #[test] 318 #[test]
295 fn test_call_scope() { 319 fn test_call_scope() {
296 do_check(r" 320 do_check(
321 r"
297 fn quux() { 322 fn quux() {
298 f(|x| <|> ); 323 f(|x| <|> );
299 }", 324 }",
@@ -303,7 +328,8 @@ mod tests {
303 328
304 #[test] 329 #[test]
305 fn test_metod_call_scope() { 330 fn test_metod_call_scope() {
306 do_check(r" 331 do_check(
332 r"
307 fn quux() { 333 fn quux() {
308 z.f(|x| <|> ); 334 z.f(|x| <|> );
309 }", 335 }",
@@ -313,7 +339,8 @@ mod tests {
313 339
314 #[test] 340 #[test]
315 fn test_loop_scope() { 341 fn test_loop_scope() {
316 do_check(r" 342 do_check(
343 r"
317 fn quux() { 344 fn quux() {
318 loop { 345 loop {
319 let x = (); 346 let x = ();
@@ -326,7 +353,8 @@ mod tests {
326 353
327 #[test] 354 #[test]
328 fn test_match() { 355 fn test_match() {
329 do_check(r" 356 do_check(
357 r"
330 fn quux() { 358 fn quux() {
331 match () { 359 match () {
332 Some(x) => { 360 Some(x) => {
@@ -340,7 +368,8 @@ mod tests {
340 368
341 #[test] 369 #[test]
342 fn test_shadow_variable() { 370 fn test_shadow_variable() {
343 do_check(r" 371 do_check(
372 r"
344 fn foo(x: String) { 373 fn foo(x: String) {
345 let x : &str = &x<|>; 374 let x : &str = &x<|>;
346 }", 375 }",
@@ -356,14 +385,20 @@ mod tests {
356 385
357 let scopes = FnScopes::new(fn_def); 386 let scopes = FnScopes::new(fn_def);
358 387
359 let local_name = resolve_local_name(name_ref, &scopes).unwrap().ast().name().unwrap(); 388 let local_name = resolve_local_name(name_ref, &scopes)
360 let expected_name = find_node_at_offset::<ast::Name>(file.syntax(), expected_offset.into()).unwrap(); 389 .unwrap()
390 .ast()
391 .name()
392 .unwrap();
393 let expected_name =
394 find_node_at_offset::<ast::Name>(file.syntax(), expected_offset.into()).unwrap();
361 assert_eq!(local_name.syntax().range(), expected_name.syntax().range()); 395 assert_eq!(local_name.syntax().range(), expected_name.syntax().range());
362 } 396 }
363 397
364 #[test] 398 #[test]
365 fn test_resolve_local_name() { 399 fn test_resolve_local_name() {
366 do_check_local_name(r#" 400 do_check_local_name(
401 r#"
367 fn foo(x: i32, y: u32) { 402 fn foo(x: i32, y: u32) {
368 { 403 {
369 let z = x * 2; 404 let z = x * 2;
@@ -372,25 +407,30 @@ mod tests {
372 let t = x<|> * 3; 407 let t = x<|> * 3;
373 } 408 }
374 }"#, 409 }"#,
375 21); 410 21,
411 );
376 } 412 }
377 413
378 #[test] 414 #[test]
379 fn test_resolve_local_name_declaration() { 415 fn test_resolve_local_name_declaration() {
380 do_check_local_name(r#" 416 do_check_local_name(
417 r#"
381 fn foo(x: String) { 418 fn foo(x: String) {
382 let x : &str = &x<|>; 419 let x : &str = &x<|>;
383 }"#, 420 }"#,
384 21); 421 21,
422 );
385 } 423 }
386 424
387 #[test] 425 #[test]
388 fn test_resolve_local_name_shadow() { 426 fn test_resolve_local_name_shadow() {
389 do_check_local_name(r" 427 do_check_local_name(
428 r"
390 fn foo(x: String) { 429 fn foo(x: String) {
391 let x : &str = &x; 430 let x : &str = &x;
392 x<|> 431 x<|>
393 }", 432 }",
394 46); 433 46,
434 );
395 } 435 }
396} 436}