1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
#![doc = include_str!("../README.md")]
#![warn(clippy::pedantic)]
#![allow(clippy::module_name_repetitions)]
#![allow(clippy::must_use_candidate)]
#![allow(clippy::trivially_copy_pass_by_ref)]
#![allow(clippy::unused_self)] // `self` is needed to change the behavior later
#![allow(clippy::missing_panics_doc)] // Temporary allow for `todo!`s
#![allow(clippy::new_without_default)] // Not very helpful as `new` is almost always cfged
#![cfg_attr(not(feature = "driver-api"), allow(dead_code))]
#![cfg_attr(marker, warn(marker::marker_lints::not_using_has_span_trait))]

pub static MARKER_API_VERSION: &str = env!("CARGO_PKG_VERSION");

mod interface;
mod private;
pub use interface::*;
mod lint;
pub use lint::*;

#[cfg(test)]
pub(crate) mod test;

pub mod ast;
pub mod common;
pub mod context;
pub mod diagnostic;
pub mod prelude;
pub mod sem;
pub mod span;

#[doc(hidden)]
pub mod ffi;

pub use context::MarkerContext;
pub use interface::{LintPassInfo, LintPassInfoBuilder};

/// A [`LintPass`] visits every node like a `Visitor`. The difference is that a
/// [`LintPass`] provides some additional information about the implemented lints.
/// The adapter will walk through the entire AST once and give each node to the
/// registered [`LintPass`]es.
pub trait LintPass {
    fn info(&self) -> LintPassInfo;

    fn check_crate<'ast>(&mut self, _cx: &'ast MarkerContext<'ast>, _krate: &'ast ast::Crate<'ast>) {}
    fn check_item<'ast>(&mut self, _cx: &'ast MarkerContext<'ast>, _item: ast::ItemKind<'ast>) {}
    fn check_field<'ast>(&mut self, _cx: &'ast MarkerContext<'ast>, _field: &'ast ast::ItemField<'ast>) {}
    fn check_variant<'ast>(&mut self, _cx: &'ast MarkerContext<'ast>, _variant: &'ast ast::EnumVariant<'ast>) {}
    fn check_body<'ast>(&mut self, _cx: &'ast MarkerContext<'ast>, _body: &'ast ast::Body<'ast>) {}
    fn check_stmt<'ast>(&mut self, _cx: &'ast MarkerContext<'ast>, _stmt: ast::StmtKind<'ast>) {}
    fn check_expr<'ast>(&mut self, _cx: &'ast MarkerContext<'ast>, _expr: ast::ExprKind<'ast>) {}
}

/// This struct blocks the construction of enum variants, similar to the `#[non_exhaustive]`
/// attribute.
///
/// Marker uses enums extensively, like [`ItemKind`][ast::ItemKind] and
/// [`ExprKind`](ast::ExprKind). There can be `*Kind` enums that wrap other
/// `*Kind` enums. In those cases, this struct is used, to block the user from
/// constructing the variant manually. This allows tools to handle the variants
/// confidently without additional verification. An example for this would be the
/// [`LitExprKind::UnaryOp`](ast::LitExprKind::UnaryOp) variant.
///
/// This basically acts like a `#[non_exhaustive]` attribute, with the difference
/// that it also works on tuple variants. Attaching `#[non_exhaustive]` to a tuple
/// variant would make it private, which we don't want.
///
/// As a normal user, you can just ignore this instance as it holds no relevant
/// information for linting.
#[repr(C)]
#[non_exhaustive]
#[derive(Copy, Clone)]
pub struct CtorBlocker {
    /// `#[repr(C)]` requires a field, to make this a proper type. This is just
    /// the smallest one.
    _data: u8,
}

impl std::fmt::Debug for CtorBlocker {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("..").finish()
    }
}

impl CtorBlocker {
    #[cfg_attr(feature = "driver-api", visibility::make(pub))]
    pub(crate) fn new() -> Self {
        Self { _data: 255 }
    }
}