diff options
Diffstat (limited to 'compiler/rustc_lint/src/passes.rs')
| -rw-r--r-- | compiler/rustc_lint/src/passes.rs | 251 |
1 files changed, 251 insertions, 0 deletions
diff --git a/compiler/rustc_lint/src/passes.rs b/compiler/rustc_lint/src/passes.rs new file mode 100644 index 00000000000..508f3e1ec31 --- /dev/null +++ b/compiler/rustc_lint/src/passes.rs @@ -0,0 +1,251 @@ +use crate::context::{EarlyContext, LateContext}; + +use rustc_session::lint::builtin::HardwiredLints; +use rustc_session::lint::LintPass; + +#[macro_export] +macro_rules! late_lint_methods { + ($macro:path, $args:tt) => ( + $macro!($args, [ + fn check_body(a: &'tcx rustc_hir::Body<'tcx>); + fn check_body_post(a: &'tcx rustc_hir::Body<'tcx>); + fn check_crate(); + fn check_crate_post(); + fn check_mod(a: &'tcx rustc_hir::Mod<'tcx>, b: rustc_hir::HirId); + fn check_foreign_item(a: &'tcx rustc_hir::ForeignItem<'tcx>); + fn check_item(a: &'tcx rustc_hir::Item<'tcx>); + fn check_item_post(a: &'tcx rustc_hir::Item<'tcx>); + fn check_local(a: &'tcx rustc_hir::Local<'tcx>); + fn check_block(a: &'tcx rustc_hir::Block<'tcx>); + fn check_block_post(a: &'tcx rustc_hir::Block<'tcx>); + fn check_stmt(a: &'tcx rustc_hir::Stmt<'tcx>); + fn check_arm(a: &'tcx rustc_hir::Arm<'tcx>); + fn check_pat(a: &'tcx rustc_hir::Pat<'tcx>); + fn check_expr(a: &'tcx rustc_hir::Expr<'tcx>); + fn check_expr_post(a: &'tcx rustc_hir::Expr<'tcx>); + fn check_ty(a: &'tcx rustc_hir::Ty<'tcx>); + fn check_generic_param(a: &'tcx rustc_hir::GenericParam<'tcx>); + fn check_generics(a: &'tcx rustc_hir::Generics<'tcx>); + fn check_poly_trait_ref(a: &'tcx rustc_hir::PolyTraitRef<'tcx>); + fn check_fn( + a: rustc_hir::intravisit::FnKind<'tcx>, + b: &'tcx rustc_hir::FnDecl<'tcx>, + c: &'tcx rustc_hir::Body<'tcx>, + d: rustc_span::Span, + e: rustc_span::def_id::LocalDefId); + fn check_trait_item(a: &'tcx rustc_hir::TraitItem<'tcx>); + fn check_impl_item(a: &'tcx rustc_hir::ImplItem<'tcx>); + fn check_impl_item_post(a: &'tcx rustc_hir::ImplItem<'tcx>); + fn check_struct_def(a: &'tcx rustc_hir::VariantData<'tcx>); + fn check_field_def(a: &'tcx rustc_hir::FieldDef<'tcx>); + fn check_variant(a: &'tcx rustc_hir::Variant<'tcx>); + fn check_path(a: &rustc_hir::Path<'tcx>, b: rustc_hir::HirId); + fn check_attribute(a: &'tcx rustc_ast::Attribute); + + /// Called when entering a syntax node that can have lint attributes such + /// as `#[allow(...)]`. Called with *all* the attributes of that node. + fn enter_lint_attrs(a: &'tcx [rustc_ast::Attribute]); + + /// Counterpart to `enter_lint_attrs`. + fn exit_lint_attrs(a: &'tcx [rustc_ast::Attribute]); + ]); + ) +} + +/// Trait for types providing lint checks. +/// +/// Each `check` method checks a single syntax node, and should not +/// invoke methods recursively (unlike `Visitor`). By default they +/// do nothing. +// +// FIXME: eliminate the duplication with `Visitor`. But this also +// contains a few lint-specific methods with no equivalent in `Visitor`. + +macro_rules! declare_late_lint_pass { + ([], [$($(#[$attr:meta])* fn $name:ident($($param:ident: $arg:ty),*);)*]) => ( + pub trait LateLintPass<'tcx>: LintPass { + $(#[inline(always)] fn $name(&mut self, _: &LateContext<'tcx>, $(_: $arg),*) {})* + } + ) +} + +// Declare the `LateLintPass` trait, which contains empty default definitions +// for all the `check_*` methods. +late_lint_methods!(declare_late_lint_pass, []); + +impl LateLintPass<'_> for HardwiredLints {} + +#[macro_export] +macro_rules! expand_combined_late_lint_pass_method { + ([$($pass:ident),*], $self: ident, $name: ident, $params:tt) => ({ + $($self.$pass.$name $params;)* + }) +} + +#[macro_export] +macro_rules! expand_combined_late_lint_pass_methods { + ($passes:tt, [$($(#[$attr:meta])* fn $name:ident($($param:ident: $arg:ty),*);)*]) => ( + $(fn $name(&mut self, context: &$crate::LateContext<'tcx>, $($param: $arg),*) { + $crate::expand_combined_late_lint_pass_method!($passes, self, $name, (context, $($param),*)); + })* + ) +} + +/// Combines multiple lints passes into a single lint pass, at compile time, +/// for maximum speed. Each `check_foo` method in `$methods` within this pass +/// simply calls `check_foo` once per `$pass`. Compare with +/// `LateLintPassObjects`, which is similar, but combines lint passes at +/// runtime. +#[macro_export] +macro_rules! declare_combined_late_lint_pass { + ([$v:vis $name:ident, [$($pass:ident: $constructor:expr,)*]], $methods:tt) => ( + #[allow(non_snake_case)] + $v struct $name { + $($pass: $pass,)* + } + + impl $name { + $v fn new() -> Self { + Self { + $($pass: $constructor,)* + } + } + + $v fn get_lints() -> $crate::LintVec { + let mut lints = Vec::new(); + $(lints.extend_from_slice(&$pass::get_lints());)* + lints + } + } + + impl<'tcx> $crate::LateLintPass<'tcx> for $name { + $crate::expand_combined_late_lint_pass_methods!([$($pass),*], $methods); + } + + #[allow(rustc::lint_pass_impl_without_macro)] + impl $crate::LintPass for $name { + fn name(&self) -> &'static str { + panic!() + } + } + ) +} + +#[macro_export] +macro_rules! early_lint_methods { + ($macro:path, $args:tt) => ( + $macro!($args, [ + fn check_param(a: &rustc_ast::Param); + fn check_ident(a: rustc_span::symbol::Ident); + fn check_crate(a: &rustc_ast::Crate); + fn check_crate_post(a: &rustc_ast::Crate); + fn check_item(a: &rustc_ast::Item); + fn check_item_post(a: &rustc_ast::Item); + fn check_local(a: &rustc_ast::Local); + fn check_block(a: &rustc_ast::Block); + fn check_stmt(a: &rustc_ast::Stmt); + fn check_arm(a: &rustc_ast::Arm); + fn check_pat(a: &rustc_ast::Pat); + fn check_pat_post(a: &rustc_ast::Pat); + fn check_expr(a: &rustc_ast::Expr); + fn check_expr_post(a: &rustc_ast::Expr); + fn check_ty(a: &rustc_ast::Ty); + fn check_generic_arg(a: &rustc_ast::GenericArg); + fn check_generic_param(a: &rustc_ast::GenericParam); + fn check_generics(a: &rustc_ast::Generics); + fn check_poly_trait_ref(a: &rustc_ast::PolyTraitRef); + fn check_fn( + a: rustc_ast::visit::FnKind<'_>, + c: rustc_span::Span, + d_: rustc_ast::NodeId); + fn check_trait_item(a: &rustc_ast::AssocItem); + fn check_impl_item(a: &rustc_ast::AssocItem); + fn check_variant(a: &rustc_ast::Variant); + fn check_attribute(a: &rustc_ast::Attribute); + fn check_mac_def(a: &rustc_ast::MacroDef); + fn check_mac(a: &rustc_ast::MacCall); + + /// Called when entering a syntax node that can have lint attributes such + /// as `#[allow(...)]`. Called with *all* the attributes of that node. + fn enter_lint_attrs(a: &[rustc_ast::Attribute]); + + /// Counterpart to `enter_lint_attrs`. + fn exit_lint_attrs(a: &[rustc_ast::Attribute]); + + fn enter_where_predicate(a: &rustc_ast::WherePredicate); + fn exit_where_predicate(a: &rustc_ast::WherePredicate); + ]); + ) +} + +macro_rules! declare_early_lint_pass { + ([], [$($(#[$attr:meta])* fn $name:ident($($param:ident: $arg:ty),*);)*]) => ( + pub trait EarlyLintPass: LintPass { + $(#[inline(always)] fn $name(&mut self, _: &EarlyContext<'_>, $(_: $arg),*) {})* + } + ) +} + +// Declare the `EarlyLintPass` trait, which contains empty default definitions +// for all the `check_*` methods. +early_lint_methods!(declare_early_lint_pass, []); + +#[macro_export] +macro_rules! expand_combined_early_lint_pass_method { + ([$($pass:ident),*], $self: ident, $name: ident, $params:tt) => ({ + $($self.$pass.$name $params;)* + }) +} + +#[macro_export] +macro_rules! expand_combined_early_lint_pass_methods { + ($passes:tt, [$($(#[$attr:meta])* fn $name:ident($($param:ident: $arg:ty),*);)*]) => ( + $(fn $name(&mut self, context: &$crate::EarlyContext<'_>, $($param: $arg),*) { + $crate::expand_combined_early_lint_pass_method!($passes, self, $name, (context, $($param),*)); + })* + ) +} + +/// Combines multiple lints passes into a single lint pass, at compile time, +/// for maximum speed. Each `check_foo` method in `$methods` within this pass +/// simply calls `check_foo` once per `$pass`. Compare with +/// `EarlyLintPassObjects`, which is similar, but combines lint passes at +/// runtime. +#[macro_export] +macro_rules! declare_combined_early_lint_pass { + ([$v:vis $name:ident, [$($pass:ident: $constructor:expr,)*]], $methods:tt) => ( + #[allow(non_snake_case)] + $v struct $name { + $($pass: $pass,)* + } + + impl $name { + $v fn new() -> Self { + Self { + $($pass: $constructor,)* + } + } + + $v fn get_lints() -> $crate::LintVec { + let mut lints = Vec::new(); + $(lints.extend_from_slice(&$pass::get_lints());)* + lints + } + } + + impl $crate::EarlyLintPass for $name { + $crate::expand_combined_early_lint_pass_methods!([$($pass),*], $methods); + } + + #[allow(rustc::lint_pass_impl_without_macro)] + impl $crate::LintPass for $name { + fn name(&self) -> &'static str { + panic!() + } + } + ) +} + +/// A lint pass boxed up as a trait object. +pub type EarlyLintPassObject = Box<dyn EarlyLintPass + 'static>; +pub type LateLintPassObject<'tcx> = Box<dyn LateLintPass<'tcx> + 'tcx>; |
