Skip to content
Closed
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
9 changes: 9 additions & 0 deletions src/Analyser/MutatingScope.php
Original file line number Diff line number Diff line change
Expand Up @@ -3649,6 +3649,15 @@
) {
continue;
}
if (
!array_key_exists($exprString, $theirExpressionTypes)
&& array_key_exists($guardExprString, $theirExpressionTypes)
&& $theirExpressionTypes[$guardExprString]->getCertainty()->yes()

Check warning on line 3655 in src/Analyser/MutatingScope.php

View workflow job for this annotation

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

Escaped Mutant for Mutator "PHPStan\Infection\TrinaryLogicMutator": @@ @@ if ( !array_key_exists($exprString, $theirExpressionTypes) && array_key_exists($guardExprString, $theirExpressionTypes) - && $theirExpressionTypes[$guardExprString]->getCertainty()->yes() + && !$theirExpressionTypes[$guardExprString]->getCertainty()->no() && $theirExpressionTypes[$guardExprString]->getType()->isObject()->no() && !$guardHolder->getType()->isSuperTypeOf($theirExpressionTypes[$guardExprString]->getType())->no() ) {

Check warning on line 3655 in src/Analyser/MutatingScope.php

View workflow job for this annotation

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

Escaped Mutant for Mutator "PHPStan\Infection\TrinaryLogicMutator": @@ @@ if ( !array_key_exists($exprString, $theirExpressionTypes) && array_key_exists($guardExprString, $theirExpressionTypes) - && $theirExpressionTypes[$guardExprString]->getCertainty()->yes() + && !$theirExpressionTypes[$guardExprString]->getCertainty()->no() && $theirExpressionTypes[$guardExprString]->getType()->isObject()->no() && !$guardHolder->getType()->isSuperTypeOf($theirExpressionTypes[$guardExprString]->getType())->no() ) {
&& $theirExpressionTypes[$guardExprString]->getType()->isObject()->no()

Check warning on line 3656 in src/Analyser/MutatingScope.php

View workflow job for this annotation

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

Escaped Mutant for Mutator "PHPStan\Infection\TrinaryLogicMutator": @@ @@ !array_key_exists($exprString, $theirExpressionTypes) && array_key_exists($guardExprString, $theirExpressionTypes) && $theirExpressionTypes[$guardExprString]->getCertainty()->yes() - && $theirExpressionTypes[$guardExprString]->getType()->isObject()->no() + && !$theirExpressionTypes[$guardExprString]->getType()->isObject()->yes() && !$guardHolder->getType()->isSuperTypeOf($theirExpressionTypes[$guardExprString]->getType())->no() ) { continue;

Check warning on line 3656 in src/Analyser/MutatingScope.php

View workflow job for this annotation

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

Escaped Mutant for Mutator "PHPStan\Infection\TrinaryLogicMutator": @@ @@ !array_key_exists($exprString, $theirExpressionTypes) && array_key_exists($guardExprString, $theirExpressionTypes) && $theirExpressionTypes[$guardExprString]->getCertainty()->yes() - && $theirExpressionTypes[$guardExprString]->getType()->isObject()->no() + && !$theirExpressionTypes[$guardExprString]->getType()->isObject()->yes() && !$guardHolder->getType()->isSuperTypeOf($theirExpressionTypes[$guardExprString]->getType())->no() ) { continue;
&& !$guardHolder->getType()->isSuperTypeOf($theirExpressionTypes[$guardExprString]->getType())->no()

Check warning on line 3657 in src/Analyser/MutatingScope.php

View workflow job for this annotation

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

Escaped Mutant for Mutator "PHPStan\Infection\IsSuperTypeOfCalleeAndArgumentMutator": @@ @@ && array_key_exists($guardExprString, $theirExpressionTypes) && $theirExpressionTypes[$guardExprString]->getCertainty()->yes() && $theirExpressionTypes[$guardExprString]->getType()->isObject()->no() - && !$guardHolder->getType()->isSuperTypeOf($theirExpressionTypes[$guardExprString]->getType())->no() + && !$theirExpressionTypes[$guardExprString]->getType()->isSuperTypeOf($guardHolder->getType())->no() ) { continue; }

Check warning on line 3657 in src/Analyser/MutatingScope.php

View workflow job for this annotation

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

Escaped Mutant for Mutator "PHPStan\Infection\IsSuperTypeOfCalleeAndArgumentMutator": @@ @@ && array_key_exists($guardExprString, $theirExpressionTypes) && $theirExpressionTypes[$guardExprString]->getCertainty()->yes() && $theirExpressionTypes[$guardExprString]->getType()->isObject()->no() - && !$guardHolder->getType()->isSuperTypeOf($theirExpressionTypes[$guardExprString]->getType())->no() + && !$theirExpressionTypes[$guardExprString]->getType()->isSuperTypeOf($guardHolder->getType())->no() ) { continue; }
) {
continue;
}
$conditionalExpression = new ConditionalExpressionHolder([$guardExprString => $guardHolder], $holder);
$conditionalExpressions[$exprString][$conditionalExpression->getKey()] = $conditionalExpression;
}
Expand Down
54 changes: 54 additions & 0 deletions tests/PHPStan/Analyser/nsrt/bug-14469-variants.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<?php declare(strict_types = 1);

namespace Bug14469Variants;

use function PHPStan\Testing\assertType;

// Variant 1: if/else where one branch doesn't access the array key
function variant1(array $R, bool $cond, int $other): void {
$aa = null;

if ($cond) {
$aa = $other;
} else {
if ($R['key']) {
$aa = $R['key'];
}
}

if ($aa) {
assertType('mixed', $R['key']);
}
}

// Variant 2: Multiple elseif branches
function variant2(array $R, bool $var1, bool $var2, int $other1, int $other2): void {
$aa = null;

if ($var1) {
$aa = $other1;
} elseif ($var2) {
$aa = $other2;
} elseif ($R['key']) {
$aa = $R['key'];
}

if ($aa) {
assertType('mixed', $R['key']);
}
}

// Variant 3: Nested array access
function variant3(array $R, bool $cond, int $other): void {
$aa = null;

if ($cond) {
$aa = $other;
} elseif ($R['nested']['key']) {
$aa = $R['nested']['key'];
}

if ($aa) {
assertType('mixed', $R['nested']['key']);
}
}
19 changes: 19 additions & 0 deletions tests/PHPStan/Analyser/nsrt/bug-14469.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php declare(strict_types = 1);

namespace Bug14469Nsrt;

use function PHPStan\Testing\assertType;

function t(array $R, bool $var1, object $user): void {
$aa = null;

if ($var1) {
$aa = $user->id === 10 ? 2 : null;
} elseif ($R['aa']) {
$aa = $R['aa'];
}

if ($aa) {
assertType('mixed', $R['aa']);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -236,4 +236,10 @@ public function testBug6702(): void
$this->analyse([__DIR__ . '/data/bug-6702.php'], []);
}

public function testBug14469(): void
{
$this->treatPhpDocTypesAsCertain = true;
$this->analyse([__DIR__ . '/data/bug-14469.php'], []);
}

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

namespace Bug14469;

function t(array $R, bool $var1, object $user, bool $is): array {
$aa = null;

if ($var1) {
$aa = $user->id === 10 ? 2 : null;
} elseif ($R['aa']) {
$aa = $R['aa'];
}

if ($aa) {
if (!$R['aa']) {
return [];
}
}
return $R;
}

function t2(array $R, bool $var1, object $user): array {
$aa = null;

if ($var1) {
$aa = $user->id === 10 ? 2 : null;
} elseif ($R['aa']) {
$aa = $R['aa'];
}

if ($aa) {
if ($R['aa'] === false) {
return [];
}
}
return $R;
}

function t3(array $R, bool $var1, int $other): array {
$aa = null;

if ($var1) {
$aa = $other;
} elseif ($R['bb']) {
$aa = $R['bb'];
}

if ($aa) {
if (!$R['bb']) {
return [];
}
}
return $R;
}

function t4(array $R, bool $var1, object $user): string {
$aa = null;

if ($var1) {
$aa = $user->id === 10 ? 2 : null;
} elseif ($R['aa']) {
$aa = $R['aa'];
}

return $aa ? ($R['aa'] ? 'yes' : 'no') : 'none';
}
Loading