aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir')
-rw-r--r--crates/ra_hir/src/ids.rs21
-rw-r--r--crates/ra_hir/src/nameres/tests.rs134
2 files changed, 94 insertions, 61 deletions
diff --git a/crates/ra_hir/src/ids.rs b/crates/ra_hir/src/ids.rs
index 2e10e5516..0aa687a08 100644
--- a/crates/ra_hir/src/ids.rs
+++ b/crates/ra_hir/src/ids.rs
@@ -253,13 +253,17 @@ impl SourceFileItems {
253 } 253 }
254 254
255 fn init(&mut self, source_file: &SourceFile) { 255 fn init(&mut self, source_file: &SourceFile) {
256 source_file.syntax().descendants().for_each(|it| { 256 // By walking the tree in bread-first order we make sure that parents
257 // get lower ids then children. That is, addding a new child does not
258 // change parent's id. This means that, say, adding a new function to a
259 // trait does not chage ids of top-level items, which helps caching.
260 bfs(source_file.syntax(), |it| {
257 if let Some(module_item) = ast::ModuleItem::cast(it) { 261 if let Some(module_item) = ast::ModuleItem::cast(it) {
258 self.alloc(module_item.syntax().to_owned()); 262 self.alloc(module_item.syntax().to_owned());
259 } else if let Some(macro_call) = ast::MacroCall::cast(it) { 263 } else if let Some(macro_call) = ast::MacroCall::cast(it) {
260 self.alloc(macro_call.syntax().to_owned()); 264 self.alloc(macro_call.syntax().to_owned());
261 } 265 }
262 }); 266 })
263 } 267 }
264 268
265 fn alloc(&mut self, item: TreePtr<SyntaxNode>) -> SourceFileItemId { 269 fn alloc(&mut self, item: TreePtr<SyntaxNode>) -> SourceFileItemId {
@@ -305,3 +309,16 @@ impl std::ops::Index<SourceFileItemId> for SourceFileItems {
305 &self.arena[idx] 309 &self.arena[idx]
306 } 310 }
307} 311}
312
313/// Walks the subtree in bfs order, calling `f` for each node.
314fn bfs(node: &SyntaxNode, mut f: impl FnMut(&SyntaxNode)) {
315 let mut curr_layer = vec![node];
316 let mut next_layer = vec![];
317 while !curr_layer.is_empty() {
318 curr_layer.drain(..).for_each(|node| {
319 next_layer.extend(node.children());
320 f(node);
321 });
322 std::mem::swap(&mut curr_layer, &mut next_layer);
323 }
324}
diff --git a/crates/ra_hir/src/nameres/tests.rs b/crates/ra_hir/src/nameres/tests.rs
index c511c40b2..17de54b44 100644
--- a/crates/ra_hir/src/nameres/tests.rs
+++ b/crates/ra_hir/src/nameres/tests.rs
@@ -322,27 +322,8 @@ fn reexport_across_crates() {
322 ); 322 );
323} 323}
324 324
325#[test] 325fn check_item_map_is_not_recomputed(initial: &str, file_change: &str) {
326fn typing_inside_a_function_should_not_invalidate_item_map() { 326 let (mut db, pos) = MockDatabase::with_position(initial);
327 let (mut db, pos) = MockDatabase::with_position(
328 "
329 //- /lib.rs
330 mod foo;
331
332 use crate::foo::bar::Baz;
333
334 //- /foo/mod.rs
335 pub mod bar;
336
337 //- /foo/bar.rs
338 <|>
339 salsa::query_group! {
340 trait Baz {
341 fn foo() -> i32 { 1 + 1 }
342 }
343 }
344 ",
345 );
346 let source_root = db.file_source_root(pos.file_id); 327 let source_root = db.file_source_root(pos.file_id);
347 { 328 {
348 let events = db.log_executed(|| { 329 let events = db.log_executed(|| {
@@ -350,18 +331,8 @@ fn typing_inside_a_function_should_not_invalidate_item_map() {
350 }); 331 });
351 assert!(format!("{:?}", events).contains("item_map")) 332 assert!(format!("{:?}", events).contains("item_map"))
352 } 333 }
353
354 let new_text = "
355 salsa::query_group! {
356 trait Baz {
357 fn foo() -> i32 { 92 }
358 }
359 }
360 "
361 .to_string();
362
363 db.query_mut(ra_db::FileTextQuery) 334 db.query_mut(ra_db::FileTextQuery)
364 .set(pos.file_id, Arc::new(new_text)); 335 .set(pos.file_id, Arc::new(file_change.to_string()));
365 336
366 { 337 {
367 let events = db.log_executed(|| { 338 let events = db.log_executed(|| {
@@ -376,8 +347,8 @@ fn typing_inside_a_function_should_not_invalidate_item_map() {
376} 347}
377 348
378#[test] 349#[test]
379fn typing_inside_a_function_inside_a_macro_should_not_invalidate_item_map() { 350fn typing_inside_a_function_should_not_invalidate_item_map() {
380 let (mut db, pos) = MockDatabase::with_position( 351 check_item_map_is_not_recomputed(
381 " 352 "
382 //- /lib.rs 353 //- /lib.rs
383 mod foo;<|> 354 mod foo;<|>
@@ -392,36 +363,81 @@ fn typing_inside_a_function_inside_a_macro_should_not_invalidate_item_map() {
392 363
393 //- /foo/bar.rs 364 //- /foo/bar.rs
394 pub struct Baz; 365 pub struct Baz;
395 ", 366 ",
396 ); 367 "
397 let source_root = db.file_source_root(pos.file_id);
398 {
399 let events = db.log_executed(|| {
400 db.item_map(source_root).unwrap();
401 });
402 assert!(format!("{:?}", events).contains("item_map"))
403 }
404
405 let new_text = "
406 mod foo; 368 mod foo;
407 369
408 use crate::foo::bar::Baz; 370 use crate::foo::bar::Baz;
409 371
410 fn foo() -> i32 { 92 } 372 fn foo() -> i32 { 92 }
411 " 373 ",
412 .to_string(); 374 );
375}
413 376
414 db.query_mut(ra_db::FileTextQuery) 377#[test]
415 .set(pos.file_id, Arc::new(new_text)); 378fn adding_inner_items_should_not_invalidate_item_map() {
379 check_item_map_is_not_recomputed(
380 "
381 //- /lib.rs
382 struct S { a: i32}
383 enum E { A }
384 trait T {
385 fn a() {}
386 }
387 mod foo;<|>
388 impl S {
389 fn a() {}
390 }
391 use crate::foo::bar::Baz;
392 //- /foo/mod.rs
393 pub mod bar;
416 394
417 { 395 //- /foo/bar.rs
418 let events = db.log_executed(|| { 396 pub struct Baz;
419 db.item_map(source_root).unwrap(); 397 ",
420 }); 398 "
421 assert!( 399 struct S { a: i32, b: () }
422 !format!("{:?}", events).contains("item_map"), 400 enum E { A, B }
423 "{:#?}", 401 trait T {
424 events 402 fn a() {}
425 ) 403 fn b() {}
426 } 404 }
405 mod foo;<|>
406 impl S {
407 fn a() {}
408 fn b() {}
409 }
410 use crate::foo::bar::Baz;
411 ",
412 );
413}
414
415#[test]
416fn typing_inside_a_function_inside_a_macro_should_not_invalidate_item_map() {
417 check_item_map_is_not_recomputed(
418 "
419 //- /lib.rs
420 mod foo;
421
422 use crate::foo::bar::Baz;
423
424 //- /foo/mod.rs
425 pub mod bar;
426
427 //- /foo/bar.rs
428 <|>
429 salsa::query_group! {
430 trait Baz {
431 fn foo() -> i32 { 1 + 1 }
432 }
433 }
434 ",
435 "
436 salsa::query_group! {
437 trait Baz {
438 fn foo() -> i32 { 92 }
439 }
440 }
441 ",
442 );
427} 443}