]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_lint_defs/src/lib.rs
Update rls
[rust.git] / compiler / rustc_lint_defs / src / lib.rs
1 #![feature(min_specialization)]
2
3 #[macro_use]
4 extern crate rustc_macros;
5
6 pub use self::Level::*;
7 use rustc_ast::node_id::{NodeId, NodeMap};
8 use rustc_ast::{AttrId, Attribute};
9 use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey};
10 use rustc_error_messages::MultiSpan;
11 use rustc_hir::HashStableContext;
12 use rustc_hir::HirId;
13 use rustc_span::edition::Edition;
14 use rustc_span::{sym, symbol::Ident, Span, Symbol};
15 use rustc_target::spec::abi::Abi;
16
17 use serde::{Deserialize, Serialize};
18
19 pub mod builtin;
20
21 #[macro_export]
22 macro_rules! pluralize {
23     ($x:expr) => {
24         if $x != 1 { "s" } else { "" }
25     };
26     ("is", $x:expr) => {
27         if $x == 1 { "is" } else { "are" }
28     };
29     ("was", $x:expr) => {
30         if $x == 1 { "was" } else { "were" }
31     };
32     ("this", $x:expr) => {
33         if $x == 1 { "this" } else { "these" }
34     };
35 }
36
37 /// Indicates the confidence in the correctness of a suggestion.
38 ///
39 /// All suggestions are marked with an `Applicability`. Tools use the applicability of a suggestion
40 /// to determine whether it should be automatically applied or if the user should be consulted
41 /// before applying the suggestion.
42 #[derive(Copy, Clone, Debug, PartialEq, Hash, Encodable, Decodable, Serialize, Deserialize)]
43 pub enum Applicability {
44     /// The suggestion is definitely what the user intended, or maintains the exact meaning of the code.
45     /// This suggestion should be automatically applied.
46     ///
47     /// In case of multiple `MachineApplicable` suggestions (whether as part of
48     /// the same `multipart_suggestion` or not), all of them should be
49     /// automatically applied.
50     MachineApplicable,
51
52     /// The suggestion may be what the user intended, but it is uncertain. The suggestion should
53     /// result in valid Rust code if it is applied.
54     MaybeIncorrect,
55
56     /// The suggestion contains placeholders like `(...)` or `{ /* fields */ }`. The suggestion
57     /// cannot be applied automatically because it will not result in valid Rust code. The user
58     /// will need to fill in the placeholders.
59     HasPlaceholders,
60
61     /// The applicability of the suggestion is unknown.
62     Unspecified,
63 }
64
65 /// Each lint expectation has a `LintExpectationId` assigned by the `LintLevelsBuilder`.
66 /// Expected `Diagnostic`s get the lint level `Expect` which stores the `LintExpectationId`
67 /// to match it with the actual expectation later on.
68 ///
69 /// The `LintExpectationId` has to be stable between compilations, as diagnostic
70 /// instances might be loaded from cache. Lint messages can be emitted during an
71 /// `EarlyLintPass` operating on the AST and during a `LateLintPass` traversing the
72 /// HIR tree. The AST doesn't have enough information to create a stable id. The
73 /// `LintExpectationId` will instead store the [`AttrId`] defining the expectation.
74 /// These `LintExpectationId` will be updated to use the stable [`HirId`] once the
75 /// AST has been lowered. The transformation is done by the `LintLevelsBuilder`
76 ///
77 /// Each lint inside the `expect` attribute is tracked individually, the `lint_index`
78 /// identifies the lint inside the attribute and ensures that the IDs are unique.
79 ///
80 /// The index values have a type of `u16` to reduce the size of the `LintExpectationId`.
81 /// It's reasonable to assume that no user will define 2^16 attributes on one node or
82 /// have that amount of lints listed. `u16` values should therefore suffice.
83 #[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Debug, Hash, Encodable, Decodable)]
84 pub enum LintExpectationId {
85     /// Used for lints emitted during the `EarlyLintPass`. This id is not
86     /// hash stable and should not be cached.
87     Unstable { attr_id: AttrId, lint_index: Option<u16> },
88     /// The [`HirId`] that the lint expectation is attached to. This id is
89     /// stable and can be cached. The additional index ensures that nodes with
90     /// several expectations can correctly match diagnostics to the individual
91     /// expectation.
92     Stable { hir_id: HirId, attr_index: u16, lint_index: Option<u16> },
93 }
94
95 impl LintExpectationId {
96     pub fn is_stable(&self) -> bool {
97         match self {
98             LintExpectationId::Unstable { .. } => false,
99             LintExpectationId::Stable { .. } => true,
100         }
101     }
102
103     pub fn get_lint_index(&self) -> Option<u16> {
104         let (LintExpectationId::Unstable { lint_index, .. }
105         | LintExpectationId::Stable { lint_index, .. }) = self;
106
107         *lint_index
108     }
109
110     pub fn set_lint_index(&mut self, new_lint_index: Option<u16>) {
111         let (LintExpectationId::Unstable { ref mut lint_index, .. }
112         | LintExpectationId::Stable { ref mut lint_index, .. }) = self;
113
114         *lint_index = new_lint_index
115     }
116 }
117
118 impl<HCX: rustc_hir::HashStableContext> HashStable<HCX> for LintExpectationId {
119     #[inline]
120     fn hash_stable(&self, hcx: &mut HCX, hasher: &mut StableHasher) {
121         match self {
122             LintExpectationId::Stable { hir_id, attr_index, lint_index: Some(lint_index) } => {
123                 hir_id.hash_stable(hcx, hasher);
124                 attr_index.hash_stable(hcx, hasher);
125                 lint_index.hash_stable(hcx, hasher);
126             }
127             _ => {
128                 unreachable!(
129                     "HashStable should only be called for filled and stable `LintExpectationId`"
130                 )
131             }
132         }
133     }
134 }
135
136 impl<HCX: rustc_hir::HashStableContext> ToStableHashKey<HCX> for LintExpectationId {
137     type KeyType = (HirId, u16, u16);
138
139     #[inline]
140     fn to_stable_hash_key(&self, _: &HCX) -> Self::KeyType {
141         match self {
142             LintExpectationId::Stable { hir_id, attr_index, lint_index: Some(lint_index) } => {
143                 (*hir_id, *attr_index, *lint_index)
144             }
145             _ => {
146                 unreachable!("HashStable should only be called for a filled `LintExpectationId`")
147             }
148         }
149     }
150 }
151
152 /// Setting for how to handle a lint.
153 ///
154 /// See: <https://doc.rust-lang.org/rustc/lints/levels.html>
155 #[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Debug, Hash, HashStable_Generic)]
156 pub enum Level {
157     /// The `allow` level will not issue any message.
158     Allow,
159     /// The `expect` level will suppress the lint message but in turn produce a message
160     /// if the lint wasn't issued in the expected scope. `Expect` should not be used as
161     /// an initial level for a lint.
162     ///
163     /// Note that this still means that the lint is enabled in this position and should
164     /// be emitted, this will in turn fulfill the expectation and suppress the lint.
165     ///
166     /// See RFC 2383.
167     ///
168     /// The [`LintExpectationId`] is used to later link a lint emission to the actual
169     /// expectation. It can be ignored in most cases.
170     Expect(LintExpectationId),
171     /// The `warn` level will produce a warning if the lint was violated, however the
172     /// compiler will continue with its execution.
173     Warn,
174     /// This lint level is a special case of [`Warn`], that can't be overridden. This is used
175     /// to ensure that a lint can't be suppressed. This lint level can currently only be set
176     /// via the console and is therefore session specific.
177     ///
178     /// The [`LintExpectationId`] is intended to fulfill expectations marked via the
179     /// `#[expect]` attribute, that will still be suppressed due to the level.
180     ForceWarn(Option<LintExpectationId>),
181     /// The `deny` level will produce an error and stop further execution after the lint
182     /// pass is complete.
183     Deny,
184     /// `Forbid` is equivalent to the `deny` level but can't be overwritten like the previous
185     /// levels.
186     Forbid,
187 }
188
189 impl Level {
190     /// Converts a level to a lower-case string.
191     pub fn as_str(self) -> &'static str {
192         match self {
193             Level::Allow => "allow",
194             Level::Expect(_) => "expect",
195             Level::Warn => "warn",
196             Level::ForceWarn(_) => "force-warn",
197             Level::Deny => "deny",
198             Level::Forbid => "forbid",
199         }
200     }
201
202     /// Converts a lower-case string to a level. This will never construct the expect
203     /// level as that would require a [`LintExpectationId`]
204     pub fn from_str(x: &str) -> Option<Level> {
205         match x {
206             "allow" => Some(Level::Allow),
207             "warn" => Some(Level::Warn),
208             "deny" => Some(Level::Deny),
209             "forbid" => Some(Level::Forbid),
210             "expect" | _ => None,
211         }
212     }
213
214     /// Converts a symbol to a level.
215     pub fn from_attr(attr: &Attribute) -> Option<Level> {
216         match attr.name_or_empty() {
217             sym::allow => Some(Level::Allow),
218             sym::expect => Some(Level::Expect(LintExpectationId::Unstable {
219                 attr_id: attr.id,
220                 lint_index: None,
221             })),
222             sym::warn => Some(Level::Warn),
223             sym::deny => Some(Level::Deny),
224             sym::forbid => Some(Level::Forbid),
225             _ => None,
226         }
227     }
228
229     pub fn is_error(self) -> bool {
230         match self {
231             Level::Allow | Level::Expect(_) | Level::Warn | Level::ForceWarn(_) => false,
232             Level::Deny | Level::Forbid => true,
233         }
234     }
235
236     pub fn get_expectation_id(&self) -> Option<LintExpectationId> {
237         match self {
238             Level::Expect(id) | Level::ForceWarn(Some(id)) => Some(*id),
239             _ => None,
240         }
241     }
242 }
243
244 /// Specification of a single lint.
245 #[derive(Copy, Clone, Debug)]
246 pub struct Lint {
247     /// A string identifier for the lint.
248     ///
249     /// This identifies the lint in attributes and in command-line arguments.
250     /// In those contexts it is always lowercase, but this field is compared
251     /// in a way which is case-insensitive for ASCII characters. This allows
252     /// `declare_lint!()` invocations to follow the convention of upper-case
253     /// statics without repeating the name.
254     ///
255     /// The name is written with underscores, e.g., "unused_imports".
256     /// On the command line, underscores become dashes.
257     ///
258     /// See <https://rustc-dev-guide.rust-lang.org/diagnostics.html#lint-naming>
259     /// for naming guidelines.
260     pub name: &'static str,
261
262     /// Default level for the lint.
263     ///
264     /// See <https://rustc-dev-guide.rust-lang.org/diagnostics.html#diagnostic-levels>
265     /// for guidelines on choosing a default level.
266     pub default_level: Level,
267
268     /// Description of the lint or the issue it detects.
269     ///
270     /// e.g., "imports that are never used"
271     pub desc: &'static str,
272
273     /// Starting at the given edition, default to the given lint level. If this is `None`, then use
274     /// `default_level`.
275     pub edition_lint_opts: Option<(Edition, Level)>,
276
277     /// `true` if this lint is reported even inside expansions of external macros.
278     pub report_in_external_macro: bool,
279
280     pub future_incompatible: Option<FutureIncompatibleInfo>,
281
282     pub is_plugin: bool,
283
284     /// `Some` if this lint is feature gated, otherwise `None`.
285     pub feature_gate: Option<Symbol>,
286
287     pub crate_level_only: bool,
288 }
289
290 /// Extra information for a future incompatibility lint.
291 #[derive(Copy, Clone, Debug)]
292 pub struct FutureIncompatibleInfo {
293     /// e.g., a URL for an issue/PR/RFC or error code
294     pub reference: &'static str,
295     /// The reason for the lint used by diagnostics to provide
296     /// the right help message
297     pub reason: FutureIncompatibilityReason,
298     /// Whether to explain the reason to the user.
299     ///
300     /// Set to false for lints that already include a more detailed
301     /// explanation.
302     pub explain_reason: bool,
303 }
304
305 /// The reason for future incompatibility
306 #[derive(Copy, Clone, Debug)]
307 pub enum FutureIncompatibilityReason {
308     /// This will be an error in a future release
309     /// for all editions
310     FutureReleaseError,
311     /// This will be an error in a future release, and
312     /// Cargo should create a report even for dependencies
313     FutureReleaseErrorReportNow,
314     /// Code that changes meaning in some way in a
315     /// future release.
316     FutureReleaseSemanticsChange,
317     /// Previously accepted code that will become an
318     /// error in the provided edition
319     EditionError(Edition),
320     /// Code that changes meaning in some way in
321     /// the provided edition
322     EditionSemanticsChange(Edition),
323     /// A custom reason.
324     Custom(&'static str),
325 }
326
327 impl FutureIncompatibilityReason {
328     pub fn edition(self) -> Option<Edition> {
329         match self {
330             Self::EditionError(e) => Some(e),
331             Self::EditionSemanticsChange(e) => Some(e),
332             _ => None,
333         }
334     }
335 }
336
337 impl FutureIncompatibleInfo {
338     pub const fn default_fields_for_macro() -> Self {
339         FutureIncompatibleInfo {
340             reference: "",
341             reason: FutureIncompatibilityReason::FutureReleaseError,
342             explain_reason: true,
343         }
344     }
345 }
346
347 impl Lint {
348     pub const fn default_fields_for_macro() -> Self {
349         Lint {
350             name: "",
351             default_level: Level::Forbid,
352             desc: "",
353             edition_lint_opts: None,
354             is_plugin: false,
355             report_in_external_macro: false,
356             future_incompatible: None,
357             feature_gate: None,
358             crate_level_only: false,
359         }
360     }
361
362     /// Gets the lint's name, with ASCII letters converted to lowercase.
363     pub fn name_lower(&self) -> String {
364         self.name.to_ascii_lowercase()
365     }
366
367     pub fn default_level(&self, edition: Edition) -> Level {
368         self.edition_lint_opts
369             .filter(|(e, _)| *e <= edition)
370             .map(|(_, l)| l)
371             .unwrap_or(self.default_level)
372     }
373 }
374
375 /// Identifies a lint known to the compiler.
376 #[derive(Clone, Copy, Debug)]
377 pub struct LintId {
378     // Identity is based on pointer equality of this field.
379     pub lint: &'static Lint,
380 }
381
382 impl PartialEq for LintId {
383     fn eq(&self, other: &LintId) -> bool {
384         std::ptr::eq(self.lint, other.lint)
385     }
386 }
387
388 impl Eq for LintId {}
389
390 impl std::hash::Hash for LintId {
391     fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
392         let ptr = self.lint as *const Lint;
393         ptr.hash(state);
394     }
395 }
396
397 impl LintId {
398     /// Gets the `LintId` for a `Lint`.
399     pub fn of(lint: &'static Lint) -> LintId {
400         LintId { lint }
401     }
402
403     pub fn lint_name_raw(&self) -> &'static str {
404         self.lint.name
405     }
406
407     /// Gets the name of the lint.
408     pub fn to_string(&self) -> String {
409         self.lint.name_lower()
410     }
411 }
412
413 impl<HCX> HashStable<HCX> for LintId {
414     #[inline]
415     fn hash_stable(&self, hcx: &mut HCX, hasher: &mut StableHasher) {
416         self.lint_name_raw().hash_stable(hcx, hasher);
417     }
418 }
419
420 impl<HCX> ToStableHashKey<HCX> for LintId {
421     type KeyType = &'static str;
422
423     #[inline]
424     fn to_stable_hash_key(&self, _: &HCX) -> &'static str {
425         self.lint_name_raw()
426     }
427 }
428
429 // This could be a closure, but then implementing derive trait
430 // becomes hacky (and it gets allocated).
431 #[derive(Debug)]
432 pub enum BuiltinLintDiagnostics {
433     Normal,
434     AbsPathWithModule(Span),
435     ProcMacroDeriveResolutionFallback(Span),
436     MacroExpandedMacroExportsAccessedByAbsolutePaths(Span),
437     ElidedLifetimesInPaths(usize, Span, bool, Span),
438     UnknownCrateTypes(Span, String, String),
439     UnusedImports(String, Vec<(Span, String)>, Option<Span>),
440     RedundantImport(Vec<(Span, bool)>, Ident),
441     DeprecatedMacro(Option<Symbol>, Span),
442     MissingAbi(Span, Abi),
443     UnusedDocComment(Span),
444     UnusedBuiltinAttribute {
445         attr_name: Symbol,
446         macro_name: String,
447         invoc_span: Span,
448     },
449     PatternsInFnsWithoutBody(Span, Ident),
450     LegacyDeriveHelpers(Span),
451     ProcMacroBackCompat(String),
452     OrPatternsBackCompat(Span, String),
453     ReservedPrefix(Span),
454     TrailingMacro(bool, Ident),
455     BreakWithLabelAndLoop(Span),
456     NamedAsmLabel(String),
457     UnicodeTextFlow(Span, String),
458     UnexpectedCfg((Symbol, Span), Option<(Symbol, Span)>),
459     DeprecatedWhereclauseLocation(Span, String),
460     SingleUseLifetime {
461         /// Span of the parameter which declares this lifetime.
462         param_span: Span,
463         /// Span of the code that should be removed when eliding this lifetime.
464         /// This span should include leading or trailing comma.
465         deletion_span: Span,
466         /// Span of the single use, or None if the lifetime is never used.
467         /// If true, the lifetime will be fully elided.
468         use_span: Option<(Span, bool)>,
469     },
470     NamedArgumentUsedPositionally(Option<Span>, Span, String),
471 }
472
473 /// Lints that are buffered up early on in the `Session` before the
474 /// `LintLevels` is calculated.
475 pub struct BufferedEarlyLint {
476     /// The span of code that we are linting on.
477     pub span: MultiSpan,
478
479     /// The lint message.
480     pub msg: String,
481
482     /// The `NodeId` of the AST node that generated the lint.
483     pub node_id: NodeId,
484
485     /// A lint Id that can be passed to
486     /// `rustc_lint::early::EarlyContextAndPass::check_id`.
487     pub lint_id: LintId,
488
489     /// Customization of the `DiagnosticBuilder<'_>` for the lint.
490     pub diagnostic: BuiltinLintDiagnostics,
491 }
492
493 #[derive(Default)]
494 pub struct LintBuffer {
495     pub map: NodeMap<Vec<BufferedEarlyLint>>,
496 }
497
498 impl LintBuffer {
499     pub fn add_early_lint(&mut self, early_lint: BufferedEarlyLint) {
500         let arr = self.map.entry(early_lint.node_id).or_default();
501         arr.push(early_lint);
502     }
503
504     pub fn add_lint(
505         &mut self,
506         lint: &'static Lint,
507         node_id: NodeId,
508         span: MultiSpan,
509         msg: &str,
510         diagnostic: BuiltinLintDiagnostics,
511     ) {
512         let lint_id = LintId::of(lint);
513         let msg = msg.to_string();
514         self.add_early_lint(BufferedEarlyLint { lint_id, node_id, span, msg, diagnostic });
515     }
516
517     pub fn take(&mut self, id: NodeId) -> Vec<BufferedEarlyLint> {
518         self.map.remove(&id).unwrap_or_default()
519     }
520
521     pub fn buffer_lint(
522         &mut self,
523         lint: &'static Lint,
524         id: NodeId,
525         sp: impl Into<MultiSpan>,
526         msg: &str,
527     ) {
528         self.add_lint(lint, id, sp.into(), msg, BuiltinLintDiagnostics::Normal)
529     }
530
531     pub fn buffer_lint_with_diagnostic(
532         &mut self,
533         lint: &'static Lint,
534         id: NodeId,
535         sp: impl Into<MultiSpan>,
536         msg: &str,
537         diagnostic: BuiltinLintDiagnostics,
538     ) {
539         self.add_lint(lint, id, sp.into(), msg, diagnostic)
540     }
541 }
542
543 /// Declares a static item of type `&'static Lint`.
544 ///
545 /// See <https://rustc-dev-guide.rust-lang.org/diagnostics.html> for
546 /// documentation and guidelines on writing lints.
547 ///
548 /// The macro call should start with a doc comment explaining the lint
549 /// which will be embedded in the rustc user documentation book. It should
550 /// be written in markdown and have a format that looks like this:
551 ///
552 /// ```rust,ignore (doc-example)
553 /// /// The `my_lint_name` lint detects [short explanation here].
554 /// ///
555 /// /// ### Example
556 /// ///
557 /// /// ```rust
558 /// /// [insert a concise example that triggers the lint]
559 /// /// ```
560 /// ///
561 /// /// {{produces}}
562 /// ///
563 /// /// ### Explanation
564 /// ///
565 /// /// This should be a detailed explanation of *why* the lint exists,
566 /// /// and also include suggestions on how the user should fix the problem.
567 /// /// Try to keep the text simple enough that a beginner can understand,
568 /// /// and include links to other documentation for terminology that a
569 /// /// beginner may not be familiar with. If this is "allow" by default,
570 /// /// it should explain why (are there false positives or other issues?). If
571 /// /// this is a future-incompatible lint, it should say so, with text that
572 /// /// looks roughly like this:
573 /// ///
574 /// /// This is a [future-incompatible] lint to transition this to a hard
575 /// /// error in the future. See [issue #xxxxx] for more details.
576 /// ///
577 /// /// [issue #xxxxx]: https://github.com/rust-lang/rust/issues/xxxxx
578 /// ```
579 ///
580 /// The `{{produces}}` tag will be automatically replaced with the output from
581 /// the example by the build system. If the lint example is too complex to run
582 /// as a simple example (for example, it needs an extern crate), mark the code
583 /// block with `ignore` and manually replace the `{{produces}}` line with the
584 /// expected output in a `text` code block.
585 ///
586 /// If this is a rustdoc-only lint, then only include a brief introduction
587 /// with a link with the text `[rustdoc book]` so that the validator knows
588 /// that this is for rustdoc only (see BROKEN_INTRA_DOC_LINKS as an example).
589 ///
590 /// Commands to view and test the documentation:
591 ///
592 /// * `./x.py doc --stage=1 src/doc/rustc --open`: Builds the rustc book and opens it.
593 /// * `./x.py test src/tools/lint-docs`: Validates that the lint docs have the
594 ///   correct style, and that the code example actually emits the expected
595 ///   lint.
596 ///
597 /// If you have already built the compiler, and you want to make changes to
598 /// just the doc comments, then use the `--keep-stage=0` flag with the above
599 /// commands to avoid rebuilding the compiler.
600 #[macro_export]
601 macro_rules! declare_lint {
602     ($(#[$attr:meta])* $vis: vis $NAME: ident, $Level: ident, $desc: expr) => (
603         $crate::declare_lint!(
604             $(#[$attr])* $vis $NAME, $Level, $desc,
605         );
606     );
607     ($(#[$attr:meta])* $vis: vis $NAME: ident, $Level: ident, $desc: expr,
608      $(@feature_gate = $gate:expr;)?
609      $(@future_incompatible = FutureIncompatibleInfo { $($field:ident : $val:expr),* $(,)*  }; )?
610      $($v:ident),*) => (
611         $(#[$attr])*
612         $vis static $NAME: &$crate::Lint = &$crate::Lint {
613             name: stringify!($NAME),
614             default_level: $crate::$Level,
615             desc: $desc,
616             edition_lint_opts: None,
617             is_plugin: false,
618             $($v: true,)*
619             $(feature_gate: Some($gate),)*
620             $(future_incompatible: Some($crate::FutureIncompatibleInfo {
621                 $($field: $val,)*
622                 ..$crate::FutureIncompatibleInfo::default_fields_for_macro()
623             }),)*
624             ..$crate::Lint::default_fields_for_macro()
625         };
626     );
627     ($(#[$attr:meta])* $vis: vis $NAME: ident, $Level: ident, $desc: expr,
628      $lint_edition: expr => $edition_level: ident
629     ) => (
630         $(#[$attr])*
631         $vis static $NAME: &$crate::Lint = &$crate::Lint {
632             name: stringify!($NAME),
633             default_level: $crate::$Level,
634             desc: $desc,
635             edition_lint_opts: Some(($lint_edition, $crate::Level::$edition_level)),
636             report_in_external_macro: false,
637             is_plugin: false,
638         };
639     );
640 }
641
642 #[macro_export]
643 macro_rules! declare_tool_lint {
644     (
645         $(#[$attr:meta])* $vis:vis $tool:ident ::$NAME:ident, $Level: ident, $desc: expr
646     ) => (
647         $crate::declare_tool_lint!{$(#[$attr])* $vis $tool::$NAME, $Level, $desc, false}
648     );
649     (
650         $(#[$attr:meta])* $vis:vis $tool:ident ::$NAME:ident, $Level:ident, $desc:expr,
651         report_in_external_macro: $rep:expr
652     ) => (
653          $crate::declare_tool_lint!{$(#[$attr])* $vis $tool::$NAME, $Level, $desc, $rep}
654     );
655     (
656         $(#[$attr:meta])* $vis:vis $tool:ident ::$NAME:ident, $Level:ident, $desc:expr,
657         $external:expr
658     ) => (
659         $(#[$attr])*
660         $vis static $NAME: &$crate::Lint = &$crate::Lint {
661             name: &concat!(stringify!($tool), "::", stringify!($NAME)),
662             default_level: $crate::$Level,
663             desc: $desc,
664             edition_lint_opts: None,
665             report_in_external_macro: $external,
666             future_incompatible: None,
667             is_plugin: true,
668             feature_gate: None,
669             crate_level_only: false,
670         };
671     );
672 }
673
674 /// Declares a static `LintArray` and return it as an expression.
675 #[macro_export]
676 macro_rules! lint_array {
677     ($( $lint:expr ),* ,) => { lint_array!( $($lint),* ) };
678     ($( $lint:expr ),*) => {{
679         vec![$($lint),*]
680     }}
681 }
682
683 pub type LintArray = Vec<&'static Lint>;
684
685 pub trait LintPass {
686     fn name(&self) -> &'static str;
687 }
688
689 /// Implements `LintPass for $ty` with the given list of `Lint` statics.
690 #[macro_export]
691 macro_rules! impl_lint_pass {
692     ($ty:ty => [$($lint:expr),* $(,)?]) => {
693         impl $crate::LintPass for $ty {
694             fn name(&self) -> &'static str { stringify!($ty) }
695         }
696         impl $ty {
697             pub fn get_lints() -> $crate::LintArray { $crate::lint_array!($($lint),*) }
698         }
699     };
700 }
701
702 /// Declares a type named `$name` which implements `LintPass`.
703 /// To the right of `=>` a comma separated list of `Lint` statics is given.
704 #[macro_export]
705 macro_rules! declare_lint_pass {
706     ($(#[$m:meta])* $name:ident => [$($lint:expr),* $(,)?]) => {
707         $(#[$m])* #[derive(Copy, Clone)] pub struct $name;
708         $crate::impl_lint_pass!($name => [$($lint),*]);
709     };
710 }