mago_linter/rule.rs
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
use std::fmt::Debug;
use mago_ast::Program;
use mago_reporting::Level;
use mago_walker::Walker;
use crate::context::LintContext;
use crate::definition::RuleDefinition;
use crate::settings::RuleSettings;
/// A `ConfiguredRule` is created after the user’s configuration is applied. If the user
/// chooses to enable a rule and set certain options or a custom severity level, those
/// details are stored here. The linter then uses this configured instance to run the rule
/// and produce issues accordingly.
#[derive(Debug)]
pub struct ConfiguredRule {
/// The unique identifier for this rule in the format `"plugin_slug/rule_slug"`.
///
/// For example, if the plugin is `"analysis"` and the rule is `"instantiation"`,
/// the slug might be `"analysis/instantiation"`. This is often used to look up
/// the rule’s settings or to reference it in messages and CLI commands.
pub slug: String,
/// The **effective level** at which this rule is enforced, such as [`Level::Error`],
/// [`Level::Warning`], [`Level::Help`], or [`Level::Note`].
///
/// This is determined by either the rule’s default level or an override from
/// user configuration. If a rule is effectively disabled, it will not appear
/// as a `ConfiguredRule` in the linter (thus it doesn’t run at all).
pub level: Level,
/// The complete **configuration settings** for this rule, as specified or overridden
/// by the user (e.g., in a TOML file). These settings might include:
pub settings: RuleSettings,
/// The **actual rule implementation**, containing the detection and reporting logic.
///
/// This is typically your struct that implements [`Rule`], including methods
/// to walk the AST and generate [`Issue`](mago_reporting::Issue) objects if
/// a violation is found. The linter invokes [`Rule::lint`] on this object
/// when applying the rule.
pub rule: Box<dyn Rule>,
}
/// A trait representing a single linting rule.
///
/// A `Rule` defines the logic for checking a program or individual nodes within the AST (Abstract Syntax Tree)
/// for specific patterns or issues and reporting diagnostics if any are found.
///
/// Implementors of this trait should provide the rule's definition and the logic for checking programs and nodes.
pub trait Rule: for<'a> Walker<LintContext<'a>> + Send + Sync + Debug {
/// Retrieves the definition of this rule.
///
/// # Returns
///
/// A [`RuleDefinition`] object representing the rule.
fn get_definition(&self) -> RuleDefinition;
/// Lint the entire program for this rule.
///
/// This method is called to apply the rule to the whole [`Program`] AST.
///
/// Note: the default implementation skips linting for non-user-defined programs, if a rule needs to lint
/// non-user-defined programs, it should override this method.
///
/// # Arguments
///
/// * `program` - The abstract syntax tree (AST) of the program to be linted.
/// * `configuration` - The configuration for this specific rule.
/// * `context` - The context for the linting process, which may contain shared state.
fn lint(&self, program: &Program, context: &mut LintContext<'_>) {
self.walk_program(program, context);
}
}