]> git.lizzy.rs Git - rust.git/blobdiff - src/librustc_session/lint.rs
Rollup merge of #67867 - matthewjasper:opaque-assoc-lookup, r=oli-obk
[rust.git] / src / librustc_session / lint.rs
index faa6a7a4644e06e26cd60332ef2f749cc99c4cc1..2ba3932c7d97e31eefc441cb3aff7be962e76a65 100644 (file)
@@ -1,13 +1,18 @@
-use syntax_pos::{MultiSpan, Symbol, sym};
-use syntax_pos::edition::Edition;
-use rustc_data_structures::stable_hasher::{HashStable, ToStableHashKey, StableHasher};
 pub use self::Level::*;
-use crate::node_id::NodeId;
+use crate::node_id::{NodeId, NodeMap};
+use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey};
+use rustc_span::edition::Edition;
+use rustc_span::{sym, symbol::Ident, MultiSpan, Span, Symbol};
+
+pub mod builtin;
 
 /// Setting for how to handle a lint.
 #[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Debug, Hash)]
 pub enum Level {
-    Allow, Warn, Deny, Forbid,
+    Allow,
+    Warn,
+    Deny,
+    Forbid,
 }
 
 rustc_data_structures::impl_stable_hash_via_hash!(Level);
@@ -130,7 +135,7 @@ fn eq(&self, other: &LintId) -> bool {
     }
 }
 
-impl Eq for LintId { }
+impl Eq for LintId {}
 
 impl std::hash::Hash for LintId {
     fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
@@ -142,9 +147,7 @@ fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
 impl LintId {
     /// Gets the `LintId` for a `Lint`.
     pub fn of(lint: &'static Lint) -> LintId {
-        LintId {
-            lint,
-        }
+        LintId { lint }
     }
 
     pub fn lint_name_raw(&self) -> &'static str {
@@ -173,19 +176,92 @@ fn to_stable_hash_key(&self, _: &HCX) -> &'static str {
     }
 }
 
-/// Stores buffered lint info which can later be passed to `librustc`.
+// This could be a closure, but then implementing derive trait
+// becomes hacky (and it gets allocated).
+#[derive(PartialEq)]
+pub enum BuiltinLintDiagnostics {
+    Normal,
+    BareTraitObject(Span, /* is_global */ bool),
+    AbsPathWithModule(Span),
+    ProcMacroDeriveResolutionFallback(Span),
+    MacroExpandedMacroExportsAccessedByAbsolutePaths(Span),
+    ElidedLifetimesInPaths(usize, Span, bool, Span, String),
+    UnknownCrateTypes(Span, String, String),
+    UnusedImports(String, Vec<(Span, String)>),
+    RedundantImport(Vec<(Span, bool)>, Ident),
+    DeprecatedMacro(Option<Symbol>, Span),
+}
+
+/// Lints that are buffered up early on in the `Session` before the
+/// `LintLevels` is calculated. These are later passed to `librustc`.
+#[derive(PartialEq)]
 pub struct BufferedEarlyLint {
     /// The span of code that we are linting on.
-   pub span: MultiSpan,
+    pub span: MultiSpan,
+
+    /// The lint message.
+    pub msg: String,
 
-   /// The lint message.
-   pub msg: String,
+    /// The `NodeId` of the AST node that generated the lint.
+    pub node_id: NodeId,
 
-   /// The `NodeId` of the AST node that generated the lint.
-   pub id: NodeId,
+    /// A lint Id that can be passed to `rustc::lint::Lint::from_parser_lint_id`.
+    pub lint_id: LintId,
 
-   /// A lint Id that can be passed to `rustc::lint::Lint::from_parser_lint_id`.
-   pub lint_id: &'static Lint,
+    /// Customization of the `DiagnosticBuilder<'_>` for the lint.
+    pub diagnostic: BuiltinLintDiagnostics,
+}
+
+#[derive(Default)]
+pub struct LintBuffer {
+    pub map: NodeMap<Vec<BufferedEarlyLint>>,
+}
+
+impl LintBuffer {
+    pub fn add_early_lint(&mut self, early_lint: BufferedEarlyLint) {
+        let arr = self.map.entry(early_lint.node_id).or_default();
+        if !arr.contains(&early_lint) {
+            arr.push(early_lint);
+        }
+    }
+
+    pub fn add_lint(
+        &mut self,
+        lint: &'static Lint,
+        node_id: NodeId,
+        span: MultiSpan,
+        msg: &str,
+        diagnostic: BuiltinLintDiagnostics,
+    ) {
+        let lint_id = LintId::of(lint);
+        let msg = msg.to_string();
+        self.add_early_lint(BufferedEarlyLint { lint_id, node_id, span, msg, diagnostic });
+    }
+
+    pub fn take(&mut self, id: NodeId) -> Vec<BufferedEarlyLint> {
+        self.map.remove(&id).unwrap_or_default()
+    }
+
+    pub fn buffer_lint(
+        &mut self,
+        lint: &'static Lint,
+        id: NodeId,
+        sp: impl Into<MultiSpan>,
+        msg: &str,
+    ) {
+        self.add_lint(lint, id, sp.into(), msg, BuiltinLintDiagnostics::Normal)
+    }
+
+    pub fn buffer_lint_with_diagnostic(
+        &mut self,
+        lint: &'static Lint,
+        id: NodeId,
+        sp: impl Into<MultiSpan>,
+        msg: &str,
+        diagnostic: BuiltinLintDiagnostics,
+    ) {
+        self.add_lint(lint, id, sp.into(), msg, diagnostic)
+    }
 }
 
 /// Declares a static item of type `&'static Lint`.
@@ -252,3 +328,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),*]);
+    };
+}