Skip to content

Commit 0b8dca7

Browse files
committed
Do not invalidate types passed by value
1 parent 52eb6f8 commit 0b8dca7

File tree

4 files changed

+42
-2
lines changed

4 files changed

+42
-2
lines changed

src/Analyser/MutatingScope.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -3617,7 +3617,7 @@ private function shouldInvalidateExpression(string $exprStringToInvalidate, Expr
36173617
}
36183618

36193619
// Variables will not contain traversable expressions. skip the NodeFinder overhead
3620-
if ($expr instanceof Variable && is_string($expr->name)) {
3620+
if ($expr instanceof Variable && is_string($expr->name) && !$requireMoreCharacters) {
36213621
return $exprStringToInvalidate === $this->getNodeKey($expr);
36223622
}
36233623

src/Analyser/NodeScopeResolver.php

+14-1
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,7 @@
148148
use PHPStan\Type\NeverType;
149149
use PHPStan\Type\NullType;
150150
use PHPStan\Type\ObjectType;
151+
use PHPStan\Type\ResourceType;
151152
use PHPStan\Type\StaticType;
152153
use PHPStan\Type\StaticTypeFactory;
153154
use PHPStan\Type\StringType;
@@ -2010,6 +2011,15 @@ static function (): void {
20102011
->invalidateExpression(new FuncCall(new Name\FullyQualified('json_last_error_msg'), []));
20112012
}
20122013

2014+
if (
2015+
$functionReflection !== null
2016+
&& $functionReflection->getName() === 'file_put_contents'
2017+
&& count($expr->getArgs()) > 0
2018+
) {
2019+
$scope = $scope->invalidateExpression(new FuncCall(new Name('file_get_contents'), [$expr->getArgs()[0]]))
2020+
->invalidateExpression(new FuncCall(new Name\FullyQualified('file_get_contents'), [$expr->getArgs()[0]]));
2021+
}
2022+
20132023
if (
20142024
$functionReflection !== null
20152025
&& in_array($functionReflection->getName(), ['array_pop', 'array_shift'], true)
@@ -3600,7 +3610,10 @@ private function processArgs(
36003610
$scope = $scope->invalidateExpression($argValue);
36013611
}
36023612
} elseif ($calleeReflection !== null && $calleeReflection->hasSideEffects()->yes()) {
3603-
$scope = $scope->invalidateExpression($arg->value, true);
3613+
$argType = $scope->getType($arg->value);
3614+
if (!$argType->isObject()->no() || !(new ResourceType())->isSuperTypeOf($argType)->no()) {
3615+
$scope = $scope->invalidateExpression($arg->value, true);
3616+
}
36043617
}
36053618
}
36063619

tests/PHPStan/Analyser/NodeScopeResolverTest.php

+1
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ public function dataFileAsserts(): iterable
5858
yield from $this->gatherAssertTypes(__DIR__ . '/data/strtotime-return-type-extensions.php');
5959
yield from $this->gatherAssertTypes(__DIR__ . '/data/closure-return-type-extensions.php');
6060
yield from $this->gatherAssertTypes(__DIR__ . '/data/array-key.php');
61+
yield from $this->gatherAssertTypes(__DIR__ . '/data/discussion-9972.php');
6162
yield from $this->gatherAssertTypes(__DIR__ . '/data/intersection-static.php');
6263
yield from $this->gatherAssertTypes(__DIR__ . '/data/static-properties.php');
6364
yield from $this->gatherAssertTypes(__DIR__ . '/data/static-methods.php');
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<?php
2+
3+
namespace Discussion9972;
4+
5+
use PHPStan\TrinaryLogic;
6+
use function PHPStan\Testing\assertVariableCertainty;
7+
8+
class HelloWorld
9+
{
10+
public function f1(bool $myBool): void
11+
{
12+
if ($myBool) {
13+
$myObject = new DateTime();
14+
}
15+
16+
$this->helper($myBool);
17+
18+
if ($myBool) {
19+
assertVariableCertainty(TrinaryLogic::createYes(), $myObject);
20+
}
21+
}
22+
23+
protected function helper(bool $input): void
24+
{
25+
}
26+
}

0 commit comments

Comments
 (0)