]>
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; |
c295e0f8 | 19 | use rustc_data_structures::sync::join; |
dfeec247 | 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; | |
5099ac24 | 24 | use rustc_middle::hir::nested_filter; |
ba9703b0 | 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> { |
5099ac24 | 97 | type NestedFilter = nested_filter::All; |
dfeec247 XL |
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. | |
5099ac24 FG |
102 | fn nested_visit_map(&mut self) -> Self::Map { |
103 | 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 | ||
94222f64 XL |
247 | fn visit_infer(&mut self, inf: &'tcx hir::InferArg) { |
248 | lint_callback!(self, check_infer, inf); | |
249 | hir_visit::walk_inf(self, inf); | |
250 | } | |
251 | ||
f9f354fc | 252 | fn visit_name(&mut self, sp: Span, name: Symbol) { |
dfeec247 XL |
253 | lint_callback!(self, check_name, sp, name); |
254 | } | |
255 | ||
256 | fn visit_mod(&mut self, m: &'tcx hir::Mod<'tcx>, s: Span, n: hir::HirId) { | |
257 | if !self.context.only_module { | |
258 | self.process_mod(m, s, n); | |
259 | } | |
260 | } | |
261 | ||
262 | fn visit_local(&mut self, l: &'tcx hir::Local<'tcx>) { | |
6a06907d | 263 | self.with_lint_attrs(l.hir_id, |cx| { |
dfeec247 XL |
264 | lint_callback!(cx, check_local, l); |
265 | hir_visit::walk_local(cx, l); | |
266 | }) | |
267 | } | |
268 | ||
269 | fn visit_block(&mut self, b: &'tcx hir::Block<'tcx>) { | |
270 | lint_callback!(self, check_block, b); | |
271 | hir_visit::walk_block(self, b); | |
272 | lint_callback!(self, check_block_post, b); | |
273 | } | |
274 | ||
275 | fn visit_arm(&mut self, a: &'tcx hir::Arm<'tcx>) { | |
276 | lint_callback!(self, check_arm, a); | |
277 | hir_visit::walk_arm(self, a); | |
278 | } | |
279 | ||
280 | fn visit_generic_param(&mut self, p: &'tcx hir::GenericParam<'tcx>) { | |
281 | lint_callback!(self, check_generic_param, p); | |
282 | hir_visit::walk_generic_param(self, p); | |
283 | } | |
284 | ||
285 | fn visit_generics(&mut self, g: &'tcx hir::Generics<'tcx>) { | |
286 | lint_callback!(self, check_generics, g); | |
287 | hir_visit::walk_generics(self, g); | |
288 | } | |
289 | ||
290 | fn visit_where_predicate(&mut self, p: &'tcx hir::WherePredicate<'tcx>) { | |
291 | lint_callback!(self, check_where_predicate, p); | |
292 | hir_visit::walk_where_predicate(self, p); | |
293 | } | |
294 | ||
295 | fn visit_poly_trait_ref( | |
296 | &mut self, | |
297 | t: &'tcx hir::PolyTraitRef<'tcx>, | |
298 | m: hir::TraitBoundModifier, | |
299 | ) { | |
300 | lint_callback!(self, check_poly_trait_ref, t, m); | |
301 | hir_visit::walk_poly_trait_ref(self, t, m); | |
302 | } | |
303 | ||
304 | fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>) { | |
305 | let generics = self.context.generics.take(); | |
306 | self.context.generics = Some(&trait_item.generics); | |
6a06907d XL |
307 | self.with_lint_attrs(trait_item.hir_id(), |cx| { |
308 | cx.with_param_env(trait_item.hir_id(), |cx| { | |
dfeec247 XL |
309 | lint_callback!(cx, check_trait_item, trait_item); |
310 | hir_visit::walk_trait_item(cx, trait_item); | |
311 | lint_callback!(cx, check_trait_item_post, trait_item); | |
312 | }); | |
313 | }); | |
314 | self.context.generics = generics; | |
315 | } | |
316 | ||
317 | fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) { | |
318 | let generics = self.context.generics.take(); | |
319 | self.context.generics = Some(&impl_item.generics); | |
6a06907d XL |
320 | self.with_lint_attrs(impl_item.hir_id(), |cx| { |
321 | cx.with_param_env(impl_item.hir_id(), |cx| { | |
dfeec247 XL |
322 | lint_callback!(cx, check_impl_item, impl_item); |
323 | hir_visit::walk_impl_item(cx, impl_item); | |
324 | lint_callback!(cx, check_impl_item_post, impl_item); | |
325 | }); | |
326 | }); | |
327 | self.context.generics = generics; | |
328 | } | |
329 | ||
330 | fn visit_lifetime(&mut self, lt: &'tcx hir::Lifetime) { | |
331 | lint_callback!(self, check_lifetime, lt); | |
332 | hir_visit::walk_lifetime(self, lt); | |
333 | } | |
334 | ||
335 | fn visit_path(&mut self, p: &'tcx hir::Path<'tcx>, id: hir::HirId) { | |
336 | lint_callback!(self, check_path, p, id); | |
337 | hir_visit::walk_path(self, p); | |
338 | } | |
339 | ||
6a06907d XL |
340 | fn visit_attribute(&mut self, hir_id: hir::HirId, attr: &'tcx ast::Attribute) { |
341 | self.with_lint_attrs(hir_id, |cx| { | |
342 | lint_callback!(cx, check_attribute, attr); | |
343 | }) | |
dfeec247 XL |
344 | } |
345 | } | |
346 | ||
347 | struct LateLintPassObjects<'a> { | |
348 | lints: &'a mut [LateLintPassObject], | |
349 | } | |
350 | ||
351 | #[allow(rustc::lint_pass_impl_without_macro)] | |
352 | impl LintPass for LateLintPassObjects<'_> { | |
353 | fn name(&self) -> &'static str { | |
354 | panic!() | |
355 | } | |
356 | } | |
357 | ||
358 | macro_rules! expand_late_lint_pass_impl_methods { | |
f035d41b XL |
359 | ([$hir:tt], [$($(#[$attr:meta])* fn $name:ident($($param:ident: $arg:ty),*);)*]) => ( |
360 | $(fn $name(&mut self, context: &LateContext<$hir>, $($param: $arg),*) { | |
dfeec247 XL |
361 | for obj in self.lints.iter_mut() { |
362 | obj.$name(context, $($param),*); | |
363 | } | |
364 | })* | |
365 | ) | |
366 | } | |
367 | ||
368 | macro_rules! late_lint_pass_impl { | |
f035d41b XL |
369 | ([], [$hir:tt], $methods:tt) => { |
370 | impl<$hir> LateLintPass<$hir> for LateLintPassObjects<'_> { | |
371 | expand_late_lint_pass_impl_methods!([$hir], $methods); | |
dfeec247 | 372 | } |
f035d41b | 373 | }; |
dfeec247 XL |
374 | } |
375 | ||
376 | crate::late_lint_methods!(late_lint_pass_impl, [], ['tcx]); | |
377 | ||
f035d41b | 378 | fn late_lint_mod_pass<'tcx, T: LateLintPass<'tcx>>( |
dfeec247 | 379 | tcx: TyCtxt<'tcx>, |
f9f354fc | 380 | module_def_id: LocalDefId, |
dfeec247 XL |
381 | pass: T, |
382 | ) { | |
17df50a5 | 383 | let access_levels = &tcx.privacy_access_levels(()); |
dfeec247 XL |
384 | |
385 | let context = LateContext { | |
386 | tcx, | |
f035d41b | 387 | enclosing_body: None, |
3dfed10e | 388 | cached_typeck_results: Cell::new(None), |
dfeec247 XL |
389 | param_env: ty::ParamEnv::empty(), |
390 | access_levels, | |
391 | lint_store: unerased_lint_store(tcx), | |
3dfed10e | 392 | last_node_with_lint_attrs: tcx.hir().local_def_id_to_hir_id(module_def_id), |
dfeec247 XL |
393 | generics: None, |
394 | only_module: true, | |
395 | }; | |
396 | ||
397 | let mut cx = LateContextAndPass { context, pass }; | |
398 | ||
399 | let (module, span, hir_id) = tcx.hir().get_module(module_def_id); | |
400 | cx.process_mod(module, span, hir_id); | |
401 | ||
402 | // Visit the crate attributes | |
403 | if hir_id == hir::CRATE_HIR_ID { | |
6a06907d XL |
404 | for attr in tcx.hir().attrs(hir::CRATE_HIR_ID).iter() { |
405 | cx.visit_attribute(hir_id, attr) | |
406 | } | |
dfeec247 XL |
407 | } |
408 | } | |
409 | ||
f035d41b | 410 | pub fn late_lint_mod<'tcx, T: LateLintPass<'tcx>>( |
dfeec247 | 411 | tcx: TyCtxt<'tcx>, |
f9f354fc | 412 | module_def_id: LocalDefId, |
dfeec247 XL |
413 | builtin_lints: T, |
414 | ) { | |
415 | if tcx.sess.opts.debugging_opts.no_interleave_lints { | |
416 | // These passes runs in late_lint_crate with -Z no_interleave_lints | |
417 | return; | |
418 | } | |
419 | ||
420 | late_lint_mod_pass(tcx, module_def_id, builtin_lints); | |
421 | ||
422 | let mut passes: Vec<_> = | |
423 | unerased_lint_store(tcx).late_module_passes.iter().map(|pass| (pass)()).collect(); | |
424 | ||
425 | if !passes.is_empty() { | |
426 | late_lint_mod_pass(tcx, module_def_id, LateLintPassObjects { lints: &mut passes[..] }); | |
427 | } | |
428 | } | |
429 | ||
f035d41b | 430 | fn late_lint_pass_crate<'tcx, T: LateLintPass<'tcx>>(tcx: TyCtxt<'tcx>, pass: T) { |
17df50a5 | 431 | let access_levels = &tcx.privacy_access_levels(()); |
dfeec247 | 432 | |
dfeec247 XL |
433 | let context = LateContext { |
434 | tcx, | |
f035d41b | 435 | enclosing_body: None, |
3dfed10e | 436 | cached_typeck_results: Cell::new(None), |
dfeec247 XL |
437 | param_env: ty::ParamEnv::empty(), |
438 | access_levels, | |
439 | lint_store: unerased_lint_store(tcx), | |
440 | last_node_with_lint_attrs: hir::CRATE_HIR_ID, | |
441 | generics: None, | |
442 | only_module: false, | |
443 | }; | |
444 | ||
445 | let mut cx = LateContextAndPass { context, pass }; | |
446 | ||
447 | // Visit the whole crate. | |
6a06907d | 448 | cx.with_lint_attrs(hir::CRATE_HIR_ID, |cx| { |
dfeec247 XL |
449 | // since the root module isn't visited as an item (because it isn't an |
450 | // item), warn for it here. | |
c295e0f8 XL |
451 | lint_callback!(cx, check_crate,); |
452 | tcx.hir().walk_toplevel_module(cx); | |
453 | tcx.hir().walk_attributes(cx); | |
454 | lint_callback!(cx, check_crate_post,); | |
dfeec247 XL |
455 | }) |
456 | } | |
457 | ||
f035d41b | 458 | fn late_lint_crate<'tcx, T: LateLintPass<'tcx>>(tcx: TyCtxt<'tcx>, builtin_lints: T) { |
dfeec247 XL |
459 | let mut passes = unerased_lint_store(tcx).late_passes.iter().map(|p| (p)()).collect::<Vec<_>>(); |
460 | ||
461 | if !tcx.sess.opts.debugging_opts.no_interleave_lints { | |
462 | if !passes.is_empty() { | |
463 | late_lint_pass_crate(tcx, LateLintPassObjects { lints: &mut passes[..] }); | |
464 | } | |
465 | ||
466 | late_lint_pass_crate(tcx, builtin_lints); | |
467 | } else { | |
468 | for pass in &mut passes { | |
74b04a01 XL |
469 | tcx.sess.prof.extra_verbose_generic_activity("run_late_lint", pass.name()).run(|| { |
470 | late_lint_pass_crate(tcx, LateLintPassObjects { lints: slice::from_mut(pass) }); | |
471 | }); | |
dfeec247 XL |
472 | } |
473 | ||
474 | let mut passes: Vec<_> = | |
475 | unerased_lint_store(tcx).late_module_passes.iter().map(|pass| (pass)()).collect(); | |
476 | ||
477 | for pass in &mut passes { | |
74b04a01 XL |
478 | tcx.sess.prof.extra_verbose_generic_activity("run_late_module_lint", pass.name()).run( |
479 | || { | |
dfeec247 | 480 | late_lint_pass_crate(tcx, LateLintPassObjects { lints: slice::from_mut(pass) }); |
74b04a01 XL |
481 | }, |
482 | ); | |
dfeec247 XL |
483 | } |
484 | } | |
485 | } | |
486 | ||
487 | /// Performs lint checking on a crate. | |
f035d41b | 488 | pub fn check_crate<'tcx, T: LateLintPass<'tcx>>( |
dfeec247 XL |
489 | tcx: TyCtxt<'tcx>, |
490 | builtin_lints: impl FnOnce() -> T + Send, | |
491 | ) { | |
492 | join( | |
493 | || { | |
494 | tcx.sess.time("crate_lints", || { | |
495 | // Run whole crate non-incremental lints | |
496 | late_lint_crate(tcx, builtin_lints()); | |
497 | }); | |
498 | }, | |
499 | || { | |
500 | tcx.sess.time("module_lints", || { | |
501 | // Run per-module lints | |
c295e0f8 | 502 | tcx.hir().par_for_each_module(|module| tcx.ensure().lint_mod(module)); |
dfeec247 XL |
503 | }); |
504 | }, | |
505 | ); | |
5e7ed085 FG |
506 | |
507 | // This check has to be run after all lints are done processing for this crate | |
508 | tcx.sess.time("check_lint_expectations", || crate::expect::check_expectations(tcx)); | |
dfeec247 | 509 | } |