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