summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_lint/src/passes.rs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_lint/src/passes.rs')
-rw-r--r--compiler/rustc_lint/src/passes.rs249
1 files changed, 249 insertions, 0 deletions
diff --git a/compiler/rustc_lint/src/passes.rs b/compiler/rustc_lint/src/passes.rs
new file mode 100644
index 000000000..cb7bd407e
--- /dev/null
+++ b/compiler/rustc_lint/src/passes.rs
@@ -0,0 +1,249 @@
+use crate::context::{EarlyContext, LateContext};
+
+use rustc_ast as ast;
+use rustc_data_structures::sync;
+use rustc_hir as hir;
+use rustc_session::lint::builtin::HardwiredLints;
+use rustc_session::lint::LintPass;
+use rustc_span::symbol::Ident;
+use rustc_span::Span;
+
+#[macro_export]
+macro_rules! late_lint_methods {
+ ($macro:path, $args:tt, [$hir:tt]) => (
+ $macro!($args, [$hir], [
+ fn check_body(a: &$hir hir::Body<$hir>);
+ fn check_body_post(a: &$hir hir::Body<$hir>);
+ fn check_crate();
+ fn check_crate_post();
+ fn check_mod(a: &$hir hir::Mod<$hir>, b: Span, c: hir::HirId);
+ fn check_foreign_item(a: &$hir hir::ForeignItem<$hir>);
+ fn check_item(a: &$hir hir::Item<$hir>);
+ fn check_item_post(a: &$hir hir::Item<$hir>);
+ fn check_local(a: &$hir hir::Local<$hir>);
+ fn check_block(a: &$hir hir::Block<$hir>);
+ fn check_block_post(a: &$hir hir::Block<$hir>);
+ fn check_stmt(a: &$hir hir::Stmt<$hir>);
+ fn check_arm(a: &$hir hir::Arm<$hir>);
+ fn check_pat(a: &$hir hir::Pat<$hir>);
+ fn check_expr(a: &$hir hir::Expr<$hir>);
+ fn check_expr_post(a: &$hir hir::Expr<$hir>);
+ fn check_ty(a: &$hir hir::Ty<$hir>);
+ fn check_generic_param(a: &$hir hir::GenericParam<$hir>);
+ fn check_generics(a: &$hir hir::Generics<$hir>);
+ fn check_poly_trait_ref(a: &$hir hir::PolyTraitRef<$hir>, b: hir::TraitBoundModifier);
+ fn check_fn(
+ a: rustc_hir::intravisit::FnKind<$hir>,
+ b: &$hir hir::FnDecl<$hir>,
+ c: &$hir hir::Body<$hir>,
+ d: Span,
+ e: hir::HirId);
+ fn check_trait_item(a: &$hir hir::TraitItem<$hir>);
+ fn check_impl_item(a: &$hir hir::ImplItem<$hir>);
+ fn check_impl_item_post(a: &$hir hir::ImplItem<$hir>);
+ fn check_struct_def(a: &$hir hir::VariantData<$hir>);
+ fn check_field_def(a: &$hir hir::FieldDef<$hir>);
+ fn check_variant(a: &$hir hir::Variant<$hir>);
+ fn check_path(a: &$hir hir::Path<$hir>, b: hir::HirId);
+ fn check_attribute(a: &$hir 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: &$hir [ast::Attribute]);
+
+ /// Counterpart to `enter_lint_attrs`.
+ fn exit_lint_attrs(a: &$hir [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! expand_lint_pass_methods {
+ ($context:ty, [$($(#[$attr:meta])* fn $name:ident($($param:ident: $arg:ty),*);)*]) => (
+ $(#[inline(always)] fn $name(&mut self, _: $context, $(_: $arg),*) {})*
+ )
+}
+
+macro_rules! declare_late_lint_pass {
+ ([], [$hir:tt], [$($methods:tt)*]) => (
+ pub trait LateLintPass<$hir>: LintPass {
+ expand_lint_pass_methods!(&LateContext<$hir>, [$($methods)*]);
+ }
+ )
+}
+
+late_lint_methods!(declare_late_lint_pass, [], ['tcx]);
+
+impl LateLintPass<'_> for HardwiredLints {}
+
+#[macro_export]
+macro_rules! expand_combined_late_lint_pass_method {
+ ([$($passes:ident),*], $self: ident, $name: ident, $params:tt) => ({
+ $($self.$passes.$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: &LateContext<'tcx>, $($param: $arg),*) {
+ expand_combined_late_lint_pass_method!($passes, self, $name, (context, $($param),*));
+ })*
+ )
+}
+
+#[macro_export]
+macro_rules! declare_combined_late_lint_pass {
+ ([$v:vis $name:ident, [$($passes:ident: $constructor:expr,)*]], [$hir:tt], $methods:tt) => (
+ #[allow(non_snake_case)]
+ $v struct $name {
+ $($passes: $passes,)*
+ }
+
+ impl $name {
+ $v fn new() -> Self {
+ Self {
+ $($passes: $constructor,)*
+ }
+ }
+
+ $v fn get_lints() -> LintArray {
+ let mut lints = Vec::new();
+ $(lints.extend_from_slice(&$passes::get_lints());)*
+ lints
+ }
+ }
+
+ impl<'tcx> LateLintPass<'tcx> for $name {
+ expand_combined_late_lint_pass_methods!([$($passes),*], $methods);
+ }
+
+ #[allow(rustc::lint_pass_impl_without_macro)]
+ impl 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: &ast::Param);
+ fn check_ident(a: Ident);
+ fn check_crate(a: &ast::Crate);
+ fn check_crate_post(a: &ast::Crate);
+ fn check_item(a: &ast::Item);
+ fn check_item_post(a: &ast::Item);
+ fn check_local(a: &ast::Local);
+ fn check_block(a: &ast::Block);
+ fn check_stmt(a: &ast::Stmt);
+ fn check_arm(a: &ast::Arm);
+ fn check_pat(a: &ast::Pat);
+ fn check_pat_post(a: &ast::Pat);
+ fn check_expr(a: &ast::Expr);
+ fn check_ty(a: &ast::Ty);
+ fn check_generic_arg(a: &ast::GenericArg);
+ fn check_generic_param(a: &ast::GenericParam);
+ fn check_generics(a: &ast::Generics);
+ fn check_poly_trait_ref(a: &ast::PolyTraitRef,
+ b: &ast::TraitBoundModifier);
+ fn check_fn(a: rustc_ast::visit::FnKind<'_>, c: Span, d_: ast::NodeId);
+ fn check_trait_item(a: &ast::AssocItem);
+ fn check_impl_item(a: &ast::AssocItem);
+ fn check_variant(a: &ast::Variant);
+ fn check_attribute(a: &ast::Attribute);
+ fn check_mac_def(a: &ast::MacroDef, b: ast::NodeId);
+ fn check_mac(a: &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: &[ast::Attribute]);
+
+ /// Counterpart to `enter_lint_attrs`.
+ fn exit_lint_attrs(a: &[ast::Attribute]);
+ ]);
+ )
+}
+
+macro_rules! expand_early_lint_pass_methods {
+ ($context:ty, [$($(#[$attr:meta])* fn $name:ident($($param:ident: $arg:ty),*);)*]) => (
+ $(#[inline(always)] fn $name(&mut self, _: $context, $(_: $arg),*) {})*
+ )
+}
+
+macro_rules! declare_early_lint_pass {
+ ([], [$($methods:tt)*]) => (
+ pub trait EarlyLintPass: LintPass {
+ expand_early_lint_pass_methods!(&EarlyContext<'_>, [$($methods)*]);
+ }
+ )
+}
+
+early_lint_methods!(declare_early_lint_pass, []);
+
+#[macro_export]
+macro_rules! expand_combined_early_lint_pass_method {
+ ([$($passes:ident),*], $self: ident, $name: ident, $params:tt) => ({
+ $($self.$passes.$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: &EarlyContext<'_>, $($param: $arg),*) {
+ expand_combined_early_lint_pass_method!($passes, self, $name, (context, $($param),*));
+ })*
+ )
+}
+
+#[macro_export]
+macro_rules! declare_combined_early_lint_pass {
+ ([$v:vis $name:ident, [$($passes:ident: $constructor:expr,)*]], $methods:tt) => (
+ #[allow(non_snake_case)]
+ $v struct $name {
+ $($passes: $passes,)*
+ }
+
+ impl $name {
+ $v fn new() -> Self {
+ Self {
+ $($passes: $constructor,)*
+ }
+ }
+
+ $v fn get_lints() -> LintArray {
+ let mut lints = Vec::new();
+ $(lints.extend_from_slice(&$passes::get_lints());)*
+ lints
+ }
+ }
+
+ impl EarlyLintPass for $name {
+ expand_combined_early_lint_pass_methods!([$($passes),*], $methods);
+ }
+
+ #[allow(rustc::lint_pass_impl_without_macro)]
+ impl LintPass for $name {
+ fn name(&self) -> &'static str {
+ panic!()
+ }
+ }
+ )
+}
+
+/// A lint pass boxed up as a trait object.
+pub type EarlyLintPassObject = Box<dyn EarlyLintPass + sync::Send + sync::Sync + 'static>;
+pub type LateLintPassObject =
+ Box<dyn for<'tcx> LateLintPass<'tcx> + sync::Send + sync::Sync + 'static>;