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}