Skip to content

Commit

Permalink
[Php80] Handle Generic TemplateType on ClassPropertyAssignToConstruct…
Browse files Browse the repository at this point in the history
…orPromotionRector (#751)

* Add failing test fixture for ClassPropertyAssignToConstructorPromotionRector

# Failing Test for ClassPropertyAssignToConstructorPromotionRector

Based on https://getrector.org/demo/1ec04a84-bde1-6cb0-a397-d7c0f606a738

* Closes #749

* naming

* phpstan

* early check is param used before assign

Co-authored-by: Jáchym Toušek <enumag@gmail.com>
  • Loading branch information
samsonasik and enumag committed Aug 24, 2021
1 parent 6ff80ba commit 885ef76
Show file tree
Hide file tree
Showing 2 changed files with 72 additions and 9 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<?php

namespace Rector\Tests\Php80\Rector\Class_\ClassPropertyAssignToConstructorPromotionRector\Fixture;

/**
* @template T
*/
final class Generic
{
/**
* @var T
*/
public mixed $value;

/**
* @param T $value
*/
public function __construct(mixed $value)
{
$this->value = $value;
}
}
?>
-----
<?php

namespace Rector\Tests\Php80\Rector\Class_\ClassPropertyAssignToConstructorPromotionRector\Fixture;

/**
* @template T
*/
final class Generic
{
/**
* @param T $value
*/
public function __construct(public mixed $value)
{
}
}
?>
40 changes: 31 additions & 9 deletions rules/Php80/NodeAnalyzer/PromotedPropertyCandidateResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Stmt\Expression;
use PhpParser\Node\Stmt\Property;
use PHPStan\Type\Generic\TemplateType;
use PHPStan\Type\Type;
use PHPStan\Type\UnionType;
use Rector\Core\PhpParser\Comparing\NodeComparator;
Expand Down Expand Up @@ -186,12 +187,11 @@ private function hasConflictingParamType(Param $param, Type $propertyType): bool

$isAllFullyQualifiedObjectType = true;
if ($propertyType instanceof UnionType) {
foreach ($propertyType->getTypes() as $type) {
if (! $type instanceof FullyQualifiedObjectType) {
$isAllFullyQualifiedObjectType = false;
break;
}
if ($this->hasGenericTemplateType($propertyType)) {
return false;
}

$isAllFullyQualifiedObjectType = ! $this->hasNonFullyQualifiedObjectType($propertyType);
}

// different types, not a good to fit
Expand All @@ -201,6 +201,28 @@ private function hasConflictingParamType(Param $param, Type $propertyType): bool
);
}

private function hasNonFullyQualifiedObjectType(UnionType $unionType): bool
{
foreach ($unionType->getTypes() as $type) {
if (! $type instanceof FullyQualifiedObjectType) {
return true;
}
}

return false;
}

private function hasGenericTemplateType(UnionType $unionType): bool
{
foreach ($unionType->getTypes() as $type) {
if ($type instanceof TemplateType) {
return true;
}
}

return false;
}

/**
* @param int[] $firstParamAsVariable
*/
Expand All @@ -215,12 +237,12 @@ private function shouldSkipParam(
return true;
}

// @todo unknown type, not suitable?
$propertyType = $this->propertyTypeInferer->inferProperty($property);
if ($this->hasConflictingParamType($matchedParam, $propertyType)) {
if ($this->isParamUsedBeforeAssign($assignedVariable, $firstParamAsVariable)) {
return true;
}

return $this->isParamUsedBeforeAssign($assignedVariable, $firstParamAsVariable);
// @todo unknown type, not suitable?
$propertyType = $this->propertyTypeInferer->inferProperty($property);
return $this->hasConflictingParamType($matchedParam, $propertyType);
}
}

0 comments on commit 885ef76

Please sign in to comment.