diff --git a/src/Rules/Debug/FileAssertRule.php b/src/Rules/Debug/FileAssertRule.php index 3f8e6a62ee..769f37bd1c 100644 --- a/src/Rules/Debug/FileAssertRule.php +++ b/src/Rules/Debug/FileAssertRule.php @@ -171,15 +171,14 @@ private function processAssertVariableCertainty(array $args, Scope $scope): arra // @phpstan-ignore staticMethod.dynamicName $expectedCertaintyValue = TrinaryLogic::{$certainty->name->toString()}(); $variable = $args[1]->value; - if (!$variable instanceof Node\Expr\Variable) { - return [ - RuleErrorBuilder::message('Invalid assertVariableCertainty call.') - ->nonIgnorable() - ->identifier('phpstan.unknownExpectation') - ->build(), - ]; - } - if (!is_string($variable->name)) { + if ($variable instanceof Node\Expr\Variable && is_string($variable->name)) { + $actualCertaintyValue = $scope->hasVariableType($variable->name); + $variableDescription = sprintf('variable $%s', $variable->name); + } elseif ($variable instanceof Node\Expr\ArrayDimFetch && $variable->dim !== null) { + $offset = $scope->getType($variable->dim); + $actualCertaintyValue = $scope->getType($variable->var)->hasOffsetValueType($offset); + $variableDescription = sprintf('offset %s', $offset->describe(VerbosityLevel::precise())); + } else { return [ RuleErrorBuilder::message('Invalid assertVariableCertainty call.') ->nonIgnorable() @@ -188,13 +187,12 @@ private function processAssertVariableCertainty(array $args, Scope $scope): arra ]; } - $actualCertaintyValue = $scope->hasVariableType($variable->name); if ($expectedCertaintyValue->equals($actualCertaintyValue)) { return []; } return [ - RuleErrorBuilder::message(sprintf('Expected variable certainty %s, actual: %s', $expectedCertaintyValue->describe(), $actualCertaintyValue->describe())) + RuleErrorBuilder::message(sprintf('Expected %s certainty %s, actual: %s', $variableDescription, $expectedCertaintyValue->describe(), $actualCertaintyValue->describe())) ->nonIgnorable() ->identifier('phpstan.variable') ->build(), diff --git a/src/Testing/TypeInferenceTestCase.php b/src/Testing/TypeInferenceTestCase.php index a80e510da3..2b8d8e855c 100644 --- a/src/Testing/TypeInferenceTestCase.php +++ b/src/Testing/TypeInferenceTestCase.php @@ -135,7 +135,7 @@ public function assertFileAsserts( $variableName = $args[2]; $this->assertTrue( $expectedCertainty->equals($actualCertainty), - sprintf('Expected %s, actual certainty of variable $%s is %s in %s on line %d.', $expectedCertainty->describe(), $variableName, $actualCertainty->describe(), $file, $args[3]), + sprintf('Expected %s, actual certainty of %s is %s in %s on line %d.', $expectedCertainty->describe(), $variableName, $actualCertainty->describe(), $file, $args[3]), ); } } @@ -216,15 +216,18 @@ public static function gatherAssertTypes(string $file): array // @phpstan-ignore staticMethod.dynamicName $expectedertaintyValue = TrinaryLogic::{$certainty->name->toString()}(); $variable = $node->getArgs()[1]->value; - if (!$variable instanceof Node\Expr\Variable) { - self::fail(sprintf('ERROR: Invalid assertVariableCertainty call.')); - } - if (!is_string($variable->name)) { + if ($variable instanceof Node\Expr\Variable && is_string($variable->name)) { + $actualCertaintyValue = $scope->hasVariableType($variable->name); + $variableDescription = sprintf('variable $%s', $variable->name); + } elseif ($variable instanceof Node\Expr\ArrayDimFetch && $variable->dim !== null) { + $offset = $scope->getType($variable->dim); + $actualCertaintyValue = $scope->getType($variable->var)->hasOffsetValueType($offset); + $variableDescription = sprintf('offset %s', $offset->describe(VerbosityLevel::precise())); + } else { self::fail(sprintf('ERROR: Invalid assertVariableCertainty call.')); } - $actualCertaintyValue = $scope->hasVariableType($variable->name); - $assert = ['variableCertainty', $file, $expectedertaintyValue, $actualCertaintyValue, $variable->name, $node->getStartLine()]; + $assert = ['variableCertainty', $file, $expectedertaintyValue, $actualCertaintyValue, $variableDescription, $node->getStartLine()]; } else { $correctFunction = null; diff --git a/tests/PHPStan/Analyser/LegacyNodeScopeResolverTest.php b/tests/PHPStan/Analyser/LegacyNodeScopeResolverTest.php index 430b0e02f8..aea1961e32 100644 --- a/tests/PHPStan/Analyser/LegacyNodeScopeResolverTest.php +++ b/tests/PHPStan/Analyser/LegacyNodeScopeResolverTest.php @@ -906,7 +906,7 @@ private function assertVariables( $this->assertTrue( $expectedCertainty->equals($certainty), sprintf( - 'Certainty of variable $%s is %s, expected %s', + 'Certainty of %s is %s, expected %s', $variableName, $certainty->describe(), $expectedCertainty->describe(), diff --git a/tests/PHPStan/Analyser/NodeScopeResolverTest.php b/tests/PHPStan/Analyser/NodeScopeResolverTest.php index 2816b5ce52..e0998e5252 100644 --- a/tests/PHPStan/Analyser/NodeScopeResolverTest.php +++ b/tests/PHPStan/Analyser/NodeScopeResolverTest.php @@ -255,7 +255,7 @@ public function testFile(string $file): void $variableName = $args[2]; if ($expectedCertainty->equals($actualCertainty) !== true) { - $failures[] = sprintf("Certainty of variable \$%s on line %d:\nExpected: %s\nActual: %s\n", $variableName, $args[3], $expectedCertainty->describe(), $actualCertainty->describe()); + $failures[] = sprintf("Certainty of %s on line %d:\nExpected: %s\nActual: %s\n", $variableName, $args[3], $expectedCertainty->describe(), $actualCertainty->describe()); } } } diff --git a/tests/PHPStan/Analyser/nsrt/assert-variable-certainty-on-array.php b/tests/PHPStan/Analyser/nsrt/assert-variable-certainty-on-array.php new file mode 100644 index 0000000000..813518812a --- /dev/null +++ b/tests/PHPStan/Analyser/nsrt/assert-variable-certainty-on-array.php @@ -0,0 +1,28 @@ +gatherAssertTypes($filePath); } + public function testVariableOrOffsetDescription(): void + { + $filePath = __DIR__ . '/data/assert-certainty-variable-or-offset.php'; + + [$variableAssert, $offsetAssert] = array_values($this->gatherAssertTypes($filePath)); + + $this->assertSame('variable $context', $variableAssert[4]); + $this->assertSame("offset 'email'", $offsetAssert[4]); + } + } diff --git a/tests/PHPStan/Testing/data/assert-certainty-variable-or-offset.php b/tests/PHPStan/Testing/data/assert-certainty-variable-or-offset.php new file mode 100644 index 0000000000..b06391db45 --- /dev/null +++ b/tests/PHPStan/Testing/data/assert-certainty-variable-or-offset.php @@ -0,0 +1,15 @@ +