From 45f27643db6e25d4377d1b7050e55c07a02a0cec Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 5 Jan 2020 10:07:26 +0100 Subject: [PATCH] prepare moving HardwiredLints to rustc_session --- src/librustc/lint/builtin.rs | 131 +---------------------- src/librustc/lint/context.rs | 125 ++++++++++++++++++++- src/librustc/lint/internal.rs | 6 +- src/librustc/lint/mod.rs | 45 ++------ src/librustc_ast_lowering/path.rs | 2 +- src/librustc_lint/array_into_iter.rs | 3 +- src/librustc_lint/builtin.rs | 9 +- src/librustc_lint/late.rs | 6 +- src/librustc_lint/lib.rs | 3 +- src/librustc_lint/non_ascii_idents.rs | 2 +- src/librustc_lint/nonstandard_style.rs | 4 +- src/librustc_lint/redundant_semicolon.rs | 2 +- src/librustc_lint/types.rs | 6 +- src/librustc_lint/unused.rs | 4 +- src/librustc_session/lint.rs | 38 +++++++ 15 files changed, 187 insertions(+), 199 deletions(-) diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs index 548b3e27ac6..9783bc36ea5 100644 --- a/src/librustc/lint/builtin.rs +++ b/src/librustc/lint/builtin.rs @@ -4,14 +4,9 @@ //! compiler code, rather than using their own custom pass. Those //! lints are all available in `rustc_lint::builtin`. -use crate::lint::{FutureIncompatibleInfo, LateLintPass, LintArray, LintPass}; -use crate::middle::stability; -use crate::session::Session; -use rustc_errors::{pluralize, Applicability, DiagnosticBuilder}; -use rustc_session::declare_lint; -use rustc_session::lint::BuiltinLintDiagnostics; +use rustc_session::lint::FutureIncompatibleInfo; +use rustc_session::{declare_lint, declare_lint_pass}; use rustc_span::edition::Edition; -use rustc_span::source_map::Span; use syntax::early_buffered_lints::{ILL_FORMED_ATTRIBUTE_INPUT, META_VARIABLE_MISUSE}; declare_lint! { @@ -512,125 +507,3 @@ declare_lint_pass! { SOFT_UNSTABLE, ] } - -impl LateLintPass<'_, '_> for HardwiredLints {} - -pub fn add_elided_lifetime_in_path_suggestion( - sess: &Session, - db: &mut DiagnosticBuilder<'_>, - n: usize, - path_span: Span, - incl_angl_brckt: bool, - insertion_span: Span, - anon_lts: String, -) { - let (replace_span, suggestion) = if incl_angl_brckt { - (insertion_span, anon_lts) - } else { - // When possible, prefer a suggestion that replaces the whole - // `Path` expression with `Path<'_, T>`, rather than inserting `'_, ` - // at a point (which makes for an ugly/confusing label) - if let Ok(snippet) = sess.source_map().span_to_snippet(path_span) { - // But our spans can get out of whack due to macros; if the place we think - // we want to insert `'_` isn't even within the path expression's span, we - // should bail out of making any suggestion rather than panicking on a - // subtract-with-overflow or string-slice-out-out-bounds (!) - // FIXME: can we do better? - if insertion_span.lo().0 < path_span.lo().0 { - return; - } - let insertion_index = (insertion_span.lo().0 - path_span.lo().0) as usize; - if insertion_index > snippet.len() { - return; - } - let (before, after) = snippet.split_at(insertion_index); - (path_span, format!("{}{}{}", before, anon_lts, after)) - } else { - (insertion_span, anon_lts) - } - }; - db.span_suggestion( - replace_span, - &format!("indicate the anonymous lifetime{}", pluralize!(n)), - suggestion, - Applicability::MachineApplicable, - ); -} - -pub fn run_builtin_lint_diagnostics( - this: BuiltinLintDiagnostics, - sess: &Session, - db: &mut DiagnosticBuilder<'_>, -) { - match this { - BuiltinLintDiagnostics::Normal => (), - BuiltinLintDiagnostics::BareTraitObject(span, is_global) => { - let (sugg, app) = match sess.source_map().span_to_snippet(span) { - Ok(s) if is_global => (format!("dyn ({})", s), Applicability::MachineApplicable), - Ok(s) => (format!("dyn {}", s), Applicability::MachineApplicable), - Err(_) => ("dyn ".to_string(), Applicability::HasPlaceholders), - }; - db.span_suggestion(span, "use `dyn`", sugg, app); - } - BuiltinLintDiagnostics::AbsPathWithModule(span) => { - let (sugg, app) = match sess.source_map().span_to_snippet(span) { - Ok(ref s) => { - // FIXME(Manishearth) ideally the emitting code - // can tell us whether or not this is global - let opt_colon = if s.trim_start().starts_with("::") { "" } else { "::" }; - - (format!("crate{}{}", opt_colon, s), Applicability::MachineApplicable) - } - Err(_) => ("crate::".to_string(), Applicability::HasPlaceholders), - }; - db.span_suggestion(span, "use `crate`", sugg, app); - } - BuiltinLintDiagnostics::ProcMacroDeriveResolutionFallback(span) => { - db.span_label( - span, - "names from parent modules are not accessible without an explicit import", - ); - } - BuiltinLintDiagnostics::MacroExpandedMacroExportsAccessedByAbsolutePaths(span_def) => { - db.span_note(span_def, "the macro is defined here"); - } - BuiltinLintDiagnostics::ElidedLifetimesInPaths( - n, - path_span, - incl_angl_brckt, - insertion_span, - anon_lts, - ) => { - add_elided_lifetime_in_path_suggestion( - sess, - db, - n, - path_span, - incl_angl_brckt, - insertion_span, - anon_lts, - ); - } - BuiltinLintDiagnostics::UnknownCrateTypes(span, note, sugg) => { - db.span_suggestion(span, ¬e, sugg, Applicability::MaybeIncorrect); - } - BuiltinLintDiagnostics::UnusedImports(message, replaces) => { - if !replaces.is_empty() { - db.tool_only_multipart_suggestion( - &message, - replaces, - Applicability::MachineApplicable, - ); - } - } - BuiltinLintDiagnostics::RedundantImport(spans, ident) => { - for (span, is_imported) in spans { - let introduced = if is_imported { "imported" } else { "defined" }; - db.span_label(span, format!("the item `{}` is already {} here", ident, introduced)); - } - } - BuiltinLintDiagnostics::DeprecatedMacro(suggestion, span) => { - stability::deprecation_suggestion(db, suggestion, span) - } - } -} diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index 759ab3749d2..3f18f4dbd1f 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -20,13 +20,14 @@ use crate::hir::map::{definitions::DisambiguatedDefPathData, DefPathData}; use crate::lint::levels::{LintLevelSets, LintLevelsBuilder}; use crate::lint::{EarlyLintPassObject, LateLintPassObject}; use crate::middle::privacy::AccessLevels; +use crate::middle::stability; use crate::session::Session; use crate::ty::layout::{LayoutError, LayoutOf, TyLayout}; use crate::ty::{self, print::Printer, subst::GenericArg, Ty, TyCtxt}; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync; use rustc_error_codes::*; -use rustc_errors::{struct_span_err, DiagnosticBuilder}; +use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder}; use rustc_hir as hir; use rustc_hir::def_id::{CrateNum, DefId}; use rustc_session::lint::BuiltinLintDiagnostics; @@ -466,6 +467,48 @@ impl LintPassObject for EarlyLintPassObject {} impl LintPassObject for LateLintPassObject {} +pub fn add_elided_lifetime_in_path_suggestion( + sess: &Session, + db: &mut DiagnosticBuilder<'_>, + n: usize, + path_span: Span, + incl_angl_brckt: bool, + insertion_span: Span, + anon_lts: String, +) { + let (replace_span, suggestion) = if incl_angl_brckt { + (insertion_span, anon_lts) + } else { + // When possible, prefer a suggestion that replaces the whole + // `Path` expression with `Path<'_, T>`, rather than inserting `'_, ` + // at a point (which makes for an ugly/confusing label) + if let Ok(snippet) = sess.source_map().span_to_snippet(path_span) { + // But our spans can get out of whack due to macros; if the place we think + // we want to insert `'_` isn't even within the path expression's span, we + // should bail out of making any suggestion rather than panicking on a + // subtract-with-overflow or string-slice-out-out-bounds (!) + // FIXME: can we do better? + if insertion_span.lo().0 < path_span.lo().0 { + return; + } + let insertion_index = (insertion_span.lo().0 - path_span.lo().0) as usize; + if insertion_index > snippet.len() { + return; + } + let (before, after) = snippet.split_at(insertion_index); + (path_span, format!("{}{}{}", before, anon_lts, after)) + } else { + (insertion_span, anon_lts) + } + }; + db.span_suggestion( + replace_span, + &format!("indicate the anonymous lifetime{}", pluralize!(n)), + suggestion, + Applicability::MachineApplicable, + ); +} + pub trait LintContext: Sized { type PassObject: LintPassObject; @@ -484,7 +527,85 @@ pub trait LintContext: Sized { diagnostic: BuiltinLintDiagnostics, ) { let mut db = self.lookup(lint, span, msg); - super::builtin::run_builtin_lint_diagnostics(diagnostic, self.sess(), &mut db); + + let sess = self.sess(); + match diagnostic { + BuiltinLintDiagnostics::Normal => (), + BuiltinLintDiagnostics::BareTraitObject(span, is_global) => { + let (sugg, app) = match sess.source_map().span_to_snippet(span) { + Ok(s) if is_global => { + (format!("dyn ({})", s), Applicability::MachineApplicable) + } + Ok(s) => (format!("dyn {}", s), Applicability::MachineApplicable), + Err(_) => ("dyn ".to_string(), Applicability::HasPlaceholders), + }; + db.span_suggestion(span, "use `dyn`", sugg, app); + } + BuiltinLintDiagnostics::AbsPathWithModule(span) => { + let (sugg, app) = match sess.source_map().span_to_snippet(span) { + Ok(ref s) => { + // FIXME(Manishearth) ideally the emitting code + // can tell us whether or not this is global + let opt_colon = if s.trim_start().starts_with("::") { "" } else { "::" }; + + (format!("crate{}{}", opt_colon, s), Applicability::MachineApplicable) + } + Err(_) => ("crate::".to_string(), Applicability::HasPlaceholders), + }; + db.span_suggestion(span, "use `crate`", sugg, app); + } + BuiltinLintDiagnostics::ProcMacroDeriveResolutionFallback(span) => { + db.span_label( + span, + "names from parent modules are not accessible without an explicit import", + ); + } + BuiltinLintDiagnostics::MacroExpandedMacroExportsAccessedByAbsolutePaths(span_def) => { + db.span_note(span_def, "the macro is defined here"); + } + BuiltinLintDiagnostics::ElidedLifetimesInPaths( + n, + path_span, + incl_angl_brckt, + insertion_span, + anon_lts, + ) => { + add_elided_lifetime_in_path_suggestion( + sess, + &mut db, + n, + path_span, + incl_angl_brckt, + insertion_span, + anon_lts, + ); + } + BuiltinLintDiagnostics::UnknownCrateTypes(span, note, sugg) => { + db.span_suggestion(span, ¬e, sugg, Applicability::MaybeIncorrect); + } + BuiltinLintDiagnostics::UnusedImports(message, replaces) => { + if !replaces.is_empty() { + db.tool_only_multipart_suggestion( + &message, + replaces, + Applicability::MachineApplicable, + ); + } + } + BuiltinLintDiagnostics::RedundantImport(spans, ident) => { + for (span, is_imported) in spans { + let introduced = if is_imported { "imported" } else { "defined" }; + db.span_label( + span, + format!("the item `{}` is already {} here", ident, introduced), + ); + } + } + BuiltinLintDiagnostics::DeprecatedMacro(suggestion, span) => { + stability::deprecation_suggestion(&mut db, suggestion, span) + } + } + db.emit(); } diff --git a/src/librustc/lint/internal.rs b/src/librustc/lint/internal.rs index 7b99b4af4f9..30679226b9b 100644 --- a/src/librustc/lint/internal.rs +++ b/src/librustc/lint/internal.rs @@ -1,13 +1,11 @@ //! Some lints that are only useful in the compiler or crates that use compiler internals, such as //! Clippy. -use crate::lint::{ - EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintArray, LintContext, LintPass, -}; +use crate::lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext}; use rustc_data_structures::fx::FxHashMap; use rustc_errors::Applicability; use rustc_hir::{GenericArg, HirId, MutTy, Mutability, Path, PathSegment, QPath, Ty, TyKind}; -use rustc_session::declare_tool_lint; +use rustc_session::{declare_lint_pass, declare_tool_lint, impl_lint_pass}; use rustc_span::symbol::{sym, Symbol}; use syntax::ast::{Ident, Item, ItemKind}; diff --git a/src/librustc/lint/mod.rs b/src/librustc/lint/mod.rs index e59e8ce1c0a..1aa4a43a2f2 100644 --- a/src/librustc/lint/mod.rs +++ b/src/librustc/lint/mod.rs @@ -21,6 +21,7 @@ pub use self::Level::*; pub use self::LintSource::*; +use crate::lint::builtin::HardwiredLints; use crate::ty::TyCtxt; use rustc_data_structures::sync; use rustc_errors::{DiagnosticBuilder, DiagnosticId}; @@ -33,48 +34,12 @@ use rustc_span::Span; use syntax::ast; pub use crate::lint::context::{ - CheckLintNameResult, EarlyContext, LateContext, LintContext, LintStore, + add_elided_lifetime_in_path_suggestion, CheckLintNameResult, EarlyContext, LateContext, + LintContext, LintStore, }; pub use rustc_session::lint::{BufferedEarlyLint, FutureIncompatibleInfo, Level, Lint, LintId}; - -/// Declares a static `LintArray` and return it as an expression. -#[macro_export] -macro_rules! lint_array { - ($( $lint:expr ),* ,) => { lint_array!( $($lint),* ) }; - ($( $lint:expr ),*) => {{ - vec![$($lint),*] - }} -} - -pub type LintArray = Vec<&'static Lint>; - -pub trait LintPass { - fn name(&self) -> &'static str; -} - -/// Implements `LintPass for $name` with the given list of `Lint` statics. -#[macro_export] -macro_rules! impl_lint_pass { - ($name:ident => [$($lint:expr),* $(,)?]) => { - impl LintPass for $name { - fn name(&self) -> &'static str { stringify!($name) } - } - impl $name { - pub fn get_lints() -> LintArray { $crate::lint_array!($($lint),*) } - } - }; -} - -/// Declares a type named `$name` which implements `LintPass`. -/// To the right of `=>` a comma separated list of `Lint` statics is given. -#[macro_export] -macro_rules! declare_lint_pass { - ($(#[$m:meta])* $name:ident => [$($lint:expr),* $(,)?]) => { - $(#[$m])* #[derive(Copy, Clone)] pub struct $name; - $crate::impl_lint_pass!($name => [$($lint),*]); - }; -} +pub use rustc_session::lint::{LintArray, LintPass}; #[macro_export] macro_rules! late_lint_methods { @@ -166,6 +131,8 @@ macro_rules! declare_late_lint_pass { 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) => ({ diff --git a/src/librustc_ast_lowering/path.rs b/src/librustc_ast_lowering/path.rs index b50295ebaae..65347d379bd 100644 --- a/src/librustc_ast_lowering/path.rs +++ b/src/librustc_ast_lowering/path.rs @@ -305,7 +305,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { E0726, "implicit elided lifetime not allowed here" ); - rustc::lint::builtin::add_elided_lifetime_in_path_suggestion( + rustc::lint::add_elided_lifetime_in_path_suggestion( &self.sess, &mut err, expected_lifetimes, diff --git a/src/librustc_lint/array_into_iter.rs b/src/librustc_lint/array_into_iter.rs index d8ddf7435b4..19d1052d1b2 100644 --- a/src/librustc_lint/array_into_iter.rs +++ b/src/librustc_lint/array_into_iter.rs @@ -1,5 +1,4 @@ -use crate::lint::{LateContext, LateLintPass, LintArray, LintContext, LintPass}; -use rustc::lint::FutureIncompatibleInfo; +use rustc::lint::{FutureIncompatibleInfo, LateContext, LateLintPass, LintContext}; use rustc::ty; use rustc::ty::adjustment::{Adjust, Adjustment}; use rustc_errors::Applicability; diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 25f6361e050..befeb84e57c 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -21,13 +21,8 @@ //! If you define a new `LateLintPass`, you will also need to add it to the //! `late_lint_methods!` invocation in `lib.rs`. -use std::fmt::Write; - -use lint::{EarlyContext, EarlyLintPass, LateLintPass, LintPass}; -use lint::{LateContext, LintArray, LintContext}; use rustc::hir::map::Map; -use rustc::lint; -use rustc::lint::FutureIncompatibleInfo; +use rustc::lint::{self, EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext}; use rustc::traits::misc::can_type_implement_copy; use rustc::ty::{self, layout::VariantIdx, Ty, TyCtxt}; use rustc_data_structures::fx::FxHashSet; @@ -39,6 +34,7 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; use rustc_hir::{GenericParamKind, PatKind}; use rustc_hir::{HirIdSet, Node}; +use rustc_session::lint::FutureIncompatibleInfo; use rustc_span::edition::Edition; use rustc_span::source_map::Spanned; use rustc_span::symbol::{kw, sym, Symbol}; @@ -52,6 +48,7 @@ use syntax::visit::FnKind; use crate::nonstandard_style::{method_context, MethodLateContext}; use log::debug; +use std::fmt::Write; // hardwired lints from librustc pub use lint::builtin::*; diff --git a/src/librustc_lint/late.rs b/src/librustc_lint/late.rs index 07c3b95d699..d8e0274cf43 100644 --- a/src/librustc_lint/late.rs +++ b/src/librustc_lint/late.rs @@ -16,7 +16,6 @@ use rustc::hir::map::Map; use rustc::lint::LateContext; -use rustc::lint::LintPass; use rustc::lint::{LateLintPass, LateLintPassObject}; use rustc::ty::{self, TyCtxt}; use rustc_data_structures::sync::{join, par_iter, ParallelIterator}; @@ -24,12 +23,13 @@ use rustc_hir as hir; use rustc_hir::def_id::{DefId, LOCAL_CRATE}; use rustc_hir::intravisit as hir_visit; use rustc_hir::intravisit::Visitor; +use rustc_session::lint::LintPass; use rustc_span::Span; -use std::slice; use syntax::ast; +use syntax::walk_list; use log::debug; -use syntax::walk_list; +use std::slice; macro_rules! lint_callback { ($cx:expr, $f:ident, $($args:expr),*) => ({ $cx.pass.$f(&$cx.context, $($args),*); diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs index e272c3af468..e708ded603b 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -38,11 +38,12 @@ use rustc::lint::builtin::{ BARE_TRAIT_OBJECTS, ELIDED_LIFETIMES_IN_PATHS, EXPLICIT_OUTLIVES_REQUIREMENTS, INTRA_DOC_LINK_RESOLUTION_FAILURE, MISSING_DOC_CODE_EXAMPLES, PRIVATE_DOC_TESTS, }; -use rustc::lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintArray, LintPass}; +use rustc::lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass}; use rustc::ty::query::Providers; use rustc::ty::TyCtxt; use rustc_hir as hir; use rustc_hir::def_id::DefId; +use rustc_session::lint::{LintArray, LintPass}; use rustc_span::Span; use syntax::ast; diff --git a/src/librustc_lint/non_ascii_idents.rs b/src/librustc_lint/non_ascii_idents.rs index f30d0bcbdd5..522aeb6b144 100644 --- a/src/librustc_lint/non_ascii_idents.rs +++ b/src/librustc_lint/non_ascii_idents.rs @@ -1,4 +1,4 @@ -use crate::lint::{EarlyContext, EarlyLintPass, LintArray, LintContext, LintPass}; +use rustc::lint::{EarlyContext, EarlyLintPass, LintContext}; use syntax::ast; declare_lint! { diff --git a/src/librustc_lint/nonstandard_style.rs b/src/librustc_lint/nonstandard_style.rs index 7e5ad097698..f75bb9ba32c 100644 --- a/src/librustc_lint/nonstandard_style.rs +++ b/src/librustc_lint/nonstandard_style.rs @@ -1,6 +1,4 @@ -use lint::{EarlyContext, LateContext, LintArray, LintContext}; -use lint::{EarlyLintPass, LateLintPass, LintPass}; -use rustc::lint; +use rustc::lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext}; use rustc::ty; use rustc_errors::Applicability; use rustc_hir as hir; diff --git a/src/librustc_lint/redundant_semicolon.rs b/src/librustc_lint/redundant_semicolon.rs index 9fc147f2a0c..dc18f15fe40 100644 --- a/src/librustc_lint/redundant_semicolon.rs +++ b/src/librustc_lint/redundant_semicolon.rs @@ -1,4 +1,4 @@ -use crate::lint::{EarlyContext, EarlyLintPass, LintArray, LintContext, LintPass}; +use rustc::lint::{EarlyContext, EarlyLintPass, LintContext}; use rustc_errors::Applicability; use syntax::ast::{ExprKind, Stmt, StmtKind}; diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index f128e25f35b..ab6841c0c09 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -1,9 +1,6 @@ #![allow(non_snake_case)] -use crate::hir::def_id::DefId; -use lint::{LateContext, LintArray, LintContext}; -use lint::{LateLintPass, LintPass}; -use rustc::lint; +use rustc::lint::{LateContext, LateLintPass, LintContext}; use rustc::mir::interpret::{sign_extend, truncate}; use rustc::ty::layout::{self, IntegerExt, LayoutOf, SizeSkeleton, VariantIdx}; use rustc::ty::subst::SubstsRef; @@ -11,6 +8,7 @@ use rustc::ty::{self, AdtKind, ParamEnv, Ty, TyCtxt}; use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; use rustc_hir as hir; +use rustc_hir::def_id::DefId; use rustc_hir::{is_range_literal, ExprKind, Node}; use rustc_index::vec::Idx; use rustc_span::source_map; diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs index d57f565d919..da8a23f041e 100644 --- a/src/librustc_lint/unused.rs +++ b/src/librustc_lint/unused.rs @@ -1,7 +1,5 @@ -use lint::{EarlyContext, LateContext, LintArray, LintContext}; -use lint::{EarlyLintPass, LateLintPass, LintPass}; -use rustc::lint; use rustc::lint::builtin::UNUSED_ATTRIBUTES; +use rustc::lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext}; use rustc::ty::adjustment; use rustc::ty::{self, Ty}; use rustc_data_structures::fx::FxHashMap; diff --git a/src/librustc_session/lint.rs b/src/librustc_session/lint.rs index 24e42928f63..40d40ce7211 100644 --- a/src/librustc_session/lint.rs +++ b/src/librustc_session/lint.rs @@ -326,3 +326,41 @@ macro_rules! declare_tool_lint { }; ); } + +/// Declares a static `LintArray` and return it as an expression. +#[macro_export] +macro_rules! lint_array { + ($( $lint:expr ),* ,) => { lint_array!( $($lint),* ) }; + ($( $lint:expr ),*) => {{ + vec![$($lint),*] + }} +} + +pub type LintArray = Vec<&'static Lint>; + +pub trait LintPass { + fn name(&self) -> &'static str; +} + +/// Implements `LintPass for $name` with the given list of `Lint` statics. +#[macro_export] +macro_rules! impl_lint_pass { + ($name:ident => [$($lint:expr),* $(,)?]) => { + impl $crate::lint::LintPass for $name { + fn name(&self) -> &'static str { stringify!($name) } + } + impl $name { + pub fn get_lints() -> $crate::lint::LintArray { $crate::lint_array!($($lint),*) } + } + }; +} + +/// Declares a type named `$name` which implements `LintPass`. +/// To the right of `=>` a comma separated list of `Lint` statics is given. +#[macro_export] +macro_rules! declare_lint_pass { + ($(#[$m:meta])* $name:ident => [$($lint:expr),* $(,)?]) => { + $(#[$m])* #[derive(Copy, Clone)] pub struct $name; + $crate::impl_lint_pass!($name => [$($lint),*]); + }; +}