Skip to content

Commit 7b73e0a

Browse files
committed
Merge branch 2.1.x into 2.2.x
2 parents e9c208d + 0cfd9b0 commit 7b73e0a

File tree

6 files changed

+162
-3
lines changed

6 files changed

+162
-3
lines changed

src/Analyser/ExprHandler/Helper/ClosureTypeResolver.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,7 @@ static function (Node $node, Scope $scope) use ($arrowScope, &$arrowFunctionImpu
184184
'property assignment',
185185
true,
186186
);
187+
$invalidateExpressions[] = new InvalidateExprNode($node->getPropertyFetch());
187188
},
188189
ExpressionContext::createDeep(),
189190
);
@@ -257,6 +258,7 @@ static function (Node $node, Scope $scope) use ($arrowScope, &$arrowFunctionImpu
257258
'property assignment',
258259
true,
259260
);
261+
$invalidateExpressions[] = new InvalidateExprNode($node->getPropertyFetch());
260262
return;
261263
}
262264

src/Analyser/NodeScopeResolver.php

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2747,6 +2747,7 @@ public function processClosureNode(
27472747
'property assignment',
27482748
true,
27492749
);
2750+
$invalidateExpressions[] = new InvalidateExprNode($node->getPropertyFetch());
27502751
return;
27512752
}
27522753
if ($node instanceof ExecutionEndNode) {
@@ -2849,7 +2850,8 @@ public function processImmediatelyCalledCallable(MutatingScope $scope, array $in
28492850
continue;
28502851
}
28512852

2852-
$scope = $scope->invalidateExpression($invalidateExpression->getExpr(), true);
2853+
$requireMoreCharacters = $invalidateExpression->getExpr() instanceof Variable;
2854+
$scope = $scope->invalidateExpression($invalidateExpression->getExpr(), $requireMoreCharacters);
28532855
}
28542856

28552857
return $scope;
@@ -3368,7 +3370,9 @@ public function processArgs(
33683370
$scope = $scope->restoreThis($restoreThisScope);
33693371
}
33703372

3371-
$deferredInvalidateExpressions[] = [$invalidateExpressions, $uses];
3373+
if ($this->callCallbackImmediately($parameter, $parameterType, $calleeReflection)) {
3374+
$deferredInvalidateExpressions[] = [$invalidateExpressions, $uses];
3375+
}
33723376
} elseif ($arg->value instanceof Expr\ArrowFunction) {
33733377
if (
33743378
$closureBindScope === null
@@ -3416,8 +3420,8 @@ public function processArgs(
34163420
if ($exprType->isCallable()->yes()) {
34173421
$acceptors = $exprType->getCallableParametersAcceptors($scope);
34183422
if (count($acceptors) === 1) {
3419-
$deferredInvalidateExpressions[] = [$acceptors[0]->getInvalidateExpressions(), $acceptors[0]->getUsedVariables()];
34203423
if ($this->callCallbackImmediately($parameter, $parameterType, $calleeReflection)) {
3424+
$deferredInvalidateExpressions[] = [$acceptors[0]->getInvalidateExpressions(), $acceptors[0]->getUsedVariables()];
34213425
$callableThrowPoints = array_map(static fn (SimpleThrowPoint $throwPoint) => $throwPoint->isExplicit() ? InternalThrowPoint::createExplicit($scope, $throwPoint->getType(), $arg->value, $throwPoint->canContainAnyThrowable()) : InternalThrowPoint::createImplicit($scope, $arg->value), $acceptors[0]->getThrowPoints());
34223426
if (!$this->implicitThrows) {
34233427
$callableThrowPoints = array_values(array_filter($callableThrowPoints, static fn (InternalThrowPoint $throwPoint) => $throwPoint->isExplicit()));

tests/PHPStan/Rules/Comparison/IfConstantConditionRuleTest.php

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,24 @@ public function testBug8926(): void
189189
$this->analyse([__DIR__ . '/data/bug-8926.php'], []);
190190
}
191191

192+
public function testBug11417(): void
193+
{
194+
$this->treatPhpDocTypesAsCertain = true;
195+
$this->analyse([__DIR__ . '/data/bug-11417.php'], [
196+
[
197+
'If condition is always true.',
198+
66,
199+
'Because the type is coming from a PHPDoc, you can turn off this check by setting <fg=cyan>treatPhpDocTypesAsCertain: false</> in your <fg=cyan>%configurationFile%</>.',
200+
],
201+
]);
202+
}
203+
204+
public function testBug10903(): void
205+
{
206+
$this->treatPhpDocTypesAsCertain = true;
207+
$this->analyse([__DIR__ . '/data/bug-10903.php'], []);
208+
}
209+
192210
#[RequiresPhp('>= 8.0')]
193211
public function testBug13384b(): void
194212
{
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace Bug10903;
4+
5+
class HelloWorld
6+
{
7+
public bool $hasFooKey = false;
8+
9+
public function sayHello(): void
10+
{
11+
/** @var array<string, string> $arr */
12+
$arr = ['foo' => 'bar'];
13+
$this->hasFooKey = false;
14+
15+
$filteredArr = \array_filter($arr, function ($value, $key) {
16+
if (\stripos($key, 'foo') !== false) {
17+
$this->hasFooKey = true;
18+
19+
return false;
20+
}
21+
22+
return true;
23+
}, ARRAY_FILTER_USE_BOTH);
24+
25+
if ($this->hasFooKey) {
26+
// do something
27+
}
28+
}
29+
}
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
<?php
2+
3+
namespace Bug11417;
4+
5+
class Wrap {
6+
/**
7+
* @param-immediately-invoked-callable $cb
8+
*/
9+
public static function run(callable $cb): void
10+
{
11+
$cb();
12+
}
13+
}
14+
15+
class HelloWorld
16+
{
17+
private ?string $conn = null;
18+
19+
public function getConn(): string
20+
{
21+
if (!is_null($this->conn)) {
22+
return $this->conn;
23+
}
24+
25+
Wrap::run(function() {
26+
$this->conn = "conn";
27+
});
28+
29+
if (is_null($this->conn)) {
30+
throw new \Exception("conn failed");
31+
}
32+
33+
return $this->conn;
34+
}
35+
36+
public function disc(): void
37+
{
38+
$this->conn = null;
39+
}
40+
}
41+
42+
class WrapLater {
43+
/**
44+
* @param-later-invoked-callable $cb
45+
*/
46+
public static function run(callable $cb): void
47+
{
48+
$cb();
49+
}
50+
}
51+
52+
class HelloWorldLater
53+
{
54+
private ?string $conn = null;
55+
56+
public function getConn(): string
57+
{
58+
if (!is_null($this->conn)) {
59+
return $this->conn;
60+
}
61+
62+
WrapLater::run(function() {
63+
$this->conn = "conn";
64+
});
65+
66+
if (is_null($this->conn)) {
67+
throw new \Exception("conn failed");
68+
}
69+
70+
return $this->conn;
71+
}
72+
}

tests/PHPStan/Rules/Comparison/data/bug-8926.php

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,4 +29,38 @@ function error(array $arr) : void {
2929
echo "...\n";
3030
}
3131
}
32+
33+
/** @param int[] $arr */
34+
function errorArrayFilter(array $arr) : void {
35+
$this->test = false;
36+
$prices = array_filter($arr, function($elt) {
37+
if ($elt === 1) {
38+
$this->test = true;
39+
}
40+
41+
return $elt === 2;
42+
});
43+
44+
45+
if ($this->test) {
46+
echo "...\n";
47+
}
48+
}
49+
50+
/** @param int[] $arr */
51+
function successLocal(array $arr) : void {
52+
$test = false;
53+
$prices = array_filter($arr, function($elt) use(&$test) {
54+
if ($elt === 1) {
55+
$test = true;
56+
}
57+
58+
return $elt === 2;
59+
});
60+
61+
62+
if ($test) {
63+
echo "...\n";
64+
}
65+
}
3266
}

0 commit comments

Comments
 (0)