use std::fmt;
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[repr(u8)]
pub enum DiagnosticSeverity {
Error = 1,
Warning = 2,
Information = 3,
Hint = 4,
}
impl DiagnosticSeverity {
pub fn to_lsp_value(self) -> u8 {
self as u8
}
}
impl fmt::Display for DiagnosticSeverity {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
DiagnosticSeverity::Error => write!(f, "error"),
DiagnosticSeverity::Warning => write!(f, "warning"),
DiagnosticSeverity::Information => write!(f, "info"),
DiagnosticSeverity::Hint => write!(f, "hint"),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum DiagnosticTag {
Unnecessary,
Deprecated,
}
impl DiagnosticTag {
pub fn to_lsp_value(self) -> u8 {
match self {
DiagnosticTag::Unnecessary => 1,
DiagnosticTag::Deprecated => 2,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum DiagnosticCode {
ParseError,
SyntaxError,
UnexpectedEof,
MissingStrict,
MissingWarnings,
UnusedVariable,
UndefinedVariable,
VariableShadowing,
VariableRedeclaration,
DuplicateParameter,
ParameterShadowsGlobal,
UnusedParameter,
UnquotedBareword,
UninitializedVariable,
MisspelledPragma,
MissingPackageDeclaration,
DuplicatePackage,
DuplicateSubroutine,
MissingReturn,
BarewordFilehandle,
TwoArgOpen,
ImplicitReturn,
AssignmentInCondition,
NumericComparisonWithUndef,
PrintfFormatMismatch,
DeprecatedDefined,
DeprecatedArrayBase,
SecurityStringEval,
SecurityBacktickExec,
UnusedImport,
ModuleNotFound,
HeredocInFormat,
HeredocInBegin,
HeredocDynamicDelimiter,
HeredocInSourceFilter,
HeredocInRegexCode,
HeredocInEval,
HeredocTiedHandle,
VersionIncompatFeature,
CriticSeverity1,
CriticSeverity2,
CriticSeverity3,
CriticSeverity4,
CriticSeverity5,
}
impl DiagnosticCode {
pub fn as_str(&self) -> &'static str {
match self {
DiagnosticCode::ParseError => "PL001",
DiagnosticCode::SyntaxError => "PL002",
DiagnosticCode::UnexpectedEof => "PL003",
DiagnosticCode::MissingStrict => "PL100",
DiagnosticCode::MissingWarnings => "PL101",
DiagnosticCode::UnusedVariable => "PL102",
DiagnosticCode::UndefinedVariable => "PL103",
DiagnosticCode::VariableShadowing => "PL104",
DiagnosticCode::VariableRedeclaration => "PL105",
DiagnosticCode::DuplicateParameter => "PL106",
DiagnosticCode::ParameterShadowsGlobal => "PL107",
DiagnosticCode::UnusedParameter => "PL108",
DiagnosticCode::UnquotedBareword => "PL109",
DiagnosticCode::UninitializedVariable => "PL110",
DiagnosticCode::MisspelledPragma => "PL111",
DiagnosticCode::MissingPackageDeclaration => "PL200",
DiagnosticCode::DuplicatePackage => "PL201",
DiagnosticCode::DuplicateSubroutine => "PL300",
DiagnosticCode::MissingReturn => "PL301",
DiagnosticCode::BarewordFilehandle => "PL400",
DiagnosticCode::TwoArgOpen => "PL401",
DiagnosticCode::ImplicitReturn => "PL402",
DiagnosticCode::AssignmentInCondition => "PL403",
DiagnosticCode::NumericComparisonWithUndef => "PL404",
DiagnosticCode::PrintfFormatMismatch => "PL405",
DiagnosticCode::DeprecatedDefined => "PL500",
DiagnosticCode::DeprecatedArrayBase => "PL501",
DiagnosticCode::SecurityStringEval => "PL600",
DiagnosticCode::SecurityBacktickExec => "PL601",
DiagnosticCode::UnusedImport => "PL700",
DiagnosticCode::ModuleNotFound => "PL701",
DiagnosticCode::HeredocInFormat => "PL800",
DiagnosticCode::HeredocInBegin => "PL801",
DiagnosticCode::HeredocDynamicDelimiter => "PL802",
DiagnosticCode::HeredocInSourceFilter => "PL803",
DiagnosticCode::HeredocInRegexCode => "PL804",
DiagnosticCode::HeredocInEval => "PL805",
DiagnosticCode::HeredocTiedHandle => "PL806",
DiagnosticCode::VersionIncompatFeature => "PL900",
DiagnosticCode::CriticSeverity1 => "PC001",
DiagnosticCode::CriticSeverity2 => "PC002",
DiagnosticCode::CriticSeverity3 => "PC003",
DiagnosticCode::CriticSeverity4 => "PC004",
DiagnosticCode::CriticSeverity5 => "PC005",
}
}
pub fn documentation_url(&self) -> Option<&'static str> {
let code = self.as_str();
if code.starts_with("PC") {
return None;
}
Some(match code {
"PL001" => "https://docs.perl-lsp.org/errors/PL001",
"PL002" => "https://docs.perl-lsp.org/errors/PL002",
"PL003" => "https://docs.perl-lsp.org/errors/PL003",
"PL100" => "https://docs.perl-lsp.org/errors/PL100",
"PL101" => "https://docs.perl-lsp.org/errors/PL101",
"PL102" => "https://docs.perl-lsp.org/errors/PL102",
"PL103" => "https://docs.perl-lsp.org/errors/PL103",
"PL104" => "https://docs.perl-lsp.org/errors/PL104",
"PL105" => "https://docs.perl-lsp.org/errors/PL105",
"PL106" => "https://docs.perl-lsp.org/errors/PL106",
"PL107" => "https://docs.perl-lsp.org/errors/PL107",
"PL108" => "https://docs.perl-lsp.org/errors/PL108",
"PL109" => "https://docs.perl-lsp.org/errors/PL109",
"PL110" => "https://docs.perl-lsp.org/errors/PL110",
"PL111" => "https://docs.perl-lsp.org/errors/PL111",
"PL200" => "https://docs.perl-lsp.org/errors/PL200",
"PL201" => "https://docs.perl-lsp.org/errors/PL201",
"PL300" => "https://docs.perl-lsp.org/errors/PL300",
"PL301" => "https://docs.perl-lsp.org/errors/PL301",
"PL400" => "https://docs.perl-lsp.org/errors/PL400",
"PL401" => "https://docs.perl-lsp.org/errors/PL401",
"PL402" => "https://docs.perl-lsp.org/errors/PL402",
"PL403" => "https://docs.perl-lsp.org/errors/PL403",
"PL404" => "https://docs.perl-lsp.org/errors/PL404",
"PL405" => "https://docs.perl-lsp.org/errors/PL405",
"PL500" => "https://docs.perl-lsp.org/errors/PL500",
"PL501" => "https://docs.perl-lsp.org/errors/PL501",
"PL600" => "https://docs.perl-lsp.org/errors/PL600",
"PL601" => "https://docs.perl-lsp.org/errors/PL601",
"PL700" => "https://docs.perl-lsp.org/errors/PL700",
"PL701" => "https://docs.perl-lsp.org/errors/PL701",
"PL800" => "https://docs.perl-lsp.org/errors/PL800",
"PL801" => "https://docs.perl-lsp.org/errors/PL801",
"PL802" => "https://docs.perl-lsp.org/errors/PL802",
"PL803" => "https://docs.perl-lsp.org/errors/PL803",
"PL804" => "https://docs.perl-lsp.org/errors/PL804",
"PL805" => "https://docs.perl-lsp.org/errors/PL805",
"PL806" => "https://docs.perl-lsp.org/errors/PL806",
"PL900" => "https://docs.perl-lsp.org/errors/PL900",
_ => return None,
})
}
pub fn severity(&self) -> DiagnosticSeverity {
match self {
DiagnosticCode::ParseError
| DiagnosticCode::SyntaxError
| DiagnosticCode::UnexpectedEof
| DiagnosticCode::UndefinedVariable
| DiagnosticCode::VariableRedeclaration
| DiagnosticCode::DuplicateParameter
| DiagnosticCode::UnquotedBareword => DiagnosticSeverity::Error,
DiagnosticCode::MissingStrict
| DiagnosticCode::MissingWarnings
| DiagnosticCode::UnusedVariable
| DiagnosticCode::VariableShadowing
| DiagnosticCode::ParameterShadowsGlobal
| DiagnosticCode::UnusedParameter
| DiagnosticCode::UninitializedVariable
| DiagnosticCode::MisspelledPragma
| DiagnosticCode::MissingPackageDeclaration
| DiagnosticCode::DuplicatePackage
| DiagnosticCode::DuplicateSubroutine
| DiagnosticCode::MissingReturn
| DiagnosticCode::BarewordFilehandle
| DiagnosticCode::TwoArgOpen
| DiagnosticCode::ImplicitReturn
| DiagnosticCode::AssignmentInCondition
| DiagnosticCode::NumericComparisonWithUndef
| DiagnosticCode::PrintfFormatMismatch
| DiagnosticCode::DeprecatedDefined
| DiagnosticCode::DeprecatedArrayBase
| DiagnosticCode::SecurityStringEval
| DiagnosticCode::SecurityBacktickExec
| DiagnosticCode::ModuleNotFound
| DiagnosticCode::VersionIncompatFeature
| DiagnosticCode::CriticSeverity1
| DiagnosticCode::CriticSeverity2 => DiagnosticSeverity::Warning,
DiagnosticCode::HeredocInFormat
| DiagnosticCode::HeredocInBegin
| DiagnosticCode::HeredocDynamicDelimiter
| DiagnosticCode::HeredocInSourceFilter
| DiagnosticCode::HeredocInRegexCode
| DiagnosticCode::HeredocInEval
| DiagnosticCode::HeredocTiedHandle => DiagnosticSeverity::Information,
DiagnosticCode::UnusedImport
| DiagnosticCode::CriticSeverity3
| DiagnosticCode::CriticSeverity4
| DiagnosticCode::CriticSeverity5 => DiagnosticSeverity::Hint,
}
}
pub fn tags(&self) -> &'static [DiagnosticTag] {
match self {
DiagnosticCode::UnusedVariable
| DiagnosticCode::UnusedParameter
| DiagnosticCode::UnusedImport => &[DiagnosticTag::Unnecessary],
DiagnosticCode::DeprecatedDefined | DiagnosticCode::DeprecatedArrayBase => {
&[DiagnosticTag::Deprecated]
}
_ => &[],
}
}
pub fn context_hint(&self) -> Option<&'static str> {
match self {
DiagnosticCode::ParseError => Some(
"The parser could not understand this code. \
Check for missing semicolons, unmatched brackets, or incorrect syntax.",
),
DiagnosticCode::SyntaxError => Some(
"Perl syntax error. Check for typos, missing operators, \
or unbalanced parentheses near this location.",
),
DiagnosticCode::UnexpectedEof => Some(
"The file ended unexpectedly. Check for unclosed blocks `{}`, \
heredocs, or multi-line strings.",
),
DiagnosticCode::MissingStrict => Some(
"Add `use strict;` at the top of your file. \
Strict mode catches common variable mistakes at compile time.",
),
DiagnosticCode::MissingWarnings => Some(
"Add `use warnings;` at the top of your file. \
Warnings highlight many common programming mistakes.",
),
DiagnosticCode::UnusedVariable => Some(
"This variable is declared but never used. \
Remove it, or prefix with `_` (e.g., `$_unused`) to suppress.",
),
DiagnosticCode::UndefinedVariable => Some(
"This variable was not declared with `my`, `our`, or `local`. \
Add `use strict;` and declare all variables before use.",
),
DiagnosticCode::MissingPackageDeclaration => Some(
"This file has no `package` declaration. \
Add `package MyModule;` at the top for module files.",
),
DiagnosticCode::DuplicatePackage => Some(
"This package name is declared more than once in the same file. \
Each package should appear once, or split into separate files.",
),
DiagnosticCode::DuplicateSubroutine => Some(
"A subroutine with this name is defined more than once. \
The later definition silently replaces the earlier one.",
),
DiagnosticCode::MissingReturn => Some(
"This subroutine has no explicit `return` statement. \
Add `return $value;` to make the return value clear.",
),
DiagnosticCode::BarewordFilehandle => Some(
"Bareword filehandles (e.g., `open FH, ...`) are global and unsafe. \
Use a lexical filehandle instead: `open my $fh, '<', $file or die $!;`",
),
DiagnosticCode::TwoArgOpen => Some(
"Two-argument `open()` is vulnerable to injection. \
Use three-argument form: `open my $fh, '<', $filename or die $!;`",
),
DiagnosticCode::ImplicitReturn => Some(
"The return value of this expression is used implicitly. \
Make it explicit with `return` or assign it to a variable.",
),
DiagnosticCode::AssignmentInCondition => Some(
"This looks like an assignment `=` inside a condition where \
a comparison `==` or `eq` was likely intended.",
),
DiagnosticCode::NumericComparisonWithUndef => Some(
"Comparing a potentially undefined value with a numeric operator \
produces a warning at runtime. Check for definedness first with `defined()`.",
),
DiagnosticCode::PrintfFormatMismatch => Some(
"The number of format specifiers does not match the number of arguments. \
Each %s/%d/%f/etc. consumes one argument (except %% which consumes none).",
),
DiagnosticCode::VariableShadowing => Some(
"This variable shadows an outer variable with the same name. \
Rename it to avoid confusion, or use the outer variable directly.",
),
DiagnosticCode::VariableRedeclaration => Some(
"This variable is declared again in the same scope. \
Remove the duplicate `my` declaration and reuse the existing variable.",
),
DiagnosticCode::DuplicateParameter => Some(
"This subroutine signature has a duplicate parameter name. \
Each parameter must have a unique name.",
),
DiagnosticCode::ParameterShadowsGlobal => Some(
"This subroutine parameter shadows a global (`our`) variable. \
Rename the parameter to avoid confusion with the global.",
),
DiagnosticCode::UnusedParameter => Some(
"This subroutine parameter is declared but never used. \
Remove it or prefix with `_` (e.g., `$_unused`) to suppress.",
),
DiagnosticCode::UnquotedBareword => Some(
"This bareword is used where a quoted string is expected. \
Under `use strict`, barewords are not allowed. Quote it: `'word'`.",
),
DiagnosticCode::UninitializedVariable => Some(
"This variable is used before being assigned a value. \
Initialize it before use to avoid `Use of uninitialized value` warnings.",
),
DiagnosticCode::MisspelledPragma => Some(
"This pragma name appears to be misspelled. \
Check the spelling and ensure the module is installed.",
),
DiagnosticCode::DeprecatedDefined => Some(
"`defined(@array)` and `defined(%hash)` are deprecated since Perl 5.6. \
Use `@array` or `%hash` directly in boolean context instead.",
),
DiagnosticCode::DeprecatedArrayBase => Some(
"The `$[` variable is deprecated. Array indices always start at 0 \
in modern Perl. Remove any assignment to `$[`.",
),
DiagnosticCode::SecurityStringEval => Some(
"String `eval` executes arbitrary code and is a security risk. \
Use block eval `eval { ... }` or safer alternatives.",
),
DiagnosticCode::SecurityBacktickExec => Some(
"Backticks/`qx()` execute shell commands and can be exploited. \
Use `system()` with a list form or IPC::Run for safer execution.",
),
DiagnosticCode::UnusedImport => Some(
"This module is imported but none of its exports appear to be used. \
Remove the `use` statement to reduce unnecessary dependencies.",
),
DiagnosticCode::ModuleNotFound => Some(
"This module was not found in the workspace or configured include paths. \
Install it with cpanm or add it to cpanfile.",
),
DiagnosticCode::HeredocInFormat => Some(
"Heredocs inside `format` blocks can cause subtle parsing issues. \
Extract the heredoc content into a variable before the format.",
),
DiagnosticCode::HeredocInBegin => Some(
"Heredocs inside `BEGIN` blocks may behave unexpectedly due to \
compile-time execution. Move the heredoc outside the BEGIN block.",
),
DiagnosticCode::HeredocDynamicDelimiter => Some(
"The heredoc delimiter contains a variable, making it dynamic. \
Use a static delimiter string to avoid surprising behavior.",
),
DiagnosticCode::HeredocInSourceFilter => Some(
"Heredocs inside source-filtered code may be mangled by the filter. \
Avoid combining heredocs with source filters.",
),
DiagnosticCode::HeredocInRegexCode => Some(
"Heredocs inside regex code blocks `(?{ ... })` can cause parsing failures. \
Move the heredoc content outside the regex.",
),
DiagnosticCode::HeredocInEval => Some(
"Heredocs inside string `eval` are fragile and error-prone. \
Use a variable or block eval instead.",
),
DiagnosticCode::HeredocTiedHandle => Some(
"Heredocs written to tied filehandles may not behave as expected. \
The tie interface may not handle multi-line heredoc output correctly.",
),
DiagnosticCode::VersionIncompatFeature => Some(
"This Perl feature requires a newer Perl version than declared. \
Update 'use vN.NN' or 'use feature' to enable it.",
),
DiagnosticCode::CriticSeverity1
| DiagnosticCode::CriticSeverity2
| DiagnosticCode::CriticSeverity3
| DiagnosticCode::CriticSeverity4
| DiagnosticCode::CriticSeverity5 => None,
}
}
pub fn from_message(msg: &str) -> Option<DiagnosticCode> {
let msg_lower = msg.to_lowercase();
if msg_lower.contains("use strict") {
Some(DiagnosticCode::MissingStrict)
} else if msg_lower.contains("use warnings") {
Some(DiagnosticCode::MissingWarnings)
} else if msg_lower.contains("unused variable") || msg_lower.contains("never used") {
Some(DiagnosticCode::UnusedVariable)
} else if msg_lower.contains("undefined") || msg_lower.contains("not declared") {
Some(DiagnosticCode::UndefinedVariable)
} else if msg_lower.contains("bareword filehandle") {
Some(DiagnosticCode::BarewordFilehandle)
} else if msg_lower.contains("two-argument") || msg_lower.contains("2-arg") {
Some(DiagnosticCode::TwoArgOpen)
} else if msg_lower.contains("parse error") || msg_lower.contains("syntax error") {
Some(DiagnosticCode::ParseError)
} else {
None
}
}
pub fn parse_code(code: &str) -> Option<DiagnosticCode> {
match code {
"PL001" => Some(DiagnosticCode::ParseError),
"PL002" => Some(DiagnosticCode::SyntaxError),
"PL003" => Some(DiagnosticCode::UnexpectedEof),
"PL100" => Some(DiagnosticCode::MissingStrict),
"PL101" => Some(DiagnosticCode::MissingWarnings),
"PL102" => Some(DiagnosticCode::UnusedVariable),
"PL103" => Some(DiagnosticCode::UndefinedVariable),
"PL104" => Some(DiagnosticCode::VariableShadowing),
"PL105" => Some(DiagnosticCode::VariableRedeclaration),
"PL106" => Some(DiagnosticCode::DuplicateParameter),
"PL107" => Some(DiagnosticCode::ParameterShadowsGlobal),
"PL108" => Some(DiagnosticCode::UnusedParameter),
"PL109" => Some(DiagnosticCode::UnquotedBareword),
"PL110" => Some(DiagnosticCode::UninitializedVariable),
"PL111" => Some(DiagnosticCode::MisspelledPragma),
"PL200" => Some(DiagnosticCode::MissingPackageDeclaration),
"PL201" => Some(DiagnosticCode::DuplicatePackage),
"PL300" => Some(DiagnosticCode::DuplicateSubroutine),
"PL301" => Some(DiagnosticCode::MissingReturn),
"PL400" => Some(DiagnosticCode::BarewordFilehandle),
"PL401" => Some(DiagnosticCode::TwoArgOpen),
"PL402" => Some(DiagnosticCode::ImplicitReturn),
"PL403" => Some(DiagnosticCode::AssignmentInCondition),
"PL404" => Some(DiagnosticCode::NumericComparisonWithUndef),
"PL405" => Some(DiagnosticCode::PrintfFormatMismatch),
"PL500" => Some(DiagnosticCode::DeprecatedDefined),
"PL501" => Some(DiagnosticCode::DeprecatedArrayBase),
"PL600" => Some(DiagnosticCode::SecurityStringEval),
"PL601" => Some(DiagnosticCode::SecurityBacktickExec),
"PL700" => Some(DiagnosticCode::UnusedImport),
"PL701" => Some(DiagnosticCode::ModuleNotFound),
"PL800" => Some(DiagnosticCode::HeredocInFormat),
"PL801" => Some(DiagnosticCode::HeredocInBegin),
"PL802" => Some(DiagnosticCode::HeredocDynamicDelimiter),
"PL803" => Some(DiagnosticCode::HeredocInSourceFilter),
"PL804" => Some(DiagnosticCode::HeredocInRegexCode),
"PL805" => Some(DiagnosticCode::HeredocInEval),
"PL806" => Some(DiagnosticCode::HeredocTiedHandle),
"PL900" => Some(DiagnosticCode::VersionIncompatFeature),
"PC001" => Some(DiagnosticCode::CriticSeverity1),
"PC002" => Some(DiagnosticCode::CriticSeverity2),
"PC003" => Some(DiagnosticCode::CriticSeverity3),
"PC004" => Some(DiagnosticCode::CriticSeverity4),
"PC005" => Some(DiagnosticCode::CriticSeverity5),
_ => None,
}
}
}
impl fmt::Display for DiagnosticCode {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.as_str())
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum DiagnosticCategory {
Parser,
StrictWarnings,
PackageModule,
Subroutine,
BestPractices,
Deprecated,
Security,
Import,
Heredoc,
PerlCritic,
}
impl DiagnosticCode {
pub fn category(&self) -> DiagnosticCategory {
match self {
DiagnosticCode::ParseError
| DiagnosticCode::SyntaxError
| DiagnosticCode::UnexpectedEof => DiagnosticCategory::Parser,
DiagnosticCode::MissingStrict
| DiagnosticCode::MissingWarnings
| DiagnosticCode::UnusedVariable
| DiagnosticCode::UndefinedVariable
| DiagnosticCode::VariableShadowing
| DiagnosticCode::VariableRedeclaration
| DiagnosticCode::DuplicateParameter
| DiagnosticCode::ParameterShadowsGlobal
| DiagnosticCode::UnusedParameter
| DiagnosticCode::UnquotedBareword
| DiagnosticCode::UninitializedVariable
| DiagnosticCode::MisspelledPragma => DiagnosticCategory::StrictWarnings,
DiagnosticCode::MissingPackageDeclaration | DiagnosticCode::DuplicatePackage => {
DiagnosticCategory::PackageModule
}
DiagnosticCode::DuplicateSubroutine | DiagnosticCode::MissingReturn => {
DiagnosticCategory::Subroutine
}
DiagnosticCode::BarewordFilehandle
| DiagnosticCode::TwoArgOpen
| DiagnosticCode::ImplicitReturn
| DiagnosticCode::AssignmentInCondition
| DiagnosticCode::NumericComparisonWithUndef
| DiagnosticCode::PrintfFormatMismatch => DiagnosticCategory::BestPractices,
DiagnosticCode::DeprecatedDefined | DiagnosticCode::DeprecatedArrayBase => {
DiagnosticCategory::Deprecated
}
DiagnosticCode::SecurityStringEval | DiagnosticCode::SecurityBacktickExec => {
DiagnosticCategory::Security
}
DiagnosticCode::UnusedImport | DiagnosticCode::ModuleNotFound => {
DiagnosticCategory::Import
}
DiagnosticCode::HeredocInFormat
| DiagnosticCode::HeredocInBegin
| DiagnosticCode::HeredocDynamicDelimiter
| DiagnosticCode::HeredocInSourceFilter
| DiagnosticCode::HeredocInRegexCode
| DiagnosticCode::HeredocInEval
| DiagnosticCode::HeredocTiedHandle => DiagnosticCategory::Heredoc,
DiagnosticCode::VersionIncompatFeature => DiagnosticCategory::BestPractices,
DiagnosticCode::CriticSeverity1
| DiagnosticCode::CriticSeverity2
| DiagnosticCode::CriticSeverity3
| DiagnosticCode::CriticSeverity4
| DiagnosticCode::CriticSeverity5 => DiagnosticCategory::PerlCritic,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_code_strings() {
assert_eq!(DiagnosticCode::ParseError.as_str(), "PL001");
assert_eq!(DiagnosticCode::MissingStrict.as_str(), "PL100");
assert_eq!(DiagnosticCode::CriticSeverity1.as_str(), "PC001");
}
#[test]
fn test_severity() {
assert_eq!(DiagnosticCode::ParseError.severity(), DiagnosticSeverity::Error);
assert_eq!(DiagnosticCode::UnusedVariable.severity(), DiagnosticSeverity::Warning);
assert_eq!(DiagnosticCode::CriticSeverity5.severity(), DiagnosticSeverity::Hint);
}
#[test]
fn test_from_message() {
assert_eq!(
DiagnosticCode::from_message("Missing 'use strict' pragma"),
Some(DiagnosticCode::MissingStrict)
);
assert_eq!(
DiagnosticCode::from_message("Unused variable $foo"),
Some(DiagnosticCode::UnusedVariable)
);
}
#[test]
fn test_from_str() {
assert_eq!(DiagnosticCode::parse_code("PL001"), Some(DiagnosticCode::ParseError));
assert_eq!(DiagnosticCode::parse_code("INVALID"), None);
}
#[test]
fn test_category() {
assert_eq!(DiagnosticCode::ParseError.category(), DiagnosticCategory::Parser);
assert_eq!(DiagnosticCode::MissingStrict.category(), DiagnosticCategory::StrictWarnings);
assert_eq!(DiagnosticCode::CriticSeverity1.category(), DiagnosticCategory::PerlCritic);
}
#[test]
fn test_tags() {
assert!(DiagnosticCode::UnusedVariable.tags().contains(&DiagnosticTag::Unnecessary));
assert!(DiagnosticCode::ParseError.tags().is_empty());
}
}