]> git.lizzy.rs Git - rust.git/blob - src/librustc_session/lint.rs
Auto merge of #66996 - ehuss:update-cargo, r=alexcrichton
[rust.git] / src / librustc_session / lint.rs
1 use syntax_pos::{MultiSpan, Symbol, sym};
2 use syntax_pos::edition::Edition;
3 use rustc_data_structures::stable_hasher::{HashStable, ToStableHashKey, StableHasher};
4 pub use self::Level::*;
5 use crate::node_id::NodeId;
6
7 /// Setting for how to handle a lint.
8 #[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Debug, Hash)]
9 pub enum Level {
10     Allow, Warn, Deny, Forbid,
11 }
12
13 rustc_data_structures::impl_stable_hash_via_hash!(Level);
14
15 impl Level {
16     /// Converts a level to a lower-case string.
17     pub fn as_str(self) -> &'static str {
18         match self {
19             Level::Allow => "allow",
20             Level::Warn => "warn",
21             Level::Deny => "deny",
22             Level::Forbid => "forbid",
23         }
24     }
25
26     /// Converts a lower-case string to a level.
27     pub fn from_str(x: &str) -> Option<Level> {
28         match x {
29             "allow" => Some(Level::Allow),
30             "warn" => Some(Level::Warn),
31             "deny" => Some(Level::Deny),
32             "forbid" => Some(Level::Forbid),
33             _ => None,
34         }
35     }
36
37     /// Converts a symbol to a level.
38     pub fn from_symbol(x: Symbol) -> Option<Level> {
39         match x {
40             sym::allow => Some(Level::Allow),
41             sym::warn => Some(Level::Warn),
42             sym::deny => Some(Level::Deny),
43             sym::forbid => Some(Level::Forbid),
44             _ => None,
45         }
46     }
47 }
48
49 /// Specification of a single lint.
50 #[derive(Copy, Clone, Debug)]
51 pub struct Lint {
52     /// A string identifier for the lint.
53     ///
54     /// This identifies the lint in attributes and in command-line arguments.
55     /// In those contexts it is always lowercase, but this field is compared
56     /// in a way which is case-insensitive for ASCII characters. This allows
57     /// `declare_lint!()` invocations to follow the convention of upper-case
58     /// statics without repeating the name.
59     ///
60     /// The name is written with underscores, e.g., "unused_imports".
61     /// On the command line, underscores become dashes.
62     pub name: &'static str,
63
64     /// Default level for the lint.
65     pub default_level: Level,
66
67     /// Description of the lint or the issue it detects.
68     ///
69     /// e.g., "imports that are never used"
70     pub desc: &'static str,
71
72     /// Starting at the given edition, default to the given lint level. If this is `None`, then use
73     /// `default_level`.
74     pub edition_lint_opts: Option<(Edition, Level)>,
75
76     /// `true` if this lint is reported even inside expansions of external macros.
77     pub report_in_external_macro: bool,
78
79     pub future_incompatible: Option<FutureIncompatibleInfo>,
80
81     pub is_plugin: bool,
82 }
83
84 /// Extra information for a future incompatibility lint.
85 #[derive(Copy, Clone, Debug)]
86 pub struct FutureIncompatibleInfo {
87     /// e.g., a URL for an issue/PR/RFC or error code
88     pub reference: &'static str,
89     /// If this is an edition fixing lint, the edition in which
90     /// this lint becomes obsolete
91     pub edition: Option<Edition>,
92 }
93
94 impl Lint {
95     pub const fn default_fields_for_macro() -> Self {
96         Lint {
97             name: "",
98             default_level: Level::Forbid,
99             desc: "",
100             edition_lint_opts: None,
101             is_plugin: false,
102             report_in_external_macro: false,
103             future_incompatible: None,
104         }
105     }
106
107     /// Gets the lint's name, with ASCII letters converted to lowercase.
108     pub fn name_lower(&self) -> String {
109         self.name.to_ascii_lowercase()
110     }
111
112     pub fn default_level(&self, edition: Edition) -> Level {
113         self.edition_lint_opts
114             .filter(|(e, _)| *e <= edition)
115             .map(|(_, l)| l)
116             .unwrap_or(self.default_level)
117     }
118 }
119
120 /// Identifies a lint known to the compiler.
121 #[derive(Clone, Copy, Debug)]
122 pub struct LintId {
123     // Identity is based on pointer equality of this field.
124     pub lint: &'static Lint,
125 }
126
127 impl PartialEq for LintId {
128     fn eq(&self, other: &LintId) -> bool {
129         std::ptr::eq(self.lint, other.lint)
130     }
131 }
132
133 impl Eq for LintId { }
134
135 impl std::hash::Hash for LintId {
136     fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
137         let ptr = self.lint as *const Lint;
138         ptr.hash(state);
139     }
140 }
141
142 impl LintId {
143     /// Gets the `LintId` for a `Lint`.
144     pub fn of(lint: &'static Lint) -> LintId {
145         LintId {
146             lint,
147         }
148     }
149
150     pub fn lint_name_raw(&self) -> &'static str {
151         self.lint.name
152     }
153
154     /// Gets the name of the lint.
155     pub fn to_string(&self) -> String {
156         self.lint.name_lower()
157     }
158 }
159
160 impl<HCX> HashStable<HCX> for LintId {
161     #[inline]
162     fn hash_stable(&self, hcx: &mut HCX, hasher: &mut StableHasher) {
163         self.lint_name_raw().hash_stable(hcx, hasher);
164     }
165 }
166
167 impl<HCX> ToStableHashKey<HCX> for LintId {
168     type KeyType = &'static str;
169
170     #[inline]
171     fn to_stable_hash_key(&self, _: &HCX) -> &'static str {
172         self.lint_name_raw()
173     }
174 }
175
176 /// Stores buffered lint info which can later be passed to `librustc`.
177 pub struct BufferedEarlyLint {
178     /// The span of code that we are linting on.
179    pub span: MultiSpan,
180
181    /// The lint message.
182    pub msg: String,
183
184    /// The `NodeId` of the AST node that generated the lint.
185    pub id: NodeId,
186
187    /// A lint Id that can be passed to `rustc::lint::Lint::from_parser_lint_id`.
188    pub lint_id: &'static Lint,
189 }
190
191 /// Declares a static item of type `&'static Lint`.
192 #[macro_export]
193 macro_rules! declare_lint {
194     ($vis: vis $NAME: ident, $Level: ident, $desc: expr) => (
195         $crate::declare_lint!(
196             $vis $NAME, $Level, $desc,
197         );
198     );
199     ($vis: vis $NAME: ident, $Level: ident, $desc: expr,
200      $(@future_incompatible = $fi:expr;)? $($v:ident),*) => (
201         $vis static $NAME: &$crate::lint::Lint = &$crate::lint::Lint {
202             name: stringify!($NAME),
203             default_level: $crate::lint::$Level,
204             desc: $desc,
205             edition_lint_opts: None,
206             is_plugin: false,
207             $($v: true,)*
208             $(future_incompatible: Some($fi),)*
209             ..$crate::lint::Lint::default_fields_for_macro()
210         };
211     );
212     ($vis: vis $NAME: ident, $Level: ident, $desc: expr,
213      $lint_edition: expr => $edition_level: ident
214     ) => (
215         $vis static $NAME: &$crate::lint::Lint = &$crate::lint::Lint {
216             name: stringify!($NAME),
217             default_level: $crate::lint::$Level,
218             desc: $desc,
219             edition_lint_opts: Some(($lint_edition, $crate::lint::Level::$edition_level)),
220             report_in_external_macro: false,
221             is_plugin: false,
222         };
223     );
224 }
225
226 #[macro_export]
227 macro_rules! declare_tool_lint {
228     (
229         $(#[$attr:meta])* $vis:vis $tool:ident ::$NAME:ident, $Level: ident, $desc: expr
230     ) => (
231         $crate::declare_tool_lint!{$(#[$attr])* $vis $tool::$NAME, $Level, $desc, false}
232     );
233     (
234         $(#[$attr:meta])* $vis:vis $tool:ident ::$NAME:ident, $Level:ident, $desc:expr,
235         report_in_external_macro: $rep:expr
236     ) => (
237          $crate::declare_tool_lint!{$(#[$attr])* $vis $tool::$NAME, $Level, $desc, $rep}
238     );
239     (
240         $(#[$attr:meta])* $vis:vis $tool:ident ::$NAME:ident, $Level:ident, $desc:expr,
241         $external:expr
242     ) => (
243         $(#[$attr])*
244         $vis static $NAME: &$crate::lint::Lint = &$crate::lint::Lint {
245             name: &concat!(stringify!($tool), "::", stringify!($NAME)),
246             default_level: $crate::lint::$Level,
247             desc: $desc,
248             edition_lint_opts: None,
249             report_in_external_macro: $external,
250             future_incompatible: None,
251             is_plugin: true,
252         };
253     );
254 }