Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
65d23fb
Apply fix diffs in a single linear pass
ondrejmirtes Nov 2, 2026
31e428f
Compute fix diffs without quadratic suffix trimming
ondrejmirtes Nov 2, 2026
11d9209
Show fixable errors in table output again
ondrejmirtes Nov 2, 2026
5b859be
Support fixNode() in CollectedDataNode rules
ondrejmirtes Nov 2, 2026
6146ee4
Test fixes in traits
ondrejmirtes Nov 2, 2026
1879a3a
Fix nodes in the file set with RuleErrorBuilder::file()
ondrejmirtes Nov 2, 2026
8840a5a
Add RuleErrorBuilder::removeNode()
ondrejmirtes Nov 2, 2026
141661b
Apply fix diffs to file contents instead of a file path
ondrejmirtes Nov 2, 2026
6158a50
Add --fix-ignored
ondrejmirtes Nov 2, 2026
50f8efe
Register every fixNode() and removeNode() call of an error
ondrejmirtes Nov 2, 2026
ad39667
Remove statements left without items by a fix
ondrejmirtes Nov 2, 2026
374c814
Make RuleErrorBuilder::fixNode() and removeNode() public API
ondrejmirtes Nov 2, 2026
23e6a7c
Fix errors in rounds until nothing fixable is left
ondrejmirtes Nov 2, 2026
bb98ac2
Find fixed nodes by position instead of identity
ondrejmirtes Nov 2, 2026
ba0c59f
Show the progress and the result of every fix round
ondrejmirtes Nov 2, 2026
1751524
Do not print the PHPStan Pro note on --fix
ondrejmirtes Nov 2, 2026
28a5705
Compute fix diffs against the current contents of a file
ondrejmirtes Nov 2, 2026
e55c4df
Fix in rounds in RuleTestCase::fix()
ondrejmirtes Nov 2, 2026
528bcf3
Add ErrorFixer for applying fixes outside of --fix
ondrejmirtes Nov 2, 2026
2044024
Tell agents to run --fix when some errors are fixable
ondrejmirtes Nov 2, 2026
3d496ca
Let PhpDocEditor edit PHPDoc text with token indexes
ondrejmirtes Nov 2, 2026
fe1ed85
Make unmatched inline ignores fixable
ondrejmirtes Nov 2, 2026
1d0a31e
Report fixable errors in JSON error format
ondrejmirtes Nov 2, 2026
0933083
Issue bot: append 🔧 to messages of fixable errors
ondrejmirtes Nov 2, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions .github/workflows/e2e-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -967,6 +967,32 @@ jobs:
OUTPUT=$(../bashunit assert exit_code "1" "../../bin/phpstan analyse -vv --error-format raw")
echo "$OUTPUT"
../bashunit assert contains 'FooTrait.php (in context of class ResultCacheE2ETraitAlongsideClass\ClassUsingFooTrait):10:Method ResultCacheE2ETraitAlongsideClass\ClassUsingFooTrait::doFooTrait() should return stdClass but returns Exception. [identifier=return.type]' "$OUTPUT"
- script: |
cd e2e/fix
composer install
rm -rf src cycle tmp && cp -r original src && cp -r cycle-original cycle
OUTPUT=$(AI_AGENT=1 ../bashunit assert exit_code "1" "../../bin/phpstan analyse --error-format raw")
echo "$OUTPUT"
../bashunit assert contains '7 of the errors can be fixed automatically. Run PHPStan again with --fix' "$OUTPUT"
OUTPUT=$(../bashunit assert exit_code "0" "../../bin/phpstan analyse --fix")
echo "$OUTPUT"
../bashunit assert contains 'Analysing fixed code (round 4)...' "$OUTPUT"
../bashunit assert not_contains 'round 5' "$OUTPUT"
../bashunit assert contains 'Round 2: fixed 3 errors in 1 file' "$OUTPUT"
../bashunit assert contains '[OK] 10 errors fixed in 2 files' "$OUTPUT"
diff -u expected/Foo.php src/Foo.php
diff -u expected/Ignored-fix.php src/Ignored.php
OUTPUT=$(../bashunit assert exit_code "0" "../../bin/phpstan analyse --fix-ignored")
echo "$OUTPUT"
../bashunit assert contains '[OK] 2 errors fixed' "$OUTPUT"
diff -u expected/Foo.php src/Foo.php
diff -u expected/Ignored-fix-ignored.php src/Ignored.php
OUTPUT=$(../bashunit assert exit_code "1" "../../bin/phpstan analyse --fix --fix-ignored")
echo "$OUTPUT"
../bashunit assert contains 'No fixable errors found' "$OUTPUT"
OUTPUT=$(../bashunit assert exit_code "1" "../../bin/phpstan analyse -c cycle.neon --fix")
echo "$OUTPUT"
../bashunit assert contains 'Fixing stopped after 10 rounds' "$OUTPUT"
- script: |
cd e2e/editor-mode
OUTPUT=$(../bashunit assert exit_code "1" "../../bin/phpstan analyse -vv --error-format raw")
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/issue-bot.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# https://help.github.com/en/categories/automating-your-workflow-with-github-actions

name: "Issue bot"

Check notice on line 3 in .github/workflows/issue-bot.yml

View workflow job for this annotation

GitHub Actions / Evaluate results

Issue bot detected open issues which are affected by this pull request - see https://github.com/phpstan/phpstan-src/actions/runs/41415443480

on:
workflow_dispatch:
Expand Down Expand Up @@ -54,9 +54,9 @@
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: ./issue-bot/tmp
key: "issue-bot-download-v8-${{ github.run_id }}"
key: "issue-bot-download-v9-${{ github.run_id }}"
restore-keys: |
issue-bot-download-v8-
issue-bot-download-v9-

- name: "Download data"
working-directory: "issue-bot"
Expand Down
6 changes: 5 additions & 1 deletion .github/workflows/phar.yml
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,12 @@ jobs:
ignore-cache: true

# only sebastian/diff ^4 supports PHP 7.4 so we need that in the PHAR
# it stays in require, the PHAR is built without dev dependencies and the fixer needs it
- name: "Downgrade PHPUnit"
run: "composer require --dev phpunit/phpunit:^9.6 sebastian/diff:^4.0 doctrine/instantiator:^1.0 --update-with-dependencies --ignore-platform-reqs"
run: |
composer require --no-update sebastian/diff:^4.0
composer require --dev --no-update phpunit/phpunit:^9.6 doctrine/instantiator:^1.0
composer update phpunit/phpunit sebastian/diff doctrine/instantiator --with-all-dependencies --ignore-platform-reqs

- name: "Install compiler dependencies"
uses: "ramsey/composer-install@65e4f84970763564f46a70b8a54b90d033b3bdda" # v4.0.0
Expand Down
24 changes: 24 additions & 0 deletions build/baseline-pre-8.0.neon
Original file line number Diff line number Diff line change
Expand Up @@ -157,3 +157,27 @@ parameters:
identifier: property.internalClass
count: 3
path: ../src/Parser/RichParser.php

-
rawMessage: Access to property $id of internal class Symfony\Polyfill\Php80\PhpToken from outside its root namespace Symfony.
identifier: property.internalClass
count: 6
path: ../src/Analyser/Ignore/UnmatchedIgnoreFixer.php

-
rawMessage: Access to property $line of internal class Symfony\Polyfill\Php80\PhpToken from outside its root namespace Symfony.
identifier: property.internalClass
count: 7
path: ../src/Analyser/Ignore/UnmatchedIgnoreFixer.php

-
rawMessage: Access to property $pos of internal class Symfony\Polyfill\Php80\PhpToken from outside its root namespace Symfony.
identifier: property.internalClass
count: 1
path: ../src/Analyser/Ignore/UnmatchedIgnoreFixer.php

-
rawMessage: Access to property $text of internal class Symfony\Polyfill\Php80\PhpToken from outside its root namespace Symfony.
identifier: property.internalClass
count: 2
path: ../src/Analyser/Ignore/UnmatchedIgnoreFixer.php
1 change: 0 additions & 1 deletion build/composer-dependency-analyser.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
];

$pinnedToSupportPhp72 = [
'symfony/process',
'symfony/service-contracts',
'symfony/string',
];
Expand Down
2 changes: 1 addition & 1 deletion build/ignore-gte-php7.4-errors.neon
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ includes:

parameters:
ignoreErrors:
- '#^Class PHPStan\\Rules\\RuleErrors\\RuleError(?:\d+) has an uninitialized property (?:\$message|\$line|\$identifier|\$tip|\$file|\$metadata|\$originalNode)#'
- '#^Class PHPStan\\Rules\\RuleErrors\\RuleError(?:\d+) has an uninitialized property (?:\$message|\$line|\$identifier|\$tip|\$file|\$metadata|\$nodeFixes)#'
- '#Extension has an uninitialized property (?:\$typeSpecifier|\$broker)#'
-
message: '#has an uninitialized property#'
Expand Down
6 changes: 0 additions & 6 deletions build/php-85.neon
Original file line number Diff line number Diff line change
@@ -1,11 +1,5 @@
parameters:
ignoreErrors:
-
rawMessage: 'Call to deprecated method setAccessible() of class ReflectionMethod.'
identifier: method.deprecated
count: 1
path: ../src/Fixable/Patcher.php

-
rawMessage: 'Call to deprecated method setAccessible() of class ReflectionProperty.'
identifier: method.deprecated
Expand Down
1 change: 0 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@
"ondram/ci-detector": "^4.0",
"ondrejmirtes/better-reflection": "6.75.0.4",
"ondrejmirtes/composer-attribute-collector": "^1.2.0",
"ondrejmirtes/php-merge": "^4.1",
"ondrejmirtes/phplrt-runtime": "4.2.4.1",
"phpstan/php-8-stubs": "0.4.43",
"phpstan/phpdoc-parser": "2.4.1",
Expand Down
60 changes: 1 addition & 59 deletions composer.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions e2e/fix/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
/src
/cycle
/tmp
/vendor
/composer.lock
7 changes: 7 additions & 0 deletions e2e/fix/composer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"autoload-dev": {
"classmap": [
"rules/"
]
}
}
8 changes: 8 additions & 0 deletions e2e/fix/cycle-original/Foo.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?php

namespace FixE2E;

function ping(): void {}
function pong(): void {}

ping();
8 changes: 8 additions & 0 deletions e2e/fix/cycle.neon
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
parameters:
level: 0
paths:
- cycle
tmpDir: tmp

rules:
- FixE2E\PingPongRule
15 changes: 15 additions & 0 deletions e2e/fix/expected/Foo.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php

namespace FixE2E;

function step1(): void {}
function step2(): void {}
function step3(): void {}
function step4(): void {}
function noArgs(int ...$args): void {}

step4();
step4();
step4();
step4();
noArgs();
6 changes: 6 additions & 0 deletions e2e/fix/expected/Ignored-fix-ignored.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?php

namespace FixE2E;

step4();
noArgs();
6 changes: 6 additions & 0 deletions e2e/fix/expected/Ignored-fix.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?php

namespace FixE2E;

step2();
noArgs();
15 changes: 15 additions & 0 deletions e2e/fix/original/Foo.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php

namespace FixE2E;

function step1(): void {}
function step2(): void {}
function step3(): void {}
function step4(): void {}
function noArgs(int ...$args): void {}

step1();
step2();
step3();
step4();
noArgs(1, 2, 3);
6 changes: 6 additions & 0 deletions e2e/fix/original/Ignored.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?php

namespace FixE2E;

step2();
noArgs(1);
13 changes: 13 additions & 0 deletions e2e/fix/phpstan.neon
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
parameters:
level: 0
paths:
- src
tmpDir: tmp
ignoreErrors:
-
identifier: fixE2E.step
path: src/Ignored.php

rules:
- FixE2E\StepRule
- FixE2E\NoArgsRule
Loading
Loading