Skip to content

Commit

Permalink
Merge branch refs/heads/1.12.x into 2.1.x
Browse files Browse the repository at this point in the history
  • Loading branch information
phpstan-bot authored Jan 11, 2025
2 parents eb0e0bc + 0711bec commit 5258f86
Show file tree
Hide file tree
Showing 6 changed files with 168 additions and 9 deletions.
4 changes: 0 additions & 4 deletions src/Rules/Comparison/ImpossibleCheckTypeFunctionCallRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
use PHPStan\Rules\Rule;
use PHPStan\Rules\RuleErrorBuilder;
use function sprintf;
use function strtolower;

/**
* @implements Rule<Node\Expr\FuncCall>
Expand Down Expand Up @@ -37,9 +36,6 @@ public function processNode(Node $node, Scope $scope): array
}

$functionName = (string) $node->name;
if (strtolower($functionName) === 'is_a') {
return [];
}
$isAlways = $this->impossibleCheckTypeHelper->findSpecifiedType($scope, $node);
if ($isAlways === null) {
return [];
Expand Down
16 changes: 15 additions & 1 deletion src/Type/Php/IsAFunctionTypeSpecifyingExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,12 @@
use PHPStan\Analyser\TypeSpecifierAwareExtension;
use PHPStan\Analyser\TypeSpecifierContext;
use PHPStan\Reflection\FunctionReflection;
use PHPStan\Type\ClassStringType;
use PHPStan\Type\Constant\ConstantBooleanType;
use PHPStan\Type\Constant\ConstantStringType;
use PHPStan\Type\FunctionTypeSpecifyingExtension;
use PHPStan\Type\ObjectWithoutClassType;
use PHPStan\Type\TypeCombinator;
use function count;
use function strtolower;

Expand Down Expand Up @@ -47,9 +50,20 @@ public function specifyTypes(FunctionReflection $functionReflection, FuncCall $n
$allowStringType = isset($node->getArgs()[2]) ? $scope->getType($node->getArgs()[2]->value) : new ConstantBooleanType(false);
$allowString = !$allowStringType->equals(new ConstantBooleanType(false));

$superType = $allowString
? TypeCombinator::union(new ObjectWithoutClassType(), new ClassStringType())
: new ObjectWithoutClassType();

$resultType = $this->isAFunctionTypeSpecifyingHelper->determineType($objectOrClassType, $classType, $allowString, true);

// prevent false-positives in IsAFunctionTypeSpecifyingHelper
if ($resultType->equals($superType) && $resultType->isSuperTypeOf($objectOrClassType)->yes()) {
return new SpecifiedTypes([], []);
}

return $this->typeSpecifier->create(
$node->getArgs()[0]->value,
$this->isAFunctionTypeSpecifyingHelper->determineType($objectOrClassType, $classType, $allowString, true),
$resultType,
$context,
$scope,
);
Expand Down
16 changes: 15 additions & 1 deletion src/Type/Php/IsSubclassOfFunctionTypeSpecifyingExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,12 @@
use PHPStan\Analyser\TypeSpecifierAwareExtension;
use PHPStan\Analyser\TypeSpecifierContext;
use PHPStan\Reflection\FunctionReflection;
use PHPStan\Type\ClassStringType;
use PHPStan\Type\Constant\ConstantBooleanType;
use PHPStan\Type\FunctionTypeSpecifyingExtension;
use PHPStan\Type\Generic\GenericClassStringType;
use PHPStan\Type\ObjectWithoutClassType;
use PHPStan\Type\TypeCombinator;
use function count;
use function strtolower;

Expand Down Expand Up @@ -48,9 +51,20 @@ public function specifyTypes(FunctionReflection $functionReflection, FuncCall $n
return new SpecifiedTypes([], []);
}

$superType = $allowString
? TypeCombinator::union(new ObjectWithoutClassType(), new ClassStringType())
: new ObjectWithoutClassType();

$resultType = $this->isAFunctionTypeSpecifyingHelper->determineType($objectOrClassType, $classType, $allowString, false);

// prevent false-positives in IsAFunctionTypeSpecifyingHelper
if ($resultType->equals($superType) && $resultType->isSuperTypeOf($objectOrClassType)->yes()) {
return new SpecifiedTypes([], []);
}

return $this->typeSpecifier->create(
$node->getArgs()[0]->value,
$this->isAFunctionTypeSpecifyingHelper->determineType($objectOrClassType, $classType, $allowString, false),
$resultType,
$context,
$scope,
);
Expand Down
4 changes: 1 addition & 3 deletions tests/PHPStan/Analyser/TypeSpecifierTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -1134,9 +1134,7 @@ public function dataCondition(): iterable
new Arg(new Variable('stringOrNull')),
new Arg(new Expr\ConstFetch(new Name('false'))),
]),
[
'$object' => 'object',
],
[],
[],
],
[
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -955,4 +955,11 @@ public function testAlwaysTruePregMatch(): void
$this->analyse([__DIR__ . '/data/always-true-preg-match.php'], []);
}

public function testBug3979(): void
{
$this->checkAlwaysTrueCheckTypeFunctionCall = true;

Check failure on line 960 in tests/PHPStan/Rules/Comparison/ImpossibleCheckTypeFunctionCallRuleTest.php

View workflow job for this annotation

GitHub Actions / PHPStan with result cache (8.3)

Access to an undefined property PHPStan\Rules\Comparison\ImpossibleCheckTypeFunctionCallRuleTest::$checkAlwaysTrueCheckTypeFunctionCall.

Check failure on line 960 in tests/PHPStan/Rules/Comparison/ImpossibleCheckTypeFunctionCallRuleTest.php

View workflow job for this annotation

GitHub Actions / PHPStan with result cache (8.2)

Access to an undefined property PHPStan\Rules\Comparison\ImpossibleCheckTypeFunctionCallRuleTest::$checkAlwaysTrueCheckTypeFunctionCall.

Check failure on line 960 in tests/PHPStan/Rules/Comparison/ImpossibleCheckTypeFunctionCallRuleTest.php

View workflow job for this annotation

GitHub Actions / PHPStan (8.4, ubuntu-latest)

Access to an undefined property PHPStan\Rules\Comparison\ImpossibleCheckTypeFunctionCallRuleTest::$checkAlwaysTrueCheckTypeFunctionCall.

Check failure on line 960 in tests/PHPStan/Rules/Comparison/ImpossibleCheckTypeFunctionCallRuleTest.php

View workflow job for this annotation

GitHub Actions / PHPStan with result cache (8.4)

Access to an undefined property PHPStan\Rules\Comparison\ImpossibleCheckTypeFunctionCallRuleTest::$checkAlwaysTrueCheckTypeFunctionCall.

Check failure on line 960 in tests/PHPStan/Rules/Comparison/ImpossibleCheckTypeFunctionCallRuleTest.php

View workflow job for this annotation

GitHub Actions / PHPStan with result cache (8.1)

Access to an undefined property PHPStan\Rules\Comparison\ImpossibleCheckTypeFunctionCallRuleTest::$checkAlwaysTrueCheckTypeFunctionCall.

Check failure on line 960 in tests/PHPStan/Rules/Comparison/ImpossibleCheckTypeFunctionCallRuleTest.php

View workflow job for this annotation

GitHub Actions / PHPStan (8.2, ubuntu-latest)

Access to an undefined property PHPStan\Rules\Comparison\ImpossibleCheckTypeFunctionCallRuleTest::$checkAlwaysTrueCheckTypeFunctionCall.

Check failure on line 960 in tests/PHPStan/Rules/Comparison/ImpossibleCheckTypeFunctionCallRuleTest.php

View workflow job for this annotation

GitHub Actions / PHPStan (8.1, ubuntu-latest)

Access to an undefined property PHPStan\Rules\Comparison\ImpossibleCheckTypeFunctionCallRuleTest::$checkAlwaysTrueCheckTypeFunctionCall.

Check failure on line 960 in tests/PHPStan/Rules/Comparison/ImpossibleCheckTypeFunctionCallRuleTest.php

View workflow job for this annotation

GitHub Actions / PHPStan (8.3, ubuntu-latest)

Access to an undefined property PHPStan\Rules\Comparison\ImpossibleCheckTypeFunctionCallRuleTest::$checkAlwaysTrueCheckTypeFunctionCall.

Check failure on line 960 in tests/PHPStan/Rules/Comparison/ImpossibleCheckTypeFunctionCallRuleTest.php

View workflow job for this annotation

GitHub Actions / PHPStan (8.0, ubuntu-latest)

Access to an undefined property PHPStan\Rules\Comparison\ImpossibleCheckTypeFunctionCallRuleTest::$checkAlwaysTrueCheckTypeFunctionCall.

Check failure on line 960 in tests/PHPStan/Rules/Comparison/ImpossibleCheckTypeFunctionCallRuleTest.php

View workflow job for this annotation

GitHub Actions / PHPStan (7.4, ubuntu-latest)

Access to an undefined property PHPStan\Rules\Comparison\ImpossibleCheckTypeFunctionCallRuleTest::$checkAlwaysTrueCheckTypeFunctionCall.

Check failure on line 960 in tests/PHPStan/Rules/Comparison/ImpossibleCheckTypeFunctionCallRuleTest.php

View workflow job for this annotation

GitHub Actions / PHPStan (8.1, windows-latest)

Access to an undefined property PHPStan\Rules\Comparison\ImpossibleCheckTypeFunctionCallRuleTest::$checkAlwaysTrueCheckTypeFunctionCall.

Check failure on line 960 in tests/PHPStan/Rules/Comparison/ImpossibleCheckTypeFunctionCallRuleTest.php

View workflow job for this annotation

GitHub Actions / PHPStan (8.4, windows-latest)

Access to an undefined property PHPStan\Rules\Comparison\ImpossibleCheckTypeFunctionCallRuleTest::$checkAlwaysTrueCheckTypeFunctionCall.

Check failure on line 960 in tests/PHPStan/Rules/Comparison/ImpossibleCheckTypeFunctionCallRuleTest.php

View workflow job for this annotation

GitHub Actions / PHPStan (8.2, windows-latest)

Access to an undefined property PHPStan\Rules\Comparison\ImpossibleCheckTypeFunctionCallRuleTest::$checkAlwaysTrueCheckTypeFunctionCall.

Check failure on line 960 in tests/PHPStan/Rules/Comparison/ImpossibleCheckTypeFunctionCallRuleTest.php

View workflow job for this annotation

GitHub Actions / PHPStan (8.3, windows-latest)

Access to an undefined property PHPStan\Rules\Comparison\ImpossibleCheckTypeFunctionCallRuleTest::$checkAlwaysTrueCheckTypeFunctionCall.

Check failure on line 960 in tests/PHPStan/Rules/Comparison/ImpossibleCheckTypeFunctionCallRuleTest.php

View workflow job for this annotation

GitHub Actions / PHPStan (8.0, windows-latest)

Access to an undefined property PHPStan\Rules\Comparison\ImpossibleCheckTypeFunctionCallRuleTest::$checkAlwaysTrueCheckTypeFunctionCall.

Check failure on line 960 in tests/PHPStan/Rules/Comparison/ImpossibleCheckTypeFunctionCallRuleTest.php

View workflow job for this annotation

GitHub Actions / PHPStan (7.4, windows-latest)

Access to an undefined property PHPStan\Rules\Comparison\ImpossibleCheckTypeFunctionCallRuleTest::$checkAlwaysTrueCheckTypeFunctionCall.
$this->treatPhpDocTypesAsCertain = true;
$this->analyse([__DIR__ . '/data/bug-3979.php'], []);
}

}
130 changes: 130 additions & 0 deletions tests/PHPStan/Rules/Comparison/data/bug-3979.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
<?php

namespace Bug3979;

class A { }
class B extends A { }
class C { }

/**
* @param mixed $value
* @param string $class_type
*/
function check_class($value, $class_type): bool
{
if (!is_string($value) || !class_exists($value) ||
($class_type && !is_subclass_of($value, $class_type)))
return false;
return true;
}

var_dump(check_class("B", "A")); // true
var_dump(check_class("C", "A")); // false

/**
* @param class-string $value
* @param string $class_type
*/
function check_class2($value, $class_type): bool
{
if (is_a($value, $class_type, true)) {
return true;
}
return false;
}

/**
* @param class-string|object $value
* @param string $class_type
*/
function check_class3($value, $class_type): bool
{
if (is_a($value, $class_type, true)) {
return true;
}
return false;
}

/**
* @param class-string|object $value
* @param string $class_type
*/
function check_class4($value, $class_type): bool
{
if (is_subclass_of($value, $class_type, true)) {
return true;
}
return false;
}

/**
* @param object $value
* @param string $class_type
*/
function check_class5($value, $class_type): bool
{
if (is_a($value, $class_type, true)) {
return true;
}
return false;
}

/**
* @param object $value
* @param string $class_type
*/
function check_class6($value, $class_type): bool
{
if (is_subclass_of($value, $class_type, true)) {
return true;
}
return false;
}

/**
* @param object $value
* @param class-string $class_type
*/
function check_class7($value, $class_type): bool
{
if (is_a($value, $class_type, true)) {
return true;
}
return false;
}

/**
* @param object $value
* @param class-string $class_type
*/
function check_class8($value, $class_type): bool
{
if (is_subclass_of($value, $class_type, true)) {
return true;
}
return false;
}

/**
* @param class-string $value
* @param class-string $class_type
*/
function check_class9($value, $class_type): bool
{
if (is_a($value, $class_type, true)) {
return true;
}
return false;
}

/**
* @param class-string $value
* @param class-string $class_type
*/
function check_class10($value, $class_type): bool
{
if (is_subclass_of($value, $class_type, true)) {
return true;
}
return false;
}

0 comments on commit 5258f86

Please sign in to comment.