Skip to content

Commit

Permalink
Understand get_class compared with static::class
Browse files Browse the repository at this point in the history
  • Loading branch information
ondrejmirtes committed Jun 19, 2023
1 parent 106526d commit 590eb03
Show file tree
Hide file tree
Showing 5 changed files with 67 additions and 32 deletions.
5 changes: 0 additions & 5 deletions phpstan-baseline.neon
Original file line number Diff line number Diff line change
Expand Up @@ -1512,11 +1512,6 @@ parameters:
count: 1
path: src/Type/StaticType.php

-
message: "#^PHPDoc tag @var assumes the expression with type PHPStan\\\\Type\\\\Type is always PHPStan\\\\Type\\\\StaticType but it's error\\-prone and dangerous\\.$#"
count: 1
path: src/Type/StaticType.php

-
message: "#^Doing instanceof PHPStan\\\\Type\\\\Constant\\\\ConstantStringType is error\\-prone and deprecated\\. Use Type\\:\\:getConstantStrings\\(\\) instead\\.$#"
count: 1
Expand Down
62 changes: 37 additions & 25 deletions src/Analyser/TypeSpecifier.php
Original file line number Diff line number Diff line change
Expand Up @@ -181,27 +181,61 @@ public function specifyTypesInCondition(
return $this->create($exprNode, new ObjectWithoutClassType(), $context, false, $scope, $rootExpr);
}
} elseif ($expr instanceof Node\Expr\BinaryOp\Identical) {
$leftExpr = $expr->left;
$rightExpr = $expr->right;
if ($rightExpr instanceof FuncCall && !$leftExpr instanceof FuncCall) {
[$leftExpr, $rightExpr] = [$rightExpr, $leftExpr];
}
$unwrappedLeftExpr = $leftExpr;
if ($leftExpr instanceof AlwaysRememberedExpr) {
$unwrappedLeftExpr = $leftExpr->getExpr();
}
$rightType = $scope->getType($rightExpr);
if (
$context->true()
&& $unwrappedLeftExpr instanceof FuncCall
&& $unwrappedLeftExpr->name instanceof Name
&& strtolower($unwrappedLeftExpr->name->toString()) === 'get_class'
&& isset($unwrappedLeftExpr->getArgs()[0])
) {
if ($rightType->getClassStringObjectType()->isObject()->yes()) {
return $this->create(
$unwrappedLeftExpr->getArgs()[0]->value,
$rightType->getClassStringObjectType(),
$context,
false,
$scope,
$rootExpr,
)->unionWith($this->create($leftExpr, $rightType, $context, false, $scope, $rootExpr));
}
}

$expressions = $this->findTypeExpressionsFromBinaryOperation($scope, $expr);
if ($expressions !== null) {
$exprNode = $expressions[0];
$constantType = $expressions[1];

if ($constantType instanceof ConstantStringType) {
$specifiedType = $this->specifyTypesForConstantStringBinaryExpression($exprNode, $constantType, $context, $scope, $rootExpr);
if ($specifiedType !== null) {
return $specifiedType;
}
}

$specifiedType = $this->specifyTypesForConstantBinaryExpression($exprNode, $constantType, $context, $scope, $rootExpr);
if ($specifiedType !== null) {
return $specifiedType;
}
}

$rightExpr = $expr->right;
if ($rightExpr instanceof AlwaysRememberedExpr) {
$rightExpr = $rightExpr->getExpr();
}

$leftExpr = $expr->left;
if ($leftExpr instanceof AlwaysRememberedExpr) {
$leftExpr = $leftExpr->getExpr();
}
$rightType = $scope->getType($rightExpr);

if (
$leftExpr instanceof ClassConstFetch &&
$leftExpr->class instanceof Expr &&
Expand Down Expand Up @@ -1020,10 +1054,6 @@ private function specifyTypesForConstantBinaryExpression(

}

if ($constantType instanceof ConstantStringType) {
return $this->specifyTypesForConstantStringBinaryExpression($exprNode, $constantType, $context, $scope, $rootExpr);
}

return null;
}

Expand Down Expand Up @@ -1110,24 +1140,6 @@ private function specifyTypesForConstantStringBinaryExpression(
}
}

if (
$context->true()
&& $unwrappedExprNode instanceof FuncCall
&& $unwrappedExprNode->name instanceof Name
&& strtolower($unwrappedExprNode->name->toString()) === 'get_class'
&& isset($unwrappedExprNode->getArgs()[0])
) {
return $this->specifyTypesInCondition(
$scope,
new Instanceof_(
$unwrappedExprNode->getArgs()[0]->value,
new Name($constantType->getValue()),
),
$context,
$rootExpr,
)->unionWith($this->create($exprNode, $constantType, $context, false, $scope, $rootExpr));
}

if (
$context->true()
&& $exprNode instanceof FuncCall
Expand Down
2 changes: 0 additions & 2 deletions src/Type/StaticType.php
Original file line number Diff line number Diff line change
Expand Up @@ -184,8 +184,6 @@ public function equals(Type $type): bool
return false;
}

/** @var StaticType $type */
$type = $type;
return $this->getStaticObjectType()->equals($type->getStaticObjectType());
}

Expand Down
2 changes: 2 additions & 0 deletions tests/PHPStan/Analyser/NodeScopeResolverTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,8 @@ public function dataFileAsserts(): iterable

yield from $this->gatherAssertTypes(__DIR__ . '/data/dynamic-sprintf.php');

yield from $this->gatherAssertTypes(__DIR__ . '/data/get-class-static-class.php');

yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-2816.php');

yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-2816-2.php');
Expand Down
28 changes: 28 additions & 0 deletions tests/PHPStan/Analyser/data/get-class-static-class.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?php

namespace GetClassStaticClass;

use function PHPStan\Testing\assertType;

class Foo
{

public function doFoo(object $o): void
{
if (get_class($o) !== static::class) {
return;
}

assertType('static(GetClassStaticClass\Foo)', $o);
}

public function doFoo2(object $o): void
{
if (static::class !== get_class($o)) {
return;
}

assertType('static(GetClassStaticClass\Foo)', $o);
}

}

0 comments on commit 590eb03

Please sign in to comment.