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
43 changes: 36 additions & 7 deletions src/Analyser/NodeScopeResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -1517,8 +1517,17 @@
}

$breakExitPoints = $finalScopeResult->getExitPointsByType(Break_::class);
foreach ($breakExitPoints as $breakExitPoint) {
$finalScope = $finalScope->mergeWith($breakExitPoint->getScope());
if ($alwaysIterates && count($breakExitPoints) > 0) {
$finalScope = null;
foreach ($breakExitPoints as $breakExitPoint) {
$finalScope = $finalScope === null
? $breakExitPoint->getScope()
: $finalScope->mergeWith($breakExitPoint->getScope());
}
} else {
foreach ($breakExitPoints as $breakExitPoint) {
$finalScope = $finalScope->mergeWith($breakExitPoint->getScope());
}
}

$isIterableAtLeastOnce = $beforeCondBooleanType->isTrue()->yes();
Expand Down Expand Up @@ -1624,8 +1633,18 @@
} else {
$this->processExprNode($stmt, $stmt->cond, $bodyScope, $storage, $nodeCallback, ExpressionContext::createDeep());
}
foreach ($bodyScopeResult->getExitPointsByType(Break_::class) as $breakExitPoint) {
$finalScope = $breakExitPoint->getScope()->mergeWith($finalScope);
$breakExitPoints = $bodyScopeResult->getExitPointsByType(Break_::class);
if ($alwaysIterates && count($breakExitPoints) > 0) {
$finalScope = null;
foreach ($breakExitPoints as $breakExitPoint) {
$finalScope = $finalScope === null
? $breakExitPoint->getScope()
: $finalScope->mergeWith($breakExitPoint->getScope());
}
} else {
foreach ($breakExitPoints as $breakExitPoint) {
$finalScope = $breakExitPoint->getScope()->mergeWith($finalScope);
}
}

return new InternalStatementResult(
Expand Down Expand Up @@ -1736,8 +1755,18 @@
$finalScope = $finalScope->filterByFalseyValue($lastCondExpr);
}

foreach ($finalScopeResult->getExitPointsByType(Break_::class) as $breakExitPoint) {
$finalScope = $breakExitPoint->getScope()->mergeWith($finalScope);
$breakExitPoints = $finalScopeResult->getExitPointsByType(Break_::class);
if ($alwaysIterates->yes() && count($breakExitPoints) > 0) {

Check warning on line 1759 in src/Analyser/NodeScopeResolver.php

View workflow job for this annotation

GitHub Actions / Mutation Testing (8.4, ubuntu-latest)

Escaped Mutant for Mutator "PHPStan\Infection\TrinaryLogicMutator": @@ @@ } $breakExitPoints = $finalScopeResult->getExitPointsByType(Break_::class); - if ($alwaysIterates->yes() && count($breakExitPoints) > 0) { + if (!$alwaysIterates->no() && count($breakExitPoints) > 0) { $finalScope = null; foreach ($breakExitPoints as $breakExitPoint) { $finalScope = $finalScope === null

Check warning on line 1759 in src/Analyser/NodeScopeResolver.php

View workflow job for this annotation

GitHub Actions / Mutation Testing (8.3, ubuntu-latest)

Escaped Mutant for Mutator "PHPStan\Infection\TrinaryLogicMutator": @@ @@ } $breakExitPoints = $finalScopeResult->getExitPointsByType(Break_::class); - if ($alwaysIterates->yes() && count($breakExitPoints) > 0) { + if (!$alwaysIterates->no() && count($breakExitPoints) > 0) { $finalScope = null; foreach ($breakExitPoints as $breakExitPoint) { $finalScope = $finalScope === null
$finalScope = null;
foreach ($breakExitPoints as $breakExitPoint) {
$finalScope = $finalScope === null
? $breakExitPoint->getScope()
: $finalScope->mergeWith($breakExitPoint->getScope());
}
} else {
foreach ($breakExitPoints as $breakExitPoint) {
$finalScope = $breakExitPoint->getScope()->mergeWith($finalScope);
}
}

if ($isIterableAtLeastOnce->no() || $finalScopeResult->isAlwaysTerminating()) {
Expand All @@ -1753,7 +1782,7 @@
} else {
$finalScope = $finalScope->mergeWith($scope);
}
} else {
} elseif (!$alwaysIterates->yes()) {

Check warning on line 1785 in src/Analyser/NodeScopeResolver.php

View workflow job for this annotation

GitHub Actions / Mutation Testing (8.4, ubuntu-latest)

Escaped Mutant for Mutator "PHPStan\Infection\TrinaryLogicMutator": @@ @@ } else { $finalScope = $finalScope->mergeWith($scope); } - } elseif (!$alwaysIterates->yes()) { + } elseif ($alwaysIterates->no()) { if (!$this->polluteScopeWithLoopInitialAssignments) { $finalScope = $finalScope->mergeWith($scope); }

Check warning on line 1785 in src/Analyser/NodeScopeResolver.php

View workflow job for this annotation

GitHub Actions / Mutation Testing (8.3, ubuntu-latest)

Escaped Mutant for Mutator "PHPStan\Infection\TrinaryLogicMutator": @@ @@ } else { $finalScope = $finalScope->mergeWith($scope); } - } elseif (!$alwaysIterates->yes()) { + } elseif ($alwaysIterates->no()) { if (!$this->polluteScopeWithLoopInitialAssignments) { $finalScope = $finalScope->mergeWith($scope); }
if (!$this->polluteScopeWithLoopInitialAssignments) {
$finalScope = $finalScope->mergeWith($scope);
}
Expand Down
25 changes: 25 additions & 0 deletions tests/PHPStan/Analyser/nsrt/bug-10245.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?php declare(strict_types = 1); // lint >= 8.0

namespace NsrtBug10245;

use function PHPStan\Testing\assertType;

/**
* @throws \Exception
*/
function produceInt(): int
{
return 1;
}

function testTryCatchInWhileTrue(): void
{
while (true) {
try {
$a = produceInt();
break;
} catch (\Throwable) {}
}

assertType('int', $a);
}
60 changes: 60 additions & 0 deletions tests/PHPStan/Rules/Variables/DefinedVariableRuleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -1257,4 +1257,64 @@ public function testBug12944(): void
$this->analyse([__DIR__ . '/data/bug-12944.php'], []);
}

public function testBug11545(): void
{
$this->cliArgumentsVariablesRegistered = true;
$this->polluteScopeWithLoopInitialAssignments = true;
$this->checkMaybeUndefinedVariables = true;
$this->polluteScopeWithAlwaysIterableForeach = true;

$this->analyse([__DIR__ . '/data/bug-11545.php'], []);
}

public function testBug11984(): void
{
$this->cliArgumentsVariablesRegistered = true;
$this->polluteScopeWithLoopInitialAssignments = true;
$this->checkMaybeUndefinedVariables = true;
$this->polluteScopeWithAlwaysIterableForeach = true;

$this->analyse([__DIR__ . '/data/bug-11984.php'], []);
}

public function testBug10245(): void
{
$this->cliArgumentsVariablesRegistered = true;
$this->polluteScopeWithLoopInitialAssignments = true;
$this->checkMaybeUndefinedVariables = true;
$this->polluteScopeWithAlwaysIterableForeach = true;

$this->analyse([__DIR__ . '/data/bug-10245.php'], []);
}

public function testBug9023(): void
{
$this->cliArgumentsVariablesRegistered = true;
$this->polluteScopeWithLoopInitialAssignments = true;
$this->checkMaybeUndefinedVariables = true;
$this->polluteScopeWithAlwaysIterableForeach = true;

$this->analyse([__DIR__ . '/data/bug-9023.php'], []);
}

public function testBug5919(): void
{
$this->cliArgumentsVariablesRegistered = true;
$this->polluteScopeWithLoopInitialAssignments = true;
$this->checkMaybeUndefinedVariables = true;
$this->polluteScopeWithAlwaysIterableForeach = true;

$this->analyse([__DIR__ . '/data/bug-5919.php'], []);
}

public function testBug5477(): void
{
$this->cliArgumentsVariablesRegistered = true;
$this->polluteScopeWithLoopInitialAssignments = true;
$this->checkMaybeUndefinedVariables = true;
$this->polluteScopeWithAlwaysIterableForeach = true;

$this->analyse([__DIR__ . '/data/bug-5477.php'], []);
}

}
36 changes: 36 additions & 0 deletions tests/PHPStan/Rules/Variables/data/bug-10245.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php declare(strict_types = 1);

namespace Bug10245;

/**
* @throws \Exception
*/
function produceInt(): int
{
return 1;
}

function testTryCatchInWhileTrue(): void
{
while (true) {
try {
$a = produceInt();
break;
} catch (\Throwable $e) {}
}

echo $a;
}

function testIfBreakInWhileTrue(int $max): void
{
$i = 0;
while (true) {
if ($i > $max) {
$result = 'done';
break;
}
++$i;
}
print $result;
}
37 changes: 37 additions & 0 deletions tests/PHPStan/Rules/Variables/data/bug-11545.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?php declare(strict_types = 1);

namespace Bug11545;

function foo(int $max): void {
$i = 0;
while (true) {
if ($i > $max) {
$result = 'done';
break;
}
++$i;
}
print $result;
}

function foo_for(int $max): void {
for ($i = 0;; ++$i) {
if ($i > $max) {
$result = 'done';
break;
}
}
print $result;
}

function foo_do_while(int $max): void {
$i = 0;
do {
if ($i > $max) {
$result = 'done';
break;
}
++$i;
} while (true);
print $result;
}
31 changes: 31 additions & 0 deletions tests/PHPStan/Rules/Variables/data/bug-11984.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php declare(strict_types = 1);

namespace Bug11984;

class Foo
{
/**
* @return array<string, mixed>
*/
public function loadFromFile(): array
{
return ['x' => 1];
}

/**
* @return array<string, mixed>
*/
public function test(): array
{
while (true) {
try {
$data = $this->loadFromFile();

break;
} catch (\Exception $ex) {
}
}

return $data;
}
}
17 changes: 17 additions & 0 deletions tests/PHPStan/Rules/Variables/data/bug-5477.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?php declare(strict_types = 1);

namespace Bug5477;

function foo(): int
{
while (true) {
try {
$transaction = 1;
break;
} catch (\Throwable $e) {
continue;
}
}

return $transaction;
}
48 changes: 48 additions & 0 deletions tests/PHPStan/Rules/Variables/data/bug-5919.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<?php declare(strict_types = 1);

namespace Bug5919;

/**
* @return mixed[]
*/
function queryApi(): array
{
return [5];
}

function testSimpleTryCatch(): void
{
while (true) {
try {
$s = queryApi();
break;
} catch (\Exception $e) {
if (false) {
throw $e;
}
}
}

var_dump(count($s));
}

function isTimeout(): bool
{
return true;
}

function testTryCatchWithRethrow(): void
{
while (true) {
try {
$s = queryApi();
break;
} catch (\Exception $e) {
if (isTimeout()) {
throw $e;
}
}
}

var_dump(count($s));
}
27 changes: 27 additions & 0 deletions tests/PHPStan/Rules/Variables/data/bug-9023.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php declare(strict_types = 1);

namespace Bug9023;

function unreliableFunc(): string
{
if (random_int(1, 5) === 1) {
return 'something';
} else {
throw new \Exception('Just demonstrating');
}
}

function testRetryUntilSuccess(): void
{
while (true) {
try {
$Defined = unreliableFunc();
break;
} catch (\Exception $e) {
sleep(10);
continue;
}
}

echo $Defined;
}
Loading