perl_lsp_tooling/perl_critic/
built_in.rs1use crate::perl_critic::{QuickFix, Severity, Violation, built_in_quick_fix, insertion_range};
2use perl_parser_core::Node;
3
4pub struct BuiltInAnalyzer {
6 policies: Vec<Box<dyn Policy>>,
8}
9
10pub trait Policy: Send + Sync {
12 fn name(&self) -> &str;
14 fn severity(&self) -> Severity;
16 fn analyze(&self, ast: &Node, content: &str) -> Vec<Violation>;
18}
19
20struct RequireUseStrict;
22
23impl Policy for RequireUseStrict {
24 fn name(&self) -> &str {
25 "TestingAndDebugging::RequireUseStrict"
26 }
27
28 fn severity(&self) -> Severity {
29 Severity::Harsh
30 }
31
32 fn analyze(&self, _ast: &Node, content: &str) -> Vec<Violation> {
33 missing_use_statement_violation(
34 self,
35 content,
36 "strict",
37 "Always use strict to catch common mistakes",
38 )
39 }
40}
41
42struct RequireUseWarnings;
44
45impl Policy for RequireUseWarnings {
46 fn name(&self) -> &str {
47 "TestingAndDebugging::RequireUseWarnings"
48 }
49
50 fn severity(&self) -> Severity {
51 Severity::Harsh
52 }
53
54 fn analyze(&self, _ast: &Node, content: &str) -> Vec<Violation> {
55 missing_use_statement_violation(
56 self,
57 content,
58 "warnings",
59 "Always use warnings to catch potential issues",
60 )
61 }
62}
63
64impl Default for BuiltInAnalyzer {
65 fn default() -> Self {
66 Self { policies: vec![Box::new(RequireUseStrict), Box::new(RequireUseWarnings)] }
67 }
68}
69
70impl BuiltInAnalyzer {
71 pub fn new() -> Self {
73 Self::default()
74 }
75
76 pub fn analyze(&self, ast: &Node, content: &str) -> Vec<Violation> {
78 let mut violations = Vec::new();
79 for policy in &self.policies {
80 violations.extend(policy.analyze(ast, content));
81 }
82 violations
83 }
84
85 pub fn get_quick_fix(&self, violation: &Violation, _content: &str) -> Option<QuickFix> {
87 built_in_quick_fix(violation)
88 }
89}
90
91fn missing_use_statement_violation(
92 policy: &dyn Policy,
93 content: &str,
94 feature: &str,
95 explanation: &str,
96) -> Vec<Violation> {
97 if content.contains(&format!("use {feature}")) {
98 return Vec::new();
99 }
100
101 vec![Violation {
102 policy: policy.name().to_string(),
103 description: format!("Code does not use {feature}"),
104 explanation: explanation.to_string(),
105 severity: policy.severity(),
106 range: insertion_range(),
107 file: String::new(),
108 }]
109}