Skip to main content

cha_core/
plugin.rs

1use schemars::JsonSchema;
2use serde::{Deserialize, Serialize};
3use std::path::PathBuf;
4
5use crate::{SourceFile, SourceModel};
6
7/// Severity level for a finding.
8#[derive(
9    Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize, JsonSchema, Default,
10)]
11#[serde(rename_all = "lowercase")]
12pub enum Severity {
13    #[default]
14    Hint,
15    Warning,
16    Error,
17}
18
19/// Smell category from refactoring literature.
20#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema, Default)]
21#[serde(rename_all = "snake_case")]
22pub enum SmellCategory {
23    #[default]
24    Bloaters,
25    OoAbusers,
26    ChangePreventers,
27    Dispensables,
28    Couplers,
29    Security,
30}
31
32/// Source location of a finding.
33#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, Default)]
34pub struct Location {
35    pub path: PathBuf,
36    pub start_line: usize,
37    pub end_line: usize,
38    pub name: Option<String>,
39}
40
41/// A single analysis finding.
42#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, Default)]
43pub struct Finding {
44    pub smell_name: String,
45    pub category: SmellCategory,
46    pub severity: Severity,
47    pub location: Location,
48    pub message: String,
49    pub suggested_refactorings: Vec<String>,
50    /// The actual measured value (e.g. line count, complexity score).
51    #[serde(skip_serializing_if = "Option::is_none")]
52    pub actual_value: Option<f64>,
53    /// The threshold that was exceeded to produce this finding.
54    #[serde(skip_serializing_if = "Option::is_none")]
55    pub threshold: Option<f64>,
56}
57
58/// Analysis context passed to plugins.
59pub struct AnalysisContext<'a> {
60    pub file: &'a SourceFile,
61    pub model: &'a SourceModel,
62}
63
64/// Core trait that all analyzers implement.
65pub trait Plugin: Send + Sync {
66    /// Unique identifier for this plugin.
67    fn name(&self) -> &str;
68
69    /// Plugin version (e.g. "1.0.0").
70    fn version(&self) -> &str {
71        env!("CARGO_PKG_VERSION")
72    }
73
74    /// Short description of what the plugin detects.
75    fn description(&self) -> &str {
76        ""
77    }
78
79    /// List of authors.
80    fn authors(&self) -> Vec<String> {
81        vec![env!("CARGO_PKG_AUTHORS").to_string()]
82    }
83
84    /// Run analysis on a single file and return findings.
85    fn analyze(&self, ctx: &AnalysisContext) -> Vec<Finding>;
86}