Skip to content

Commit 172a5e4

Browse files
authored
Merge branch 'phpstan:2.1.x' into Assert-and-throws-are-side-effects
2 parents abee33d + 72d2f3b commit 172a5e4

File tree

309 files changed

+13264
-1354
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

309 files changed

+13264
-1354
lines changed

.github/workflows/e2e-tests.yml

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -190,25 +190,25 @@ jobs:
190190
OUTPUT=$(../bashunit -a exit_code "1" "../../bin/phpstan analyse -c ignore.neon")
191191
echo "$OUTPUT"
192192
../bashunit -a contains 'Invalid entry in ignoreErrors' "$OUTPUT"
193-
../bashunit -a contains 'tests is neither a directory, nor a file path, nor a fnmatch pattern.' "$OUTPUT"
193+
../bashunit -a contains 'tests" is neither a directory, nor a file path, nor a fnmatch pattern.' "$OUTPUT"
194194
- script: |
195195
cd e2e/bad-exclude-paths
196196
OUTPUT=$(../bashunit -a exit_code "1" "../../bin/phpstan analyse -c phpneon.php")
197197
echo "$OUTPUT"
198198
../bashunit -a contains 'Invalid entry in ignoreErrors' "$OUTPUT"
199-
../bashunit -a contains 'src/test.php is neither a directory, nor a file path, nor a fnmatch pattern.' "$OUTPUT"
199+
../bashunit -a contains '"src/test.php" is neither a directory, nor a file path, nor a fnmatch pattern.' "$OUTPUT"
200200
- script: |
201201
cd e2e/bad-exclude-paths
202202
OUTPUT=$(../bashunit -a exit_code "1" "../../bin/phpstan analyse -c excludePaths.neon")
203203
echo "$OUTPUT"
204204
../bashunit -a contains 'Invalid entry in excludePaths' "$OUTPUT"
205-
../bashunit -a contains 'tests is neither a directory, nor a file path, nor a fnmatch pattern.' "$OUTPUT"
205+
../bashunit -a contains 'tests" is neither a directory, nor a file path, nor a fnmatch pattern.' "$OUTPUT"
206206
- script: |
207207
cd e2e/bad-exclude-paths
208208
OUTPUT=$(../bashunit -a exit_code "1" "../../bin/phpstan analyse -c phpneon2.php")
209209
echo "$OUTPUT"
210210
../bashunit -a contains 'Invalid entry in excludePaths' "$OUTPUT"
211-
../bashunit -a contains 'src/test.php is neither a directory, nor a file path, nor a fnmatch pattern.' "$OUTPUT"
211+
../bashunit -a contains '"src/test.php" is neither a directory, nor a file path, nor a fnmatch pattern.' "$OUTPUT"
212212
- script: |
213213
cd e2e/bad-exclude-paths
214214
OUTPUT=$(../../bin/phpstan analyse -c ignoreNonexistentExcludePath.neon)
@@ -243,6 +243,14 @@ jobs:
243243
echo "$OUTPUT"
244244
../bashunit -a matches "Note: Using configuration file .+phpstan.neon." "$OUTPUT"
245245
../bashunit -a contains 'Result cache not used because the metadata do not match: metaExtensions' "$OUTPUT"
246+
- script: |
247+
cd e2e/bug-12606
248+
export CONFIGTEST=test
249+
../../bin/phpstan
250+
- script: |
251+
cd e2e/ignore-error-extension
252+
composer install
253+
../../bin/phpstan
246254
247255
steps:
248256
- name: "Checkout"

.github/workflows/issue-bot.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,9 @@ jobs:
4848
uses: actions/cache@v4
4949
with:
5050
path: ./issue-bot/tmp
51-
key: "issue-bot-download-v6-${{ github.run_id }}"
51+
key: "issue-bot-download-v7-${{ github.run_id }}"
5252
restore-keys: |
53-
issue-bot-download-v6-
53+
issue-bot-download-v7-
5454
5555
- name: "Download data"
5656
working-directory: "issue-bot"

.github/workflows/spelling.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,6 @@ jobs:
1818
uses: actions/checkout@v4
1919

2020
- name: "Check for typos"
21-
uses: "crate-ci/typos@v1.27.0"
21+
uses: "crate-ci/typos@v1"
2222
with:
2323
files: "README.md src/"

.typos.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,7 @@ ignore-hidden = false
88
# Known typos
99
NonRemoveableTypeTrait = "NonRemoveableTypeTrait"
1010
supportsLessOverridenParametersWithVariadic = "supportsLessOverridenParametersWithVariadic"
11+
12+
[default.extend-words]
13+
# override false-positives
14+
Excluder = "Excluder"

Makefile

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,14 +90,26 @@ lint:
9090
--exclude tests/PHPStan/Rules/Properties/data/hooked-properties-without-bodies-in-class.php \
9191
--exclude tests/PHPStan/Rules/Properties/data/readonly-property-hooks.php \
9292
--exclude tests/PHPStan/Rules/Properties/data/readonly-property-hooks-in-interface.php \
93+
--exclude tests/PHPStan/Rules/Properties/data/static-hooked-properties.php \
94+
--exclude tests/PHPStan/Rules/Properties/data/static-hooked-property-in-interface.php \
95+
--exclude tests/PHPStan/Rules/Properties/data/virtual-hooked-properties.php \
9396
--exclude tests/PHPStan/Rules/Classes/data/bug-12281.php \
9497
--exclude tests/PHPStan/Rules/Traits/data/bug-12281.php \
9598
--exclude tests/PHPStan/Rules/Classes/data/invalid-hooked-properties.php \
9699
--exclude tests/PHPStan/Parser/data/cleaning-property-hooks-before.php \
97100
--exclude tests/PHPStan/Parser/data/cleaning-property-hooks-after.php \
101+
--exclude tests/PHPStan/Rules/Properties/data/abstract-private-property-hook.php \
98102
--exclude tests/PHPStan/Rules/Properties/data/existing-classes-property-hooks.php \
99103
--exclude tests/PHPStan/Rules/Properties/data/set-property-hook-parameter.php \
100104
--exclude tests/PHPStan/Rules/Properties/data/overriding-final-property.php \
105+
--exclude tests/PHPStan/Rules/Properties/data/private-final-property-hooks.php \
106+
--exclude tests/PHPStan/Rules/Properties/data/abstract-final-property-hook.php \
107+
--exclude tests/PHPStan/Rules/Properties/data/final-property-hooks-in-interface.php \
108+
--exclude tests/PHPStan/Rules/Properties/data/final-property-hooks.php \
109+
--exclude tests/PHPStan/Rules/Properties/data/final-properties.php \
110+
--exclude tests/PHPStan/Rules/Properties/data/property-in-interface-explicit-abstract.php \
111+
--exclude tests/PHPStan/Rules/Constants/data/final-private-const.php \
112+
--exclude tests/PHPStan/Rules/Properties/data/abstract-final-property-hook-parse-error.php \
101113
src tests
102114

103115
cs:

bin/functionMetadata_original.php

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -70,16 +70,13 @@
7070
'chown' => ['hasSideEffects' => true],
7171
'copy' => ['hasSideEffects' => true],
7272
'count' => ['hasSideEffects' => false],
73-
'connection_aborted' => ['hasSideEffects' => true],
74-
'connection_status' => ['hasSideEffects' => true],
7573
'error_log' => ['hasSideEffects' => true],
7674
'fclose' => ['hasSideEffects' => true],
7775
'fflush' => ['hasSideEffects' => true],
7876
'fgetc' => ['hasSideEffects' => true],
7977
'fgetcsv' => ['hasSideEffects' => true],
8078
'fgets' => ['hasSideEffects' => true],
8179
'fgetss' => ['hasSideEffects' => true],
82-
'file_get_contents' => ['hasSideEffects' => true],
8380
'file_put_contents' => ['hasSideEffects' => true],
8481
'flock' => ['hasSideEffects' => true],
8582
'fopen' => ['hasSideEffects' => true],
@@ -98,6 +95,18 @@
9895
'mb_str_pad' => ['hasSideEffects' => false],
9996
'mkdir' => ['hasSideEffects' => true],
10097
'move_uploaded_file' => ['hasSideEffects' => true],
98+
'ob_clean' => ['hasSideEffects' => true],
99+
'ob_end_clean' => ['hasSideEffects' => true],
100+
'ob_end_flush' => ['hasSideEffects' => true],
101+
'ob_flush' => ['hasSideEffects' => true],
102+
'ob_get_clean' => ['hasSideEffects' => true],
103+
'ob_get_contents' => ['hasSideEffects' => true],
104+
'ob_get_length' => ['hasSideEffects' => true],
105+
'ob_get_level' => ['hasSideEffects' => true],
106+
'ob_get_status' => ['hasSideEffects' => true],
107+
'ob_list_handlers' => ['hasSideEffects' => true],
108+
'output_add_rewrite_var' => ['hasSideEffects' => true],
109+
'output_reset_rewrite_vars' => ['hasSideEffects' => true],
101110
'pclose' => ['hasSideEffects' => true],
102111
'popen' => ['hasSideEffects' => true],
103112
'readfile' => ['hasSideEffects' => true],

bin/generate-function-metadata.php

Lines changed: 61 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -25,18 +25,63 @@
2525
/** @var string[] */
2626
public array $functions = [];
2727

28+
/** @var list<string> */
29+
public array $impureFunctions = [];
30+
2831
/** @var string[] */
2932
public array $methods = [];
3033

3134
public function enterNode(Node $node)
3235
{
3336
if ($node instanceof Node\Stmt\Function_) {
37+
assert(isset($node->namespacedName));
38+
$functionName = $node->namespacedName->toLowerString();
39+
3440
foreach ($node->attrGroups as $attrGroup) {
3541
foreach ($attrGroup->attrs as $attr) {
36-
if ($attr->name->toString() === Pure::class) {
37-
$this->functions[] = $node->namespacedName->toLowerString();
42+
if ($attr->name->toString() !== Pure::class) {
43+
continue;
44+
}
45+
46+
// The following functions have side effects, but their state is managed within the PHPStan scope:
47+
if (in_array($functionName, [
48+
'stat',
49+
'lstat',
50+
'file_exists',
51+
'is_writable',
52+
'is_writeable',
53+
'is_readable',
54+
'is_executable',
55+
'is_file',
56+
'is_dir',
57+
'is_link',
58+
'filectime',
59+
'fileatime',
60+
'filemtime',
61+
'fileinode',
62+
'filegroup',
63+
'fileowner',
64+
'filesize',
65+
'filetype',
66+
'fileperms',
67+
'ftell',
68+
'ini_get',
69+
'function_exists',
70+
'json_last_error',
71+
'json_last_error_msg',
72+
], true)) {
73+
$this->functions[] = $functionName;
3874
break 2;
3975
}
76+
77+
// PhpStorm stub's #[Pure(true)] means the function has side effects but its return value is important.
78+
// In PHPStan's criteria, these functions are simply considered as ['hasSideEffect' => true].
79+
if (isset($attr->args[0]->value->name->name) && $attr->args[0]->value->name->name === 'true') {
80+
$this->impureFunctions[] = $functionName;
81+
} else {
82+
$this->functions[] = $functionName;
83+
}
84+
break 2;
4085
}
4186
}
4287
}
@@ -74,26 +119,29 @@ public function enterNode(Node $node)
74119
);
75120
}
76121

122+
/** @var array<string, array{hasSideEffects: bool}> $metadata */
77123
$metadata = require __DIR__ . '/functionMetadata_original.php';
78124
foreach ($visitor->functions as $functionName) {
79125
if (array_key_exists($functionName, $metadata)) {
80126
if ($metadata[$functionName]['hasSideEffects']) {
81-
if (in_array($functionName, [
82-
'mt_rand',
83-
'rand',
84-
'random_bytes',
85-
'random_int',
86-
'connection_aborted',
87-
'connection_status',
88-
'file_get_contents',
89-
], true)) {
90-
continue;
91-
}
92127
throw new ShouldNotHappenException($functionName);
93128
}
94129
}
95130
$metadata[$functionName] = ['hasSideEffects' => false];
96131
}
132+
foreach ($visitor->impureFunctions as $functionName) {
133+
if (array_key_exists($functionName, $metadata)) {
134+
if (in_array($functionName, [
135+
'ob_get_contents',
136+
], true)) {
137+
continue;
138+
}
139+
if ($metadata[$functionName]['hasSideEffects']) {
140+
throw new ShouldNotHappenException($functionName);
141+
}
142+
}
143+
$metadata[$functionName] = ['hasSideEffects' => true];
144+
}
97145

98146
foreach ($visitor->methods as $methodName) {
99147
if (array_key_exists($methodName, $metadata)) {

build/PHPStan/Build/FinalClassRule.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ public function processNode(Node $node, Scope $scope): array
4444
if ($classReflection->isFinal()) {
4545
return [];
4646
}
47-
if ($classReflection->isSubclassOf(Type::class)) {
47+
if ($classReflection->is(Type::class)) {
4848
return [];
4949
}
5050

build/collision-detector.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
"../tests/PHPStan/Rules/Names/data/no-namespace.php",
1414
"../tests/notAutoloaded",
1515
"../tests/PHPStan/Rules/Functions/data/define-bug-3349.php",
16-
"../tests/PHPStan/Levels/data/stubs/function.php"
16+
"../tests/PHPStan/Levels/data/stubs/function.php",
17+
"../tests/PHPStan/Rules/Properties/data/abstract-final-property-hook-parse-error.php",
18+
"../tests/PHPStan/Rules/Properties/data/final-property-hooks.php"
1719
]
1820
}

composer.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
"hoa/compiler": "3.17.08.08",
1616
"hoa/exception": "^1.0",
1717
"hoa/file": "1.17.07.11",
18-
"jetbrains/phpstorm-stubs": "dev-master#6c6bf204cbdf39006f12a6c923b8217444acd67f",
18+
"jetbrains/phpstorm-stubs": "dev-master#7385d3075dc365911c4a3168fa762de6aa4550c9",
1919
"nette/bootstrap": "^3.0",
2020
"nette/di": "^3.1.4",
2121
"nette/neon": "3.3.4",
@@ -24,9 +24,9 @@
2424
"nette/utils": "^3.2.5",
2525
"nikic/php-parser": "^5.4.0",
2626
"ondram/ci-detector": "^3.4.0",
27-
"ondrejmirtes/better-reflection": "6.55.0.0",
28-
"phpstan/php-8-stubs": "0.4.9",
29-
"phpstan/phpdoc-parser": "2.0.0",
27+
"ondrejmirtes/better-reflection": "6.57.0.0",
28+
"phpstan/php-8-stubs": "0.4.11",
29+
"phpstan/phpdoc-parser": "2.1.0",
3030
"psr/http-message": "^1.1",
3131
"react/async": "^3",
3232
"react/child-process": "^0.7",

0 commit comments

Comments
 (0)