class

Analyzer::Haskell::Cli

Inherits CliEndpointSupport < Analyzer < FileHelper < Reference < Object

Surfaces the command-line attack surface of Haskell programs as cli:// endpoints: optparse-applicative (long/argument/command), turtle (Turtle.Options: optText/optInt/optPath/switch/arg/argText) plus getEnv reads. Line-scan, merged by URL.

Constants

ARGUMENT = /(?<![A-Za-z0-9_'])argument\b.*?\bmetavar\s+"([A-Za-z0-9][\w-]*)"/
COMMAND = /(?<![A-Za-z0-9_'])command\s+"([A-Za-z0-9][\w-]*)"/
GET_ENV = /(?<![A-Za-z0-9_'])(?:getEnv|lookupEnv)\s+"([A-Za-z0-9_]\w*)"/
LONG = /(?<![A-Za-z0-9_'])long\s+"([A-Za-z0-9][\w-]*)"/
MARKERS = /\bimport\s+(?:qualified\s+)?Options\.Applicative\b|\b(?:execParser|strOption|subparser|hsubparser)\b|\bimport\s+(?:qualified\s+)?System\.Console\.(?:GetOpt|CmdArgs)\b|\bgetArgs\b|#{TURTLE_MARKERS}/
TEST_PATH_RE = Regex.union("/test/", "_spec.")

Per-path test-file gate. A precompiled Regex.union (PCRE2 JIT) replaces the two OR-ed String#includes? scans it used to run -- provably equivalent since union auto-escapes each literal, and a single regex pass over lower is cheaper than two substring scans.

TURTLE_ARG = /(?<![A-Za-z0-9_'])arg(?:Text|Int|Integer|Double|Read|Path)\s+"([A-Za-z0-9][\w-]*)"/

argText plus the type-suffixed positional combinators, mirroring the TURTLE_OPT alternation above.

TURTLE_ARG_FN = /(?<![A-Za-z0-9_'])arg\s+(?:[A-Za-z_][\w.']*|\([^()]*\))\s+"([A-Za-z0-9][\w-]*)"\s+"[^"]*"/

arg (the generic reader-based combinator) is an even more common bare word than switch (ordinary local variables/parameters are routinely named arg). Real usage is always arg <reader> "name" "desc": the reader is an identifier/qualified-name or a parenthesized expression, and BOTH the name and description string literals are required -- a stray f arg x "str" call/comment only has one trailing string and won't match.

TURTLE_MARKERS = /\bimport\s+(?:qualified\s+)?Turtle\.Options\b|\bimport\s+(?:qualified\s+)?Turtle\b\s*\([^)]*\boptions\b[^)]*\)/

Turtle re-exports Turtle.Options from the top-level Turtle module, which is used pervasively for plain shell scripting too, so gate on either the qualified submodule import or an explicit options name in the unqualified import list, never a bare import Turtle.

TURTLE_OPT = /(?<![A-Za-z0-9_'])opt(?:Text|Int|Integer|Double|Path|Read|Bool)\s+"([A-Za-z0-9][\w-]*)"/

Turtle.Options: optText/optInt/optPath/... and switch take the flag name as their own first quoted argument (no long "..." wrapper), so these need dedicated regexes distinct from LONG above.

TURTLE_SWITCH = /(?<![A-Za-z0-9_'])switch\s+"([A-Za-z0-9][\w-]*)"\s+'.'\s+"[^"]*"/

switch is a bare, extremely common Haskell identifier (also used by optparse-applicative itself, and as a plain string-pattern dispatch function). Real Turtle usage is always the full 3-argument shape switch "name" 'c' "desc"; require the trailing short-char + description so we don't fire on unrelated switch "x" = ... equations.

WEB_RE = /\bimport\s+(?:qualified\s+)?(?:Web\.Scotty|Servant|Yesod|Network\.Wai)\b/

Class methods

tech_name
Source

Instance methods

analyze
Source
tech

Instance-side view of the same declaration. The per-file rescues live on this base class, which has no way to name the analyzer that is running inside them, so a skipped file could not be attributed to a tech. Deriving it from analyzer_for keeps the name written exactly once.

Source