aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir_def/src/body/scope.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir_def/src/body/scope.rs')
-rw-r--r--crates/ra_hir_def/src/body/scope.rs140
1 files changed, 96 insertions, 44 deletions
diff --git a/crates/ra_hir_def/src/body/scope.rs b/crates/ra_hir_def/src/body/scope.rs
index e48ff38f9..99e876683 100644
--- a/crates/ra_hir_def/src/body/scope.rs
+++ b/crates/ra_hir_def/src/body/scope.rs
@@ -87,15 +87,13 @@ impl ExprScopes {
87 } 87 }
88 88
89 fn add_bindings(&mut self, body: &Body, scope: ScopeId, pat: PatId) { 89 fn add_bindings(&mut self, body: &Body, scope: ScopeId, pat: PatId) {
90 match &body[pat] { 90 let pattern = &body[pat];
91 Pat::Bind { name, .. } => { 91 if let Pat::Bind { name, .. } = pattern {
92 // bind can have a sub pattern, but it's actually not allowed 92 let entry = ScopeEntry { name: name.clone(), pat };
93 // to bind to things in there 93 self.scopes[scope].entries.push(entry);
94 let entry = ScopeEntry { name: name.clone(), pat };
95 self.scopes[scope].entries.push(entry)
96 }
97 p => p.walk_child_pats(|pat| self.add_bindings(body, scope, pat)),
98 } 94 }
95
96 pattern.walk_child_pats(|pat| self.add_bindings(body, scope, pat));
99 } 97 }
100 98
101 fn add_params_bindings(&mut self, body: &Body, scope: ScopeId, params: &[PatId]) { 99 fn add_params_bindings(&mut self, body: &Body, scope: ScopeId, params: &[PatId]) {
@@ -190,21 +188,23 @@ mod tests {
190 } 188 }
191 } 189 }
192 190
193 fn do_check(code: &str, expected: &[&str]) { 191 fn do_check(ra_fixture: &str, expected: &[&str]) {
194 let (off, code) = extract_offset(code); 192 let (offset, code) = extract_offset(ra_fixture);
195 let code = { 193 let code = {
196 let mut buf = String::new(); 194 let mut buf = String::new();
197 let off: usize = off.into(); 195 let off: usize = offset.into();
198 buf.push_str(&code[..off]); 196 buf.push_str(&code[..off]);
199 buf.push_str("marker"); 197 buf.push_str("<|>marker");
200 buf.push_str(&code[off..]); 198 buf.push_str(&code[off..]);
201 buf 199 buf
202 }; 200 };
203 201
204 let (db, file_id) = TestDB::with_single_file(&code); 202 let (db, position) = TestDB::with_position(&code);
203 let file_id = position.file_id;
204 let offset = position.offset;
205 205
206 let file_syntax = db.parse(file_id).syntax_node(); 206 let file_syntax = db.parse(file_id).syntax_node();
207 let marker: ast::PathExpr = find_node_at_offset(&file_syntax, off).unwrap(); 207 let marker: ast::PathExpr = find_node_at_offset(&file_syntax, offset).unwrap();
208 let function = find_function(&db, file_id); 208 let function = find_function(&db, file_id);
209 209
210 let scopes = db.expr_scopes(function.into()); 210 let scopes = db.expr_scopes(function.into());
@@ -300,15 +300,65 @@ mod tests {
300 ); 300 );
301 } 301 }
302 302
303 fn do_check_local_name(code: &str, expected_offset: u32) { 303 #[test]
304 let (off, code) = extract_offset(code); 304 fn test_bindings_after_at() {
305 do_check(
306 r"
307fn foo() {
308 match Some(()) {
309 opt @ Some(unit) => {
310 <|>
311 }
312 _ => {}
313 }
314}
315",
316 &["opt", "unit"],
317 );
318 }
319
320 #[test]
321 fn macro_inner_item() {
322 do_check(
323 r"
324 macro_rules! mac {
325 () => {{
326 fn inner() {}
327 inner();
328 }};
329 }
330
331 fn foo() {
332 mac!();
333 <|>
334 }
335 ",
336 &[],
337 );
338 }
339
340 #[test]
341 fn broken_inner_item() {
342 do_check(
343 r"
344 fn foo() {
345 trait {}
346 <|>
347 }
348 ",
349 &[],
350 );
351 }
305 352
306 let (db, file_id) = TestDB::with_single_file(&code); 353 fn do_check_local_name(ra_fixture: &str, expected_offset: u32) {
354 let (db, position) = TestDB::with_position(ra_fixture);
355 let file_id = position.file_id;
356 let offset = position.offset;
307 357
308 let file = db.parse(file_id).ok().unwrap(); 358 let file = db.parse(file_id).ok().unwrap();
309 let expected_name = find_node_at_offset::<ast::Name>(file.syntax(), expected_offset.into()) 359 let expected_name = find_node_at_offset::<ast::Name>(file.syntax(), expected_offset.into())
310 .expect("failed to find a name at the target offset"); 360 .expect("failed to find a name at the target offset");
311 let name_ref: ast::NameRef = find_node_at_offset(file.syntax(), off).unwrap(); 361 let name_ref: ast::NameRef = find_node_at_offset(file.syntax(), offset).unwrap();
312 362
313 let function = find_function(&db, file_id); 363 let function = find_function(&db, file_id);
314 364
@@ -336,15 +386,16 @@ mod tests {
336 fn test_resolve_local_name() { 386 fn test_resolve_local_name() {
337 do_check_local_name( 387 do_check_local_name(
338 r#" 388 r#"
339 fn foo(x: i32, y: u32) { 389fn foo(x: i32, y: u32) {
340 { 390 {
341 let z = x * 2; 391 let z = x * 2;
342 } 392 }
343 { 393 {
344 let t = x<|> * 3; 394 let t = x<|> * 3;
345 } 395 }
346 }"#, 396}
347 21, 397"#,
398 7,
348 ); 399 );
349 } 400 }
350 401
@@ -352,10 +403,11 @@ mod tests {
352 fn test_resolve_local_name_declaration() { 403 fn test_resolve_local_name_declaration() {
353 do_check_local_name( 404 do_check_local_name(
354 r#" 405 r#"
355 fn foo(x: String) { 406fn foo(x: String) {
356 let x : &str = &x<|>; 407 let x : &str = &x<|>;
357 }"#, 408}
358 21, 409"#,
410 7,
359 ); 411 );
360 } 412 }
361 413
@@ -363,12 +415,12 @@ mod tests {
363 fn test_resolve_local_name_shadow() { 415 fn test_resolve_local_name_shadow() {
364 do_check_local_name( 416 do_check_local_name(
365 r" 417 r"
366 fn foo(x: String) { 418fn foo(x: String) {
367 let x : &str = &x; 419 let x : &str = &x;
368 x<|> 420 x<|>
369 } 421}
370 ", 422",
371 53, 423 28,
372 ); 424 );
373 } 425 }
374 426
@@ -376,13 +428,13 @@ mod tests {
376 fn ref_patterns_contribute_bindings() { 428 fn ref_patterns_contribute_bindings() {
377 do_check_local_name( 429 do_check_local_name(
378 r" 430 r"
379 fn foo() { 431fn foo() {
380 if let Some(&from) = bar() { 432 if let Some(&from) = bar() {
381 from<|>; 433 from<|>;
382 } 434 }
383 } 435}
384 ", 436",
385 53, 437 28,
386 ); 438 );
387 } 439 }
388 440