Skip to main content

perl_parser/heredoc_anti_patterns/
model.rs

1//! Shared anti-pattern data model types.
2
3/// Source location of a detected anti-pattern.
4///
5/// All three coordinates are provided so callers can serve both LSP (line/column)
6/// and byte-level (offset) consumers without re-computing positions.
7#[derive(Debug, Clone, PartialEq)]
8pub struct Location {
9    /// Zero-based line number within the scanned source fragment.
10    pub line: usize,
11    /// Zero-based column (byte offset from the start of the line).
12    pub column: usize,
13    /// Absolute byte offset from the start of the scanned source fragment.
14    pub offset: usize,
15}
16
17/// Diagnostic severity level for a detected anti-pattern.
18#[derive(Debug, Clone, PartialEq)]
19pub enum Severity {
20    /// The construct will likely cause a runtime or parse failure.
21    Error,
22    /// The construct works but is fragile or difficult to analyze statically.
23    Warning,
24    /// The construct is valid but could be improved for readability or tooling support.
25    Info,
26}
27
28/// A specific category of heredoc-related anti-pattern found in Perl source.
29///
30/// Each variant captures the [`Location`] of the offending construct plus any
31/// context needed to produce a useful diagnostic message.
32#[derive(Debug, Clone, PartialEq)]
33pub enum AntiPattern {
34    /// A heredoc declared inside a `format` body.
35    FormatHeredoc { location: Location, format_name: String, heredoc_delimiter: String },
36    /// A heredoc declared inside a `BEGIN { ... }` block, evaluated at compile time.
37    BeginTimeHeredoc { location: Location, heredoc_content: String, side_effects: Vec<String> },
38    /// A heredoc whose terminator is determined by a variable or expression at runtime.
39    DynamicHeredocDelimiter { location: Location, expression: String },
40    /// A `use Filter::*` statement that may rewrite source before static analysis runs.
41    SourceFilterHeredoc { location: Location, module: String },
42    /// A heredoc embedded inside a `(?{ ... })` regex code block.
43    RegexCodeBlockHeredoc { location: Location },
44    /// A heredoc embedded inside a string argument to `eval`.
45    EvalStringHeredoc { location: Location },
46    /// A heredoc written to a filehandle that has been `tie`d to a custom class.
47    TiedHandleHeredoc { location: Location, handle_name: String },
48}
49
50/// A fully-formed diagnostic produced by the anti-pattern detector.
51///
52/// Contains everything needed to display a problem in an IDE or report:
53/// the severity, the matched pattern (with location), a human-readable message,
54/// a longer explanation, an optional suggested fix, and `perldoc` references.
55#[derive(Debug, Clone, PartialEq)]
56pub struct Diagnostic {
57    /// How serious the problem is.
58    pub severity: Severity,
59    /// The specific anti-pattern that triggered this diagnostic.
60    pub pattern: AntiPattern,
61    /// Short one-line summary suitable for an IDE problem marker.
62    pub message: String,
63    /// Longer explanation of why the construct is problematic.
64    pub explanation: String,
65    /// Optional concrete suggestion for fixing the problem.
66    pub suggested_fix: Option<String>,
67    /// Relevant `perldoc` pages or documentation references.
68    pub references: Vec<String>,
69}