Skip to content

Commit 4883ae4

Browse files
authored
Merge branch '2.1.x' into explode-const-arrays
2 parents b441442 + 19df9a2 commit 4883ae4

30 files changed

+567
-279
lines changed

Makefile

+1
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ lint:
109109
--exclude tests/PHPStan/Rules/Properties/data/final-properties.php \
110110
--exclude tests/PHPStan/Rules/Properties/data/property-in-interface-explicit-abstract.php \
111111
--exclude tests/PHPStan/Rules/Constants/data/final-private-const.php \
112+
--exclude tests/PHPStan/Rules/Properties/data/abstract-final-property-hook-parse-error.php \
112113
src tests
113114

114115
cs:

bin/functionMetadata_original.php

+12-3
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

+61-13
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/collision-detector.json

+3-1
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
}

0 commit comments

Comments
 (0)