1use schemars::JsonSchema;
2use serde::{Deserialize, Serialize};
3use std::path::PathBuf;
4
5use crate::{SourceFile, SourceModel};
6
7#[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#[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#[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#[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 #[serde(skip_serializing_if = "Option::is_none")]
52 pub actual_value: Option<f64>,
53 #[serde(skip_serializing_if = "Option::is_none")]
55 pub threshold: Option<f64>,
56}
57
58pub struct AnalysisContext<'a> {
60 pub file: &'a SourceFile,
61 pub model: &'a SourceModel,
62}
63
64pub trait Plugin: Send + Sync {
66 fn name(&self) -> &str;
68
69 fn version(&self) -> &str {
71 env!("CARGO_PKG_VERSION")
72 }
73
74 fn description(&self) -> &str {
76 ""
77 }
78
79 fn authors(&self) -> Vec<String> {
81 vec![env!("CARGO_PKG_AUTHORS").to_string()]
82 }
83
84 fn analyze(&self, ctx: &AnalysisContext) -> Vec<Finding>;
86}