]>
Commit | Line | Data |
---|---|---|
4b012472 | 1 | use base_db::{SourceDatabase, SourceDatabaseExt}; |
fe692bf9 | 2 | use triomphe::Arc; |
064997fb | 3 | |
4b012472 FG |
4 | use crate::{ |
5 | db::DefDatabase, | |
6 | nameres::tests::{TestDB, WithFixture}, | |
7 | AdtId, ModuleDefId, | |
8 | }; | |
064997fb FG |
9 | |
10 | fn check_def_map_is_not_recomputed(ra_fixture_initial: &str, ra_fixture_change: &str) { | |
11 | let (mut db, pos) = TestDB::with_position(ra_fixture_initial); | |
4b012472 FG |
12 | let krate = { |
13 | let crate_graph = db.crate_graph(); | |
14 | // Some of these tests use minicore/proc-macros which will be injected as the first crate | |
15 | crate_graph.iter().last().unwrap() | |
16 | }; | |
064997fb FG |
17 | { |
18 | let events = db.log_executed(|| { | |
19 | db.crate_def_map(krate); | |
20 | }); | |
9c376795 | 21 | assert!(format!("{events:?}").contains("crate_def_map"), "{events:#?}") |
064997fb | 22 | } |
fe692bf9 | 23 | db.set_file_text(pos.file_id, Arc::from(ra_fixture_change)); |
064997fb FG |
24 | |
25 | { | |
26 | let events = db.log_executed(|| { | |
27 | db.crate_def_map(krate); | |
28 | }); | |
9c376795 | 29 | assert!(!format!("{events:?}").contains("crate_def_map"), "{events:#?}") |
064997fb FG |
30 | } |
31 | } | |
32 | ||
33 | #[test] | |
34 | fn typing_inside_a_function_should_not_invalidate_def_map() { | |
35 | check_def_map_is_not_recomputed( | |
36 | r" | |
4b012472 FG |
37 | //- /lib.rs |
38 | mod foo;$0 | |
064997fb | 39 | |
4b012472 | 40 | use crate::foo::bar::Baz; |
064997fb | 41 | |
4b012472 FG |
42 | enum E { A, B } |
43 | use E::*; | |
064997fb | 44 | |
4b012472 FG |
45 | fn foo() -> i32 { |
46 | 1 + 1 | |
47 | } | |
064997fb | 48 | |
4b012472 FG |
49 | #[cfg(never)] |
50 | fn no() {} | |
51 | //- /foo/mod.rs | |
52 | pub mod bar; | |
064997fb | 53 | |
4b012472 FG |
54 | //- /foo/bar.rs |
55 | pub struct Baz; | |
56 | ", | |
064997fb | 57 | r" |
4b012472 | 58 | mod foo; |
064997fb | 59 | |
4b012472 | 60 | use crate::foo::bar::Baz; |
064997fb | 61 | |
4b012472 FG |
62 | enum E { A, B } |
63 | use E::*; | |
064997fb | 64 | |
4b012472 | 65 | fn foo() -> i32 { 92 } |
064997fb | 66 | |
4b012472 FG |
67 | #[cfg(never)] |
68 | fn no() {} | |
69 | ", | |
064997fb FG |
70 | ); |
71 | } | |
72 | ||
73 | #[test] | |
74 | fn typing_inside_a_macro_should_not_invalidate_def_map() { | |
4b012472 FG |
75 | check_def_map_is_not_recomputed( |
76 | r" | |
77 | //- /lib.rs | |
78 | macro_rules! m { | |
79 | ($ident:ident) => { | |
80 | fn f() { | |
81 | $ident + $ident; | |
82 | }; | |
83 | } | |
84 | } | |
85 | mod foo; | |
86 | ||
87 | //- /foo/mod.rs | |
88 | pub mod bar; | |
89 | ||
90 | //- /foo/bar.rs | |
91 | $0 | |
92 | m!(X); | |
93 | ||
94 | pub struct S {} | |
95 | ", | |
064997fb | 96 | r" |
4b012472 FG |
97 | m!(Y); |
98 | ||
99 | pub struct S {} | |
100 | ", | |
064997fb | 101 | ); |
4b012472 FG |
102 | } |
103 | ||
104 | #[test] | |
105 | fn typing_inside_an_attribute_should_not_invalidate_def_map() { | |
106 | check_def_map_is_not_recomputed( | |
107 | r" | |
108 | //- proc_macros: identity | |
109 | //- /lib.rs | |
110 | mod foo; | |
111 | ||
112 | //- /foo/mod.rs | |
113 | pub mod bar; | |
114 | ||
115 | //- /foo/bar.rs | |
116 | $0 | |
117 | #[proc_macros::identity] | |
118 | fn f() {} | |
119 | ", | |
120 | r" | |
121 | #[proc_macros::identity] | |
122 | fn f() { foo } | |
123 | ", | |
124 | ); | |
125 | } | |
126 | ||
127 | #[test] | |
128 | fn typing_inside_an_attribute_arg_should_not_invalidate_def_map() { | |
129 | check_def_map_is_not_recomputed( | |
130 | r" | |
131 | //- proc_macros: identity | |
132 | //- /lib.rs | |
133 | mod foo; | |
134 | ||
135 | //- /foo/mod.rs | |
136 | pub mod bar; | |
137 | ||
138 | //- /foo/bar.rs | |
139 | $0 | |
140 | #[proc_macros::identity] | |
141 | fn f() {} | |
142 | ", | |
143 | r" | |
144 | #[proc_macros::identity(foo)] | |
145 | fn f() {} | |
146 | ", | |
147 | ); | |
148 | } | |
149 | #[test] | |
150 | fn typing_inside_macro_heavy_file_should_not_invalidate_def_map() { | |
151 | check_def_map_is_not_recomputed( | |
152 | r" | |
153 | //- proc_macros: identity, derive_identity | |
154 | //- /lib.rs | |
155 | macro_rules! m { | |
156 | ($ident:ident) => { | |
157 | fn fm() { | |
158 | $ident + $ident; | |
159 | }; | |
064997fb | 160 | } |
4b012472 FG |
161 | } |
162 | mod foo; | |
064997fb | 163 | |
4b012472 FG |
164 | //- /foo/mod.rs |
165 | pub mod bar; | |
166 | ||
167 | //- /foo/bar.rs | |
168 | $0 | |
169 | fn f() {} | |
170 | ||
171 | m!(X); | |
172 | macro_rules! m2 { | |
173 | ($ident:ident) => { | |
174 | fn f2() { | |
175 | $ident + $ident; | |
176 | }; | |
064997fb FG |
177 | } |
178 | } | |
4b012472 FG |
179 | m2!(X); |
180 | ||
181 | #[proc_macros::identity] | |
182 | #[derive(proc_macros::DeriveIdentity)] | |
183 | pub struct S {} | |
184 | ", | |
185 | r" | |
186 | fn f() {0} | |
187 | ||
188 | m!(X); | |
189 | macro_rules! m2 { | |
190 | ($ident:ident) => { | |
191 | fn f2() { | |
192 | $ident + $ident; | |
193 | }; | |
194 | } | |
195 | } | |
196 | m2!(X); | |
197 | ||
198 | #[proc_macros::identity] | |
199 | #[derive(proc_macros::DeriveIdentity)] | |
200 | pub struct S {} | |
201 | ", | |
202 | ); | |
203 | } | |
204 | ||
205 | #[test] | |
206 | fn typing_inside_a_derive_should_not_invalidate_def_map() { | |
207 | check_def_map_is_not_recomputed( | |
208 | r" | |
209 | //- proc_macros: derive_identity | |
210 | //- minicore:derive | |
211 | //- /lib.rs | |
212 | mod foo; | |
213 | ||
214 | //- /foo/mod.rs | |
215 | pub mod bar; | |
216 | ||
217 | //- /foo/bar.rs | |
218 | $0 | |
219 | #[derive(proc_macros::DeriveIdentity)] | |
220 | #[allow()] | |
221 | struct S; | |
222 | ", | |
223 | r" | |
224 | #[derive(proc_macros::DeriveIdentity)] | |
225 | #[allow(dead_code)] | |
226 | struct S; | |
227 | ", | |
228 | ); | |
229 | } | |
064997fb FG |
230 | |
231 | #[test] | |
fe692bf9 | 232 | fn typing_inside_a_function_should_not_invalidate_item_expansions() { |
064997fb FG |
233 | let (mut db, pos) = TestDB::with_position( |
234 | r#" | |
235 | //- /lib.rs | |
236 | macro_rules! m { | |
237 | ($ident:ident) => { | |
238 | fn $ident() { }; | |
239 | } | |
240 | } | |
241 | mod foo; | |
242 | ||
243 | //- /foo/mod.rs | |
244 | pub mod bar; | |
245 | ||
246 | //- /foo/bar.rs | |
247 | m!(X); | |
248 | fn quux() { 1$0 } | |
249 | m!(Y); | |
250 | m!(Z); | |
251 | "#, | |
252 | ); | |
253 | let krate = db.test_crate(); | |
254 | { | |
255 | let events = db.log_executed(|| { | |
256 | let crate_def_map = db.crate_def_map(krate); | |
257 | let (_, module_data) = crate_def_map.modules.iter().last().unwrap(); | |
258 | assert_eq!(module_data.scope.resolutions().count(), 4); | |
259 | }); | |
260 | let n_recalculated_item_trees = events.iter().filter(|it| it.contains("item_tree")).count(); | |
261 | assert_eq!(n_recalculated_item_trees, 6); | |
262 | let n_reparsed_macros = | |
fe692bf9 | 263 | events.iter().filter(|it| it.contains("parse_macro_expansion(")).count(); |
064997fb FG |
264 | assert_eq!(n_reparsed_macros, 3); |
265 | } | |
266 | ||
267 | let new_text = r#" | |
268 | m!(X); | |
269 | fn quux() { 92 } | |
270 | m!(Y); | |
271 | m!(Z); | |
272 | "#; | |
fe692bf9 | 273 | db.set_file_text(pos.file_id, Arc::from(new_text)); |
064997fb FG |
274 | |
275 | { | |
276 | let events = db.log_executed(|| { | |
277 | let crate_def_map = db.crate_def_map(krate); | |
278 | let (_, module_data) = crate_def_map.modules.iter().last().unwrap(); | |
279 | assert_eq!(module_data.scope.resolutions().count(), 4); | |
280 | }); | |
281 | let n_recalculated_item_trees = events.iter().filter(|it| it.contains("item_tree")).count(); | |
282 | assert_eq!(n_recalculated_item_trees, 1); | |
283 | let n_reparsed_macros = | |
fe692bf9 | 284 | events.iter().filter(|it| it.contains("parse_macro_expansion(")).count(); |
064997fb FG |
285 | assert_eq!(n_reparsed_macros, 0); |
286 | } | |
287 | } | |
288 | ||
289 | #[test] | |
290 | fn item_tree_prevents_reparsing() { | |
291 | // The `ItemTree` is used by both name resolution and the various queries in `adt.rs` and | |
292 | // `data.rs`. After computing the `ItemTree` and deleting the parse tree, we should be able to | |
293 | // run those other queries without triggering a reparse. | |
294 | ||
295 | let (db, pos) = TestDB::with_position( | |
296 | r#" | |
297 | pub struct S; | |
298 | pub union U {} | |
299 | pub enum E { | |
300 | Variant, | |
301 | } | |
302 | pub fn f(_: S) { $0 } | |
303 | pub trait Tr {} | |
304 | impl Tr for () {} | |
305 | pub const C: u8 = 0; | |
306 | pub static ST: u8 = 0; | |
307 | pub type Ty = (); | |
308 | "#, | |
309 | ); | |
310 | let krate = db.test_crate(); | |
311 | { | |
312 | let events = db.log_executed(|| { | |
313 | db.file_item_tree(pos.file_id.into()); | |
314 | }); | |
315 | let n_calculated_item_trees = events.iter().filter(|it| it.contains("item_tree")).count(); | |
316 | assert_eq!(n_calculated_item_trees, 1); | |
317 | let n_parsed_files = events.iter().filter(|it| it.contains("parse(")).count(); | |
318 | assert_eq!(n_parsed_files, 1); | |
319 | } | |
320 | ||
321 | // Delete the parse tree. | |
322 | base_db::ParseQuery.in_db(&db).purge(); | |
323 | ||
324 | { | |
325 | let events = db.log_executed(|| { | |
326 | let crate_def_map = db.crate_def_map(krate); | |
327 | let (_, module_data) = crate_def_map.modules.iter().last().unwrap(); | |
328 | assert_eq!(module_data.scope.resolutions().count(), 8); | |
329 | assert_eq!(module_data.scope.impls().count(), 1); | |
330 | ||
331 | for imp in module_data.scope.impls() { | |
332 | db.impl_data(imp); | |
333 | } | |
334 | ||
335 | for (_, res) in module_data.scope.resolutions() { | |
781aab86 | 336 | match res.values.map(|(a, _, _)| a).or(res.types.map(|(a, _, _)| a)).unwrap() { |
add651ee | 337 | ModuleDefId::FunctionId(f) => _ = db.function_data(f), |
064997fb | 338 | ModuleDefId::AdtId(adt) => match adt { |
add651ee FG |
339 | AdtId::StructId(it) => _ = db.struct_data(it), |
340 | AdtId::UnionId(it) => _ = db.union_data(it), | |
341 | AdtId::EnumId(it) => _ = db.enum_data(it), | |
064997fb | 342 | }, |
add651ee FG |
343 | ModuleDefId::ConstId(it) => _ = db.const_data(it), |
344 | ModuleDefId::StaticId(it) => _ = db.static_data(it), | |
345 | ModuleDefId::TraitId(it) => _ = db.trait_data(it), | |
346 | ModuleDefId::TraitAliasId(it) => _ = db.trait_alias_data(it), | |
347 | ModuleDefId::TypeAliasId(it) => _ = db.type_alias_data(it), | |
064997fb FG |
348 | ModuleDefId::EnumVariantId(_) |
349 | | ModuleDefId::ModuleId(_) | |
350 | | ModuleDefId::MacroId(_) | |
351 | | ModuleDefId::BuiltinType(_) => unreachable!(), | |
352 | } | |
353 | } | |
354 | }); | |
355 | let n_reparsed_files = events.iter().filter(|it| it.contains("parse(")).count(); | |
356 | assert_eq!(n_reparsed_files, 0); | |
357 | } | |
358 | } |