]>
Commit | Line | Data |
---|---|---|
dfeec247 XL |
1 | //! Implementation of lint checking. |
2 | //! | |
3 | //! The lint checking is mostly consolidated into one pass which runs | |
4 | //! after all other analyses. Throughout compilation, lint warnings | |
5 | //! can be added via the `add_lint` method on the Session structure. This | |
6 | //! requires a span and an ID of the node that the lint is being added to. The | |
7 | //! lint isn't actually emitted at that time because it is unknown what the | |
8 | //! actual lint level at that location is. | |
9 | //! | |
10 | //! To actually emit lint warnings/errors, a separate pass is used. | |
11 | //! A context keeps track of the current state of all lint levels. | |
12 | //! Upon entering a node of the ast which can modify the lint settings, the | |
13 | //! previous lint state is pushed onto a stack and the ast is then recursed | |
14 | //! upon. As the ast is traversed, this keeps track of the current lint level | |
15 | //! for all lint attributes. | |
16 | ||
17 | use crate::{passes::LateLintPassObject, LateContext, LateLintPass, LintStore}; | |
3dfed10e | 18 | use rustc_ast as ast; |
dfeec247 XL |
19 | use rustc_data_structures::sync::{join, par_iter, ParallelIterator}; |
20 | use rustc_hir as hir; | |
17df50a5 | 21 | use rustc_hir::def_id::LocalDefId; |
dfeec247 XL |
22 | use rustc_hir::intravisit as hir_visit; |
23 | use rustc_hir::intravisit::Visitor; | |
ba9703b0 XL |
24 | use rustc_middle::hir::map::Map; |
25 | use rustc_middle::ty::{self, TyCtxt}; | |
dfeec247 | 26 | use rustc_session::lint::LintPass; |
f9f354fc | 27 | use rustc_span::symbol::Symbol; |
dfeec247 | 28 | use rustc_span::Span; |
dfeec247 | 29 | |
dfeec247 | 30 | use std::any::Any; |
f035d41b | 31 | use std::cell::Cell; |
dfeec247 | 32 | use std::slice; |
3dfed10e | 33 | use tracing::debug; |
dfeec247 XL |
34 | |
35 | /// Extract the `LintStore` from the query context. | |
36 | /// This function exists because we've erased `LintStore` as `dyn Any` in the context. | |
ba9703b0 | 37 | crate fn unerased_lint_store(tcx: TyCtxt<'_>) -> &LintStore { |
dfeec247 XL |
38 | let store: &dyn Any = &*tcx.lint_store; |
39 | store.downcast_ref().unwrap() | |
40 | } | |
41 | ||
42 | macro_rules! lint_callback { ($cx:expr, $f:ident, $($args:expr),*) => ({ | |
43 | $cx.pass.$f(&$cx.context, $($args),*); | |
44 | }) } | |
45 | ||
f035d41b XL |
46 | struct LateContextAndPass<'tcx, T: LateLintPass<'tcx>> { |
47 | context: LateContext<'tcx>, | |
dfeec247 XL |
48 | pass: T, |
49 | } | |
50 | ||
f035d41b | 51 | impl<'tcx, T: LateLintPass<'tcx>> LateContextAndPass<'tcx, T> { |
dfeec247 XL |
52 | /// Merge the lints specified by any lint attributes into the |
53 | /// current lint context, call the provided function, then reset the | |
54 | /// lints in effect to their previous state. | |
6a06907d | 55 | fn with_lint_attrs<F>(&mut self, id: hir::HirId, f: F) |
dfeec247 XL |
56 | where |
57 | F: FnOnce(&mut Self), | |
58 | { | |
6a06907d | 59 | let attrs = self.context.tcx.hir().attrs(id); |
dfeec247 XL |
60 | let prev = self.context.last_node_with_lint_attrs; |
61 | self.context.last_node_with_lint_attrs = id; | |
62 | self.enter_attrs(attrs); | |
63 | f(self); | |
64 | self.exit_attrs(attrs); | |
65 | self.context.last_node_with_lint_attrs = prev; | |
66 | } | |
67 | ||
68 | fn with_param_env<F>(&mut self, id: hir::HirId, f: F) | |
69 | where | |
70 | F: FnOnce(&mut Self), | |
71 | { | |
72 | let old_param_env = self.context.param_env; | |
73 | self.context.param_env = | |
74 | self.context.tcx.param_env(self.context.tcx.hir().local_def_id(id)); | |
75 | f(self); | |
76 | self.context.param_env = old_param_env; | |
77 | } | |
78 | ||
79 | fn process_mod(&mut self, m: &'tcx hir::Mod<'tcx>, s: Span, n: hir::HirId) { | |
80 | lint_callback!(self, check_mod, m, s, n); | |
81 | hir_visit::walk_mod(self, m, n); | |
82 | lint_callback!(self, check_mod_post, m, s, n); | |
83 | } | |
84 | ||
85 | fn enter_attrs(&mut self, attrs: &'tcx [ast::Attribute]) { | |
86 | debug!("late context: enter_attrs({:?})", attrs); | |
87 | lint_callback!(self, enter_lint_attrs, attrs); | |
88 | } | |
89 | ||
90 | fn exit_attrs(&mut self, attrs: &'tcx [ast::Attribute]) { | |
91 | debug!("late context: exit_attrs({:?})", attrs); | |
92 | lint_callback!(self, exit_lint_attrs, attrs); | |
93 | } | |
94 | } | |
95 | ||
f035d41b | 96 | impl<'tcx, T: LateLintPass<'tcx>> hir_visit::Visitor<'tcx> for LateContextAndPass<'tcx, T> { |
dfeec247 XL |
97 | type Map = Map<'tcx>; |
98 | ||
99 | /// Because lints are scoped lexically, we want to walk nested | |
100 | /// items in the context of the outer item, so enable | |
101 | /// deep-walking. | |
ba9703b0 XL |
102 | fn nested_visit_map(&mut self) -> hir_visit::NestedVisitorMap<Self::Map> { |
103 | hir_visit::NestedVisitorMap::All(self.context.tcx.hir()) | |
dfeec247 XL |
104 | } |
105 | ||
f035d41b XL |
106 | fn visit_nested_body(&mut self, body_id: hir::BodyId) { |
107 | let old_enclosing_body = self.context.enclosing_body.replace(body_id); | |
3dfed10e | 108 | let old_cached_typeck_results = self.context.cached_typeck_results.get(); |
f035d41b | 109 | |
3dfed10e | 110 | // HACK(eddyb) avoid trashing `cached_typeck_results` when we're |
f035d41b XL |
111 | // nested in `visit_fn`, which may have already resulted in them |
112 | // being queried. | |
113 | if old_enclosing_body != Some(body_id) { | |
3dfed10e | 114 | self.context.cached_typeck_results.set(None); |
f035d41b XL |
115 | } |
116 | ||
117 | let body = self.context.tcx.hir().body(body_id); | |
dfeec247 | 118 | self.visit_body(body); |
f035d41b XL |
119 | self.context.enclosing_body = old_enclosing_body; |
120 | ||
121 | // See HACK comment above. | |
122 | if old_enclosing_body != Some(body_id) { | |
3dfed10e | 123 | self.context.cached_typeck_results.set(old_cached_typeck_results); |
f035d41b | 124 | } |
dfeec247 XL |
125 | } |
126 | ||
127 | fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) { | |
6a06907d | 128 | self.with_lint_attrs(param.hir_id, |cx| { |
dfeec247 XL |
129 | lint_callback!(cx, check_param, param); |
130 | hir_visit::walk_param(cx, param); | |
131 | }); | |
132 | } | |
133 | ||
134 | fn visit_body(&mut self, body: &'tcx hir::Body<'tcx>) { | |
135 | lint_callback!(self, check_body, body); | |
136 | hir_visit::walk_body(self, body); | |
137 | lint_callback!(self, check_body_post, body); | |
138 | } | |
139 | ||
140 | fn visit_item(&mut self, it: &'tcx hir::Item<'tcx>) { | |
141 | let generics = self.context.generics.take(); | |
142 | self.context.generics = it.kind.generics(); | |
5869c6ff XL |
143 | let old_cached_typeck_results = self.context.cached_typeck_results.take(); |
144 | let old_enclosing_body = self.context.enclosing_body.take(); | |
6a06907d XL |
145 | self.with_lint_attrs(it.hir_id(), |cx| { |
146 | cx.with_param_env(it.hir_id(), |cx| { | |
dfeec247 XL |
147 | lint_callback!(cx, check_item, it); |
148 | hir_visit::walk_item(cx, it); | |
149 | lint_callback!(cx, check_item_post, it); | |
150 | }); | |
151 | }); | |
5869c6ff XL |
152 | self.context.enclosing_body = old_enclosing_body; |
153 | self.context.cached_typeck_results.set(old_cached_typeck_results); | |
dfeec247 XL |
154 | self.context.generics = generics; |
155 | } | |
156 | ||
157 | fn visit_foreign_item(&mut self, it: &'tcx hir::ForeignItem<'tcx>) { | |
6a06907d XL |
158 | self.with_lint_attrs(it.hir_id(), |cx| { |
159 | cx.with_param_env(it.hir_id(), |cx| { | |
dfeec247 XL |
160 | lint_callback!(cx, check_foreign_item, it); |
161 | hir_visit::walk_foreign_item(cx, it); | |
162 | lint_callback!(cx, check_foreign_item_post, it); | |
163 | }); | |
164 | }) | |
165 | } | |
166 | ||
167 | fn visit_pat(&mut self, p: &'tcx hir::Pat<'tcx>) { | |
168 | lint_callback!(self, check_pat, p); | |
169 | hir_visit::walk_pat(self, p); | |
170 | } | |
171 | ||
172 | fn visit_expr(&mut self, e: &'tcx hir::Expr<'tcx>) { | |
6a06907d | 173 | self.with_lint_attrs(e.hir_id, |cx| { |
dfeec247 XL |
174 | lint_callback!(cx, check_expr, e); |
175 | hir_visit::walk_expr(cx, e); | |
176 | lint_callback!(cx, check_expr_post, e); | |
177 | }) | |
178 | } | |
179 | ||
180 | fn visit_stmt(&mut self, s: &'tcx hir::Stmt<'tcx>) { | |
29967ef6 XL |
181 | // See `EarlyContextAndPass::visit_stmt` for an explanation |
182 | // of why we call `walk_stmt` outside of `with_lint_attrs` | |
6a06907d | 183 | self.with_lint_attrs(s.hir_id, |cx| { |
29967ef6 XL |
184 | lint_callback!(cx, check_stmt, s); |
185 | }); | |
dfeec247 XL |
186 | hir_visit::walk_stmt(self, s); |
187 | } | |
188 | ||
189 | fn visit_fn( | |
190 | &mut self, | |
191 | fk: hir_visit::FnKind<'tcx>, | |
192 | decl: &'tcx hir::FnDecl<'tcx>, | |
193 | body_id: hir::BodyId, | |
194 | span: Span, | |
195 | id: hir::HirId, | |
196 | ) { | |
3dfed10e | 197 | // Wrap in typeck results here, not just in visit_nested_body, |
dfeec247 | 198 | // in order for `check_fn` to be able to use them. |
f035d41b | 199 | let old_enclosing_body = self.context.enclosing_body.replace(body_id); |
3dfed10e | 200 | let old_cached_typeck_results = self.context.cached_typeck_results.take(); |
dfeec247 XL |
201 | let body = self.context.tcx.hir().body(body_id); |
202 | lint_callback!(self, check_fn, fk, decl, body, span, id); | |
203 | hir_visit::walk_fn(self, fk, decl, body_id, span, id); | |
204 | lint_callback!(self, check_fn_post, fk, decl, body, span, id); | |
f035d41b | 205 | self.context.enclosing_body = old_enclosing_body; |
3dfed10e | 206 | self.context.cached_typeck_results.set(old_cached_typeck_results); |
dfeec247 XL |
207 | } |
208 | ||
209 | fn visit_variant_data( | |
210 | &mut self, | |
211 | s: &'tcx hir::VariantData<'tcx>, | |
f9f354fc | 212 | _: Symbol, |
dfeec247 XL |
213 | _: &'tcx hir::Generics<'tcx>, |
214 | _: hir::HirId, | |
215 | _: Span, | |
216 | ) { | |
217 | lint_callback!(self, check_struct_def, s); | |
218 | hir_visit::walk_struct_def(self, s); | |
219 | lint_callback!(self, check_struct_def_post, s); | |
220 | } | |
221 | ||
6a06907d XL |
222 | fn visit_field_def(&mut self, s: &'tcx hir::FieldDef<'tcx>) { |
223 | self.with_lint_attrs(s.hir_id, |cx| { | |
224 | lint_callback!(cx, check_field_def, s); | |
225 | hir_visit::walk_field_def(cx, s); | |
dfeec247 XL |
226 | }) |
227 | } | |
228 | ||
229 | fn visit_variant( | |
230 | &mut self, | |
231 | v: &'tcx hir::Variant<'tcx>, | |
232 | g: &'tcx hir::Generics<'tcx>, | |
233 | item_id: hir::HirId, | |
234 | ) { | |
6a06907d | 235 | self.with_lint_attrs(v.id, |cx| { |
dfeec247 XL |
236 | lint_callback!(cx, check_variant, v); |
237 | hir_visit::walk_variant(cx, v, g, item_id); | |
238 | lint_callback!(cx, check_variant_post, v); | |
239 | }) | |
240 | } | |
241 | ||
242 | fn visit_ty(&mut self, t: &'tcx hir::Ty<'tcx>) { | |
243 | lint_callback!(self, check_ty, t); | |
244 | hir_visit::walk_ty(self, t); | |
245 | } | |
246 | ||
f9f354fc | 247 | fn visit_name(&mut self, sp: Span, name: Symbol) { |
dfeec247 XL |
248 | lint_callback!(self, check_name, sp, name); |
249 | } | |
250 | ||
251 | fn visit_mod(&mut self, m: &'tcx hir::Mod<'tcx>, s: Span, n: hir::HirId) { | |
252 | if !self.context.only_module { | |
253 | self.process_mod(m, s, n); | |
254 | } | |
255 | } | |
256 | ||
257 | fn visit_local(&mut self, l: &'tcx hir::Local<'tcx>) { | |
6a06907d | 258 | self.with_lint_attrs(l.hir_id, |cx| { |
dfeec247 XL |
259 | lint_callback!(cx, check_local, l); |
260 | hir_visit::walk_local(cx, l); | |
261 | }) | |
262 | } | |
263 | ||
264 | fn visit_block(&mut self, b: &'tcx hir::Block<'tcx>) { | |
265 | lint_callback!(self, check_block, b); | |
266 | hir_visit::walk_block(self, b); | |
267 | lint_callback!(self, check_block_post, b); | |
268 | } | |
269 | ||
270 | fn visit_arm(&mut self, a: &'tcx hir::Arm<'tcx>) { | |
271 | lint_callback!(self, check_arm, a); | |
272 | hir_visit::walk_arm(self, a); | |
273 | } | |
274 | ||
275 | fn visit_generic_param(&mut self, p: &'tcx hir::GenericParam<'tcx>) { | |
276 | lint_callback!(self, check_generic_param, p); | |
277 | hir_visit::walk_generic_param(self, p); | |
278 | } | |
279 | ||
280 | fn visit_generics(&mut self, g: &'tcx hir::Generics<'tcx>) { | |
281 | lint_callback!(self, check_generics, g); | |
282 | hir_visit::walk_generics(self, g); | |
283 | } | |
284 | ||
285 | fn visit_where_predicate(&mut self, p: &'tcx hir::WherePredicate<'tcx>) { | |
286 | lint_callback!(self, check_where_predicate, p); | |
287 | hir_visit::walk_where_predicate(self, p); | |
288 | } | |
289 | ||
290 | fn visit_poly_trait_ref( | |
291 | &mut self, | |
292 | t: &'tcx hir::PolyTraitRef<'tcx>, | |
293 | m: hir::TraitBoundModifier, | |
294 | ) { | |
295 | lint_callback!(self, check_poly_trait_ref, t, m); | |
296 | hir_visit::walk_poly_trait_ref(self, t, m); | |
297 | } | |
298 | ||
299 | fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>) { | |
300 | let generics = self.context.generics.take(); | |
301 | self.context.generics = Some(&trait_item.generics); | |
6a06907d XL |
302 | self.with_lint_attrs(trait_item.hir_id(), |cx| { |
303 | cx.with_param_env(trait_item.hir_id(), |cx| { | |
dfeec247 XL |
304 | lint_callback!(cx, check_trait_item, trait_item); |
305 | hir_visit::walk_trait_item(cx, trait_item); | |
306 | lint_callback!(cx, check_trait_item_post, trait_item); | |
307 | }); | |
308 | }); | |
309 | self.context.generics = generics; | |
310 | } | |
311 | ||
312 | fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) { | |
313 | let generics = self.context.generics.take(); | |
314 | self.context.generics = Some(&impl_item.generics); | |
6a06907d XL |
315 | self.with_lint_attrs(impl_item.hir_id(), |cx| { |
316 | cx.with_param_env(impl_item.hir_id(), |cx| { | |
dfeec247 XL |
317 | lint_callback!(cx, check_impl_item, impl_item); |
318 | hir_visit::walk_impl_item(cx, impl_item); | |
319 | lint_callback!(cx, check_impl_item_post, impl_item); | |
320 | }); | |
321 | }); | |
322 | self.context.generics = generics; | |
323 | } | |
324 | ||
325 | fn visit_lifetime(&mut self, lt: &'tcx hir::Lifetime) { | |
326 | lint_callback!(self, check_lifetime, lt); | |
327 | hir_visit::walk_lifetime(self, lt); | |
328 | } | |
329 | ||
330 | fn visit_path(&mut self, p: &'tcx hir::Path<'tcx>, id: hir::HirId) { | |
331 | lint_callback!(self, check_path, p, id); | |
332 | hir_visit::walk_path(self, p); | |
333 | } | |
334 | ||
6a06907d XL |
335 | fn visit_attribute(&mut self, hir_id: hir::HirId, attr: &'tcx ast::Attribute) { |
336 | self.with_lint_attrs(hir_id, |cx| { | |
337 | lint_callback!(cx, check_attribute, attr); | |
338 | }) | |
dfeec247 XL |
339 | } |
340 | } | |
341 | ||
342 | struct LateLintPassObjects<'a> { | |
343 | lints: &'a mut [LateLintPassObject], | |
344 | } | |
345 | ||
346 | #[allow(rustc::lint_pass_impl_without_macro)] | |
347 | impl LintPass for LateLintPassObjects<'_> { | |
348 | fn name(&self) -> &'static str { | |
349 | panic!() | |
350 | } | |
351 | } | |
352 | ||
353 | macro_rules! expand_late_lint_pass_impl_methods { | |
f035d41b XL |
354 | ([$hir:tt], [$($(#[$attr:meta])* fn $name:ident($($param:ident: $arg:ty),*);)*]) => ( |
355 | $(fn $name(&mut self, context: &LateContext<$hir>, $($param: $arg),*) { | |
dfeec247 XL |
356 | for obj in self.lints.iter_mut() { |
357 | obj.$name(context, $($param),*); | |
358 | } | |
359 | })* | |
360 | ) | |
361 | } | |
362 | ||
363 | macro_rules! late_lint_pass_impl { | |
f035d41b XL |
364 | ([], [$hir:tt], $methods:tt) => { |
365 | impl<$hir> LateLintPass<$hir> for LateLintPassObjects<'_> { | |
366 | expand_late_lint_pass_impl_methods!([$hir], $methods); | |
dfeec247 | 367 | } |
f035d41b | 368 | }; |
dfeec247 XL |
369 | } |
370 | ||
371 | crate::late_lint_methods!(late_lint_pass_impl, [], ['tcx]); | |
372 | ||
f035d41b | 373 | fn late_lint_mod_pass<'tcx, T: LateLintPass<'tcx>>( |
dfeec247 | 374 | tcx: TyCtxt<'tcx>, |
f9f354fc | 375 | module_def_id: LocalDefId, |
dfeec247 XL |
376 | pass: T, |
377 | ) { | |
17df50a5 | 378 | let access_levels = &tcx.privacy_access_levels(()); |
dfeec247 XL |
379 | |
380 | let context = LateContext { | |
381 | tcx, | |
f035d41b | 382 | enclosing_body: None, |
3dfed10e | 383 | cached_typeck_results: Cell::new(None), |
dfeec247 XL |
384 | param_env: ty::ParamEnv::empty(), |
385 | access_levels, | |
386 | lint_store: unerased_lint_store(tcx), | |
3dfed10e | 387 | last_node_with_lint_attrs: tcx.hir().local_def_id_to_hir_id(module_def_id), |
dfeec247 XL |
388 | generics: None, |
389 | only_module: true, | |
390 | }; | |
391 | ||
392 | let mut cx = LateContextAndPass { context, pass }; | |
393 | ||
394 | let (module, span, hir_id) = tcx.hir().get_module(module_def_id); | |
395 | cx.process_mod(module, span, hir_id); | |
396 | ||
397 | // Visit the crate attributes | |
398 | if hir_id == hir::CRATE_HIR_ID { | |
6a06907d XL |
399 | for attr in tcx.hir().attrs(hir::CRATE_HIR_ID).iter() { |
400 | cx.visit_attribute(hir_id, attr) | |
401 | } | |
dfeec247 XL |
402 | } |
403 | } | |
404 | ||
f035d41b | 405 | pub fn late_lint_mod<'tcx, T: LateLintPass<'tcx>>( |
dfeec247 | 406 | tcx: TyCtxt<'tcx>, |
f9f354fc | 407 | module_def_id: LocalDefId, |
dfeec247 XL |
408 | builtin_lints: T, |
409 | ) { | |
410 | if tcx.sess.opts.debugging_opts.no_interleave_lints { | |
411 | // These passes runs in late_lint_crate with -Z no_interleave_lints | |
412 | return; | |
413 | } | |
414 | ||
415 | late_lint_mod_pass(tcx, module_def_id, builtin_lints); | |
416 | ||
417 | let mut passes: Vec<_> = | |
418 | unerased_lint_store(tcx).late_module_passes.iter().map(|pass| (pass)()).collect(); | |
419 | ||
420 | if !passes.is_empty() { | |
421 | late_lint_mod_pass(tcx, module_def_id, LateLintPassObjects { lints: &mut passes[..] }); | |
422 | } | |
423 | } | |
424 | ||
f035d41b | 425 | fn late_lint_pass_crate<'tcx, T: LateLintPass<'tcx>>(tcx: TyCtxt<'tcx>, pass: T) { |
17df50a5 | 426 | let access_levels = &tcx.privacy_access_levels(()); |
dfeec247 XL |
427 | |
428 | let krate = tcx.hir().krate(); | |
429 | ||
430 | let context = LateContext { | |
431 | tcx, | |
f035d41b | 432 | enclosing_body: None, |
3dfed10e | 433 | cached_typeck_results: Cell::new(None), |
dfeec247 XL |
434 | param_env: ty::ParamEnv::empty(), |
435 | access_levels, | |
436 | lint_store: unerased_lint_store(tcx), | |
437 | last_node_with_lint_attrs: hir::CRATE_HIR_ID, | |
438 | generics: None, | |
439 | only_module: false, | |
440 | }; | |
441 | ||
442 | let mut cx = LateContextAndPass { context, pass }; | |
443 | ||
444 | // Visit the whole crate. | |
6a06907d | 445 | cx.with_lint_attrs(hir::CRATE_HIR_ID, |cx| { |
dfeec247 XL |
446 | // since the root module isn't visited as an item (because it isn't an |
447 | // item), warn for it here. | |
448 | lint_callback!(cx, check_crate, krate); | |
449 | ||
450 | hir_visit::walk_crate(cx, krate); | |
17df50a5 XL |
451 | for attr in krate.non_exported_macro_attrs { |
452 | // This HIR ID is a lie, since the macro ID isn't available. | |
453 | cx.visit_attribute(hir::CRATE_HIR_ID, attr); | |
454 | } | |
dfeec247 XL |
455 | |
456 | lint_callback!(cx, check_crate_post, krate); | |
457 | }) | |
458 | } | |
459 | ||
f035d41b | 460 | fn late_lint_crate<'tcx, T: LateLintPass<'tcx>>(tcx: TyCtxt<'tcx>, builtin_lints: T) { |
dfeec247 XL |
461 | let mut passes = unerased_lint_store(tcx).late_passes.iter().map(|p| (p)()).collect::<Vec<_>>(); |
462 | ||
463 | if !tcx.sess.opts.debugging_opts.no_interleave_lints { | |
464 | if !passes.is_empty() { | |
465 | late_lint_pass_crate(tcx, LateLintPassObjects { lints: &mut passes[..] }); | |
466 | } | |
467 | ||
468 | late_lint_pass_crate(tcx, builtin_lints); | |
469 | } else { | |
470 | for pass in &mut passes { | |
74b04a01 XL |
471 | tcx.sess.prof.extra_verbose_generic_activity("run_late_lint", pass.name()).run(|| { |
472 | late_lint_pass_crate(tcx, LateLintPassObjects { lints: slice::from_mut(pass) }); | |
473 | }); | |
dfeec247 XL |
474 | } |
475 | ||
476 | let mut passes: Vec<_> = | |
477 | unerased_lint_store(tcx).late_module_passes.iter().map(|pass| (pass)()).collect(); | |
478 | ||
479 | for pass in &mut passes { | |
74b04a01 XL |
480 | tcx.sess.prof.extra_verbose_generic_activity("run_late_module_lint", pass.name()).run( |
481 | || { | |
dfeec247 | 482 | late_lint_pass_crate(tcx, LateLintPassObjects { lints: slice::from_mut(pass) }); |
74b04a01 XL |
483 | }, |
484 | ); | |
dfeec247 XL |
485 | } |
486 | } | |
487 | } | |
488 | ||
489 | /// Performs lint checking on a crate. | |
f035d41b | 490 | pub fn check_crate<'tcx, T: LateLintPass<'tcx>>( |
dfeec247 XL |
491 | tcx: TyCtxt<'tcx>, |
492 | builtin_lints: impl FnOnce() -> T + Send, | |
493 | ) { | |
494 | join( | |
495 | || { | |
496 | tcx.sess.time("crate_lints", || { | |
497 | // Run whole crate non-incremental lints | |
498 | late_lint_crate(tcx, builtin_lints()); | |
499 | }); | |
500 | }, | |
501 | || { | |
502 | tcx.sess.time("module_lints", || { | |
503 | // Run per-module lints | |
504 | par_iter(&tcx.hir().krate().modules).for_each(|(&module, _)| { | |
6a06907d | 505 | tcx.ensure().lint_mod(module); |
dfeec247 XL |
506 | }); |
507 | }); | |
508 | }, | |
509 | ); | |
510 | } |