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;
7 /// Setting for how to handle a lint.
8 #[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Debug, Hash)]
10 Allow, Warn, Deny, Forbid,
13 rustc_data_structures::impl_stable_hash_via_hash!(Level);
16 /// Converts a level to a lower-case string.
17 pub fn as_str(self) -> &'static str {
19 Level::Allow => "allow",
20 Level::Warn => "warn",
21 Level::Deny => "deny",
22 Level::Forbid => "forbid",
26 /// Converts a lower-case string to a level.
27 pub fn from_str(x: &str) -> Option<Level> {
29 "allow" => Some(Level::Allow),
30 "warn" => Some(Level::Warn),
31 "deny" => Some(Level::Deny),
32 "forbid" => Some(Level::Forbid),
37 /// Converts a symbol to a level.
38 pub fn from_symbol(x: Symbol) -> Option<Level> {
40 sym::allow => Some(Level::Allow),
41 sym::warn => Some(Level::Warn),
42 sym::deny => Some(Level::Deny),
43 sym::forbid => Some(Level::Forbid),
49 /// Specification of a single lint.
50 #[derive(Copy, Clone, Debug)]
52 /// A string identifier for the lint.
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.
60 /// The name is written with underscores, e.g., "unused_imports".
61 /// On the command line, underscores become dashes.
62 pub name: &'static str,
64 /// Default level for the lint.
65 pub default_level: Level,
67 /// Description of the lint or the issue it detects.
69 /// e.g., "imports that are never used"
70 pub desc: &'static str,
72 /// Starting at the given edition, default to the given lint level. If this is `None`, then use
74 pub edition_lint_opts: Option<(Edition, Level)>,
76 /// `true` if this lint is reported even inside expansions of external macros.
77 pub report_in_external_macro: bool,
79 pub future_incompatible: Option<FutureIncompatibleInfo>,
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>,
95 pub const fn default_fields_for_macro() -> Self {
98 default_level: Level::Forbid,
100 edition_lint_opts: None,
102 report_in_external_macro: false,
103 future_incompatible: None,
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()
112 pub fn default_level(&self, edition: Edition) -> Level {
113 self.edition_lint_opts
114 .filter(|(e, _)| *e <= edition)
116 .unwrap_or(self.default_level)
120 /// Identifies a lint known to the compiler.
121 #[derive(Clone, Copy, Debug)]
123 // Identity is based on pointer equality of this field.
124 pub lint: &'static Lint,
127 impl PartialEq for LintId {
128 fn eq(&self, other: &LintId) -> bool {
129 std::ptr::eq(self.lint, other.lint)
133 impl Eq for LintId { }
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;
143 /// Gets the `LintId` for a `Lint`.
144 pub fn of(lint: &'static Lint) -> LintId {
150 pub fn lint_name_raw(&self) -> &'static str {
154 /// Gets the name of the lint.
155 pub fn to_string(&self) -> String {
156 self.lint.name_lower()
160 impl<HCX> HashStable<HCX> for LintId {
162 fn hash_stable(&self, hcx: &mut HCX, hasher: &mut StableHasher) {
163 self.lint_name_raw().hash_stable(hcx, hasher);
167 impl<HCX> ToStableHashKey<HCX> for LintId {
168 type KeyType = &'static str;
171 fn to_stable_hash_key(&self, _: &HCX) -> &'static str {
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.
181 /// The lint message.
184 /// The `NodeId` of the AST node that generated the lint.
187 /// A lint Id that can be passed to `rustc::lint::Lint::from_parser_lint_id`.
188 pub lint_id: &'static Lint,
191 /// Declares a static item of type `&'static Lint`.
193 macro_rules! declare_lint {
194 ($vis: vis $NAME: ident, $Level: ident, $desc: expr) => (
195 $crate::declare_lint!(
196 $vis $NAME, $Level, $desc,
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,
205 edition_lint_opts: None,
208 $(future_incompatible: Some($fi),)*
209 ..$crate::lint::Lint::default_fields_for_macro()
212 ($vis: vis $NAME: ident, $Level: ident, $desc: expr,
213 $lint_edition: expr => $edition_level: ident
215 $vis static $NAME: &$crate::lint::Lint = &$crate::lint::Lint {
216 name: stringify!($NAME),
217 default_level: $crate::lint::$Level,
219 edition_lint_opts: Some(($lint_edition, $crate::lint::Level::$edition_level)),
220 report_in_external_macro: false,
227 macro_rules! declare_tool_lint {
229 $(#[$attr:meta])* $vis:vis $tool:ident ::$NAME:ident, $Level: ident, $desc: expr
231 $crate::declare_tool_lint!{$(#[$attr])* $vis $tool::$NAME, $Level, $desc, false}
234 $(#[$attr:meta])* $vis:vis $tool:ident ::$NAME:ident, $Level:ident, $desc:expr,
235 report_in_external_macro: $rep:expr
237 $crate::declare_tool_lint!{$(#[$attr])* $vis $tool::$NAME, $Level, $desc, $rep}
240 $(#[$attr:meta])* $vis:vis $tool:ident ::$NAME:ident, $Level:ident, $desc:expr,
244 $vis static $NAME: &$crate::lint::Lint = &$crate::lint::Lint {
245 name: &concat!(stringify!($tool), "::", stringify!($NAME)),
246 default_level: $crate::lint::$Level,
248 edition_lint_opts: None,
249 report_in_external_macro: $external,
250 future_incompatible: None,