diff options
-rw-r--r-- | crates/ra_assists/src/doc_tests.rs | 7 | ||||
-rw-r--r-- | crates/ra_assists/src/lib.rs | 40 | ||||
-rw-r--r-- | crates/ra_assists/src/test_db.rs | 45 | ||||
-rw-r--r-- | crates/ra_hir/src/code_model.rs | 4 | ||||
-rw-r--r-- | crates/ra_hir/src/db.rs | 4 | ||||
-rw-r--r-- | crates/ra_hir/src/expr/scope.rs | 8 | ||||
-rw-r--r-- | crates/ra_hir/src/lib.rs | 9 | ||||
-rw-r--r-- | crates/ra_hir/src/mock.rs | 262 | ||||
-rw-r--r-- | crates/ra_hir/src/test_db.rs | 120 | ||||
-rw-r--r-- | crates/ra_hir/src/ty.rs | 2 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/infer/expr.rs | 6 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/infer/path.rs | 4 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/lower.rs | 15 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/tests.rs | 32 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/traits/chalk.rs | 7 | ||||
-rw-r--r-- | crates/ra_hir_def/src/nameres.rs | 8 | ||||
-rw-r--r-- | crates/ra_hir_def/src/nameres/mod_resolution.rs | 12 | ||||
-rw-r--r-- | crates/ra_hir_def/src/nameres/per_ns.rs | 8 | ||||
-rw-r--r-- | crates/ra_mbe/src/lib.rs | 45 | ||||
-rw-r--r-- | crates/ra_mbe/src/tests.rs | 27 |
20 files changed, 323 insertions, 342 deletions
diff --git a/crates/ra_assists/src/doc_tests.rs b/crates/ra_assists/src/doc_tests.rs index 6e1e3de84..a8f8446cb 100644 --- a/crates/ra_assists/src/doc_tests.rs +++ b/crates/ra_assists/src/doc_tests.rs | |||
@@ -5,13 +5,14 @@ | |||
5 | 5 | ||
6 | mod generated; | 6 | mod generated; |
7 | 7 | ||
8 | use hir::mock::MockDatabase; | 8 | use ra_db::{fixture::WithFixture, FileRange}; |
9 | use ra_db::FileRange; | ||
10 | use test_utils::{assert_eq_text, extract_range_or_offset}; | 9 | use test_utils::{assert_eq_text, extract_range_or_offset}; |
11 | 10 | ||
11 | use crate::test_db::TestDB; | ||
12 | |||
12 | fn check(assist_id: &str, before: &str, after: &str) { | 13 | fn check(assist_id: &str, before: &str, after: &str) { |
13 | let (selection, before) = extract_range_or_offset(before); | 14 | let (selection, before) = extract_range_or_offset(before); |
14 | let (db, _source_root, file_id) = MockDatabase::with_single_file(&before); | 15 | let (db, file_id) = TestDB::with_single_file(&before); |
15 | let frange = FileRange { file_id, range: selection.into() }; | 16 | let frange = FileRange { file_id, range: selection.into() }; |
16 | 17 | ||
17 | let (_assist_id, action) = crate::assists(&db, frange) | 18 | let (_assist_id, action) = crate::assists(&db, frange) |
diff --git a/crates/ra_assists/src/lib.rs b/crates/ra_assists/src/lib.rs index 38599d4f1..39c1c283f 100644 --- a/crates/ra_assists/src/lib.rs +++ b/crates/ra_assists/src/lib.rs | |||
@@ -9,6 +9,8 @@ mod assist_ctx; | |||
9 | mod marks; | 9 | mod marks; |
10 | #[cfg(test)] | 10 | #[cfg(test)] |
11 | mod doc_tests; | 11 | mod doc_tests; |
12 | #[cfg(test)] | ||
13 | mod test_db; | ||
12 | 14 | ||
13 | use hir::db::HirDatabase; | 15 | use hir::db::HirDatabase; |
14 | use ra_db::FileRange; | 16 | use ra_db::FileRange; |
@@ -146,20 +148,19 @@ mod assists { | |||
146 | 148 | ||
147 | #[cfg(test)] | 149 | #[cfg(test)] |
148 | mod helpers { | 150 | mod helpers { |
149 | use hir::mock::MockDatabase; | 151 | use ra_db::{fixture::WithFixture, FileRange}; |
150 | use ra_db::FileRange; | ||
151 | use ra_syntax::TextRange; | 152 | use ra_syntax::TextRange; |
152 | use test_utils::{add_cursor, assert_eq_text, extract_offset, extract_range}; | 153 | use test_utils::{add_cursor, assert_eq_text, extract_offset, extract_range}; |
153 | 154 | ||
154 | use crate::{Assist, AssistCtx}; | 155 | use crate::{test_db::TestDB, Assist, AssistCtx}; |
155 | 156 | ||
156 | pub(crate) fn check_assist( | 157 | pub(crate) fn check_assist( |
157 | assist: fn(AssistCtx<MockDatabase>) -> Option<Assist>, | 158 | assist: fn(AssistCtx<TestDB>) -> Option<Assist>, |
158 | before: &str, | 159 | before: &str, |
159 | after: &str, | 160 | after: &str, |
160 | ) { | 161 | ) { |
161 | let (before_cursor_pos, before) = extract_offset(before); | 162 | let (before_cursor_pos, before) = extract_offset(before); |
162 | let (db, _source_root, file_id) = MockDatabase::with_single_file(&before); | 163 | let (db, file_id) = TestDB::with_single_file(&before); |
163 | let frange = | 164 | let frange = |
164 | FileRange { file_id, range: TextRange::offset_len(before_cursor_pos, 0.into()) }; | 165 | FileRange { file_id, range: TextRange::offset_len(before_cursor_pos, 0.into()) }; |
165 | let assist = | 166 | let assist = |
@@ -182,12 +183,12 @@ mod helpers { | |||
182 | } | 183 | } |
183 | 184 | ||
184 | pub(crate) fn check_assist_range( | 185 | pub(crate) fn check_assist_range( |
185 | assist: fn(AssistCtx<MockDatabase>) -> Option<Assist>, | 186 | assist: fn(AssistCtx<TestDB>) -> Option<Assist>, |
186 | before: &str, | 187 | before: &str, |
187 | after: &str, | 188 | after: &str, |
188 | ) { | 189 | ) { |
189 | let (range, before) = extract_range(before); | 190 | let (range, before) = extract_range(before); |
190 | let (db, _source_root, file_id) = MockDatabase::with_single_file(&before); | 191 | let (db, file_id) = TestDB::with_single_file(&before); |
191 | let frange = FileRange { file_id, range }; | 192 | let frange = FileRange { file_id, range }; |
192 | let assist = | 193 | let assist = |
193 | AssistCtx::with_ctx(&db, frange, true, assist).expect("code action is not applicable"); | 194 | AssistCtx::with_ctx(&db, frange, true, assist).expect("code action is not applicable"); |
@@ -204,12 +205,12 @@ mod helpers { | |||
204 | } | 205 | } |
205 | 206 | ||
206 | pub(crate) fn check_assist_target( | 207 | pub(crate) fn check_assist_target( |
207 | assist: fn(AssistCtx<MockDatabase>) -> Option<Assist>, | 208 | assist: fn(AssistCtx<TestDB>) -> Option<Assist>, |
208 | before: &str, | 209 | before: &str, |
209 | target: &str, | 210 | target: &str, |
210 | ) { | 211 | ) { |
211 | let (before_cursor_pos, before) = extract_offset(before); | 212 | let (before_cursor_pos, before) = extract_offset(before); |
212 | let (db, _source_root, file_id) = MockDatabase::with_single_file(&before); | 213 | let (db, file_id) = TestDB::with_single_file(&before); |
213 | let frange = | 214 | let frange = |
214 | FileRange { file_id, range: TextRange::offset_len(before_cursor_pos, 0.into()) }; | 215 | FileRange { file_id, range: TextRange::offset_len(before_cursor_pos, 0.into()) }; |
215 | let assist = | 216 | let assist = |
@@ -224,12 +225,12 @@ mod helpers { | |||
224 | } | 225 | } |
225 | 226 | ||
226 | pub(crate) fn check_assist_range_target( | 227 | pub(crate) fn check_assist_range_target( |
227 | assist: fn(AssistCtx<MockDatabase>) -> Option<Assist>, | 228 | assist: fn(AssistCtx<TestDB>) -> Option<Assist>, |
228 | before: &str, | 229 | before: &str, |
229 | target: &str, | 230 | target: &str, |
230 | ) { | 231 | ) { |
231 | let (range, before) = extract_range(before); | 232 | let (range, before) = extract_range(before); |
232 | let (db, _source_root, file_id) = MockDatabase::with_single_file(&before); | 233 | let (db, file_id) = TestDB::with_single_file(&before); |
233 | let frange = FileRange { file_id, range }; | 234 | let frange = FileRange { file_id, range }; |
234 | let assist = | 235 | let assist = |
235 | AssistCtx::with_ctx(&db, frange, true, assist).expect("code action is not applicable"); | 236 | AssistCtx::with_ctx(&db, frange, true, assist).expect("code action is not applicable"); |
@@ -243,11 +244,11 @@ mod helpers { | |||
243 | } | 244 | } |
244 | 245 | ||
245 | pub(crate) fn check_assist_not_applicable( | 246 | pub(crate) fn check_assist_not_applicable( |
246 | assist: fn(AssistCtx<MockDatabase>) -> Option<Assist>, | 247 | assist: fn(AssistCtx<TestDB>) -> Option<Assist>, |
247 | before: &str, | 248 | before: &str, |
248 | ) { | 249 | ) { |
249 | let (before_cursor_pos, before) = extract_offset(before); | 250 | let (before_cursor_pos, before) = extract_offset(before); |
250 | let (db, _source_root, file_id) = MockDatabase::with_single_file(&before); | 251 | let (db, file_id) = TestDB::with_single_file(&before); |
251 | let frange = | 252 | let frange = |
252 | FileRange { file_id, range: TextRange::offset_len(before_cursor_pos, 0.into()) }; | 253 | FileRange { file_id, range: TextRange::offset_len(before_cursor_pos, 0.into()) }; |
253 | let assist = AssistCtx::with_ctx(&db, frange, true, assist); | 254 | let assist = AssistCtx::with_ctx(&db, frange, true, assist); |
@@ -255,11 +256,11 @@ mod helpers { | |||
255 | } | 256 | } |
256 | 257 | ||
257 | pub(crate) fn check_assist_range_not_applicable( | 258 | pub(crate) fn check_assist_range_not_applicable( |
258 | assist: fn(AssistCtx<MockDatabase>) -> Option<Assist>, | 259 | assist: fn(AssistCtx<TestDB>) -> Option<Assist>, |
259 | before: &str, | 260 | before: &str, |
260 | ) { | 261 | ) { |
261 | let (range, before) = extract_range(before); | 262 | let (range, before) = extract_range(before); |
262 | let (db, _source_root, file_id) = MockDatabase::with_single_file(&before); | 263 | let (db, file_id) = TestDB::with_single_file(&before); |
263 | let frange = FileRange { file_id, range }; | 264 | let frange = FileRange { file_id, range }; |
264 | let assist = AssistCtx::with_ctx(&db, frange, true, assist); | 265 | let assist = AssistCtx::with_ctx(&db, frange, true, assist); |
265 | assert!(assist.is_none()); | 266 | assert!(assist.is_none()); |
@@ -268,16 +269,17 @@ mod helpers { | |||
268 | 269 | ||
269 | #[cfg(test)] | 270 | #[cfg(test)] |
270 | mod tests { | 271 | mod tests { |
271 | use hir::mock::MockDatabase; | 272 | use ra_db::{fixture::WithFixture, FileRange}; |
272 | use ra_db::FileRange; | ||
273 | use ra_syntax::TextRange; | 273 | use ra_syntax::TextRange; |
274 | use test_utils::{extract_offset, extract_range}; | 274 | use test_utils::{extract_offset, extract_range}; |
275 | 275 | ||
276 | use crate::test_db::TestDB; | ||
277 | |||
276 | #[test] | 278 | #[test] |
277 | fn assist_order_field_struct() { | 279 | fn assist_order_field_struct() { |
278 | let before = "struct Foo { <|>bar: u32 }"; | 280 | let before = "struct Foo { <|>bar: u32 }"; |
279 | let (before_cursor_pos, before) = extract_offset(before); | 281 | let (before_cursor_pos, before) = extract_offset(before); |
280 | let (db, _source_root, file_id) = MockDatabase::with_single_file(&before); | 282 | let (db, file_id) = TestDB::with_single_file(&before); |
281 | let frange = | 283 | let frange = |
282 | FileRange { file_id, range: TextRange::offset_len(before_cursor_pos, 0.into()) }; | 284 | FileRange { file_id, range: TextRange::offset_len(before_cursor_pos, 0.into()) }; |
283 | let assists = super::assists(&db, frange); | 285 | let assists = super::assists(&db, frange); |
@@ -298,7 +300,7 @@ mod tests { | |||
298 | } | 300 | } |
299 | }"; | 301 | }"; |
300 | let (range, before) = extract_range(before); | 302 | let (range, before) = extract_range(before); |
301 | let (db, _source_root, file_id) = MockDatabase::with_single_file(&before); | 303 | let (db, file_id) = TestDB::with_single_file(&before); |
302 | let frange = FileRange { file_id, range }; | 304 | let frange = FileRange { file_id, range }; |
303 | let assists = super::assists(&db, frange); | 305 | let assists = super::assists(&db, frange); |
304 | let mut assists = assists.iter(); | 306 | let mut assists = assists.iter(); |
diff --git a/crates/ra_assists/src/test_db.rs b/crates/ra_assists/src/test_db.rs new file mode 100644 index 000000000..5be7383ed --- /dev/null +++ b/crates/ra_assists/src/test_db.rs | |||
@@ -0,0 +1,45 @@ | |||
1 | //! Database used for testing `ra_assists`. | ||
2 | |||
3 | use std::sync::Arc; | ||
4 | |||
5 | use ra_db::{salsa, CrateId, FileId, FileLoader, FileLoaderDelegate, RelativePath}; | ||
6 | |||
7 | #[salsa::database( | ||
8 | ra_db::SourceDatabaseExtStorage, | ||
9 | ra_db::SourceDatabaseStorage, | ||
10 | hir::db::InternDatabaseStorage, | ||
11 | hir::db::AstDatabaseStorage, | ||
12 | hir::db::DefDatabaseStorage, | ||
13 | hir::db::DefDatabase2Storage, | ||
14 | hir::db::HirDatabaseStorage | ||
15 | )] | ||
16 | #[derive(Debug, Default)] | ||
17 | pub struct TestDB { | ||
18 | runtime: salsa::Runtime<TestDB>, | ||
19 | } | ||
20 | |||
21 | impl salsa::Database for TestDB { | ||
22 | fn salsa_runtime(&self) -> &salsa::Runtime<Self> { | ||
23 | &self.runtime | ||
24 | } | ||
25 | } | ||
26 | |||
27 | impl std::panic::RefUnwindSafe for TestDB {} | ||
28 | |||
29 | impl FileLoader for TestDB { | ||
30 | fn file_text(&self, file_id: FileId) -> Arc<String> { | ||
31 | FileLoaderDelegate(self).file_text(file_id) | ||
32 | } | ||
33 | fn resolve_relative_path( | ||
34 | &self, | ||
35 | anchor: FileId, | ||
36 | relative_path: &RelativePath, | ||
37 | ) -> Option<FileId> { | ||
38 | FileLoaderDelegate(self).resolve_relative_path(anchor, relative_path) | ||
39 | } | ||
40 | fn relevant_crates(&self, file_id: FileId) -> Arc<Vec<CrateId>> { | ||
41 | FileLoaderDelegate(self).relevant_crates(file_id) | ||
42 | } | ||
43 | } | ||
44 | |||
45 | impl hir::debug::HirDebugHelper for TestDB {} | ||
diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs index 181c5d47a..4e273d9e4 100644 --- a/crates/ra_hir/src/code_model.rs +++ b/crates/ra_hir/src/code_model.rs | |||
@@ -30,8 +30,8 @@ use crate::{ | |||
30 | impl_block::ImplBlock, | 30 | impl_block::ImplBlock, |
31 | resolve::{Resolver, Scope, TypeNs}, | 31 | resolve::{Resolver, Scope, TypeNs}, |
32 | traits::TraitData, | 32 | traits::TraitData, |
33 | ty::{InferenceResult, TraitRef}, | 33 | ty::{InferenceResult, Namespace, TraitRef}, |
34 | Either, HasSource, Name, ScopeDef, Ty, {ImportId, Namespace}, | 34 | Either, HasSource, ImportId, Name, ScopeDef, Ty, |
35 | }; | 35 | }; |
36 | 36 | ||
37 | /// hir::Crate describes a single crate. It's the main interface with which | 37 | /// hir::Crate describes a single crate. It's the main interface with which |
diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs index eb66325f7..11b3f94ae 100644 --- a/crates/ra_hir/src/db.rs +++ b/crates/ra_hir/src/db.rs | |||
@@ -14,10 +14,10 @@ use crate::{ | |||
14 | traits::TraitData, | 14 | traits::TraitData, |
15 | ty::{ | 15 | ty::{ |
16 | method_resolution::CrateImplBlocks, traits::Impl, CallableDef, FnSig, GenericPredicate, | 16 | method_resolution::CrateImplBlocks, traits::Impl, CallableDef, FnSig, GenericPredicate, |
17 | InferenceResult, Substs, Ty, TypableDef, TypeCtor, | 17 | InferenceResult, Namespace, Substs, Ty, TypableDef, TypeCtor, |
18 | }, | 18 | }, |
19 | type_alias::TypeAliasData, | 19 | type_alias::TypeAliasData, |
20 | Const, ConstData, Crate, DefWithBody, ExprScopes, FnData, Function, Module, Namespace, Static, | 20 | Const, ConstData, Crate, DefWithBody, ExprScopes, FnData, Function, Module, Static, |
21 | StructField, Trait, TypeAlias, | 21 | StructField, Trait, TypeAlias, |
22 | }; | 22 | }; |
23 | 23 | ||
diff --git a/crates/ra_hir/src/expr/scope.rs b/crates/ra_hir/src/expr/scope.rs index 5496822e7..c14c2ab66 100644 --- a/crates/ra_hir/src/expr/scope.rs +++ b/crates/ra_hir/src/expr/scope.rs | |||
@@ -174,11 +174,11 @@ fn compute_expr_scopes(expr: ExprId, body: &Body, scopes: &mut ExprScopes, scope | |||
174 | 174 | ||
175 | #[cfg(test)] | 175 | #[cfg(test)] |
176 | mod tests { | 176 | mod tests { |
177 | use ra_db::SourceDatabase; | 177 | use ra_db::{fixture::WithFixture, SourceDatabase}; |
178 | use ra_syntax::{algo::find_node_at_offset, ast, AstNode}; | 178 | use ra_syntax::{algo::find_node_at_offset, ast, AstNode}; |
179 | use test_utils::{assert_eq_text, extract_offset}; | 179 | use test_utils::{assert_eq_text, extract_offset}; |
180 | 180 | ||
181 | use crate::{mock::MockDatabase, source_binder::SourceAnalyzer}; | 181 | use crate::{source_binder::SourceAnalyzer, test_db::TestDB}; |
182 | 182 | ||
183 | fn do_check(code: &str, expected: &[&str]) { | 183 | fn do_check(code: &str, expected: &[&str]) { |
184 | let (off, code) = extract_offset(code); | 184 | let (off, code) = extract_offset(code); |
@@ -191,7 +191,7 @@ mod tests { | |||
191 | buf | 191 | buf |
192 | }; | 192 | }; |
193 | 193 | ||
194 | let (db, _source_root, file_id) = MockDatabase::with_single_file(&code); | 194 | let (db, file_id) = TestDB::with_single_file(&code); |
195 | let file = db.parse(file_id).ok().unwrap(); | 195 | let file = db.parse(file_id).ok().unwrap(); |
196 | let marker: ast::PathExpr = find_node_at_offset(file.syntax(), off).unwrap(); | 196 | let marker: ast::PathExpr = find_node_at_offset(file.syntax(), off).unwrap(); |
197 | let analyzer = SourceAnalyzer::new(&db, file_id, marker.syntax(), None); | 197 | let analyzer = SourceAnalyzer::new(&db, file_id, marker.syntax(), None); |
@@ -288,7 +288,7 @@ mod tests { | |||
288 | fn do_check_local_name(code: &str, expected_offset: u32) { | 288 | fn do_check_local_name(code: &str, expected_offset: u32) { |
289 | let (off, code) = extract_offset(code); | 289 | let (off, code) = extract_offset(code); |
290 | 290 | ||
291 | let (db, _source_root, file_id) = MockDatabase::with_single_file(&code); | 291 | let (db, file_id) = TestDB::with_single_file(&code); |
292 | let file = db.parse(file_id).ok().unwrap(); | 292 | let file = db.parse(file_id).ok().unwrap(); |
293 | let expected_name = find_node_at_offset::<ast::Name>(file.syntax(), expected_offset.into()) | 293 | let expected_name = find_node_at_offset::<ast::Name>(file.syntax(), expected_offset.into()) |
294 | .expect("failed to find a name at the target offset"); | 294 | .expect("failed to find a name at the target offset"); |
diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs index 3ba99d92d..5f2a05e76 100644 --- a/crates/ra_hir/src/lib.rs +++ b/crates/ra_hir/src/lib.rs | |||
@@ -29,8 +29,6 @@ macro_rules! impl_froms { | |||
29 | pub mod debug; | 29 | pub mod debug; |
30 | 30 | ||
31 | pub mod db; | 31 | pub mod db; |
32 | #[macro_use] | ||
33 | pub mod mock; | ||
34 | pub mod source_binder; | 32 | pub mod source_binder; |
35 | 33 | ||
36 | mod ids; | 34 | mod ids; |
@@ -52,6 +50,8 @@ mod code_model; | |||
52 | pub mod from_source; | 50 | pub mod from_source; |
53 | 51 | ||
54 | #[cfg(test)] | 52 | #[cfg(test)] |
53 | mod test_db; | ||
54 | #[cfg(test)] | ||
55 | mod marks; | 55 | mod marks; |
56 | 56 | ||
57 | use hir_expand::AstId; | 57 | use hir_expand::AstId; |
@@ -81,10 +81,7 @@ pub use crate::{ | |||
81 | 81 | ||
82 | pub use hir_def::{ | 82 | pub use hir_def::{ |
83 | builtin_type::BuiltinType, | 83 | builtin_type::BuiltinType, |
84 | nameres::{ | 84 | nameres::{per_ns::PerNs, raw::ImportId}, |
85 | per_ns::{Namespace, PerNs}, | ||
86 | raw::ImportId, | ||
87 | }, | ||
88 | path::{Path, PathKind}, | 85 | path::{Path, PathKind}, |
89 | type_ref::Mutability, | 86 | type_ref::Mutability, |
90 | }; | 87 | }; |
diff --git a/crates/ra_hir/src/mock.rs b/crates/ra_hir/src/mock.rs deleted file mode 100644 index ab97a09b9..000000000 --- a/crates/ra_hir/src/mock.rs +++ /dev/null | |||
@@ -1,262 +0,0 @@ | |||
1 | //! FIXME: write short doc here | ||
2 | |||
3 | use std::{panic, sync::Arc}; | ||
4 | |||
5 | use hir_expand::diagnostics::DiagnosticSink; | ||
6 | use parking_lot::Mutex; | ||
7 | use ra_cfg::CfgOptions; | ||
8 | use ra_db::{ | ||
9 | salsa, CrateGraph, CrateId, Edition, FileId, FileLoader, FileLoaderDelegate, FilePosition, | ||
10 | RelativePath, RelativePathBuf, SourceDatabase, SourceDatabaseExt, SourceRoot, SourceRootId, | ||
11 | }; | ||
12 | use rustc_hash::FxHashMap; | ||
13 | use test_utils::{extract_offset, parse_fixture, CURSOR_MARKER}; | ||
14 | |||
15 | use crate::{db, debug::HirDebugHelper}; | ||
16 | |||
17 | pub const WORKSPACE: SourceRootId = SourceRootId(0); | ||
18 | |||
19 | #[salsa::database( | ||
20 | ra_db::SourceDatabaseExtStorage, | ||
21 | ra_db::SourceDatabaseStorage, | ||
22 | db::InternDatabaseStorage, | ||
23 | db::AstDatabaseStorage, | ||
24 | db::DefDatabaseStorage, | ||
25 | db::DefDatabase2Storage, | ||
26 | db::HirDatabaseStorage | ||
27 | )] | ||
28 | #[derive(Debug)] | ||
29 | pub struct MockDatabase { | ||
30 | events: Mutex<Option<Vec<salsa::Event<MockDatabase>>>>, | ||
31 | runtime: salsa::Runtime<MockDatabase>, | ||
32 | files: FxHashMap<String, FileId>, | ||
33 | crate_names: Arc<FxHashMap<CrateId, String>>, | ||
34 | file_paths: Arc<FxHashMap<FileId, String>>, | ||
35 | } | ||
36 | |||
37 | impl panic::RefUnwindSafe for MockDatabase {} | ||
38 | |||
39 | impl FileLoader for MockDatabase { | ||
40 | fn file_text(&self, file_id: FileId) -> Arc<String> { | ||
41 | FileLoaderDelegate(self).file_text(file_id) | ||
42 | } | ||
43 | fn resolve_relative_path( | ||
44 | &self, | ||
45 | anchor: FileId, | ||
46 | relative_path: &RelativePath, | ||
47 | ) -> Option<FileId> { | ||
48 | FileLoaderDelegate(self).resolve_relative_path(anchor, relative_path) | ||
49 | } | ||
50 | fn relevant_crates(&self, file_id: FileId) -> Arc<Vec<CrateId>> { | ||
51 | FileLoaderDelegate(self).relevant_crates(file_id) | ||
52 | } | ||
53 | } | ||
54 | |||
55 | impl HirDebugHelper for MockDatabase { | ||
56 | fn crate_name(&self, krate: CrateId) -> Option<String> { | ||
57 | self.crate_names.get(&krate).cloned() | ||
58 | } | ||
59 | |||
60 | fn file_path(&self, file_id: FileId) -> Option<String> { | ||
61 | self.file_paths.get(&file_id).cloned() | ||
62 | } | ||
63 | } | ||
64 | |||
65 | impl MockDatabase { | ||
66 | pub fn with_files(fixture: &str) -> MockDatabase { | ||
67 | let (db, position) = MockDatabase::from_fixture(fixture); | ||
68 | assert!(position.is_none()); | ||
69 | db | ||
70 | } | ||
71 | |||
72 | pub fn with_single_file(text: &str) -> (MockDatabase, SourceRoot, FileId) { | ||
73 | let mut db = MockDatabase::default(); | ||
74 | let mut source_root = SourceRoot::default(); | ||
75 | let file_id = db.add_file(WORKSPACE, "/", &mut source_root, "/main.rs", text); | ||
76 | db.set_source_root(WORKSPACE, Arc::new(source_root.clone())); | ||
77 | (db, source_root, file_id) | ||
78 | } | ||
79 | |||
80 | pub fn file_id_of(&self, path: &str) -> FileId { | ||
81 | match self.files.get(path) { | ||
82 | Some(it) => *it, | ||
83 | None => panic!("unknown file: {:?}\nexisting files:\n{:#?}", path, self.files), | ||
84 | } | ||
85 | } | ||
86 | |||
87 | pub fn diagnostics(&self) -> String { | ||
88 | let mut buf = String::new(); | ||
89 | let mut files: Vec<FileId> = self.files.values().copied().collect(); | ||
90 | files.sort(); | ||
91 | for file in files { | ||
92 | let src = crate::Source { | ||
93 | file_id: file.into(), | ||
94 | ast: crate::ModuleSource::new(self, Some(file), None), | ||
95 | }; | ||
96 | let module = crate::Module::from_definition(self, src).unwrap(); | ||
97 | module.diagnostics( | ||
98 | self, | ||
99 | &mut DiagnosticSink::new(|d| { | ||
100 | buf += &format!("{:?}: {}\n", d.syntax_node(self).text(), d.message()); | ||
101 | }), | ||
102 | ) | ||
103 | } | ||
104 | buf | ||
105 | } | ||
106 | |||
107 | fn from_fixture(fixture: &str) -> (MockDatabase, Option<FilePosition>) { | ||
108 | let mut db = MockDatabase::default(); | ||
109 | |||
110 | let pos = db.add_fixture(fixture); | ||
111 | |||
112 | (db, pos) | ||
113 | } | ||
114 | |||
115 | fn add_fixture(&mut self, fixture: &str) -> Option<FilePosition> { | ||
116 | let mut position = None; | ||
117 | let mut source_root = SourceRoot::default(); | ||
118 | let mut source_root_id = WORKSPACE; | ||
119 | let mut source_root_prefix = "/".to_string(); | ||
120 | for entry in parse_fixture(fixture) { | ||
121 | if entry.meta.starts_with("root") { | ||
122 | self.set_source_root(source_root_id, Arc::new(source_root)); | ||
123 | source_root = SourceRoot::default(); | ||
124 | |||
125 | source_root_id = SourceRootId(source_root_id.0 + 1); | ||
126 | source_root_prefix = entry.meta["root".len()..].trim().to_string(); | ||
127 | continue; | ||
128 | } | ||
129 | if entry.text.contains(CURSOR_MARKER) { | ||
130 | assert!(position.is_none(), "only one marker (<|>) per fixture is allowed"); | ||
131 | position = Some(self.add_file_with_position( | ||
132 | source_root_id, | ||
133 | &source_root_prefix, | ||
134 | &mut source_root, | ||
135 | &entry.meta, | ||
136 | &entry.text, | ||
137 | )); | ||
138 | } else { | ||
139 | self.add_file( | ||
140 | source_root_id, | ||
141 | &source_root_prefix, | ||
142 | &mut source_root, | ||
143 | &entry.meta, | ||
144 | &entry.text, | ||
145 | ); | ||
146 | } | ||
147 | } | ||
148 | self.set_source_root(source_root_id, Arc::new(source_root)); | ||
149 | position | ||
150 | } | ||
151 | |||
152 | fn add_file( | ||
153 | &mut self, | ||
154 | source_root_id: SourceRootId, | ||
155 | source_root_prefix: &str, | ||
156 | source_root: &mut SourceRoot, | ||
157 | path: &str, | ||
158 | text: &str, | ||
159 | ) -> FileId { | ||
160 | assert!(source_root_prefix.starts_with('/')); | ||
161 | assert!(source_root_prefix.ends_with('/')); | ||
162 | assert!(path.starts_with(source_root_prefix)); | ||
163 | let rel_path = RelativePathBuf::from_path(&path[source_root_prefix.len()..]).unwrap(); | ||
164 | |||
165 | let is_crate_root = rel_path == "lib.rs" || rel_path == "/main.rs"; | ||
166 | |||
167 | let file_id = FileId(self.files.len() as u32); | ||
168 | |||
169 | let prev = self.files.insert(path.to_string(), file_id); | ||
170 | assert!(prev.is_none(), "duplicate files in the text fixture"); | ||
171 | Arc::make_mut(&mut self.file_paths).insert(file_id, path.to_string()); | ||
172 | |||
173 | let text = Arc::new(text.to_string()); | ||
174 | self.set_file_text(file_id, text); | ||
175 | self.set_file_relative_path(file_id, rel_path.clone()); | ||
176 | self.set_file_source_root(file_id, source_root_id); | ||
177 | source_root.insert_file(rel_path, file_id); | ||
178 | |||
179 | if is_crate_root { | ||
180 | let mut crate_graph = CrateGraph::default(); | ||
181 | crate_graph.add_crate_root(file_id, Edition::Edition2018, CfgOptions::default()); | ||
182 | self.set_crate_graph(Arc::new(crate_graph)); | ||
183 | } | ||
184 | file_id | ||
185 | } | ||
186 | |||
187 | fn add_file_with_position( | ||
188 | &mut self, | ||
189 | source_root_id: SourceRootId, | ||
190 | source_root_prefix: &str, | ||
191 | source_root: &mut SourceRoot, | ||
192 | path: &str, | ||
193 | text: &str, | ||
194 | ) -> FilePosition { | ||
195 | let (offset, text) = extract_offset(text); | ||
196 | let file_id = self.add_file(source_root_id, source_root_prefix, source_root, path, &text); | ||
197 | FilePosition { file_id, offset } | ||
198 | } | ||
199 | } | ||
200 | |||
201 | impl salsa::Database for MockDatabase { | ||
202 | fn salsa_runtime(&self) -> &salsa::Runtime<MockDatabase> { | ||
203 | &self.runtime | ||
204 | } | ||
205 | |||
206 | fn salsa_event(&self, event: impl Fn() -> salsa::Event<MockDatabase>) { | ||
207 | let mut events = self.events.lock(); | ||
208 | if let Some(events) = &mut *events { | ||
209 | events.push(event()); | ||
210 | } | ||
211 | } | ||
212 | } | ||
213 | |||
214 | impl Default for MockDatabase { | ||
215 | fn default() -> MockDatabase { | ||
216 | let mut db = MockDatabase { | ||
217 | events: Default::default(), | ||
218 | runtime: salsa::Runtime::default(), | ||
219 | files: FxHashMap::default(), | ||
220 | crate_names: Default::default(), | ||
221 | file_paths: Default::default(), | ||
222 | }; | ||
223 | db.set_crate_graph(Default::default()); | ||
224 | db | ||
225 | } | ||
226 | } | ||
227 | |||
228 | impl salsa::ParallelDatabase for MockDatabase { | ||
229 | fn snapshot(&self) -> salsa::Snapshot<MockDatabase> { | ||
230 | salsa::Snapshot::new(MockDatabase { | ||
231 | events: Default::default(), | ||
232 | runtime: self.runtime.snapshot(self), | ||
233 | // only the root database can be used to get file_id by path. | ||
234 | files: FxHashMap::default(), | ||
235 | file_paths: Arc::clone(&self.file_paths), | ||
236 | crate_names: Arc::clone(&self.crate_names), | ||
237 | }) | ||
238 | } | ||
239 | } | ||
240 | |||
241 | impl MockDatabase { | ||
242 | pub fn log(&self, f: impl FnOnce()) -> Vec<salsa::Event<MockDatabase>> { | ||
243 | *self.events.lock() = Some(Vec::new()); | ||
244 | f(); | ||
245 | self.events.lock().take().unwrap() | ||
246 | } | ||
247 | |||
248 | pub fn log_executed(&self, f: impl FnOnce()) -> Vec<String> { | ||
249 | let events = self.log(f); | ||
250 | events | ||
251 | .into_iter() | ||
252 | .filter_map(|e| match e.kind { | ||
253 | // This pretty horrible, but `Debug` is the only way to inspect | ||
254 | // QueryDescriptor at the moment. | ||
255 | salsa::EventKind::WillExecute { database_key } => { | ||
256 | Some(format!("{:?}", database_key)) | ||
257 | } | ||
258 | _ => None, | ||
259 | }) | ||
260 | .collect() | ||
261 | } | ||
262 | } | ||
diff --git a/crates/ra_hir/src/test_db.rs b/crates/ra_hir/src/test_db.rs new file mode 100644 index 000000000..5237b303a --- /dev/null +++ b/crates/ra_hir/src/test_db.rs | |||
@@ -0,0 +1,120 @@ | |||
1 | //! Database used for testing `hir`. | ||
2 | |||
3 | use std::{panic, sync::Arc}; | ||
4 | |||
5 | use hir_def::{db::DefDatabase2, ModuleId}; | ||
6 | use hir_expand::diagnostics::DiagnosticSink; | ||
7 | use parking_lot::Mutex; | ||
8 | use ra_db::{salsa, CrateId, FileId, FileLoader, FileLoaderDelegate, RelativePath, SourceDatabase}; | ||
9 | |||
10 | use crate::{db, debug::HirDebugHelper}; | ||
11 | |||
12 | #[salsa::database( | ||
13 | ra_db::SourceDatabaseExtStorage, | ||
14 | ra_db::SourceDatabaseStorage, | ||
15 | db::InternDatabaseStorage, | ||
16 | db::AstDatabaseStorage, | ||
17 | db::DefDatabaseStorage, | ||
18 | db::DefDatabase2Storage, | ||
19 | db::HirDatabaseStorage | ||
20 | )] | ||
21 | #[derive(Debug, Default)] | ||
22 | pub struct TestDB { | ||
23 | events: Mutex<Option<Vec<salsa::Event<TestDB>>>>, | ||
24 | runtime: salsa::Runtime<TestDB>, | ||
25 | } | ||
26 | |||
27 | impl salsa::Database for TestDB { | ||
28 | fn salsa_runtime(&self) -> &salsa::Runtime<TestDB> { | ||
29 | &self.runtime | ||
30 | } | ||
31 | |||
32 | fn salsa_event(&self, event: impl Fn() -> salsa::Event<TestDB>) { | ||
33 | let mut events = self.events.lock(); | ||
34 | if let Some(events) = &mut *events { | ||
35 | events.push(event()); | ||
36 | } | ||
37 | } | ||
38 | } | ||
39 | |||
40 | impl salsa::ParallelDatabase for TestDB { | ||
41 | fn snapshot(&self) -> salsa::Snapshot<TestDB> { | ||
42 | salsa::Snapshot::new(TestDB { | ||
43 | events: Default::default(), | ||
44 | runtime: self.runtime.snapshot(self), | ||
45 | }) | ||
46 | } | ||
47 | } | ||
48 | |||
49 | impl panic::RefUnwindSafe for TestDB {} | ||
50 | |||
51 | impl FileLoader for TestDB { | ||
52 | fn file_text(&self, file_id: FileId) -> Arc<String> { | ||
53 | FileLoaderDelegate(self).file_text(file_id) | ||
54 | } | ||
55 | fn resolve_relative_path( | ||
56 | &self, | ||
57 | anchor: FileId, | ||
58 | relative_path: &RelativePath, | ||
59 | ) -> Option<FileId> { | ||
60 | FileLoaderDelegate(self).resolve_relative_path(anchor, relative_path) | ||
61 | } | ||
62 | fn relevant_crates(&self, file_id: FileId) -> Arc<Vec<CrateId>> { | ||
63 | FileLoaderDelegate(self).relevant_crates(file_id) | ||
64 | } | ||
65 | } | ||
66 | |||
67 | // FIXME: improve `WithFixture` to bring useful hir debugging back | ||
68 | impl HirDebugHelper for TestDB { | ||
69 | fn crate_name(&self, _krate: CrateId) -> Option<String> { | ||
70 | None | ||
71 | } | ||
72 | |||
73 | fn file_path(&self, _file_id: FileId) -> Option<String> { | ||
74 | None | ||
75 | } | ||
76 | } | ||
77 | |||
78 | impl TestDB { | ||
79 | pub fn diagnostics(&self) -> String { | ||
80 | let mut buf = String::new(); | ||
81 | let crate_graph = self.crate_graph(); | ||
82 | for krate in crate_graph.iter().next() { | ||
83 | let crate_def_map = self.crate_def_map(krate); | ||
84 | for (module_id, _) in crate_def_map.modules.iter() { | ||
85 | let module_id = ModuleId { krate, module_id }; | ||
86 | let module = crate::Module::from(module_id); | ||
87 | module.diagnostics( | ||
88 | self, | ||
89 | &mut DiagnosticSink::new(|d| { | ||
90 | buf += &format!("{:?}: {}\n", d.syntax_node(self).text(), d.message()); | ||
91 | }), | ||
92 | ) | ||
93 | } | ||
94 | } | ||
95 | buf | ||
96 | } | ||
97 | } | ||
98 | |||
99 | impl TestDB { | ||
100 | pub fn log(&self, f: impl FnOnce()) -> Vec<salsa::Event<TestDB>> { | ||
101 | *self.events.lock() = Some(Vec::new()); | ||
102 | f(); | ||
103 | self.events.lock().take().unwrap() | ||
104 | } | ||
105 | |||
106 | pub fn log_executed(&self, f: impl FnOnce()) -> Vec<String> { | ||
107 | let events = self.log(f); | ||
108 | events | ||
109 | .into_iter() | ||
110 | .filter_map(|e| match e.kind { | ||
111 | // This pretty horrible, but `Debug` is the only way to inspect | ||
112 | // QueryDescriptor at the moment. | ||
113 | salsa::EventKind::WillExecute { database_key } => { | ||
114 | Some(format!("{:?}", database_key)) | ||
115 | } | ||
116 | _ => None, | ||
117 | }) | ||
118 | .collect() | ||
119 | } | ||
120 | } | ||
diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs index d1a9d7411..cd2ac0e8b 100644 --- a/crates/ra_hir/src/ty.rs +++ b/crates/ra_hir/src/ty.rs | |||
@@ -27,7 +27,7 @@ pub(crate) use infer::{infer_query, InferTy, InferenceResult}; | |||
27 | pub use lower::CallableDef; | 27 | pub use lower::CallableDef; |
28 | pub(crate) use lower::{ | 28 | pub(crate) use lower::{ |
29 | callable_item_sig, generic_defaults_query, generic_predicates_for_param_query, | 29 | callable_item_sig, generic_defaults_query, generic_predicates_for_param_query, |
30 | generic_predicates_query, type_for_def, type_for_field, TypableDef, | 30 | generic_predicates_query, type_for_def, type_for_field, Namespace, TypableDef, |
31 | }; | 31 | }; |
32 | pub(crate) use traits::{InEnvironment, Obligation, ProjectionPredicate, TraitEnvironment}; | 32 | pub(crate) use traits::{InEnvironment, Obligation, ProjectionPredicate, TraitEnvironment}; |
33 | 33 | ||
diff --git a/crates/ra_hir/src/ty/infer/expr.rs b/crates/ra_hir/src/ty/infer/expr.rs index a09ef5c5d..4af1d65ee 100644 --- a/crates/ra_hir/src/ty/infer/expr.rs +++ b/crates/ra_hir/src/ty/infer/expr.rs | |||
@@ -12,10 +12,10 @@ use crate::{ | |||
12 | expr::{self, Array, BinaryOp, Expr, ExprId, Literal, Statement, UnaryOp}, | 12 | expr::{self, Array, BinaryOp, Expr, ExprId, Literal, Statement, UnaryOp}, |
13 | generics::{GenericParams, HasGenericParams}, | 13 | generics::{GenericParams, HasGenericParams}, |
14 | ty::{ | 14 | ty::{ |
15 | autoderef, method_resolution, op, primitive, CallableDef, InferTy, Mutability, Obligation, | 15 | autoderef, method_resolution, op, primitive, CallableDef, InferTy, Mutability, Namespace, |
16 | ProjectionPredicate, ProjectionTy, Substs, TraitRef, Ty, TypeCtor, TypeWalk, | 16 | Obligation, ProjectionPredicate, ProjectionTy, Substs, TraitRef, Ty, TypeCtor, TypeWalk, |
17 | }, | 17 | }, |
18 | Adt, Name, Namespace, | 18 | Adt, Name, |
19 | }; | 19 | }; |
20 | 20 | ||
21 | impl<'a, D: HirDatabase> InferenceContext<'a, D> { | 21 | impl<'a, D: HirDatabase> InferenceContext<'a, D> { |
diff --git a/crates/ra_hir/src/ty/infer/path.rs b/crates/ra_hir/src/ty/infer/path.rs index 59b7f7eb6..865ced5a1 100644 --- a/crates/ra_hir/src/ty/infer/path.rs +++ b/crates/ra_hir/src/ty/infer/path.rs | |||
@@ -6,8 +6,8 @@ use super::{ExprOrPatId, InferenceContext, TraitRef}; | |||
6 | use crate::{ | 6 | use crate::{ |
7 | db::HirDatabase, | 7 | db::HirDatabase, |
8 | resolve::{ResolveValueResult, Resolver, TypeNs, ValueNs}, | 8 | resolve::{ResolveValueResult, Resolver, TypeNs, ValueNs}, |
9 | ty::{method_resolution, Substs, Ty, TypableDef, TypeWalk}, | 9 | ty::{method_resolution, Namespace, Substs, Ty, TypableDef, TypeWalk}, |
10 | AssocItem, Container, HasGenericParams, Name, Namespace, Path, | 10 | AssocItem, Container, HasGenericParams, Name, Path, |
11 | }; | 11 | }; |
12 | 12 | ||
13 | impl<'a, D: HirDatabase> InferenceContext<'a, D> { | 13 | impl<'a, D: HirDatabase> InferenceContext<'a, D> { |
diff --git a/crates/ra_hir/src/ty/lower.rs b/crates/ra_hir/src/ty/lower.rs index e29ab8492..d26b16cb2 100644 --- a/crates/ra_hir/src/ty/lower.rs +++ b/crates/ra_hir/src/ty/lower.rs | |||
@@ -29,10 +29,21 @@ use crate::{ | |||
29 | Adt, | 29 | Adt, |
30 | }, | 30 | }, |
31 | util::make_mut_slice, | 31 | util::make_mut_slice, |
32 | Const, Enum, EnumVariant, Function, ModuleDef, Namespace, Path, Static, Struct, StructField, | 32 | Const, Enum, EnumVariant, Function, ModuleDef, Path, Static, Struct, StructField, Trait, |
33 | Trait, TypeAlias, Union, | 33 | TypeAlias, Union, |
34 | }; | 34 | }; |
35 | 35 | ||
36 | // FIXME: this is only really used in `type_for_def`, which contains a bunch of | ||
37 | // impossible cases. Perhaps we should recombine `TypeableDef` and `Namespace` | ||
38 | // into a `AsTypeDef`, `AsValueDef` enums? | ||
39 | #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] | ||
40 | pub enum Namespace { | ||
41 | Types, | ||
42 | Values, | ||
43 | // Note that only type inference uses this enum, and it doesn't care about macros. | ||
44 | // Macro, | ||
45 | } | ||
46 | |||
36 | impl Ty { | 47 | impl Ty { |
37 | pub(crate) fn from_hir(db: &impl HirDatabase, resolver: &Resolver, type_ref: &TypeRef) -> Self { | 48 | pub(crate) fn from_hir(db: &impl HirDatabase, resolver: &Resolver, type_ref: &TypeRef) -> Self { |
38 | match type_ref { | 49 | match type_ref { |
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs index 4b7e34878..e56b9356e 100644 --- a/crates/ra_hir/src/ty/tests.rs +++ b/crates/ra_hir/src/ty/tests.rs | |||
@@ -11,7 +11,7 @@ use ra_syntax::{ | |||
11 | use test_utils::covers; | 11 | use test_utils::covers; |
12 | 12 | ||
13 | use crate::{ | 13 | use crate::{ |
14 | expr::BodySourceMap, mock::MockDatabase, ty::display::HirDisplay, ty::InferenceResult, | 14 | expr::BodySourceMap, test_db::TestDB, ty::display::HirDisplay, ty::InferenceResult, |
15 | SourceAnalyzer, | 15 | SourceAnalyzer, |
16 | }; | 16 | }; |
17 | 17 | ||
@@ -24,7 +24,7 @@ mod coercion; | |||
24 | 24 | ||
25 | #[test] | 25 | #[test] |
26 | fn cfg_impl_block() { | 26 | fn cfg_impl_block() { |
27 | let (db, pos) = MockDatabase::with_position( | 27 | let (db, pos) = TestDB::with_position( |
28 | r#" | 28 | r#" |
29 | //- /main.rs crate:main deps:foo cfg:test | 29 | //- /main.rs crate:main deps:foo cfg:test |
30 | use foo::S as T; | 30 | use foo::S as T; |
@@ -64,7 +64,7 @@ impl S { | |||
64 | 64 | ||
65 | #[test] | 65 | #[test] |
66 | fn infer_await() { | 66 | fn infer_await() { |
67 | let (db, pos) = MockDatabase::with_position( | 67 | let (db, pos) = TestDB::with_position( |
68 | r#" | 68 | r#" |
69 | //- /main.rs crate:main deps:std | 69 | //- /main.rs crate:main deps:std |
70 | 70 | ||
@@ -95,7 +95,7 @@ mod future { | |||
95 | 95 | ||
96 | #[test] | 96 | #[test] |
97 | fn infer_box() { | 97 | fn infer_box() { |
98 | let (db, pos) = MockDatabase::with_position( | 98 | let (db, pos) = TestDB::with_position( |
99 | r#" | 99 | r#" |
100 | //- /main.rs crate:main deps:std | 100 | //- /main.rs crate:main deps:std |
101 | 101 | ||
@@ -122,7 +122,7 @@ mod boxed { | |||
122 | 122 | ||
123 | #[test] | 123 | #[test] |
124 | fn infer_adt_self() { | 124 | fn infer_adt_self() { |
125 | let (db, pos) = MockDatabase::with_position( | 125 | let (db, pos) = TestDB::with_position( |
126 | r#" | 126 | r#" |
127 | //- /main.rs | 127 | //- /main.rs |
128 | enum Nat { Succ(Self), Demo(Nat), Zero } | 128 | enum Nat { Succ(Self), Demo(Nat), Zero } |
@@ -141,7 +141,7 @@ fn test() { | |||
141 | 141 | ||
142 | #[test] | 142 | #[test] |
143 | fn infer_try() { | 143 | fn infer_try() { |
144 | let (db, pos) = MockDatabase::with_position( | 144 | let (db, pos) = TestDB::with_position( |
145 | r#" | 145 | r#" |
146 | //- /main.rs crate:main deps:std | 146 | //- /main.rs crate:main deps:std |
147 | 147 | ||
@@ -181,7 +181,7 @@ mod result { | |||
181 | 181 | ||
182 | #[test] | 182 | #[test] |
183 | fn infer_for_loop() { | 183 | fn infer_for_loop() { |
184 | let (db, pos) = MockDatabase::with_position( | 184 | let (db, pos) = TestDB::with_position( |
185 | r#" | 185 | r#" |
186 | //- /main.rs crate:main deps:std | 186 | //- /main.rs crate:main deps:std |
187 | 187 | ||
@@ -223,7 +223,7 @@ mod collections { | |||
223 | #[test] | 223 | #[test] |
224 | fn infer_while_let() { | 224 | fn infer_while_let() { |
225 | covers!(infer_while_let); | 225 | covers!(infer_while_let); |
226 | let (db, pos) = MockDatabase::with_position( | 226 | let (db, pos) = TestDB::with_position( |
227 | r#" | 227 | r#" |
228 | //- /main.rs | 228 | //- /main.rs |
229 | enum Option<T> { Some(T), None } | 229 | enum Option<T> { Some(T), None } |
@@ -2484,7 +2484,7 @@ pub fn main_loop() { | |||
2484 | 2484 | ||
2485 | #[test] | 2485 | #[test] |
2486 | fn cross_crate_associated_method_call() { | 2486 | fn cross_crate_associated_method_call() { |
2487 | let (db, pos) = MockDatabase::with_position( | 2487 | let (db, pos) = TestDB::with_position( |
2488 | r#" | 2488 | r#" |
2489 | //- /main.rs crate:main deps:other_crate | 2489 | //- /main.rs crate:main deps:other_crate |
2490 | fn test() { | 2490 | fn test() { |
@@ -3378,7 +3378,7 @@ fn test() { S.foo()<|>; } | |||
3378 | 3378 | ||
3379 | #[test] | 3379 | #[test] |
3380 | fn infer_macro_with_dollar_crate_is_correct_in_expr() { | 3380 | fn infer_macro_with_dollar_crate_is_correct_in_expr() { |
3381 | let (db, pos) = MockDatabase::with_position( | 3381 | let (db, pos) = TestDB::with_position( |
3382 | r#" | 3382 | r#" |
3383 | //- /main.rs crate:main deps:foo | 3383 | //- /main.rs crate:main deps:foo |
3384 | fn test() { | 3384 | fn test() { |
@@ -3482,7 +3482,7 @@ fn test() { (&S).foo()<|>; } | |||
3482 | 3482 | ||
3483 | #[test] | 3483 | #[test] |
3484 | fn method_resolution_trait_from_prelude() { | 3484 | fn method_resolution_trait_from_prelude() { |
3485 | let (db, pos) = MockDatabase::with_position( | 3485 | let (db, pos) = TestDB::with_position( |
3486 | r#" | 3486 | r#" |
3487 | //- /main.rs crate:main deps:other_crate | 3487 | //- /main.rs crate:main deps:other_crate |
3488 | struct S; | 3488 | struct S; |
@@ -4651,7 +4651,7 @@ fn test<T, U>() where T: Trait<U::Item>, U: Trait<T::Item> { | |||
4651 | assert_eq!(t, "{unknown}"); | 4651 | assert_eq!(t, "{unknown}"); |
4652 | } | 4652 | } |
4653 | 4653 | ||
4654 | fn type_at_pos(db: &MockDatabase, pos: FilePosition) -> String { | 4654 | fn type_at_pos(db: &TestDB, pos: FilePosition) -> String { |
4655 | let file = db.parse(pos.file_id).ok().unwrap(); | 4655 | let file = db.parse(pos.file_id).ok().unwrap(); |
4656 | let expr = algo::find_node_at_offset::<ast::Expr>(file.syntax(), pos.offset).unwrap(); | 4656 | let expr = algo::find_node_at_offset::<ast::Expr>(file.syntax(), pos.offset).unwrap(); |
4657 | let analyzer = SourceAnalyzer::new(db, pos.file_id, expr.syntax(), Some(pos.offset)); | 4657 | let analyzer = SourceAnalyzer::new(db, pos.file_id, expr.syntax(), Some(pos.offset)); |
@@ -4660,12 +4660,12 @@ fn type_at_pos(db: &MockDatabase, pos: FilePosition) -> String { | |||
4660 | } | 4660 | } |
4661 | 4661 | ||
4662 | fn type_at(content: &str) -> String { | 4662 | fn type_at(content: &str) -> String { |
4663 | let (db, file_pos) = MockDatabase::with_position(content); | 4663 | let (db, file_pos) = TestDB::with_position(content); |
4664 | type_at_pos(&db, file_pos) | 4664 | type_at_pos(&db, file_pos) |
4665 | } | 4665 | } |
4666 | 4666 | ||
4667 | fn infer(content: &str) -> String { | 4667 | fn infer(content: &str) -> String { |
4668 | let (db, _, file_id) = MockDatabase::with_single_file(content); | 4668 | let (db, file_id) = TestDB::with_single_file(content); |
4669 | let source_file = db.parse(file_id).ok().unwrap(); | 4669 | let source_file = db.parse(file_id).ok().unwrap(); |
4670 | 4670 | ||
4671 | let mut acc = String::new(); | 4671 | let mut acc = String::new(); |
@@ -4748,7 +4748,7 @@ fn ellipsize(mut text: String, max_len: usize) -> String { | |||
4748 | 4748 | ||
4749 | #[test] | 4749 | #[test] |
4750 | fn typing_whitespace_inside_a_function_should_not_invalidate_types() { | 4750 | fn typing_whitespace_inside_a_function_should_not_invalidate_types() { |
4751 | let (mut db, pos) = MockDatabase::with_position( | 4751 | let (mut db, pos) = TestDB::with_position( |
4752 | " | 4752 | " |
4753 | //- /lib.rs | 4753 | //- /lib.rs |
4754 | fn foo() -> i32 { | 4754 | fn foo() -> i32 { |
@@ -4788,7 +4788,7 @@ fn typing_whitespace_inside_a_function_should_not_invalidate_types() { | |||
4788 | 4788 | ||
4789 | #[test] | 4789 | #[test] |
4790 | fn no_such_field_diagnostics() { | 4790 | fn no_such_field_diagnostics() { |
4791 | let diagnostics = MockDatabase::with_files( | 4791 | let diagnostics = TestDB::with_files( |
4792 | r" | 4792 | r" |
4793 | //- /lib.rs | 4793 | //- /lib.rs |
4794 | struct S { foo: i32, bar: () } | 4794 | struct S { foo: i32, bar: () } |
diff --git a/crates/ra_hir/src/ty/traits/chalk.rs b/crates/ra_hir/src/ty/traits/chalk.rs index 39ef92182..c694952f3 100644 --- a/crates/ra_hir/src/ty/traits/chalk.rs +++ b/crates/ra_hir/src/ty/traits/chalk.rs | |||
@@ -18,7 +18,10 @@ use crate::{ | |||
18 | db::HirDatabase, | 18 | db::HirDatabase, |
19 | generics::GenericDef, | 19 | generics::GenericDef, |
20 | ty::display::HirDisplay, | 20 | ty::display::HirDisplay, |
21 | ty::{ApplicationTy, GenericPredicate, ProjectionTy, Substs, TraitRef, Ty, TypeCtor, TypeWalk}, | 21 | ty::{ |
22 | ApplicationTy, GenericPredicate, Namespace, ProjectionTy, Substs, TraitRef, Ty, TypeCtor, | ||
23 | TypeWalk, | ||
24 | }, | ||
22 | AssocItem, Crate, HasGenericParams, ImplBlock, Trait, TypeAlias, | 25 | AssocItem, Crate, HasGenericParams, ImplBlock, Trait, TypeAlias, |
23 | }; | 26 | }; |
24 | 27 | ||
@@ -652,7 +655,7 @@ fn impl_block_datum( | |||
652 | }) | 655 | }) |
653 | .filter_map(|t| { | 656 | .filter_map(|t| { |
654 | let assoc_ty = trait_.associated_type_by_name(db, &t.name(db))?; | 657 | let assoc_ty = trait_.associated_type_by_name(db, &t.name(db))?; |
655 | let ty = db.type_for_def(t.into(), crate::Namespace::Types).subst(&bound_vars); | 658 | let ty = db.type_for_def(t.into(), Namespace::Types).subst(&bound_vars); |
656 | Some(chalk_rust_ir::AssociatedTyValue { | 659 | Some(chalk_rust_ir::AssociatedTyValue { |
657 | impl_id, | 660 | impl_id, |
658 | associated_ty_id: assoc_ty.to_chalk(db), | 661 | associated_ty_id: assoc_ty.to_chalk(db), |
diff --git a/crates/ra_hir_def/src/nameres.rs b/crates/ra_hir_def/src/nameres.rs index 433bdde48..e1959cdb9 100644 --- a/crates/ra_hir_def/src/nameres.rs +++ b/crates/ra_hir_def/src/nameres.rs | |||
@@ -50,8 +50,8 @@ | |||
50 | // FIXME: review privacy of submodules | 50 | // FIXME: review privacy of submodules |
51 | pub mod raw; | 51 | pub mod raw; |
52 | pub mod per_ns; | 52 | pub mod per_ns; |
53 | pub mod collector; | 53 | mod collector; |
54 | pub mod mod_resolution; | 54 | mod mod_resolution; |
55 | 55 | ||
56 | #[cfg(test)] | 56 | #[cfg(test)] |
57 | mod tests; | 57 | mod tests; |
@@ -196,7 +196,7 @@ pub struct Resolution { | |||
196 | } | 196 | } |
197 | 197 | ||
198 | impl Resolution { | 198 | impl Resolution { |
199 | pub(crate) fn from_macro(macro_: MacroDefId) -> Self { | 199 | fn from_macro(macro_: MacroDefId) -> Self { |
200 | Resolution { def: PerNs::macros(macro_), import: None } | 200 | Resolution { def: PerNs::macros(macro_), import: None } |
201 | } | 201 | } |
202 | } | 202 | } |
@@ -460,7 +460,7 @@ impl CrateDefMap { | |||
460 | from_crate_root.or(from_extern_prelude) | 460 | from_crate_root.or(from_extern_prelude) |
461 | } | 461 | } |
462 | 462 | ||
463 | pub(crate) fn resolve_name_in_module( | 463 | fn resolve_name_in_module( |
464 | &self, | 464 | &self, |
465 | db: &impl DefDatabase2, | 465 | db: &impl DefDatabase2, |
466 | module: CrateModuleId, | 466 | module: CrateModuleId, |
diff --git a/crates/ra_hir_def/src/nameres/mod_resolution.rs b/crates/ra_hir_def/src/nameres/mod_resolution.rs index f6b0b8fb1..b3b1379d0 100644 --- a/crates/ra_hir_def/src/nameres/mod_resolution.rs +++ b/crates/ra_hir_def/src/nameres/mod_resolution.rs | |||
@@ -6,7 +6,7 @@ use ra_syntax::SmolStr; | |||
6 | use crate::{db::DefDatabase2, HirFileId}; | 6 | use crate::{db::DefDatabase2, HirFileId}; |
7 | 7 | ||
8 | #[derive(Clone, Debug)] | 8 | #[derive(Clone, Debug)] |
9 | pub struct ModDir { | 9 | pub(super) struct ModDir { |
10 | /// `.` for `mod.rs`, `lib.rs` | 10 | /// `.` for `mod.rs`, `lib.rs` |
11 | /// `./foo` for `foo.rs` | 11 | /// `./foo` for `foo.rs` |
12 | /// `./foo/bar` for `mod bar { mod x; }` nested in `foo.rs` | 12 | /// `./foo/bar` for `mod bar { mod x; }` nested in `foo.rs` |
@@ -16,11 +16,15 @@ pub struct ModDir { | |||
16 | } | 16 | } |
17 | 17 | ||
18 | impl ModDir { | 18 | impl ModDir { |
19 | pub fn root() -> ModDir { | 19 | pub(super) fn root() -> ModDir { |
20 | ModDir { path: RelativePathBuf::default(), root_non_dir_owner: false } | 20 | ModDir { path: RelativePathBuf::default(), root_non_dir_owner: false } |
21 | } | 21 | } |
22 | 22 | ||
23 | pub fn descend_into_definition(&self, name: &Name, attr_path: Option<&SmolStr>) -> ModDir { | 23 | pub(super) fn descend_into_definition( |
24 | &self, | ||
25 | name: &Name, | ||
26 | attr_path: Option<&SmolStr>, | ||
27 | ) -> ModDir { | ||
24 | let mut path = self.path.clone(); | 28 | let mut path = self.path.clone(); |
25 | match attr_to_path(attr_path) { | 29 | match attr_to_path(attr_path) { |
26 | None => path.push(&name.to_string()), | 30 | None => path.push(&name.to_string()), |
@@ -34,7 +38,7 @@ impl ModDir { | |||
34 | ModDir { path, root_non_dir_owner: false } | 38 | ModDir { path, root_non_dir_owner: false } |
35 | } | 39 | } |
36 | 40 | ||
37 | pub fn resolve_declaration( | 41 | pub(super) fn resolve_declaration( |
38 | &self, | 42 | &self, |
39 | db: &impl DefDatabase2, | 43 | db: &impl DefDatabase2, |
40 | file_id: HirFileId, | 44 | file_id: HirFileId, |
diff --git a/crates/ra_hir_def/src/nameres/per_ns.rs b/crates/ra_hir_def/src/nameres/per_ns.rs index 298b0b0c7..717ed1ef9 100644 --- a/crates/ra_hir_def/src/nameres/per_ns.rs +++ b/crates/ra_hir_def/src/nameres/per_ns.rs | |||
@@ -4,14 +4,6 @@ use hir_expand::MacroDefId; | |||
4 | 4 | ||
5 | use crate::ModuleDefId; | 5 | use crate::ModuleDefId; |
6 | 6 | ||
7 | #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] | ||
8 | pub enum Namespace { | ||
9 | Types, | ||
10 | Values, | ||
11 | // Note that only type inference uses this enum, and it doesn't care about macros. | ||
12 | // Macro, | ||
13 | } | ||
14 | |||
15 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] | 7 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] |
16 | pub struct PerNs { | 8 | pub struct PerNs { |
17 | pub types: Option<ModuleDefId>, | 9 | pub types: Option<ModuleDefId>, |
diff --git a/crates/ra_mbe/src/lib.rs b/crates/ra_mbe/src/lib.rs index afdbee84e..15f000175 100644 --- a/crates/ra_mbe/src/lib.rs +++ b/crates/ra_mbe/src/lib.rs | |||
@@ -42,6 +42,8 @@ pub use crate::syntax_bridge::{ | |||
42 | #[derive(Clone, Debug, PartialEq, Eq)] | 42 | #[derive(Clone, Debug, PartialEq, Eq)] |
43 | pub struct MacroRules { | 43 | pub struct MacroRules { |
44 | pub(crate) rules: Vec<Rule>, | 44 | pub(crate) rules: Vec<Rule>, |
45 | /// Highest id of the token we have in TokenMap | ||
46 | pub(crate) shift: u32, | ||
45 | } | 47 | } |
46 | 48 | ||
47 | #[derive(Clone, Debug, PartialEq, Eq)] | 49 | #[derive(Clone, Debug, PartialEq, Eq)] |
@@ -50,6 +52,38 @@ pub(crate) struct Rule { | |||
50 | pub(crate) rhs: tt::Subtree, | 52 | pub(crate) rhs: tt::Subtree, |
51 | } | 53 | } |
52 | 54 | ||
55 | // Find the max token id inside a subtree | ||
56 | fn max_id(subtree: &tt::Subtree) -> Option<u32> { | ||
57 | subtree | ||
58 | .token_trees | ||
59 | .iter() | ||
60 | .filter_map(|tt| match tt { | ||
61 | tt::TokenTree::Subtree(subtree) => max_id(subtree), | ||
62 | tt::TokenTree::Leaf(tt::Leaf::Ident(ident)) | ||
63 | if ident.id != tt::TokenId::unspecified() => | ||
64 | { | ||
65 | Some(ident.id.0) | ||
66 | } | ||
67 | _ => None, | ||
68 | }) | ||
69 | .max() | ||
70 | } | ||
71 | |||
72 | /// Shift given TokenTree token id | ||
73 | fn shift_subtree(tt: &mut tt::Subtree, shift: u32) { | ||
74 | for t in tt.token_trees.iter_mut() { | ||
75 | match t { | ||
76 | tt::TokenTree::Leaf(leaf) => match leaf { | ||
77 | tt::Leaf::Ident(ident) if ident.id != tt::TokenId::unspecified() => { | ||
78 | ident.id.0 += shift; | ||
79 | } | ||
80 | _ => (), | ||
81 | }, | ||
82 | tt::TokenTree::Subtree(tt) => shift_subtree(tt, shift), | ||
83 | } | ||
84 | } | ||
85 | } | ||
86 | |||
53 | impl MacroRules { | 87 | impl MacroRules { |
54 | pub fn parse(tt: &tt::Subtree) -> Result<MacroRules, ParseError> { | 88 | pub fn parse(tt: &tt::Subtree) -> Result<MacroRules, ParseError> { |
55 | // Note: this parsing can be implemented using mbe machinery itself, by | 89 | // Note: this parsing can be implemented using mbe machinery itself, by |
@@ -72,10 +106,17 @@ impl MacroRules { | |||
72 | validate(&rule.lhs)?; | 106 | validate(&rule.lhs)?; |
73 | } | 107 | } |
74 | 108 | ||
75 | Ok(MacroRules { rules }) | 109 | // Note that TokenId is started from zero, |
110 | // We have to add 1 to prevent duplication. | ||
111 | let shift = max_id(tt).map_or(0, |it| it + 1); | ||
112 | Ok(MacroRules { rules, shift }) | ||
76 | } | 113 | } |
114 | |||
77 | pub fn expand(&self, tt: &tt::Subtree) -> Result<tt::Subtree, ExpandError> { | 115 | pub fn expand(&self, tt: &tt::Subtree) -> Result<tt::Subtree, ExpandError> { |
78 | mbe_expander::expand(self, tt) | 116 | // apply shift |
117 | let mut tt = tt.clone(); | ||
118 | shift_subtree(&mut tt, self.shift); | ||
119 | mbe_expander::expand(self, &tt) | ||
79 | } | 120 | } |
80 | } | 121 | } |
81 | 122 | ||
diff --git a/crates/ra_mbe/src/tests.rs b/crates/ra_mbe/src/tests.rs index f34ab52e1..a23e3afe3 100644 --- a/crates/ra_mbe/src/tests.rs +++ b/crates/ra_mbe/src/tests.rs | |||
@@ -59,6 +59,33 @@ mod rule_parsing { | |||
59 | // * Make it pass :-) | 59 | // * Make it pass :-) |
60 | 60 | ||
61 | #[test] | 61 | #[test] |
62 | fn test_token_id_shift() { | ||
63 | let macro_definition = r#" | ||
64 | macro_rules! foobar { | ||
65 | ($e:ident) => { foo bar $e } | ||
66 | } | ||
67 | "#; | ||
68 | let rules = create_rules(macro_definition); | ||
69 | let expansion = expand(&rules, "foobar!(baz);"); | ||
70 | |||
71 | fn get_id(t: &tt::TokenTree) -> Option<u32> { | ||
72 | if let tt::TokenTree::Leaf(tt::Leaf::Ident(ident)) = t { | ||
73 | return Some(ident.id.0); | ||
74 | } | ||
75 | None | ||
76 | } | ||
77 | |||
78 | assert_eq!(expansion.token_trees.len(), 3); | ||
79 | // ($e:ident) => { foo bar $e } | ||
80 | // 0 1 2 3 4 | ||
81 | assert_eq!(get_id(&expansion.token_trees[0]), Some(2)); | ||
82 | assert_eq!(get_id(&expansion.token_trees[1]), Some(3)); | ||
83 | |||
84 | // So baz should be 5 | ||
85 | assert_eq!(get_id(&expansion.token_trees[2]), Some(5)); | ||
86 | } | ||
87 | |||
88 | #[test] | ||
62 | fn test_convert_tt() { | 89 | fn test_convert_tt() { |
63 | let macro_definition = r#" | 90 | let macro_definition = r#" |
64 | macro_rules! impl_froms { | 91 | macro_rules! impl_froms { |