PHPantom — CLI Fix Command¶
The fix subcommand applies automated code fixes across a PHP project,
modeled after php-cs-fixer. Each "rule" corresponds to a diagnostic code
and its associated code action.
Implemented Rules¶
unused_import — Remove unused imports¶
Detects unused use statements and removes them. Handles simple imports,
group imports (removing individual members), and blank-line collapsing to
keep formatting clean.
Planned Native Rules¶
These rules use PHPantom's own diagnostics and do not require external tools.
FX1. deprecated — Replace deprecated symbol usage¶
Prerequisite: The existing replace_deprecated code action
(src/code_actions/replace_deprecated.rs), already implemented and
shipped as an LSP quickfix.
When a symbol carries a #[Deprecated(replacement: "...")] attribute
(the phpstorm-stubs convention, using %parametersList%,
%parameter0%, %class% template placeholders), automatically apply
the replacement. The action already does this mechanically from the
structured attribute, not from free-text message parsing; the
remaining work is wiring it into fix.rs's NATIVE_RULES the same
way unused_import is wired.
FX2. unused_variable — Remove unused variables¶
The unused-variable diagnostic already ships
(src/diagnostics/unused_variables.rs), so this rule's diagnostic
prerequisite is satisfied. There is no code action yet to remove the
assignment, so this rule needs both a code action and CLI wiring:
remove assignments to variables that are never read, skipping
variables with side effects in the RHS (method calls, function calls).
When the RHS is pure (literal, property access, simple expression),
remove the entire statement.
FX7. add_return_type — Generate @return docblocks from function bodies¶
The return-type inference this needs already exists and is shared by
two other consumers: the docblock-generation completion item (typing
/** above a function) and the "Update docblock to match signature"
quickfix's enrichment of an existing @return tag
(enrichment_return_type in
src/code_actions/phpstan/fix_return_type/inference.rs). Neither of
those triggers fires for a function that has no docblock at all, so
this rule still needs a new trigger path (a code action, or a
dedicated fix-CLI pass) that adds a fresh @return tag when a
function or method has a native array return type (or no return
type at all) and the body contains enough information to infer a
specific element type, e.g. @return list<Butterfly>.
This lets teams that want to reach PHPStan level 6 (require return type declarations) run a single command and get specific, useful return types across the entire codebase for free, instead of adding them by hand file by file.
Planned PHPStan Rules¶
These rules require running PHPStan first to collect diagnostics.
They are gated behind --with-phpstan.
FX3. phpstan.return.unusedType — Remove unused type from return union¶
Backlog ID: H10
The underlying logic already ships as the "Remove unused return type"
LSP quickfix (src/code_actions/phpstan/remove_unused_return_type.rs,
matching PHPStan identifier return.unusedType): it parses the unused
type from PHPStan's message, finds the return type (native or
@return), removes the unused member from the union or intersection,
and simplifies a resulting single-member union. What remains for this
rule is exclusively CLI wiring: invoking the quickfix's resolve
function headlessly from fix.rs against diagnostics collected via
--with-phpstan.
FX4. phpstan.missingType.iterableValue — Add @return with iterable type¶
Backlog ID: H17
The underlying logic already ships as the "Add @return type" LSP
quickfix (src/code_actions/phpstan/add_iterable_type.rs, matching
PHPStan identifier missingType.iterableValue): it infers the element
type from return statements (array literals, variable types, new
ClassName() expressions) and falls back to <mixed> only when
inference cannot determine a concrete type. What remains for this rule
is exclusively CLI wiring, same as FX3.
FX5. phpstan.property.unused / phpstan.method.unused — Remove unused member¶
Backlog ID: H19
When PHPStan reports an unused property, method, or class constant, remove the entire declaration including its docblock.
FX6. phpstan.generics.callSiteVarianceRedundant — Remove redundant variance¶
Backlog ID: H20
Strip covariant or contravariant keywords from generic type
arguments in docblocks when PHPStan reports them as redundant.
Infrastructure¶
Rule selection¶
Rules are identified by their diagnostic code string:
- Native rules: bare identifiers (e.g. unused_import)
- PHPStan rules: prefixed with phpstan. (e.g. phpstan.return.unusedType)
When no --rule flags are provided, all "preferred" native rules run.
A rule is "preferred" if its corresponding code action has
is_preferred: true in the LSP protocol.
PHPStan rules only run when --with-phpstan is passed. This is an
explicit opt-in because PHPStan adds significant runtime (it must
analyze the entire project first).
PHPStan integration¶
The CLI already accepts --with-phpstan (src/main.rs, src/fix.rs),
but today it only relaxes rule validation; no PHPStan process is ever
run from fix.rs. The batch-invocation and JSON-parsing pieces this
needs already exist elsewhere and just need to be called from the fix
pipeline:
- Run PHPStan on all target files (or the entire project if no path
filter is given) in a single batch invocation.
run_phpstan_workspaceinsrc/phpstan.rsalready does this (used today by the LSP's workspace-wide external-tool diagnostic proxy). - Parse the JSON output to collect diagnostics per file.
run_phpstan_workspacealready returns aHashMap<PathBuf, Vec<Diagnostic>>with eachDiagnostic.codeset to the PHPStan identifier (e.g.return.unusedType). - Match diagnostics to registered PHPStan rules by prefixing the
diagnostic code with
phpstan.and comparing to the requested rule strings. - For each matched diagnostic, invoke the corresponding code action's
resolve function headlessly and apply the resulting edit. This part
is unwritten: the existing PHPStan quickfixes
(
src/code_actions/phpstan/) are wired for the LSP code-action protocol, not for headless batch invocation fromfix.rs.
To maximize efficiency, PHPStan runs once for all files rather than per-file.
Dry-run mode¶
--dry-run reports what would change without writing files. Exit code
2 indicates fixable issues were found. This is useful for CI
pipelines that want to enforce code style without modifying files.
Idempotency¶
Running fix twice should produce the same result as running it once.
Each rule must be idempotent: if the fix has already been applied, the
rule should detect no issues and make no changes.
Exit codes¶
| Code | Meaning |
|---|---|
| 0 | Success (fixes applied, or nothing to fix) |
| 1 | Error (bad arguments, write failure, etc.) |
| 2 | Dry-run found fixable issues |