Skip to content

Commit

Permalink
[Performance][TypeDeclaration] Reduce resolve ClassReflection from Pr…
Browse files Browse the repository at this point in the history
…operty on AllAssignNodePropertyTypeInferer (#4539)

Co-authored-by: GitHub Action <actions@github.com>
  • Loading branch information
samsonasik and actions-user committed Jul 19, 2023
1 parent d060450 commit 6451387
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 51 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ private function isAllowedExpr(Expr $expr, Scope $scope): bool
return false;
}

$type = $this->allAssignNodePropertyTypeInferer->inferProperty($property);
$type = $this->allAssignNodePropertyTypeInferer->inferProperty($property, $classReflection);
return $type instanceof ArrayType;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,16 @@

use PhpParser\Node;
use PhpParser\Node\Expr;
use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\Property;
use PHPStan\Reflection\ClassReflection;
use PHPStan\Type\MixedType;
use PHPStan\Type\Type;
use PHPStan\Type\TypeCombinator;
use PHPStan\Type\UnionType;
use Rector\Core\Contract\Rector\AllowEmptyConfigurableRectorInterface;
use Rector\Core\Rector\AbstractRector;
use Rector\Core\Reflection\ReflectionResolver;
use Rector\Core\ValueObject\PhpVersionFeature;
use Rector\DeadCode\PhpDoc\TagRemover\VarTagRemover;
use Rector\Php74\Guard\MakePropertyTypedGuard;
Expand Down Expand Up @@ -49,6 +52,7 @@ public function __construct(
private readonly PropertyTypeDecorator $propertyTypeDecorator,
private readonly VarTagRemover $varTagRemover,
private readonly MakePropertyTypedGuard $makePropertyTypedGuard,
private readonly ReflectionResolver $reflectionResolver
) {
}

Expand Down Expand Up @@ -98,7 +102,7 @@ public function run()
*/
public function getNodeTypes(): array
{
return [Property::class];
return [Class_::class];
}

public function provideMinPhpVersion(): int
Expand All @@ -107,54 +111,73 @@ public function provideMinPhpVersion(): int
}

/**
* @param Property $node
* @param Node\Stmt\Class_ $node
*/
public function refactor(Node $node): ?Node
{
if (! $this->makePropertyTypedGuard->isLegal($node, $this->inlinePublic)) {
return null;
$hasChanged = false;
$classReflection = null;

foreach ($node->getProperties() as $property) {
if (! $this->makePropertyTypedGuard->isLegal($property, $this->inlinePublic)) {
continue;
}

// non-private property can be anything with not inline public configured
if (! $property->isPrivate() && ! $this->inlinePublic) {
continue;
}

if (! $classReflection instanceof ClassReflection) {
$classReflection = $this->reflectionResolver->resolveClassReflection($node);
}

if (! $classReflection instanceof ClassReflection) {
return null;
}

$inferredType = $this->allAssignNodePropertyTypeInferer->inferProperty($property, $classReflection);
if (! $inferredType instanceof Type) {
continue;
}

if ($inferredType instanceof MixedType) {
continue;
}

$inferredType = $this->decorateTypeWithNullableIfDefaultPropertyNull($property, $inferredType);
$typeNode = $this->staticTypeMapper->mapPHPStanTypeToPhpParserNode($inferredType, TypeKind::PROPERTY);
if ($typeNode === null) {
continue;
}

$hasChanged = true;

$phpDocInfo = $this->phpDocInfoFactory->createFromNodeOrEmpty($property);
if ($inferredType instanceof UnionType) {
$this->propertyTypeDecorator->decoratePropertyUnionType(
$inferredType,
$typeNode,
$property,
$phpDocInfo,
false
);
} else {
$property->type = $typeNode;
}

if (! $property->type instanceof Node) {
continue;
}

$this->varTagRemover->removeVarTagIfUseless($phpDocInfo, $property);
}

// non-private property can be anything with not inline public configured
if (! $node->isPrivate() && ! $this->inlinePublic) {
return null;
if ($hasChanged) {
return $node;
}

$inferredType = $this->allAssignNodePropertyTypeInferer->inferProperty($node);
if (! $inferredType instanceof Type) {
return null;
}

if ($inferredType instanceof MixedType) {
return null;
}

$inferredType = $this->decorateTypeWithNullableIfDefaultPropertyNull($node, $inferredType);
$typeNode = $this->staticTypeMapper->mapPHPStanTypeToPhpParserNode($inferredType, TypeKind::PROPERTY);
if ($typeNode === null) {
return null;
}

$phpDocInfo = $this->phpDocInfoFactory->createFromNodeOrEmpty($node);
if ($inferredType instanceof UnionType) {
$this->propertyTypeDecorator->decoratePropertyUnionType(
$inferredType,
$typeNode,
$node,
$phpDocInfo,
false
);
} else {
$node->type = $typeNode;
}

if (! $node->type instanceof Node) {
return null;
}

$this->varTagRemover->removeVarTagIfUseless($phpDocInfo, $node);

return $node;
return null;
}

private function decorateTypeWithNullableIfDefaultPropertyNull(Property $property, Type $inferredType): Type
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
use PHPStan\Reflection\ClassReflection;
use PHPStan\Type\Type;
use Rector\Core\PhpParser\ClassLikeAstResolver;
use Rector\Core\Reflection\ReflectionResolver;
use Rector\NodeNameResolver\NodeNameResolver;
use Rector\TypeDeclaration\TypeInferer\AssignToPropertyTypeInferer;

Expand All @@ -18,18 +17,12 @@ final class AllAssignNodePropertyTypeInferer
public function __construct(
private readonly AssignToPropertyTypeInferer $assignToPropertyTypeInferer,
private readonly NodeNameResolver $nodeNameResolver,
private readonly ReflectionResolver $reflectionResolver,
private readonly ClassLikeAstResolver $classLikeAstResolver
) {
}

public function inferProperty(Property $property): ?Type
public function inferProperty(Property $property, ClassReflection $classReflection): ?Type
{
$classReflection = $this->reflectionResolver->resolveClassReflection($property);
if (! $classReflection instanceof ClassReflection) {
return null;
}

/** @var ClassLike $classLike */
$classLike = $this->classLikeAstResolver->resolveClassFromClassReflection($classReflection);
$propertyName = $this->nodeNameResolver->getName($property);
Expand Down

0 comments on commit 6451387

Please sign in to comment.