perl_diagnostics/codes/mod.rs
1//! Diagnostic codes, severity levels, tags, and categories.
2//!
3//! This module contains the canonical definitions of all diagnostic codes used
4//! throughout the Perl LSP ecosystem. These codes are stable and can be
5//! referenced in documentation and error messages.
6//!
7//! # Code Ranges
8//!
9//! | Range | Category |
10//! |-------------|---------------------------|
11//! | PL001-PL099 | Parser diagnostics |
12//! | PL100-PL199 | Strict/warnings |
13//! | PL200-PL299 | Package/module |
14//! | PL300-PL399 | Subroutine |
15//! | PL400-PL499 | Best practices |
16//! | PL500-PL599 | Deprecated syntax |
17//! | PL600-PL699 | Security |
18//! | PL700-PL799 | Import |
19//! | PL800-PL899 | Heredoc anti-patterns |
20//! | PL900-PL999 | Version compatibility |
21//! | PC001-PC005 | Perl::Critic violations |
22
23use std::fmt;
24
25mod category;
26mod metadata;
27mod severity;
28mod tag;
29
30pub use category::DiagnosticCategory;
31pub use severity::DiagnosticSeverity;
32pub use tag::DiagnosticTag;
33
34/// Stable diagnostic codes for Perl LSP.
35///
36/// Each code has a fixed string representation and associated metadata.
37#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
38#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
39pub enum DiagnosticCode {
40 // Parser diagnostics (PL001-PL099)
41 /// General parse error
42 #[default]
43 ParseError,
44 /// Syntax error
45 SyntaxError,
46 /// Unexpected end-of-file
47 UnexpectedEof,
48
49 // Strict/warnings (PL100-PL199)
50 /// Missing 'use strict' pragma
51 MissingStrict,
52 /// Missing 'use warnings' pragma
53 MissingWarnings,
54 /// Unused variable
55 UnusedVariable,
56 /// Undefined variable
57 UndefinedVariable,
58 /// Variable shadowing an outer declaration
59 VariableShadowing,
60 /// Variable redeclared in the same scope
61 VariableRedeclaration,
62 /// Duplicate parameter in a subroutine signature
63 DuplicateParameter,
64 /// Subroutine parameter shadows a global variable
65 ParameterShadowsGlobal,
66 /// Subroutine parameter is declared but never used
67 UnusedParameter,
68 /// Bareword used where a quoted string is expected (under strict)
69 UnquotedBareword,
70 /// Variable used before being initialized
71 UninitializedVariable,
72 /// Pragma name appears to be misspelled
73 MisspelledPragma,
74 /// Capture variable ($1, $2, etc.) used without a preceding regex match in scope
75 CaptureVarWithoutRegexMatch,
76
77 // Package/module (PL200-PL299)
78 /// Missing package declaration
79 MissingPackageDeclaration,
80 /// Duplicate package declaration
81 DuplicatePackage,
82
83 // Subroutine (PL300-PL399)
84 /// Duplicate subroutine definition
85 DuplicateSubroutine,
86 /// Missing explicit return statement
87 MissingReturn,
88 /// Invalid character(s) in a subroutine prototype
89 ///
90 /// Perl only allows `$`, `@`, `%`, `&`, `*`, `\`, `;`, `+`, `_`, and
91 /// spaces in old-style prototypes. Any other character triggers Perl's
92 /// "Illegal character in prototype" warning.
93 InvalidPrototype,
94 /// Same-file Moo/Moose roles provide conflicting methods
95 RoleConflict,
96 /// Exported subroutine lacks POD documentation
97 MissingPodCoverage,
98
99 // Best practices (PL400-PL499)
100 /// Bareword filehandle usage
101 BarewordFilehandle,
102 /// Two-argument open() call
103 TwoArgOpen,
104 /// Implicit return value
105 ImplicitReturn,
106 /// Assignment used where a comparison was likely intended
107 AssignmentInCondition,
108 /// Numeric comparison against a potentially undefined value
109 NumericComparisonWithUndef,
110 /// printf/sprintf format specifier count does not match argument count
111 PrintfFormatMismatch,
112 /// Statement that cannot be reached due to preceding unconditional exit
113 UnreachableCode,
114 /// `$@` / `$EVAL_ERROR` reads that are not paired with a nearby `eval`/`try`
115 EvalErrorFlow,
116 /// Duplicate key in a hash literal or hash reference constructor
117 DuplicateHashKey,
118 /// `goto LABEL` references a label that does not exist in this file
119 GotoUndefinedLabel,
120 /// `next`/`last`/`redo LABEL` references a label that does not exist in this file
121 LoopControlUndefinedLabel,
122
123 // Pragma pitfalls / deprecated syntax (PL500-PL599)
124 /// Use of deprecated defined(@array) / defined(%hash)
125 DeprecatedDefined,
126 /// Use of deprecated $[ array base variable
127 DeprecatedArrayBase,
128 /// `use strict` appears only inside a phase block and does not affect file scope
129 PhaseScopedStrictPragma,
130 /// `use warnings` appears only inside a phase block and does not affect file scope
131 PhaseScopedWarningsPragma,
132
133 // Security (PL600-PL699)
134 /// String eval is a security risk
135 SecurityStringEval,
136 /// Backtick/qx command execution detected
137 SecurityBacktickExec,
138 /// Global assignment to `$SIG{__DIE__}` / `$SIG{__WARN__}`
139 SecuritySignalHandler,
140 /// `system()` call executes shell commands
141 SecuritySystemCall,
142 /// `exec()` call replaces the current process with a shell command
143 SecurityExecCall,
144 /// Pipe-open `open(FH, "|-", ...)` / `open(FH, "-|", ...)` executes shell commands
145 SecurityPipeOpen,
146 /// `readpipe()` function call executes shell commands (equivalent to qx//)
147 SecurityReadpipe,
148
149 // Import (PL700-PL799)
150 /// Module appears to be unused
151 UnusedImport,
152 /// Module not found in workspace or configured include paths
153 ModuleNotFound,
154
155 // Heredoc anti-patterns (PL800-PL899)
156 /// Heredoc used inside a format block
157 HeredocInFormat,
158 /// Heredoc used inside a BEGIN block
159 HeredocInBegin,
160 /// Heredoc delimiter is dynamic (variable interpolation)
161 HeredocDynamicDelimiter,
162 /// Heredoc used inside a source filter
163 HeredocInSourceFilter,
164 /// Heredoc used inside a regex code block
165 HeredocInRegexCode,
166 /// Heredoc used inside string eval
167 HeredocInEval,
168 /// Heredoc used with a tied filehandle
169 HeredocTiedHandle,
170
171 // Version compatibility (PL900-PL999)
172 /// Use of a Perl feature not available in the declared version
173 VersionIncompatFeature,
174
175 // Perl::Critic violations (PC001-PC005)
176 /// Perl::Critic brutal (severity 1) violation
177 CriticSeverity1,
178 /// Perl::Critic cruel (severity 2) violation
179 CriticSeverity2,
180 /// Perl::Critic harsh (severity 3) violation
181 CriticSeverity3,
182 /// Perl::Critic stern (severity 4) violation
183 CriticSeverity4,
184 /// Perl::Critic gentle (severity 5) violation
185 CriticSeverity5,
186}
187
188impl fmt::Display for DiagnosticCode {
189 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
190 write!(f, "{}", self.as_str())
191 }
192}