diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index d7174f5db4..7325f424b4 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -1587,12 +1587,6 @@ parameters: count: 1 path: src/Type/Php/FilterFunctionReturnTypeHelper.php - - - rawMessage: 'Doing instanceof PHPStan\Type\Constant\ConstantStringType is error-prone and deprecated. Use Type::getConstantStrings() instead.' - identifier: phpstanApi.instanceofType - count: 1 - path: src/Type/Php/FunctionExistsFunctionTypeSpecifyingExtension.php - - rawMessage: 'Doing instanceof PHPStan\Type\Constant\ConstantArrayType is error-prone and deprecated. Use Type::getConstantArrays() instead.' identifier: phpstanApi.instanceofType diff --git a/src/Rules/Comparison/ImpossibleCheckTypeHelper.php b/src/Rules/Comparison/ImpossibleCheckTypeHelper.php index 69d934aba8..0a1621c842 100644 --- a/src/Rules/Comparison/ImpossibleCheckTypeHelper.php +++ b/src/Rules/Comparison/ImpossibleCheckTypeHelper.php @@ -81,6 +81,7 @@ public function findSpecifiedType( 'interface_exists', 'trait_exists', 'enum_exists', + 'function_exists', ], true)) { return null; } diff --git a/src/Type/Php/FunctionExistsFunctionTypeSpecifyingExtension.php b/src/Type/Php/FunctionExistsFunctionTypeSpecifyingExtension.php index 330735d9e4..ccab9e96ae 100644 --- a/src/Type/Php/FunctionExistsFunctionTypeSpecifyingExtension.php +++ b/src/Type/Php/FunctionExistsFunctionTypeSpecifyingExtension.php @@ -15,8 +15,8 @@ use PHPStan\Reflection\FunctionReflection; use PHPStan\Type\CallableType; use PHPStan\Type\Constant\ConstantBooleanType; -use PHPStan\Type\Constant\ConstantStringType; use PHPStan\Type\FunctionTypeSpecifyingExtension; +use function count; use function ltrim; #[AutowiredService] @@ -37,15 +37,23 @@ public function isFunctionSupported( public function specifyTypes(FunctionReflection $functionReflection, FuncCall $node, Scope $scope, TypeSpecifierContext $context): SpecifiedTypes { $argType = $scope->getType($node->getArgs()[0]->value); - if ($argType instanceof ConstantStringType) { - return $this->typeSpecifier->create( - new FuncCall(new FullyQualified('function_exists'), [ - new Arg(new String_(ltrim($argType->getValue(), '\\'))), - ]), - new ConstantBooleanType(true), - $context, - $scope, - ); + + $constantStrings = $argType->getConstantStrings(); + if (count($constantStrings) === 1) { + $specifiedTypes = new SpecifiedTypes(); + + foreach ($constantStrings as $constantString) { + $specifiedTypes = $specifiedTypes->unionWith($this->typeSpecifier->create( + new FuncCall(new FullyQualified('function_exists'), [ + new Arg(new String_(ltrim($constantString->getValue(), '\\'))), + ]), + new ConstantBooleanType(true), + $context, + $scope, + )); + } + + return $specifiedTypes; } return $this->typeSpecifier->create( diff --git a/tests/PHPStan/Rules/Comparison/IfConstantConditionRuleTest.php b/tests/PHPStan/Rules/Comparison/IfConstantConditionRuleTest.php index 5a847ad029..197afcbd3f 100644 --- a/tests/PHPStan/Rules/Comparison/IfConstantConditionRuleTest.php +++ b/tests/PHPStan/Rules/Comparison/IfConstantConditionRuleTest.php @@ -261,4 +261,15 @@ public function testBug5020(): void $this->analyse([__DIR__ . '/data/bug-5020.php'], []); } + public function testBug8980(): void + { + $this->treatPhpDocTypesAsCertain = true; + $this->analyse([__DIR__ . '/data/bug-8980.php'], [ + [ + 'If condition is always true.', + 23, + ], + ]); + } + } diff --git a/tests/PHPStan/Rules/Comparison/ImpossibleCheckTypeFunctionCallRuleTest.php b/tests/PHPStan/Rules/Comparison/ImpossibleCheckTypeFunctionCallRuleTest.php index ce1094a5b2..00306e738b 100644 --- a/tests/PHPStan/Rules/Comparison/ImpossibleCheckTypeFunctionCallRuleTest.php +++ b/tests/PHPStan/Rules/Comparison/ImpossibleCheckTypeFunctionCallRuleTest.php @@ -1236,6 +1236,12 @@ public function testBug8217(): void $this->analyse([__DIR__ . '/data/bug-8217.php'], []); } + public function testBug8980(): void + { + $this->treatPhpDocTypesAsCertain = true; + $this->analyse([__DIR__ . '/data/bug-8980.php'], []); + } + public function testBug6211(): void { $this->treatPhpDocTypesAsCertain = true; diff --git a/tests/PHPStan/Rules/Comparison/data/bug-8980.php b/tests/PHPStan/Rules/Comparison/data/bug-8980.php new file mode 100644 index 0000000000..fb5709ab11 --- /dev/null +++ b/tests/PHPStan/Rules/Comparison/data/bug-8980.php @@ -0,0 +1,26 @@ +analyse([__DIR__ . '/data/bug-14384.php'], []); } + public function testBug8980(): void + { + $this->analyse([__DIR__ . '/data/bug-8980.php'], [ + [ + 'Function funcA not found.', + 13, + 'Learn more at https://phpstan.org/user-guide/discovering-symbols', + ], + [ + 'Function funcB not found.', + 14, + 'Learn more at https://phpstan.org/user-guide/discovering-symbols', + ], + ]); + } + } diff --git a/tests/PHPStan/Rules/Functions/data/bug-8980.php b/tests/PHPStan/Rules/Functions/data/bug-8980.php new file mode 100644 index 0000000000..5cdcfbb85c --- /dev/null +++ b/tests/PHPStan/Rules/Functions/data/bug-8980.php @@ -0,0 +1,16 @@ +