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 #[serde(default, skip_serializing_if = "crate::is_zero_usize")]
39 pub start_col: usize,
40 pub end_line: usize,
41 #[serde(default, skip_serializing_if = "crate::is_zero_usize")]
43 pub end_col: usize,
44 pub name: Option<String>,
45}
46
47#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, Default)]
49pub struct Finding {
50 pub smell_name: String,
51 pub category: SmellCategory,
52 pub severity: Severity,
53 pub location: Location,
54 pub message: String,
55 pub suggested_refactorings: Vec<String>,
56 #[serde(skip_serializing_if = "Option::is_none")]
58 pub actual_value: Option<f64>,
59 #[serde(skip_serializing_if = "Option::is_none")]
61 pub threshold: Option<f64>,
62}
63
64pub struct AnalysisContext<'a> {
66 pub file: &'a SourceFile,
67 pub model: &'a SourceModel,
68}
69
70pub trait Plugin: Send + Sync {
72 fn name(&self) -> &str;
74
75 fn version(&self) -> &str {
77 env!("CARGO_PKG_VERSION")
78 }
79
80 fn description(&self) -> &str {
82 ""
83 }
84
85 fn authors(&self) -> Vec<String> {
87 vec![env!("CARGO_PKG_AUTHORS").to_string()]
88 }
89
90 fn smells(&self) -> Vec<String> {
94 Vec::new()
95 }
96
97 fn analyze(&self, ctx: &AnalysisContext) -> Vec<Finding>;
99}
100
101pub fn func_location(path: &std::path::Path, f: &crate::FunctionInfo) -> Location {
103 Location {
104 path: path.into(),
105 start_line: f.start_line,
106 start_col: f.name_col,
107 end_line: f.start_line,
108 end_col: f.name_end_col,
109 name: Some(f.name.clone()),
110 }
111}
112
113pub fn class_location(path: &std::path::Path, c: &crate::ClassInfo) -> Location {
115 Location {
116 path: path.into(),
117 start_line: c.start_line,
118 start_col: c.name_col,
119 end_line: c.start_line,
120 end_col: c.name_end_col,
121 name: Some(c.name.clone()),
122 }
123}