mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-11-03 05:13:35 +00:00
739 lines
20 KiB
Rust
739 lines
20 KiB
Rust
use base_db::SourceDatabase;
|
|
use expect_test::Expect;
|
|
use hir_def::{DefWithBodyId, ModuleDefId};
|
|
use salsa::EventKind;
|
|
use test_fixture::WithFixture;
|
|
|
|
use crate::{db::HirDatabase, test_db::TestDB};
|
|
|
|
use super::visit_module;
|
|
|
|
#[test]
|
|
fn typing_whitespace_inside_a_function_should_not_invalidate_types() {
|
|
let (mut db, pos) = TestDB::with_position(
|
|
"
|
|
//- /lib.rs
|
|
fn foo() -> i32 {
|
|
$01 + 1
|
|
}",
|
|
);
|
|
execute_assert_events(
|
|
&db,
|
|
|| {
|
|
let module = db.module_for_file(pos.file_id.file_id(&db));
|
|
let crate_def_map = module.def_map(&db);
|
|
visit_module(&db, crate_def_map, module.local_id, &mut |def| {
|
|
if let ModuleDefId::FunctionId(it) = def {
|
|
db.infer(it.into());
|
|
}
|
|
});
|
|
},
|
|
&[("infer_shim", 1)],
|
|
expect_test::expect![[r#"
|
|
[
|
|
"source_root_crates_shim",
|
|
"crate_local_def_map",
|
|
"file_item_tree_query",
|
|
"ast_id_map_shim",
|
|
"parse_shim",
|
|
"real_span_map_shim",
|
|
"infer_shim",
|
|
"function_signature_shim",
|
|
"function_signature_with_source_map_shim",
|
|
"attrs_shim",
|
|
"body_shim",
|
|
"body_with_source_map_shim",
|
|
"trait_environment_shim",
|
|
"return_type_impl_traits_shim",
|
|
"expr_scopes_shim",
|
|
"lang_item",
|
|
"crate_lang_items",
|
|
"lang_item",
|
|
]
|
|
"#]],
|
|
);
|
|
|
|
let new_text = "
|
|
fn foo() -> i32 {
|
|
1
|
|
+
|
|
1
|
|
}";
|
|
|
|
db.set_file_text(pos.file_id.file_id(&db), new_text);
|
|
|
|
execute_assert_events(
|
|
&db,
|
|
|| {
|
|
let module = db.module_for_file(pos.file_id.file_id(&db));
|
|
let crate_def_map = module.def_map(&db);
|
|
visit_module(&db, crate_def_map, module.local_id, &mut |def| {
|
|
if let ModuleDefId::FunctionId(it) = def {
|
|
db.infer(it.into());
|
|
}
|
|
});
|
|
},
|
|
&[("infer_shim", 0)],
|
|
expect_test::expect![[r#"
|
|
[
|
|
"parse_shim",
|
|
"ast_id_map_shim",
|
|
"file_item_tree_query",
|
|
"real_span_map_shim",
|
|
"attrs_shim",
|
|
"function_signature_with_source_map_shim",
|
|
"function_signature_shim",
|
|
"body_with_source_map_shim",
|
|
"body_shim",
|
|
]
|
|
"#]],
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn typing_inside_a_function_should_not_invalidate_types_in_another() {
|
|
let (mut db, pos) = TestDB::with_position(
|
|
"
|
|
//- /lib.rs
|
|
fn foo() -> f32 {
|
|
1.0 + 2.0
|
|
}
|
|
fn bar() -> i32 {
|
|
$01 + 1
|
|
}
|
|
fn baz() -> i32 {
|
|
1 + 1
|
|
}",
|
|
);
|
|
execute_assert_events(
|
|
&db,
|
|
|| {
|
|
let module = db.module_for_file(pos.file_id.file_id(&db));
|
|
let crate_def_map = module.def_map(&db);
|
|
visit_module(&db, crate_def_map, module.local_id, &mut |def| {
|
|
if let ModuleDefId::FunctionId(it) = def {
|
|
db.infer(it.into());
|
|
}
|
|
});
|
|
},
|
|
&[("infer_shim", 3)],
|
|
expect_test::expect![[r#"
|
|
[
|
|
"source_root_crates_shim",
|
|
"crate_local_def_map",
|
|
"file_item_tree_query",
|
|
"ast_id_map_shim",
|
|
"parse_shim",
|
|
"real_span_map_shim",
|
|
"infer_shim",
|
|
"function_signature_shim",
|
|
"function_signature_with_source_map_shim",
|
|
"attrs_shim",
|
|
"body_shim",
|
|
"body_with_source_map_shim",
|
|
"trait_environment_shim",
|
|
"return_type_impl_traits_shim",
|
|
"expr_scopes_shim",
|
|
"lang_item",
|
|
"crate_lang_items",
|
|
"attrs_shim",
|
|
"attrs_shim",
|
|
"lang_item",
|
|
"infer_shim",
|
|
"function_signature_shim",
|
|
"function_signature_with_source_map_shim",
|
|
"body_shim",
|
|
"body_with_source_map_shim",
|
|
"trait_environment_shim",
|
|
"return_type_impl_traits_shim",
|
|
"expr_scopes_shim",
|
|
"infer_shim",
|
|
"function_signature_shim",
|
|
"function_signature_with_source_map_shim",
|
|
"body_shim",
|
|
"body_with_source_map_shim",
|
|
"trait_environment_shim",
|
|
"return_type_impl_traits_shim",
|
|
"expr_scopes_shim",
|
|
]
|
|
"#]],
|
|
);
|
|
|
|
let new_text = "
|
|
fn foo() -> f32 {
|
|
1.0 + 2.0
|
|
}
|
|
fn bar() -> i32 {
|
|
53
|
|
}
|
|
fn baz() -> i32 {
|
|
1 + 1
|
|
}
|
|
";
|
|
|
|
db.set_file_text(pos.file_id.file_id(&db), new_text);
|
|
|
|
execute_assert_events(
|
|
&db,
|
|
|| {
|
|
let module = db.module_for_file(pos.file_id.file_id(&db));
|
|
let crate_def_map = module.def_map(&db);
|
|
visit_module(&db, crate_def_map, module.local_id, &mut |def| {
|
|
if let ModuleDefId::FunctionId(it) = def {
|
|
db.infer(it.into());
|
|
}
|
|
});
|
|
},
|
|
&[("infer_shim", 1)],
|
|
expect_test::expect![[r#"
|
|
[
|
|
"parse_shim",
|
|
"ast_id_map_shim",
|
|
"file_item_tree_query",
|
|
"real_span_map_shim",
|
|
"attrs_shim",
|
|
"function_signature_with_source_map_shim",
|
|
"function_signature_shim",
|
|
"body_with_source_map_shim",
|
|
"body_shim",
|
|
"attrs_shim",
|
|
"attrs_shim",
|
|
"function_signature_with_source_map_shim",
|
|
"function_signature_shim",
|
|
"body_with_source_map_shim",
|
|
"body_shim",
|
|
"infer_shim",
|
|
"expr_scopes_shim",
|
|
"function_signature_with_source_map_shim",
|
|
"function_signature_shim",
|
|
"body_with_source_map_shim",
|
|
"body_shim",
|
|
]
|
|
"#]],
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn adding_struct_invalidates_infer() {
|
|
let (mut db, pos) = TestDB::with_position(
|
|
"
|
|
//- /lib.rs
|
|
fn foo() -> i32 {
|
|
1 + 1
|
|
}
|
|
|
|
fn bar() -> f32 {
|
|
2.0 * 3.0
|
|
}
|
|
$0",
|
|
);
|
|
execute_assert_events(
|
|
&db,
|
|
|| {
|
|
let module = db.module_for_file(pos.file_id.file_id(&db));
|
|
let _crate_def_map = module.def_map(&db);
|
|
db.trait_impls_in_crate(module.krate());
|
|
},
|
|
&[("trait_impls_in_crate_shim", 1)],
|
|
expect_test::expect![[r#"
|
|
[
|
|
"source_root_crates_shim",
|
|
"crate_local_def_map",
|
|
"file_item_tree_query",
|
|
"ast_id_map_shim",
|
|
"parse_shim",
|
|
"real_span_map_shim",
|
|
"trait_impls_in_crate_shim",
|
|
]
|
|
"#]],
|
|
);
|
|
|
|
let new_text = "
|
|
fn foo() -> i32 {
|
|
1 + 1
|
|
}
|
|
|
|
fn bar() -> f32 {
|
|
2.0 * 3.0
|
|
}
|
|
|
|
pub struct NewStruct {
|
|
field: i32,
|
|
}
|
|
";
|
|
|
|
db.set_file_text(pos.file_id.file_id(&db), new_text);
|
|
|
|
execute_assert_events(
|
|
&db,
|
|
|| {
|
|
let module = db.module_for_file(pos.file_id.file_id(&db));
|
|
let _crate_def_map = module.def_map(&db);
|
|
db.trait_impls_in_crate(module.krate());
|
|
},
|
|
&[("trait_impls_in_crate_shim", 1)],
|
|
expect_test::expect![[r#"
|
|
[
|
|
"parse_shim",
|
|
"ast_id_map_shim",
|
|
"file_item_tree_query",
|
|
"real_span_map_shim",
|
|
"crate_local_def_map",
|
|
"trait_impls_in_crate_shim",
|
|
]
|
|
"#]],
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn adding_enum_query_log() {
|
|
let (mut db, pos) = TestDB::with_position(
|
|
"
|
|
//- /lib.rs
|
|
fn foo() -> i32 {
|
|
1 + 1
|
|
}
|
|
|
|
fn bar() -> f32 {
|
|
2.0 * 3.0
|
|
}
|
|
$0",
|
|
);
|
|
execute_assert_events(
|
|
&db,
|
|
|| {
|
|
let module = db.module_for_file(pos.file_id.file_id(&db));
|
|
let _crate_def_map = module.def_map(&db);
|
|
db.trait_impls_in_crate(module.krate());
|
|
},
|
|
&[("trait_impls_in_crate_shim", 1)],
|
|
expect_test::expect![[r#"
|
|
[
|
|
"source_root_crates_shim",
|
|
"crate_local_def_map",
|
|
"file_item_tree_query",
|
|
"ast_id_map_shim",
|
|
"parse_shim",
|
|
"real_span_map_shim",
|
|
"trait_impls_in_crate_shim",
|
|
]
|
|
"#]],
|
|
);
|
|
|
|
let new_text = "
|
|
fn foo() -> i32 {
|
|
1 + 1
|
|
}
|
|
|
|
fn bar() -> f32 {
|
|
2.0 * 3.0
|
|
}
|
|
|
|
pub enum SomeEnum {
|
|
A,
|
|
B
|
|
}
|
|
";
|
|
|
|
db.set_file_text(pos.file_id.file_id(&db), new_text);
|
|
|
|
execute_assert_events(
|
|
&db,
|
|
|| {
|
|
let module = db.module_for_file(pos.file_id.file_id(&db));
|
|
let _crate_def_map = module.def_map(&db);
|
|
db.trait_impls_in_crate(module.krate());
|
|
},
|
|
&[("trait_impls_in_crate_shim", 1)],
|
|
expect_test::expect![[r#"
|
|
[
|
|
"parse_shim",
|
|
"ast_id_map_shim",
|
|
"file_item_tree_query",
|
|
"real_span_map_shim",
|
|
"crate_local_def_map",
|
|
"trait_impls_in_crate_shim",
|
|
]
|
|
"#]],
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn adding_use_query_log() {
|
|
let (mut db, pos) = TestDB::with_position(
|
|
"
|
|
//- /lib.rs
|
|
fn foo() -> i32 {
|
|
1 + 1
|
|
}
|
|
|
|
fn bar() -> f32 {
|
|
2.0 * 3.0
|
|
}
|
|
$0",
|
|
);
|
|
execute_assert_events(
|
|
&db,
|
|
|| {
|
|
let module = db.module_for_file(pos.file_id.file_id(&db));
|
|
let _crate_def_map = module.def_map(&db);
|
|
db.trait_impls_in_crate(module.krate());
|
|
},
|
|
&[("trait_impls_in_crate_shim", 1)],
|
|
expect_test::expect![[r#"
|
|
[
|
|
"source_root_crates_shim",
|
|
"crate_local_def_map",
|
|
"file_item_tree_query",
|
|
"ast_id_map_shim",
|
|
"parse_shim",
|
|
"real_span_map_shim",
|
|
"trait_impls_in_crate_shim",
|
|
]
|
|
"#]],
|
|
);
|
|
|
|
let new_text = "
|
|
use std::collections::HashMap;
|
|
|
|
fn foo() -> i32 {
|
|
1 + 1
|
|
}
|
|
|
|
fn bar() -> f32 {
|
|
2.0 * 3.0
|
|
}
|
|
";
|
|
|
|
db.set_file_text(pos.file_id.file_id(&db), new_text);
|
|
|
|
execute_assert_events(
|
|
&db,
|
|
|| {
|
|
let module = db.module_for_file(pos.file_id.file_id(&db));
|
|
let _crate_def_map = module.def_map(&db);
|
|
db.trait_impls_in_crate(module.krate());
|
|
},
|
|
&[("trait_impls_in_crate_shim", 1)],
|
|
expect_test::expect![[r#"
|
|
[
|
|
"parse_shim",
|
|
"ast_id_map_shim",
|
|
"file_item_tree_query",
|
|
"real_span_map_shim",
|
|
"crate_local_def_map",
|
|
"trait_impls_in_crate_shim",
|
|
]
|
|
"#]],
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn adding_impl_query_log() {
|
|
let (mut db, pos) = TestDB::with_position(
|
|
"
|
|
//- /lib.rs
|
|
fn foo() -> i32 {
|
|
1 + 1
|
|
}
|
|
|
|
fn bar() -> f32 {
|
|
2.0 * 3.0
|
|
}
|
|
|
|
pub struct SomeStruct {
|
|
field: i32,
|
|
}
|
|
$0",
|
|
);
|
|
execute_assert_events(
|
|
&db,
|
|
|| {
|
|
let module = db.module_for_file(pos.file_id.file_id(&db));
|
|
let _crate_def_map = module.def_map(&db);
|
|
db.trait_impls_in_crate(module.krate());
|
|
},
|
|
&[("trait_impls_in_crate_shim", 1)],
|
|
expect_test::expect![[r#"
|
|
[
|
|
"source_root_crates_shim",
|
|
"crate_local_def_map",
|
|
"file_item_tree_query",
|
|
"ast_id_map_shim",
|
|
"parse_shim",
|
|
"real_span_map_shim",
|
|
"trait_impls_in_crate_shim",
|
|
]
|
|
"#]],
|
|
);
|
|
|
|
let new_text = "
|
|
fn foo() -> i32 {
|
|
1 + 1
|
|
}
|
|
|
|
fn bar() -> f32 {
|
|
2.0 * 3.0
|
|
}
|
|
|
|
pub struct SomeStruct {
|
|
field: i32,
|
|
}
|
|
|
|
impl SomeStruct {
|
|
pub fn new(value: i32) -> Self {
|
|
Self { field: value }
|
|
}
|
|
}
|
|
";
|
|
|
|
db.set_file_text(pos.file_id.file_id(&db), new_text);
|
|
|
|
execute_assert_events(
|
|
&db,
|
|
|| {
|
|
let module = db.module_for_file(pos.file_id.file_id(&db));
|
|
let _crate_def_map = module.def_map(&db);
|
|
db.trait_impls_in_crate(module.krate());
|
|
},
|
|
&[("trait_impls_in_crate_shim", 1)],
|
|
expect_test::expect![[r#"
|
|
[
|
|
"parse_shim",
|
|
"ast_id_map_shim",
|
|
"file_item_tree_query",
|
|
"real_span_map_shim",
|
|
"crate_local_def_map",
|
|
"trait_impls_in_crate_shim",
|
|
"attrs_shim",
|
|
"impl_trait_with_diagnostics_shim",
|
|
"impl_signature_shim",
|
|
"impl_signature_with_source_map_shim",
|
|
"impl_self_ty_with_diagnostics_shim",
|
|
"struct_signature_shim",
|
|
"struct_signature_with_source_map_shim",
|
|
"attrs_shim",
|
|
"type_for_adt_tracked",
|
|
]
|
|
"#]],
|
|
);
|
|
}
|
|
|
|
// FIXME(next-solver): does this test make sense with fast path?
|
|
#[test]
|
|
fn add_struct_invalidates_trait_solve() {
|
|
let (mut db, file_id) = TestDB::with_single_file(
|
|
"
|
|
//- /main.rs crate:main
|
|
struct SomeStruct;
|
|
|
|
trait Trait<T> {
|
|
fn method(&self) -> T;
|
|
}
|
|
impl Trait<u32> for SomeStruct {}
|
|
|
|
fn main() {
|
|
let s = SomeStruct;
|
|
s.method();
|
|
s.$0
|
|
}",
|
|
);
|
|
|
|
execute_assert_events(
|
|
&db,
|
|
|| {
|
|
let module = db.module_for_file(file_id.file_id(&db));
|
|
let crate_def_map = module.def_map(&db);
|
|
let mut defs: Vec<DefWithBodyId> = vec![];
|
|
visit_module(&db, crate_def_map, module.local_id, &mut |it| {
|
|
let def = match it {
|
|
ModuleDefId::FunctionId(it) => it.into(),
|
|
ModuleDefId::EnumVariantId(it) => it.into(),
|
|
ModuleDefId::ConstId(it) => it.into(),
|
|
ModuleDefId::StaticId(it) => it.into(),
|
|
_ => return,
|
|
};
|
|
defs.push(def);
|
|
});
|
|
|
|
for def in defs {
|
|
let _inference_result = db.infer(def);
|
|
}
|
|
},
|
|
&[("trait_solve_shim", 0)],
|
|
expect_test::expect![[r#"
|
|
[
|
|
"source_root_crates_shim",
|
|
"crate_local_def_map",
|
|
"file_item_tree_query",
|
|
"ast_id_map_shim",
|
|
"parse_shim",
|
|
"real_span_map_shim",
|
|
"TraitItems::query_with_diagnostics_",
|
|
"body_shim",
|
|
"body_with_source_map_shim",
|
|
"attrs_shim",
|
|
"ImplItems::of_",
|
|
"infer_shim",
|
|
"trait_signature_shim",
|
|
"trait_signature_with_source_map_shim",
|
|
"attrs_shim",
|
|
"function_signature_shim",
|
|
"function_signature_with_source_map_shim",
|
|
"attrs_shim",
|
|
"body_shim",
|
|
"body_with_source_map_shim",
|
|
"trait_environment_shim",
|
|
"lang_item",
|
|
"crate_lang_items",
|
|
"attrs_shim",
|
|
"attrs_shim",
|
|
"return_type_impl_traits_shim",
|
|
"generic_predicates_ns_shim",
|
|
"infer_shim",
|
|
"function_signature_shim",
|
|
"function_signature_with_source_map_shim",
|
|
"trait_environment_shim",
|
|
"expr_scopes_shim",
|
|
"struct_signature_shim",
|
|
"struct_signature_with_source_map_shim",
|
|
"generic_predicates_shim",
|
|
"value_ty_shim",
|
|
"VariantFields::firewall_",
|
|
"VariantFields::query_",
|
|
"lang_item",
|
|
"inherent_impls_in_crate_shim",
|
|
"impl_signature_shim",
|
|
"impl_signature_with_source_map_shim",
|
|
"callable_item_signature_shim",
|
|
"trait_impls_in_deps_shim",
|
|
"trait_impls_in_crate_shim",
|
|
"impl_trait_with_diagnostics_shim",
|
|
"impl_self_ty_with_diagnostics_shim",
|
|
"type_for_adt_tracked",
|
|
"impl_trait_with_diagnostics_ns_shim",
|
|
"impl_self_ty_with_diagnostics_ns_shim",
|
|
"generic_predicates_ns_shim",
|
|
"value_ty_shim",
|
|
"generic_predicates_shim",
|
|
"lang_item",
|
|
]
|
|
"#]],
|
|
);
|
|
|
|
let new_text = "
|
|
//- /main.rs crate:main
|
|
struct AnotherStruct;
|
|
|
|
struct SomeStruct;
|
|
|
|
trait Trait<T> {
|
|
fn method(&self) -> T;
|
|
}
|
|
impl Trait<u32> for SomeStruct {}
|
|
|
|
fn main() {
|
|
let s = SomeStruct;
|
|
s.method();
|
|
s.$0
|
|
}";
|
|
|
|
db.set_file_text(file_id.file_id(&db), new_text);
|
|
|
|
execute_assert_events(
|
|
&db,
|
|
|| {
|
|
let module = db.module_for_file(file_id.file_id(&db));
|
|
let crate_def_map = module.def_map(&db);
|
|
let mut defs: Vec<DefWithBodyId> = vec![];
|
|
|
|
visit_module(&db, crate_def_map, module.local_id, &mut |it| {
|
|
let def = match it {
|
|
ModuleDefId::FunctionId(it) => it.into(),
|
|
ModuleDefId::EnumVariantId(it) => it.into(),
|
|
ModuleDefId::ConstId(it) => it.into(),
|
|
ModuleDefId::StaticId(it) => it.into(),
|
|
_ => return,
|
|
};
|
|
defs.push(def);
|
|
});
|
|
|
|
for def in defs {
|
|
let _inference_result = db.infer(def);
|
|
}
|
|
},
|
|
&[("trait_solve_shim", 0)],
|
|
expect_test::expect![[r#"
|
|
[
|
|
"parse_shim",
|
|
"ast_id_map_shim",
|
|
"file_item_tree_query",
|
|
"real_span_map_shim",
|
|
"crate_local_def_map",
|
|
"TraitItems::query_with_diagnostics_",
|
|
"body_with_source_map_shim",
|
|
"attrs_shim",
|
|
"body_shim",
|
|
"ImplItems::of_",
|
|
"infer_shim",
|
|
"attrs_shim",
|
|
"trait_signature_with_source_map_shim",
|
|
"attrs_shim",
|
|
"function_signature_with_source_map_shim",
|
|
"function_signature_shim",
|
|
"body_with_source_map_shim",
|
|
"body_shim",
|
|
"trait_environment_shim",
|
|
"crate_lang_items",
|
|
"attrs_shim",
|
|
"attrs_shim",
|
|
"attrs_shim",
|
|
"return_type_impl_traits_shim",
|
|
"generic_predicates_ns_shim",
|
|
"infer_shim",
|
|
"function_signature_with_source_map_shim",
|
|
"expr_scopes_shim",
|
|
"struct_signature_with_source_map_shim",
|
|
"VariantFields::query_",
|
|
"inherent_impls_in_crate_shim",
|
|
"impl_signature_with_source_map_shim",
|
|
"impl_signature_shim",
|
|
"callable_item_signature_shim",
|
|
"trait_impls_in_crate_shim",
|
|
"impl_trait_with_diagnostics_shim",
|
|
"impl_self_ty_with_diagnostics_shim",
|
|
"impl_trait_with_diagnostics_ns_shim",
|
|
"impl_self_ty_with_diagnostics_ns_shim",
|
|
"generic_predicates_ns_shim",
|
|
"generic_predicates_shim",
|
|
]
|
|
"#]],
|
|
);
|
|
}
|
|
|
|
fn execute_assert_events(
|
|
db: &TestDB,
|
|
f: impl FnOnce(),
|
|
required: &[(&str, usize)],
|
|
expect: Expect,
|
|
) {
|
|
let (executed, events) = db.log_executed(f);
|
|
salsa::attach(db, || {
|
|
for (event, count) in required {
|
|
let n = executed.iter().filter(|it| it.contains(event)).count();
|
|
assert_eq!(
|
|
n,
|
|
*count,
|
|
"Expected {event} to be executed {count} times, but only got {n}:\n \
|
|
Executed: {executed:#?}\n \
|
|
Event log: {events:#?}",
|
|
events = events
|
|
.iter()
|
|
.filter(|event| !matches!(event.kind, EventKind::WillCheckCancellation))
|
|
.map(|event| { format!("{:?}", event.kind) })
|
|
.collect::<Vec<_>>(),
|
|
);
|
|
}
|
|
expect.assert_debug_eq(&executed);
|
|
});
|
|
}
|