Skip to content

Offer PHPStan's --fix as auto-fixer in the phpstan task - #1238

Open
Kanti wants to merge 2 commits into
phpro:v2.xfrom
Kanti:ccr-377c09f1-bxqh6w
Open

Kanti wants to merge 2 commits into
phpro:v2.xfrom
Kanti:ccr-377c09f1-bxqh6w

Conversation

@Kanti

@Kanti Kanti commented Nov 3, 2026 •

Copy link
Copy Markdown
Contributor
Q A
Branch v2.x
Bug fix? no
New feature? yes
BC breaks? no
Deprecations? no
Documented? yes
Fixed tickets -

PHPStan 2.3.5 made many built-in errors auto-fixable (e.g. method.missingOverride, cast.useless, phpunit.*). It marks them with 🔧 and ends its report with "Run PHPStan again with --fix".

This PR plugs that into GrumPHP's fixer the same way as the other fixable tasks (ECS, Rector, Mago): when the analysis fails and PHPStan reports fixable errors, the phpstan task returns a FixableTaskResult that reruns the same phpstan analyse command with --fix (same files, configuration, level and memory limit).

Why only when PHPStan reports fixable errors?

  • Most PHPStan errors (e.g. type errors) cannot be fixed automatically. In that case phpstan analyse --fix exits with 1 and "No fixable errors found", so GrumPHP would ask to fix and then report a failing fixer.
  • Older PHPStan versions never print the hint, so they keep the current behaviour. (In PHPStan ≤ 2.1, --fix launched PHPStan Pro instead of fixing.)

The hint for fixable ignored errors (--fix-ignored) is deliberately not taken into account, since ignored errors don't make the task fail. If PHPStan ever rewords the hint, the task falls back to the current non-fixable behaviour.

Tested manually against the PHPStan phars

  • 2.3.5 with a fixable and a non-fixable error: --fix exits with 0 even though the non-fixable error remains, the fixer reports ✔ and only #[\Override] was added.
  • 2.3.5 with only non-fixable errors: no fixer offered.
  • 2.3.4: no fixer offered, behaviour unchanged.
  • PHPStan passes the given paths on to its fix rounds, so only the files analysed by GrumPHP are changed.

The docs mention that --fix is experimental in PHPStan and also removes unmatched ignoreErrors entries from the configuration/baseline and unmatched @phpstan-ignore comments.

New Task Checklist:

  • Are the dependencies added to the composer.json suggestions? (phpstan/phpstan is already suggested)
  • Is the doc/tasks.md file updated? (PHPStan is already listed, no change needed)
  • Are the task parameters documented? (no new parameters, the auto-fixing behaviour is documented in doc/tasks/phpstan.md)
  • Is the task registered in the tasks.yml file? (already registered)
  • Does the task contains phpunit tests? (test/Unit/Task/PhpStanTest.php covers fixable, non-fixable and fixable-ignored output and the fix command)
  • Is the configuration having logical allowed types? (configuration unchanged)
  • Does the task run in the correct context? (unchanged: pre-commit and run)
  • Is the run() method readable?
  • Is the run() method using the configuration correctly? (the fix command reuses the same arguments)
  • Are all CI services returning green?

Kanti added 2 commits November 3, 2026 13:33
PHPStan 2.3.5 marks errors it can fix automatically and suggests to run
it again with --fix. When the analysis reports such errors, the phpstan
task now returns a fixable result that reruns the same command with
--fix, like the other fixable tasks.

The fixer is only offered when PHPStan reports fixable errors: without
them, "phpstan analyse --fix" fails with "No fixable errors found".
Since symfony/yaml 7.4.22 and 8.1.10, ParseException::getSnippet() and
ParseException::getParsedFile() are declared as nullable. Psalm fails on
the highest dependencies, and a parse error without snippet ends in a
TypeError when creating the YamlLintError. Fall back to an empty string.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant