Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion src/Analyser/ExprHandler/StaticCallHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ public function processExpr(NodeScopeResolver $nodeScopeResolver, Stmt $stmt, Ex
&& $scope->isInClass()
&& $scope->getClassReflection()->is($methodReflection->getDeclaringClass()->getName())
) {
$scope = $scope->invalidateExpression(new Variable('this'), true, $methodReflection->getDeclaringClass());
$scope = $scope->invalidateExpression(new Variable('this'), true, $methodReflection->getDeclaringClass(), $methodReflection->isStatic());
} elseif (
$methodReflection !== null
&& $this->rememberPossiblyImpureFunctionValues
Expand Down
32 changes: 27 additions & 5 deletions src/Analyser/MutatingScope.php
Original file line number Diff line number Diff line change
Expand Up @@ -2857,7 +2857,7 @@ public function assignInitializedProperty(Type $fetchedOnType, string $propertyN
return $this->assignExpression(new PropertyInitializationExpr($propertyName), new MixedType(), new MixedType());
}

public function invalidateExpression(Expr $expressionToInvalidate, bool $requireMoreCharacters = false, ?ClassReflection $invalidatingClass = null): self
public function invalidateExpression(Expr $expressionToInvalidate, bool $requireMoreCharacters = false, ?ClassReflection $invalidatingClass = null, bool $fromStaticCall = false): self
{
$expressionTypes = $this->expressionTypes;
$nativeExpressionTypes = $this->nativeExpressionTypes;
Expand All @@ -2866,7 +2866,7 @@ public function invalidateExpression(Expr $expressionToInvalidate, bool $require

foreach ($expressionTypes as $exprString => $exprTypeHolder) {
$exprExpr = $exprTypeHolder->getExpr();
if (!$this->shouldInvalidateExpression($exprStringToInvalidate, $expressionToInvalidate, $exprExpr, $exprString, $requireMoreCharacters, $invalidatingClass)) {
if (!$this->shouldInvalidateExpression($exprStringToInvalidate, $expressionToInvalidate, $exprExpr, $exprString, $requireMoreCharacters, $invalidatingClass, $fromStaticCall)) {
continue;
}

Expand All @@ -2881,7 +2881,7 @@ public function invalidateExpression(Expr $expressionToInvalidate, bool $require
continue;
}
$firstExpr = $holders[array_key_first($holders)]->getTypeHolder()->getExpr();
if ($this->shouldInvalidateExpression($exprStringToInvalidate, $expressionToInvalidate, $firstExpr, $this->getNodeKey($firstExpr), false, $invalidatingClass)) {
if ($this->shouldInvalidateExpression($exprStringToInvalidate, $expressionToInvalidate, $firstExpr, $this->getNodeKey($firstExpr), false, $invalidatingClass, $fromStaticCall)) {
$invalidated = true;
continue;
}
Expand All @@ -2890,7 +2890,7 @@ public function invalidateExpression(Expr $expressionToInvalidate, bool $require
$shouldKeep = true;
$conditionalTypeHolders = $holder->getConditionExpressionTypeHolders();
foreach ($conditionalTypeHolders as $conditionalTypeHolderExprString => $conditionalTypeHolder) {
if ($this->shouldInvalidateExpression($exprStringToInvalidate, $expressionToInvalidate, $conditionalTypeHolder->getExpr(), $conditionalTypeHolderExprString, false, $invalidatingClass)) {
if ($this->shouldInvalidateExpression($exprStringToInvalidate, $expressionToInvalidate, $conditionalTypeHolder->getExpr(), $conditionalTypeHolderExprString, false, $invalidatingClass, $fromStaticCall)) {
$invalidated = true;
$shouldKeep = false;
break;
Expand Down Expand Up @@ -2944,7 +2944,7 @@ private function getIntertwinedRefRootVariableName(Expr $expr): ?string
return null;
}

private function shouldInvalidateExpression(string $exprStringToInvalidate, Expr $exprToInvalidate, Expr $expr, string $exprString, bool $requireMoreCharacters = false, ?ClassReflection $invalidatingClass = null): bool
private function shouldInvalidateExpression(string $exprStringToInvalidate, Expr $exprToInvalidate, Expr $expr, string $exprString, bool $requireMoreCharacters = false, ?ClassReflection $invalidatingClass = null, bool $fromStaticCall = false): bool
{
if (
$expr instanceof IntertwinedVariableByReferenceWithExpr
Expand Down Expand Up @@ -3011,6 +3011,13 @@ private function shouldInvalidateExpression(string $exprStringToInvalidate, Expr
return false;
}

if (
$fromStaticCall
&& $this->isThisInstancePropertyAccessChain($expr)
) {
return false;
}

return true;
}

Expand All @@ -3030,6 +3037,21 @@ private function isPrivatePropertyOfDifferentClass(Expr $expr, ClassReflection $
return false;
}

private function isThisInstancePropertyAccessChain(Expr $expr): bool
{
if ($expr instanceof Variable && is_string($expr->name) && $expr->name === 'this') {
return true;
}
if ($expr instanceof PropertyFetch) {
return $this->isThisInstancePropertyAccessChain($expr->var);
}
if ($expr instanceof Expr\ArrayDimFetch) {
return $this->isThisInstancePropertyAccessChain($expr->var);
}

return false;
}

private function invalidateMethodsOnExpression(Expr $expressionToInvalidate): self
{
$exprStringToInvalidate = null;
Expand Down
31 changes: 31 additions & 0 deletions tests/PHPStan/Analyser/nsrt/bug-13735.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php // lint >= 8.0

declare(strict_types = 1);

namespace Bug13735;

use function PHPStan\Testing\assertType;

class Bug13735Test
{
private ?Foo $foo = null;

public function testFoo(): void
{
$this->foo = new Foo();
assertType('Bug13735\Foo', $this->foo);
self::assertTrue(true);
assertType('Bug13735\Foo', $this->foo);
}

public static function assertTrue(mixed $condition, string $message = ''): void
{

}
}

class Foo {
public function doSomething(): bool {
return true;
}
}
Loading