Skip to content

Commit

Permalink
[TypeDeclaration] Handle Anonymous class extends existing class in un…
Browse files Browse the repository at this point in the history
…ion (#3161)

Co-authored-by: GitHub Action <action@github.com>
  • Loading branch information
samsonasik and actions-user committed Dec 6, 2022
1 parent 91ebee8 commit d3abaa1
Show file tree
Hide file tree
Showing 6 changed files with 179 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
use PHPStan\Type\ObjectWithoutClassType;
use PHPStan\Type\Type;
use Rector\BetterPhpDocParser\ValueObject\Type\EmptyGenericTypeNode;
use Rector\BetterPhpDocParser\ValueObject\Type\FullyQualifiedIdentifierTypeNode;
use Rector\Core\Php\PhpVersionProvider;
use Rector\Core\ValueObject\PhpVersionFeature;
use Rector\NodeTypeResolver\PHPStan\ObjectWithoutClassTypeWithParentTypes;
Expand Down Expand Up @@ -51,6 +52,15 @@ public function mapToPHPStanPhpDocTypeNode(Type $type, string $typeKind): TypeNo
return new EmptyGenericTypeNode($attributeAwareIdentifierTypeNode);
}

// special case for anonymous classes that implement another type
if ($type instanceof ObjectWithoutClassTypeWithParentTypes) {
$parentTypes = $type->getParentTypes();
if (count($parentTypes) === 1) {
$parentType = $parentTypes[0];
return new FullyQualifiedIdentifierTypeNode($parentType->getClassName());
}
}

return new IdentifierTypeNode('object');
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php

namespace Rector\Tests\TypeDeclaration\Rector\Property\TypedPropertyFromAssignsRector\Fixture;

final class AnonymousExtendsExistingClass
{
private $x;

public function __construct()
{
$this->x = new class extends \DateTime {};
}
}

?>
-----
<?php

namespace Rector\Tests\TypeDeclaration\Rector\Property\TypedPropertyFromAssignsRector\Fixture;

final class AnonymousExtendsExistingClass
{
private \DateTime $x;

public function __construct()
{
$this->x = new class extends \DateTime {};
}
}

?>
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<?php

namespace Rector\Tests\TypeDeclaration\Rector\Property\TypedPropertyFromAssignsRector\Fixture;

final class AnonymousExtendsExistingClassInUnion
{
private $x;

public function __construct()
{
if (rand(0,1)) {
$this->x = new \DateTime('now');
} else {
$this->x = new class extends \DateTime {};
}
}
}

?>
-----
<?php

namespace Rector\Tests\TypeDeclaration\Rector\Property\TypedPropertyFromAssignsRector\Fixture;

final class AnonymousExtendsExistingClassInUnion
{
/**
* @var \DateTime|null
*/
private $x;

public function __construct()
{
if (rand(0,1)) {
$this->x = new \DateTime('now');
} else {
$this->x = new class extends \DateTime {};
}
}
}

?>
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<?php

namespace Rector\Tests\TypeDeclaration\Rector\Property\TypedPropertyFromAssignsRector\FixtureComplexTypes;

final class AnonymousExtendsExistingClassInUnion
{
private $x;

public function __construct()
{
if (rand(0,1)) {
$this->x = new \DateTime('now');
} else {
$this->x = new class extends \DateTime {};
}
}
}

?>
-----
<?php

namespace Rector\Tests\TypeDeclaration\Rector\Property\TypedPropertyFromAssignsRector\FixtureComplexTypes;

final class AnonymousExtendsExistingClassInUnion
{
private \DateTime|null $x = null;

public function __construct()
{
if (rand(0,1)) {
$this->x = new \DateTime('now');
} else {
$this->x = new class extends \DateTime {};
}
}
}

?>
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<?php declare(strict_types=1);

namespace Rector\Tests\TypeDeclaration\Rector\Property\TypedPropertyFromAssignsRector\FixtureComplexTypes;

final class AnonymousExtendsExistingClassInUnionRemoveDocblock
{
/**
* @var \DateTime|null
*/
private $x;

public function __construct()
{
if (rand(0, 1)) {
$this->x = new \DateTime('now');
} else {
$this->x = new class() extends \DateTime {
};
}
}
}

?>
-----
<?php

namespace Rector\Tests\TypeDeclaration\Rector\Property\TypedPropertyFromAssignsRector\FixtureComplexTypes;

final class AnonymousExtendsExistingClassInUnion
{
private \DateTime|null $x = null;

public function __construct()
{
if (rand(0, 1)) {
$this->x = new \DateTime('now');
} else {
$this->x = new class() extends \DateTime {
};
}
}
}

?>
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
use PHPStan\Type\Type;
use PHPStan\Type\TypeCombinator;
use PHPStan\Type\UnionType;
use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfo;
use Rector\BetterPhpDocParser\PhpDocManipulator\PhpDocTypeChanger;
use Rector\Core\Contract\Rector\AllowEmptyConfigurableRectorInterface;
use Rector\Core\Php\PhpVersionProvider;
Expand Down Expand Up @@ -129,18 +130,18 @@ public function refactor(Node $node): ?Node
$typeNode = $this->staticTypeMapper->mapPHPStanTypeToPhpParserNode($inferredType, TypeKind::PROPERTY);
if ($typeNode === null) {
$this->phpDocTypeChanger->changeVarType($phpDocInfo, $inferredType);
return $node;
return $this->processChangedPhpDocInfo($phpDocInfo, $node);
}

if (! $this->phpVersionProvider->isAtLeastPhpVersion(PhpVersionFeature::TYPED_PROPERTIES)) {
$this->phpDocTypeChanger->changeVarType($phpDocInfo, $inferredType);
return $node;
return $this->processChangedPhpDocInfo($phpDocInfo, $node);
}

// non-private property can be anything with not inline public configured
if (! $node->isPrivate() && ! $this->inlinePublic) {
$this->phpDocTypeChanger->changeVarType($phpDocInfo, $inferredType);
return $node;
return $this->processChangedPhpDocInfo($phpDocInfo, $node);
}

if ($inferredType instanceof UnionType) {
Expand All @@ -154,6 +155,15 @@ public function refactor(Node $node): ?Node
return $node;
}

private function processChangedPhpDocInfo(PhpDocInfo $phpDocInfo, Node $node): ?Node
{
if ($phpDocInfo->hasChanged()) {
return $node;
}

return null;
}

private function decorateTypeWithNullableIfDefaultPropertyNull(Property $property, Type $inferredType): Type
{
$defaultExpr = $property->props[0]->default;
Expand Down

0 comments on commit d3abaa1

Please sign in to comment.