Skip to content

Commit

Permalink
Better strategy
Browse files Browse the repository at this point in the history
  • Loading branch information
VincentLanglet committed Jan 19, 2025
1 parent c89e58b commit f4a6d4e
Show file tree
Hide file tree
Showing 4 changed files with 38 additions and 16 deletions.
9 changes: 1 addition & 8 deletions src/Type/Php/IsAFunctionTypeSpecifyingExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,9 @@
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 @@ -50,14 +47,10 @@ 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()) {
if ($classType->getConstantStrings() === [] && $resultType->isSuperTypeOf($objectOrClassType)->yes()) {
return new SpecifiedTypes([], []);
}

Expand Down
9 changes: 1 addition & 8 deletions src/Type/Php/IsSubclassOfFunctionTypeSpecifyingExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,9 @@
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 @@ -51,14 +48,10 @@ 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()) {
if ($classType->getConstantStrings() === [] && $resultType->isSuperTypeOf($objectOrClassType)->yes()) {
return new SpecifiedTypes([], []);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1127,4 +1127,16 @@ public function testBug8954(): void
$this->analyse([__DIR__ . '/data/bug-8954.php'], []);
}

public function testBugPR3404(): void
{
$this->checkAlwaysTrueCheckTypeFunctionCall = true;
$this->treatPhpDocTypesAsCertain = true;
$this->analyse([__DIR__ . '/data/bug-pr-3404.php'], [
[
'Call to function is_a() with arguments BugPR3404\Location, \'BugPR3404\\\\Location\' and true will always evaluate to true.',
21,
],
]);
}

}
24 changes: 24 additions & 0 deletions tests/PHPStan/Rules/Comparison/data/bug-pr-3404.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php // lint >= 8.0

namespace BugPR3404;

interface Location
{

}

/** @return class-string<Location> */
function aaa(): string
{

}

function (Location $l): void {
if (is_a($l, aaa(), true)) {
// might not always be true. $l might be one subtype of Location, aaa() might return a name of a different subtype of Location
}

if (is_a($l, Location::class, true)) {
// always true
}
};

0 comments on commit f4a6d4e

Please sign in to comment.