alexandr-penkin/psalm-fixer
最新稳定版本:0.0.9
Composer 安装命令:
composer require alexandr-penkin/psalm-fixer
包简介
Automatic fixer for Psalm static analysis issues via AST transformations
README 文档
README
Automatic fixing of Psalm static analysis issues via AST transformations using nikic/php-parser.
psalm-fixer reads Psalm's JSON output, matches each issue to a registered fixer, and rewrites source files using a format-preserving printer so diffs stay minimal.
Installation
composer require alexandr-penkin/psalm-fixer --dev
Usage
# Run Psalm with JSON output and pipe to the fixer vendor/bin/psalm --output-format=json | vendor/bin/psalm-fixer fix - # Or via file vendor/bin/psalm --output-format=json > psalm-issues.json vendor/bin/psalm-fixer fix psalm-issues.json # Preview without writing (shows a unified diff) vendor/bin/psalm-fixer fix psalm-issues.json --diff # Fix only specific issue types vendor/bin/psalm-fixer fix psalm-issues.json --issue-type=RedundantCast,MissingOverrideAttribute # Fix only files matching a pattern vendor/bin/psalm-fixer fix psalm-issues.json --file=src/Foo.php # Fix issues listed in a Psalm baseline XML file vendor/bin/psalm-fixer fix --baseline=psalm-baseline.xml vendor/bin/psalm-fixer fix --baseline=psalm-baseline.xml --diff
fix is the default command, so vendor/bin/psalm-fixer psalm-issues.json also works.
Options
| Option | Description |
|---|---|
--baseline=path.xml |
Read issues from a Psalm baseline XML file instead of JSON. Mutually exclusive with the JSON source argument. |
--dry-run |
Show what would be fixed without modifying files |
--diff |
Show diff of changes (implies --dry-run) |
--backup |
Create .bak files before modifying |
--issue-type=X,Y |
Fix only the specified issue types (comma-separated) |
--file=pattern |
Fix only files matching the pattern (comma-separated) |
Fixing from a Psalm baseline
Psalm's baseline file (psalm-baseline.xml) records suppressed issues by file + issue type + code snippet, but without line numbers. With --baseline, psalm-fixer resolves each <code> snippet to a source line by trim + substring matching in document order — so two identical snippets in the baseline map to the first two matching source lines. If a snippet can't be found (stale baseline) or the referenced file is missing, the entry is skipped with a Baseline warning: message instead of failing the run.
Relative <file src="..."> paths are resolved against the directory containing the baseline XML.
Limitation: the baseline format does not include the original Psalm message text. Fixers that rely only on the AST node at the issue line work identically with baseline input — this includes MissingOverrideAttribute, RedundantCast, UnusedForeachValue, the null-safety set, TypeDoesNotContainNullFixer (direction is read from the comparison operator), and RedundantConditionFixer for literal if (true) / if (false) cases. Fixers that need the message to disambiguate (e.g. RedundantConditionFixer for "is never X" / "can never contain X" patterns, or ArgumentTypeCoercionFixer's expected-type lookup) report those issues as not fixed with a clear reason instead of producing a wrong rewrite — for them, prefer running with Psalm's JSON output as the source.
Other commands
# List all registered fixers with descriptions
vendor/bin/psalm-fixer list-fixers
Report output
After a run, psalm-fixer prints a summary grouped by:
- Fixed — issues successfully rewritten
- Unfixed — a fixer matched but could not apply the change (reason included)
- No fixer — no fixer is registered for the issue type
Supported Issue Types
CodeQuality — RedundantCast, RedundantIdentityWithTrue, UnusedForeachValue, UnusedClosureParam
ClassDesign — MissingOverrideAttribute, MissingClassConstType, PropertyNotSetInConstructor
NullSafety — PossiblyNullReference, PossiblyNullPropertyFetch, PossiblyNullArgument, PossiblyNullArrayAccess
TypeSafety — InvalidScalarArgument, RedundantCondition, TypeDoesNotContainNull, ArgumentTypeCoercion, PropertyTypeCoercion
Mixed — MixedArgument, MixedAssignment, MixedMethodCall, MixedReturnStatement, MixedPropertyFetch, MixedArrayAccess
Docblock — MismatchingDocblockPropertyType, UnusedPsalmSuppress
How it works
Psalm JSON ─┐
├─> Parser -> PsalmIssue value objects
Baseline XML ─┘
-> FileProcessor (groups issues by file, parses AST)
-> FixerRegistry (maps issue type -> fixer)
-> Fixer (mutates AST, returns FixResult)
-> format-preserving printer (writes file back)
Fixes are applied bottom-up (descending line order) so earlier edits don't shift positions of later ones. When a fixer changes the node type (e.g. -> to ?->) the format-preserving printer is bypassed and a full pretty-print is used as fallback.
Fix strategies
Most fixers either rewrite the AST directly (insert assert, unwrap if, drop redundant operand from &&, etc.) or fall back to attaching a @psalm-suppress <Type> annotation when no safe runtime rewrite exists. The suppress-fallback is used by ArgumentTypeCoercionFixer, PropertyTypeCoercionFixer and MixedAssignmentFixer for generic / template types and genuinely-mixed values where Psalm cannot infer a narrower type at the call site.
Adding a new fixer
- Create a class under
src/PsalmFixer/Fixer/<Category>/extendingAbstractFixer.- For fixers that locate an
ifstatement at the issue line, extendAbstractIfWalkingFixerinstead — it provides the recursive walk (through namespaces, classes, methods, control-flow blocks),spliceDeadBranch(), and&&-chain helpers (flattenAnd/buildAndChain). Implement justtryFixIf().
- For fixers that locate an
- Implement
getSupportedTypes()returning the Psalm issue type strings it handles. - Implement
getName(),getDescription(), andfix(). - Register it in
FixerRegistry::createDefault(). - Add unit tests in
tests/Unit/Fixer/.
Development
# Run the test suite vendor/bin/phpunit # Run a single test vendor/bin/phpunit tests/Unit/Fixer/RedundantCastFixerTest.php # Run Psalm on the project itself vendor/bin/psalm
Requirements
- PHP >= 8.0
- Psalm >= 6.15 (for JSON output generation)
License
MIT
统计信息
- 总下载量: 18
- 月度下载量: 0
- 日度下载量: 0
- 收藏数: 0
- 点击次数: 3
- 依赖项目数: 0
- 推荐数: 0
其他信息
- 授权协议: MIT
- 更新时间: 2026-05-11