2019-12-30 14:22:46 +01:00
|
|
|
//! Implementation of lint checking.
|
|
|
|
|
//!
|
|
|
|
|
//! The lint checking is mostly consolidated into one pass which runs
|
|
|
|
|
//! after all other analyses. Throughout compilation, lint warnings
|
|
|
|
|
//! can be added via the `add_lint` method on the Session structure. This
|
|
|
|
|
//! requires a span and an ID of the node that the lint is being added to. The
|
|
|
|
|
//! lint isn't actually emitted at that time because it is unknown what the
|
|
|
|
|
//! actual lint level at that location is.
|
|
|
|
|
//!
|
|
|
|
|
//! To actually emit lint warnings/errors, a separate pass is used.
|
|
|
|
|
//! A context keeps track of the current state of all lint levels.
|
|
|
|
|
//! Upon entering a node of the ast which can modify the lint settings, the
|
|
|
|
|
//! previous lint state is pushed onto a stack and the ast is then recursed
|
|
|
|
|
//! upon. As the ast is traversed, this keeps track of the current lint level
|
|
|
|
|
//! for all lint attributes.
|
|
|
|
|
|
2020-01-09 07:52:01 +01:00
|
|
|
use crate::{passes::LateLintPassObject, LateContext, LateLintPass, LintStore};
|
2020-04-27 23:26:11 +05:30
|
|
|
use rustc_ast as ast;
|
2021-07-18 18:12:17 +02:00
|
|
|
use rustc_data_structures::sync::join;
|
2020-01-05 02:37:57 +01:00
|
|
|
use rustc_hir as hir;
|
2021-05-11 13:49:00 +02:00
|
|
|
use rustc_hir::def_id::LocalDefId;
|
2020-01-07 18:12:06 +01:00
|
|
|
use rustc_hir::intravisit as hir_visit;
|
|
|
|
|
use rustc_hir::intravisit::Visitor;
|
2021-11-03 18:03:12 -05:00
|
|
|
use rustc_middle::hir::nested_filter;
|
2020-03-29 17:19:48 +02:00
|
|
|
use rustc_middle::ty::{self, TyCtxt};
|
2020-01-05 10:07:26 +01:00
|
|
|
use rustc_session::lint::LintPass;
|
2019-12-30 14:22:46 +01:00
|
|
|
use rustc_span::Span;
|
|
|
|
|
|
2020-01-09 09:40:55 +01:00
|
|
|
use std::any::Any;
|
2020-06-26 02:56:23 +03:00
|
|
|
use std::cell::Cell;
|
2020-01-05 10:07:26 +01:00
|
|
|
use std::slice;
|
2019-12-30 14:22:46 +01:00
|
|
|
|
2020-01-09 03:45:42 +01:00
|
|
|
/// Extract the `LintStore` from the query context.
|
|
|
|
|
/// This function exists because we've erased `LintStore` as `dyn Any` in the context.
|
2021-07-13 18:45:20 +02:00
|
|
|
pub fn unerased_lint_store(tcx: TyCtxt<'_>) -> &LintStore {
|
2020-01-09 09:40:55 +01:00
|
|
|
let store: &dyn Any = &*tcx.lint_store;
|
|
|
|
|
store.downcast_ref().unwrap()
|
2020-01-09 03:45:42 +01:00
|
|
|
}
|
|
|
|
|
|
2019-12-30 14:22:46 +01:00
|
|
|
macro_rules! lint_callback { ($cx:expr, $f:ident, $($args:expr),*) => ({
|
|
|
|
|
$cx.pass.$f(&$cx.context, $($args),*);
|
|
|
|
|
}) }
|
|
|
|
|
|
2020-06-25 23:41:36 +03:00
|
|
|
struct LateContextAndPass<'tcx, T: LateLintPass<'tcx>> {
|
|
|
|
|
context: LateContext<'tcx>,
|
2019-12-30 14:22:46 +01:00
|
|
|
pass: T,
|
|
|
|
|
}
|
|
|
|
|
|
2020-06-25 23:41:36 +03:00
|
|
|
impl<'tcx, T: LateLintPass<'tcx>> LateContextAndPass<'tcx, T> {
|
2019-12-30 14:22:46 +01:00
|
|
|
/// Merge the lints specified by any lint attributes into the
|
|
|
|
|
/// current lint context, call the provided function, then reset the
|
|
|
|
|
/// lints in effect to their previous state.
|
2020-11-25 23:19:54 +01:00
|
|
|
fn with_lint_attrs<F>(&mut self, id: hir::HirId, f: F)
|
2019-12-30 14:22:46 +01:00
|
|
|
where
|
|
|
|
|
F: FnOnce(&mut Self),
|
|
|
|
|
{
|
2020-11-25 23:19:54 +01:00
|
|
|
let attrs = self.context.tcx.hir().attrs(id);
|
2019-12-30 14:22:46 +01:00
|
|
|
let prev = self.context.last_node_with_lint_attrs;
|
|
|
|
|
self.context.last_node_with_lint_attrs = id;
|
2022-06-16 09:47:07 +10:00
|
|
|
debug!("late context: enter_attrs({:?})", attrs);
|
|
|
|
|
lint_callback!(self, enter_lint_attrs, attrs);
|
2019-12-30 14:22:46 +01:00
|
|
|
f(self);
|
2022-06-16 09:47:07 +10:00
|
|
|
debug!("late context: exit_attrs({:?})", attrs);
|
|
|
|
|
lint_callback!(self, exit_lint_attrs, attrs);
|
2019-12-30 14:22:46 +01:00
|
|
|
self.context.last_node_with_lint_attrs = prev;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn with_param_env<F>(&mut self, id: hir::HirId, f: F)
|
|
|
|
|
where
|
|
|
|
|
F: FnOnce(&mut Self),
|
|
|
|
|
{
|
|
|
|
|
let old_param_env = self.context.param_env;
|
|
|
|
|
self.context.param_env =
|
|
|
|
|
self.context.tcx.param_env(self.context.tcx.hir().local_def_id(id));
|
|
|
|
|
f(self);
|
|
|
|
|
self.context.param_env = old_param_env;
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-12 13:23:26 +10:00
|
|
|
fn process_mod(&mut self, m: &'tcx hir::Mod<'tcx>, n: hir::HirId) {
|
|
|
|
|
lint_callback!(self, check_mod, m, n);
|
2019-12-30 14:22:46 +01:00
|
|
|
hir_visit::walk_mod(self, m, n);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-06-25 23:41:36 +03:00
|
|
|
impl<'tcx, T: LateLintPass<'tcx>> hir_visit::Visitor<'tcx> for LateContextAndPass<'tcx, T> {
|
2021-11-03 18:03:12 -05:00
|
|
|
type NestedFilter = nested_filter::All;
|
2020-01-07 17:25:33 +01:00
|
|
|
|
2019-12-30 14:22:46 +01:00
|
|
|
/// Because lints are scoped lexically, we want to walk nested
|
|
|
|
|
/// items in the context of the outer item, so enable
|
|
|
|
|
/// deep-walking.
|
2021-11-03 18:03:12 -05:00
|
|
|
fn nested_visit_map(&mut self) -> Self::Map {
|
|
|
|
|
self.context.tcx.hir()
|
2019-12-30 14:22:46 +01:00
|
|
|
}
|
|
|
|
|
|
2020-06-26 02:56:23 +03:00
|
|
|
fn visit_nested_body(&mut self, body_id: hir::BodyId) {
|
|
|
|
|
let old_enclosing_body = self.context.enclosing_body.replace(body_id);
|
2020-07-17 08:47:04 +00:00
|
|
|
let old_cached_typeck_results = self.context.cached_typeck_results.get();
|
2020-06-26 02:56:23 +03:00
|
|
|
|
2020-07-17 08:47:04 +00:00
|
|
|
// HACK(eddyb) avoid trashing `cached_typeck_results` when we're
|
2020-06-26 02:56:23 +03:00
|
|
|
// nested in `visit_fn`, which may have already resulted in them
|
|
|
|
|
// being queried.
|
|
|
|
|
if old_enclosing_body != Some(body_id) {
|
2020-07-17 08:47:04 +00:00
|
|
|
self.context.cached_typeck_results.set(None);
|
2020-06-26 02:56:23 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let body = self.context.tcx.hir().body(body_id);
|
2019-12-30 14:22:46 +01:00
|
|
|
self.visit_body(body);
|
2020-06-26 02:56:23 +03:00
|
|
|
self.context.enclosing_body = old_enclosing_body;
|
|
|
|
|
|
|
|
|
|
// See HACK comment above.
|
|
|
|
|
if old_enclosing_body != Some(body_id) {
|
2020-07-17 08:47:04 +00:00
|
|
|
self.context.cached_typeck_results.set(old_cached_typeck_results);
|
2020-06-26 02:56:23 +03:00
|
|
|
}
|
2019-12-30 14:22:46 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) {
|
2020-11-25 23:19:54 +01:00
|
|
|
self.with_lint_attrs(param.hir_id, |cx| {
|
2019-12-30 14:22:46 +01:00
|
|
|
hir_visit::walk_param(cx, param);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn visit_body(&mut self, body: &'tcx hir::Body<'tcx>) {
|
|
|
|
|
lint_callback!(self, check_body, body);
|
|
|
|
|
hir_visit::walk_body(self, body);
|
|
|
|
|
lint_callback!(self, check_body_post, body);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn visit_item(&mut self, it: &'tcx hir::Item<'tcx>) {
|
|
|
|
|
let generics = self.context.generics.take();
|
|
|
|
|
self.context.generics = it.kind.generics();
|
2021-01-18 11:55:23 -06:00
|
|
|
let old_cached_typeck_results = self.context.cached_typeck_results.take();
|
|
|
|
|
let old_enclosing_body = self.context.enclosing_body.take();
|
2020-11-25 23:19:54 +01:00
|
|
|
self.with_lint_attrs(it.hir_id(), |cx| {
|
2021-01-30 17:47:51 +01:00
|
|
|
cx.with_param_env(it.hir_id(), |cx| {
|
2019-12-30 14:22:46 +01:00
|
|
|
lint_callback!(cx, check_item, it);
|
|
|
|
|
hir_visit::walk_item(cx, it);
|
|
|
|
|
lint_callback!(cx, check_item_post, it);
|
|
|
|
|
});
|
|
|
|
|
});
|
2021-01-18 11:55:23 -06:00
|
|
|
self.context.enclosing_body = old_enclosing_body;
|
|
|
|
|
self.context.cached_typeck_results.set(old_cached_typeck_results);
|
2019-12-30 14:22:46 +01:00
|
|
|
self.context.generics = generics;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn visit_foreign_item(&mut self, it: &'tcx hir::ForeignItem<'tcx>) {
|
2020-11-25 23:19:54 +01:00
|
|
|
self.with_lint_attrs(it.hir_id(), |cx| {
|
2021-02-01 00:33:38 +01:00
|
|
|
cx.with_param_env(it.hir_id(), |cx| {
|
2019-12-30 14:22:46 +01:00
|
|
|
lint_callback!(cx, check_foreign_item, it);
|
|
|
|
|
hir_visit::walk_foreign_item(cx, it);
|
|
|
|
|
});
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn visit_pat(&mut self, p: &'tcx hir::Pat<'tcx>) {
|
|
|
|
|
lint_callback!(self, check_pat, p);
|
|
|
|
|
hir_visit::walk_pat(self, p);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn visit_expr(&mut self, e: &'tcx hir::Expr<'tcx>) {
|
2020-11-25 23:19:54 +01:00
|
|
|
self.with_lint_attrs(e.hir_id, |cx| {
|
2019-12-30 14:22:46 +01:00
|
|
|
lint_callback!(cx, check_expr, e);
|
|
|
|
|
hir_visit::walk_expr(cx, e);
|
|
|
|
|
lint_callback!(cx, check_expr_post, e);
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn visit_stmt(&mut self, s: &'tcx hir::Stmt<'tcx>) {
|
Fix inconsistencies in handling of inert attributes on statements
When the 'early' and 'late' visitors visit an attribute target, they
activate any lint attributes (e.g. `#[allow]`) that apply to it.
This can affect warnings emitted on sibiling attributes. For example,
the following code does not produce an `unused_attributes` for
`#[inline]`, since the sibiling `#[allow(unused_attributes)]` suppressed
the warning.
```rust
trait Foo {
#[allow(unused_attributes)] #[inline] fn first();
#[inline] #[allow(unused_attributes)] fn second();
}
```
However, we do not do this for statements - instead, the lint attributes
only become active when we visit the struct nested inside `StmtKind`
(e.g. `Item`).
Currently, this is difficult to observe due to another issue - the
`HasAttrs` impl for `StmtKind` ignores attributes for `StmtKind::Item`.
As a result, the `unused_doc_comments` lint will never see attributes on
item statements.
This commit makes two interrelated fixes to the handling of inert
(non-proc-macro) attributes on statements:
* The `HasAttr` impl for `StmtKind` now returns attributes for
`StmtKind::Item`, treating it just like every other `StmtKind`
variant. The only place relying on the old behavior was macro
which has been updated to explicitly ignore attributes on item
statements. This allows the `unused_doc_comments` lint to fire for
item statements.
* The `early` and `late` lint visitors now activate lint attributes when
invoking the callback for `Stmt`. This ensures that a lint
attribute (e.g. `#[allow(unused_doc_comments)]`) can be applied to
sibiling attributes on an item statement.
For now, the `unused_doc_comments` lint is explicitly disabled on item
statements, which preserves the current behavior. The exact locatiosn
where this lint should fire are being discussed in PR #78306
2020-10-23 18:17:00 -04:00
|
|
|
// See `EarlyContextAndPass::visit_stmt` for an explanation
|
|
|
|
|
// of why we call `walk_stmt` outside of `with_lint_attrs`
|
2020-11-25 23:19:54 +01:00
|
|
|
self.with_lint_attrs(s.hir_id, |cx| {
|
Fix inconsistencies in handling of inert attributes on statements
When the 'early' and 'late' visitors visit an attribute target, they
activate any lint attributes (e.g. `#[allow]`) that apply to it.
This can affect warnings emitted on sibiling attributes. For example,
the following code does not produce an `unused_attributes` for
`#[inline]`, since the sibiling `#[allow(unused_attributes)]` suppressed
the warning.
```rust
trait Foo {
#[allow(unused_attributes)] #[inline] fn first();
#[inline] #[allow(unused_attributes)] fn second();
}
```
However, we do not do this for statements - instead, the lint attributes
only become active when we visit the struct nested inside `StmtKind`
(e.g. `Item`).
Currently, this is difficult to observe due to another issue - the
`HasAttrs` impl for `StmtKind` ignores attributes for `StmtKind::Item`.
As a result, the `unused_doc_comments` lint will never see attributes on
item statements.
This commit makes two interrelated fixes to the handling of inert
(non-proc-macro) attributes on statements:
* The `HasAttr` impl for `StmtKind` now returns attributes for
`StmtKind::Item`, treating it just like every other `StmtKind`
variant. The only place relying on the old behavior was macro
which has been updated to explicitly ignore attributes on item
statements. This allows the `unused_doc_comments` lint to fire for
item statements.
* The `early` and `late` lint visitors now activate lint attributes when
invoking the callback for `Stmt`. This ensures that a lint
attribute (e.g. `#[allow(unused_doc_comments)]`) can be applied to
sibiling attributes on an item statement.
For now, the `unused_doc_comments` lint is explicitly disabled on item
statements, which preserves the current behavior. The exact locatiosn
where this lint should fire are being discussed in PR #78306
2020-10-23 18:17:00 -04:00
|
|
|
lint_callback!(cx, check_stmt, s);
|
|
|
|
|
});
|
2019-12-30 14:22:46 +01:00
|
|
|
hir_visit::walk_stmt(self, s);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn visit_fn(
|
|
|
|
|
&mut self,
|
|
|
|
|
fk: hir_visit::FnKind<'tcx>,
|
|
|
|
|
decl: &'tcx hir::FnDecl<'tcx>,
|
|
|
|
|
body_id: hir::BodyId,
|
|
|
|
|
span: Span,
|
|
|
|
|
id: hir::HirId,
|
|
|
|
|
) {
|
2020-07-17 08:47:04 +00:00
|
|
|
// Wrap in typeck results here, not just in visit_nested_body,
|
2019-12-30 14:22:46 +01:00
|
|
|
// in order for `check_fn` to be able to use them.
|
2020-06-26 02:56:23 +03:00
|
|
|
let old_enclosing_body = self.context.enclosing_body.replace(body_id);
|
2020-07-17 08:47:04 +00:00
|
|
|
let old_cached_typeck_results = self.context.cached_typeck_results.take();
|
2019-12-30 14:22:46 +01:00
|
|
|
let body = self.context.tcx.hir().body(body_id);
|
|
|
|
|
lint_callback!(self, check_fn, fk, decl, body, span, id);
|
2022-09-12 13:13:22 +10:00
|
|
|
hir_visit::walk_fn(self, fk, decl, body_id, id);
|
2020-06-26 02:56:23 +03:00
|
|
|
self.context.enclosing_body = old_enclosing_body;
|
2020-07-17 08:47:04 +00:00
|
|
|
self.context.cached_typeck_results.set(old_cached_typeck_results);
|
2019-12-30 14:22:46 +01:00
|
|
|
}
|
|
|
|
|
|
2022-08-10 11:22:01 +10:00
|
|
|
fn visit_variant_data(&mut self, s: &'tcx hir::VariantData<'tcx>) {
|
2019-12-30 14:22:46 +01:00
|
|
|
lint_callback!(self, check_struct_def, s);
|
|
|
|
|
hir_visit::walk_struct_def(self, s);
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-16 00:36:07 +03:00
|
|
|
fn visit_field_def(&mut self, s: &'tcx hir::FieldDef<'tcx>) {
|
2020-11-25 23:19:54 +01:00
|
|
|
self.with_lint_attrs(s.hir_id, |cx| {
|
2021-03-16 00:36:07 +03:00
|
|
|
lint_callback!(cx, check_field_def, s);
|
|
|
|
|
hir_visit::walk_field_def(cx, s);
|
2019-12-30 14:22:46 +01:00
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
2022-08-10 11:22:01 +10:00
|
|
|
fn visit_variant(&mut self, v: &'tcx hir::Variant<'tcx>) {
|
2022-11-06 19:46:55 +00:00
|
|
|
self.with_lint_attrs(v.hir_id, |cx| {
|
2019-12-30 14:22:46 +01:00
|
|
|
lint_callback!(cx, check_variant, v);
|
2022-08-10 11:22:01 +10:00
|
|
|
hir_visit::walk_variant(cx, v);
|
2019-12-30 14:22:46 +01:00
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn visit_ty(&mut self, t: &'tcx hir::Ty<'tcx>) {
|
|
|
|
|
lint_callback!(self, check_ty, t);
|
|
|
|
|
hir_visit::walk_ty(self, t);
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-26 18:19:23 +00:00
|
|
|
fn visit_infer(&mut self, inf: &'tcx hir::InferArg) {
|
|
|
|
|
hir_visit::walk_inf(self, inf);
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-12 13:23:26 +10:00
|
|
|
fn visit_mod(&mut self, m: &'tcx hir::Mod<'tcx>, _: Span, n: hir::HirId) {
|
2019-12-30 14:22:46 +01:00
|
|
|
if !self.context.only_module {
|
2022-09-12 13:23:26 +10:00
|
|
|
self.process_mod(m, n);
|
2019-12-30 14:22:46 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn visit_local(&mut self, l: &'tcx hir::Local<'tcx>) {
|
2020-11-25 23:19:54 +01:00
|
|
|
self.with_lint_attrs(l.hir_id, |cx| {
|
2019-12-30 14:22:46 +01:00
|
|
|
lint_callback!(cx, check_local, l);
|
|
|
|
|
hir_visit::walk_local(cx, l);
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn visit_block(&mut self, b: &'tcx hir::Block<'tcx>) {
|
|
|
|
|
lint_callback!(self, check_block, b);
|
|
|
|
|
hir_visit::walk_block(self, b);
|
|
|
|
|
lint_callback!(self, check_block_post, b);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn visit_arm(&mut self, a: &'tcx hir::Arm<'tcx>) {
|
|
|
|
|
lint_callback!(self, check_arm, a);
|
|
|
|
|
hir_visit::walk_arm(self, a);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn visit_generic_param(&mut self, p: &'tcx hir::GenericParam<'tcx>) {
|
|
|
|
|
lint_callback!(self, check_generic_param, p);
|
|
|
|
|
hir_visit::walk_generic_param(self, p);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn visit_generics(&mut self, g: &'tcx hir::Generics<'tcx>) {
|
|
|
|
|
lint_callback!(self, check_generics, g);
|
|
|
|
|
hir_visit::walk_generics(self, g);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn visit_where_predicate(&mut self, p: &'tcx hir::WherePredicate<'tcx>) {
|
|
|
|
|
hir_visit::walk_where_predicate(self, p);
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-12 13:37:18 +10:00
|
|
|
fn visit_poly_trait_ref(&mut self, t: &'tcx hir::PolyTraitRef<'tcx>) {
|
|
|
|
|
lint_callback!(self, check_poly_trait_ref, t);
|
|
|
|
|
hir_visit::walk_poly_trait_ref(self, t);
|
2019-12-30 14:22:46 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>) {
|
|
|
|
|
let generics = self.context.generics.take();
|
|
|
|
|
self.context.generics = Some(&trait_item.generics);
|
2020-11-25 23:19:54 +01:00
|
|
|
self.with_lint_attrs(trait_item.hir_id(), |cx| {
|
2021-01-30 20:46:50 +01:00
|
|
|
cx.with_param_env(trait_item.hir_id(), |cx| {
|
2019-12-30 14:22:46 +01:00
|
|
|
lint_callback!(cx, check_trait_item, trait_item);
|
|
|
|
|
hir_visit::walk_trait_item(cx, trait_item);
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
self.context.generics = generics;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) {
|
|
|
|
|
let generics = self.context.generics.take();
|
|
|
|
|
self.context.generics = Some(&impl_item.generics);
|
2020-11-25 23:19:54 +01:00
|
|
|
self.with_lint_attrs(impl_item.hir_id(), |cx| {
|
2021-01-30 23:25:03 +01:00
|
|
|
cx.with_param_env(impl_item.hir_id(), |cx| {
|
2019-12-30 14:22:46 +01:00
|
|
|
lint_callback!(cx, check_impl_item, impl_item);
|
|
|
|
|
hir_visit::walk_impl_item(cx, impl_item);
|
|
|
|
|
lint_callback!(cx, check_impl_item_post, impl_item);
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
self.context.generics = generics;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn visit_lifetime(&mut self, lt: &'tcx hir::Lifetime) {
|
|
|
|
|
hir_visit::walk_lifetime(self, lt);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn visit_path(&mut self, p: &'tcx hir::Path<'tcx>, id: hir::HirId) {
|
|
|
|
|
lint_callback!(self, check_path, p, id);
|
|
|
|
|
hir_visit::walk_path(self, p);
|
|
|
|
|
}
|
|
|
|
|
|
2022-06-16 07:54:03 +10:00
|
|
|
fn visit_attribute(&mut self, attr: &'tcx ast::Attribute) {
|
2022-06-15 17:44:53 +10:00
|
|
|
lint_callback!(self, check_attribute, attr);
|
2019-12-30 14:22:46 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-06 14:23:03 -04:00
|
|
|
struct LateLintPassObjects<'a, 'tcx> {
|
|
|
|
|
lints: &'a mut [LateLintPassObject<'tcx>],
|
2019-12-30 14:22:46 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[allow(rustc::lint_pass_impl_without_macro)]
|
2022-09-06 14:23:03 -04:00
|
|
|
impl LintPass for LateLintPassObjects<'_, '_> {
|
2019-12-30 14:22:46 +01:00
|
|
|
fn name(&self) -> &'static str {
|
|
|
|
|
panic!()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
macro_rules! expand_late_lint_pass_impl_methods {
|
2020-06-25 23:41:36 +03:00
|
|
|
([$hir:tt], [$($(#[$attr:meta])* fn $name:ident($($param:ident: $arg:ty),*);)*]) => (
|
|
|
|
|
$(fn $name(&mut self, context: &LateContext<$hir>, $($param: $arg),*) {
|
2019-12-30 14:22:46 +01:00
|
|
|
for obj in self.lints.iter_mut() {
|
|
|
|
|
obj.$name(context, $($param),*);
|
|
|
|
|
}
|
|
|
|
|
})*
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
macro_rules! late_lint_pass_impl {
|
2020-06-25 23:41:36 +03:00
|
|
|
([], [$hir:tt], $methods:tt) => {
|
2022-09-06 14:23:03 -04:00
|
|
|
impl<$hir> LateLintPass<$hir> for LateLintPassObjects<'_, $hir> {
|
2020-06-25 23:41:36 +03:00
|
|
|
expand_late_lint_pass_impl_methods!([$hir], $methods);
|
2019-12-30 14:22:46 +01:00
|
|
|
}
|
2020-06-25 23:41:36 +03:00
|
|
|
};
|
2019-12-30 14:22:46 +01:00
|
|
|
}
|
|
|
|
|
|
2020-01-09 07:52:01 +01:00
|
|
|
crate::late_lint_methods!(late_lint_pass_impl, [], ['tcx]);
|
2019-12-30 14:22:46 +01:00
|
|
|
|
2020-06-25 23:41:36 +03:00
|
|
|
fn late_lint_mod_pass<'tcx, T: LateLintPass<'tcx>>(
|
2019-12-30 14:22:46 +01:00
|
|
|
tcx: TyCtxt<'tcx>,
|
2020-04-12 13:45:41 +01:00
|
|
|
module_def_id: LocalDefId,
|
2019-12-30 14:22:46 +01:00
|
|
|
pass: T,
|
|
|
|
|
) {
|
2022-09-22 16:19:53 +03:00
|
|
|
let effective_visibilities = &tcx.effective_visibilities(());
|
2019-12-30 14:22:46 +01:00
|
|
|
|
|
|
|
|
let context = LateContext {
|
|
|
|
|
tcx,
|
2020-06-26 02:56:23 +03:00
|
|
|
enclosing_body: None,
|
2020-07-17 08:47:04 +00:00
|
|
|
cached_typeck_results: Cell::new(None),
|
2019-12-30 14:22:46 +01:00
|
|
|
param_env: ty::ParamEnv::empty(),
|
2022-09-22 16:19:53 +03:00
|
|
|
effective_visibilities,
|
2020-01-09 03:45:42 +01:00
|
|
|
lint_store: unerased_lint_store(tcx),
|
2020-08-12 12:22:56 +02:00
|
|
|
last_node_with_lint_attrs: tcx.hir().local_def_id_to_hir_id(module_def_id),
|
2019-12-30 14:22:46 +01:00
|
|
|
generics: None,
|
|
|
|
|
only_module: true,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
let mut cx = LateContextAndPass { context, pass };
|
|
|
|
|
|
2022-09-12 13:23:26 +10:00
|
|
|
let (module, _span, hir_id) = tcx.hir().get_module(module_def_id);
|
|
|
|
|
cx.process_mod(module, hir_id);
|
2019-12-30 14:22:46 +01:00
|
|
|
|
|
|
|
|
// Visit the crate attributes
|
|
|
|
|
if hir_id == hir::CRATE_HIR_ID {
|
2020-12-05 17:40:19 +01:00
|
|
|
for attr in tcx.hir().attrs(hir::CRATE_HIR_ID).iter() {
|
2022-06-16 07:54:03 +10:00
|
|
|
cx.visit_attribute(attr)
|
2020-12-05 17:40:19 +01:00
|
|
|
}
|
2019-12-30 14:22:46 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-06-25 23:41:36 +03:00
|
|
|
pub fn late_lint_mod<'tcx, T: LateLintPass<'tcx>>(
|
2019-12-30 14:22:46 +01:00
|
|
|
tcx: TyCtxt<'tcx>,
|
2020-04-12 13:45:41 +01:00
|
|
|
module_def_id: LocalDefId,
|
2019-12-30 14:22:46 +01:00
|
|
|
builtin_lints: T,
|
|
|
|
|
) {
|
2022-07-06 07:44:47 -05:00
|
|
|
if tcx.sess.opts.unstable_opts.no_interleave_lints {
|
2019-12-30 14:22:46 +01:00
|
|
|
// These passes runs in late_lint_crate with -Z no_interleave_lints
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
late_lint_mod_pass(tcx, module_def_id, builtin_lints);
|
|
|
|
|
|
|
|
|
|
let mut passes: Vec<_> =
|
2022-09-06 14:23:03 -04:00
|
|
|
unerased_lint_store(tcx).late_module_passes.iter().map(|pass| (pass)(tcx)).collect();
|
2019-12-30 14:22:46 +01:00
|
|
|
|
|
|
|
|
if !passes.is_empty() {
|
|
|
|
|
late_lint_mod_pass(tcx, module_def_id, LateLintPassObjects { lints: &mut passes[..] });
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-06-25 23:41:36 +03:00
|
|
|
fn late_lint_pass_crate<'tcx, T: LateLintPass<'tcx>>(tcx: TyCtxt<'tcx>, pass: T) {
|
2022-09-22 16:19:53 +03:00
|
|
|
let effective_visibilities = &tcx.effective_visibilities(());
|
2019-12-30 14:22:46 +01:00
|
|
|
|
|
|
|
|
let context = LateContext {
|
|
|
|
|
tcx,
|
2020-06-26 02:56:23 +03:00
|
|
|
enclosing_body: None,
|
2020-07-17 08:47:04 +00:00
|
|
|
cached_typeck_results: Cell::new(None),
|
2019-12-30 14:22:46 +01:00
|
|
|
param_env: ty::ParamEnv::empty(),
|
2022-09-22 16:19:53 +03:00
|
|
|
effective_visibilities,
|
2020-01-09 03:45:42 +01:00
|
|
|
lint_store: unerased_lint_store(tcx),
|
2019-12-30 14:22:46 +01:00
|
|
|
last_node_with_lint_attrs: hir::CRATE_HIR_ID,
|
|
|
|
|
generics: None,
|
|
|
|
|
only_module: false,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
let mut cx = LateContextAndPass { context, pass };
|
|
|
|
|
|
|
|
|
|
// Visit the whole crate.
|
2020-11-25 23:19:54 +01:00
|
|
|
cx.with_lint_attrs(hir::CRATE_HIR_ID, |cx| {
|
2019-12-30 14:22:46 +01:00
|
|
|
// since the root module isn't visited as an item (because it isn't an
|
|
|
|
|
// item), warn for it here.
|
2021-09-12 11:58:27 +02:00
|
|
|
lint_callback!(cx, check_crate,);
|
2021-09-02 19:22:24 +02:00
|
|
|
tcx.hir().walk_toplevel_module(cx);
|
2021-08-26 18:42:08 +02:00
|
|
|
tcx.hir().walk_attributes(cx);
|
2021-09-12 11:58:27 +02:00
|
|
|
lint_callback!(cx, check_crate_post,);
|
2019-12-30 14:22:46 +01:00
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
2020-06-25 23:41:36 +03:00
|
|
|
fn late_lint_crate<'tcx, T: LateLintPass<'tcx>>(tcx: TyCtxt<'tcx>, builtin_lints: T) {
|
2022-09-06 14:23:03 -04:00
|
|
|
let mut passes =
|
|
|
|
|
unerased_lint_store(tcx).late_passes.iter().map(|p| (p)(tcx)).collect::<Vec<_>>();
|
2019-12-30 14:22:46 +01:00
|
|
|
|
2022-07-06 07:44:47 -05:00
|
|
|
if !tcx.sess.opts.unstable_opts.no_interleave_lints {
|
2019-12-30 14:22:46 +01:00
|
|
|
if !passes.is_empty() {
|
|
|
|
|
late_lint_pass_crate(tcx, LateLintPassObjects { lints: &mut passes[..] });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
late_lint_pass_crate(tcx, builtin_lints);
|
|
|
|
|
} else {
|
|
|
|
|
for pass in &mut passes {
|
Remove `-Ztime` option.
The compiler currently has `-Ztime` and `-Ztime-passes`. I've used
`-Ztime-passes` for years but only recently learned about `-Ztime`.
What's the difference? Let's look at the `-Zhelp` output:
```
-Z time=val -- measure time of rustc processes (default: no)
-Z time-passes=val -- measure time of each rustc pass (default: no)
```
The `-Ztime-passes` description is clear, but the `-Ztime` one is less so.
Sounds like it measures the time for the entire process?
No. The real difference is that `-Ztime-passes` prints out info about passes,
and `-Ztime` does the same, but only for a subset of those passes. More
specifically, there is a distinction in the profiling code between a "verbose
generic activity" and an "extra verbose generic activity". `-Ztime-passes`
prints both kinds, while `-Ztime` only prints the first one. (It took me
a close reading of the source code to determine this difference.)
In practice this distinction has low value. Perhaps in the past the "extra
verbose" output was more voluminous, but now that we only print stats for a
pass if it exceeds 5ms or alters the RSS, `-Ztime-passes` is less spammy. Also,
a lot of the "extra verbose" cases are for individual lint passes, and you need
to also use `-Zno-interleave-lints` to see those anyway.
Therefore, this commit removes `-Ztime` and the associated machinery. One thing
to note is that the existing "extra verbose" activities all have an extra
string argument, so the commit adds the ability to accept an extra argument to
the "verbose" activities.
2022-10-06 14:51:45 +11:00
|
|
|
tcx.sess.prof.verbose_generic_activity_with_arg("run_late_lint", pass.name()).run(
|
|
|
|
|
|| {
|
|
|
|
|
late_lint_pass_crate(tcx, LateLintPassObjects { lints: slice::from_mut(pass) });
|
|
|
|
|
},
|
|
|
|
|
);
|
2019-12-30 14:22:46 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let mut passes: Vec<_> =
|
2022-09-06 14:23:03 -04:00
|
|
|
unerased_lint_store(tcx).late_module_passes.iter().map(|pass| (pass)(tcx)).collect();
|
2019-12-30 14:22:46 +01:00
|
|
|
|
|
|
|
|
for pass in &mut passes {
|
Remove `-Ztime` option.
The compiler currently has `-Ztime` and `-Ztime-passes`. I've used
`-Ztime-passes` for years but only recently learned about `-Ztime`.
What's the difference? Let's look at the `-Zhelp` output:
```
-Z time=val -- measure time of rustc processes (default: no)
-Z time-passes=val -- measure time of each rustc pass (default: no)
```
The `-Ztime-passes` description is clear, but the `-Ztime` one is less so.
Sounds like it measures the time for the entire process?
No. The real difference is that `-Ztime-passes` prints out info about passes,
and `-Ztime` does the same, but only for a subset of those passes. More
specifically, there is a distinction in the profiling code between a "verbose
generic activity" and an "extra verbose generic activity". `-Ztime-passes`
prints both kinds, while `-Ztime` only prints the first one. (It took me
a close reading of the source code to determine this difference.)
In practice this distinction has low value. Perhaps in the past the "extra
verbose" output was more voluminous, but now that we only print stats for a
pass if it exceeds 5ms or alters the RSS, `-Ztime-passes` is less spammy. Also,
a lot of the "extra verbose" cases are for individual lint passes, and you need
to also use `-Zno-interleave-lints` to see those anyway.
Therefore, this commit removes `-Ztime` and the associated machinery. One thing
to note is that the existing "extra verbose" activities all have an extra
string argument, so the commit adds the ability to accept an extra argument to
the "verbose" activities.
2022-10-06 14:51:45 +11:00
|
|
|
tcx.sess
|
|
|
|
|
.prof
|
|
|
|
|
.verbose_generic_activity_with_arg("run_late_module_lint", pass.name())
|
|
|
|
|
.run(|| {
|
2020-01-07 21:34:08 +01:00
|
|
|
late_lint_pass_crate(tcx, LateLintPassObjects { lints: slice::from_mut(pass) });
|
Remove `-Ztime` option.
The compiler currently has `-Ztime` and `-Ztime-passes`. I've used
`-Ztime-passes` for years but only recently learned about `-Ztime`.
What's the difference? Let's look at the `-Zhelp` output:
```
-Z time=val -- measure time of rustc processes (default: no)
-Z time-passes=val -- measure time of each rustc pass (default: no)
```
The `-Ztime-passes` description is clear, but the `-Ztime` one is less so.
Sounds like it measures the time for the entire process?
No. The real difference is that `-Ztime-passes` prints out info about passes,
and `-Ztime` does the same, but only for a subset of those passes. More
specifically, there is a distinction in the profiling code between a "verbose
generic activity" and an "extra verbose generic activity". `-Ztime-passes`
prints both kinds, while `-Ztime` only prints the first one. (It took me
a close reading of the source code to determine this difference.)
In practice this distinction has low value. Perhaps in the past the "extra
verbose" output was more voluminous, but now that we only print stats for a
pass if it exceeds 5ms or alters the RSS, `-Ztime-passes` is less spammy. Also,
a lot of the "extra verbose" cases are for individual lint passes, and you need
to also use `-Zno-interleave-lints` to see those anyway.
Therefore, this commit removes `-Ztime` and the associated machinery. One thing
to note is that the existing "extra verbose" activities all have an extra
string argument, so the commit adds the ability to accept an extra argument to
the "verbose" activities.
2022-10-06 14:51:45 +11:00
|
|
|
});
|
2019-12-30 14:22:46 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Performs lint checking on a crate.
|
2020-06-25 23:41:36 +03:00
|
|
|
pub fn check_crate<'tcx, T: LateLintPass<'tcx>>(
|
2019-12-30 14:22:46 +01:00
|
|
|
tcx: TyCtxt<'tcx>,
|
|
|
|
|
builtin_lints: impl FnOnce() -> T + Send,
|
|
|
|
|
) {
|
|
|
|
|
join(
|
|
|
|
|
|| {
|
2020-01-07 21:34:08 +01:00
|
|
|
tcx.sess.time("crate_lints", || {
|
2019-12-30 14:22:46 +01:00
|
|
|
// Run whole crate non-incremental lints
|
|
|
|
|
late_lint_crate(tcx, builtin_lints());
|
|
|
|
|
});
|
|
|
|
|
},
|
|
|
|
|
|| {
|
2020-01-07 21:34:08 +01:00
|
|
|
tcx.sess.time("module_lints", || {
|
2019-12-30 14:22:46 +01:00
|
|
|
// Run per-module lints
|
2021-07-18 18:12:17 +02:00
|
|
|
tcx.hir().par_for_each_module(|module| tcx.ensure().lint_mod(module));
|
2019-12-30 14:22:46 +01:00
|
|
|
});
|
|
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
}
|