Skip to content

Commit

Permalink
Cleaning up NodeRepository dependency (#280)
Browse files Browse the repository at this point in the history
Co-authored-by: GitHub Action <action@github.com>
  • Loading branch information
TomasVotruba and actions-user committed Jun 24, 2021
1 parent 5daf169 commit 29e9bf5
Show file tree
Hide file tree
Showing 14 changed files with 237 additions and 194 deletions.
13 changes: 12 additions & 1 deletion packages/StaticTypeMapper/StaticTypeMapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
use PhpParser\Node;
use PhpParser\Node\Name;
use PhpParser\Node\NullableType;
use PhpParser\Node\Param;
use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\UnionType as PhpParserUnionType;
use PHPStan\PhpDocParser\Ast\PhpDoc\ParamTagValueNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocTagValueNode;
Expand All @@ -19,6 +21,7 @@
use PHPStan\Type\MixedType;
use PHPStan\Type\Type;
use Rector\Core\Exception\NotImplementedYetException;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Rector\PHPStanStaticTypeMapper\PHPStanStaticTypeMapper;
use Rector\StaticTypeMapper\Mapper\PhpParserNodeMapper;
use Rector\StaticTypeMapper\Naming\NameScopeFactory;
Expand All @@ -36,7 +39,6 @@ public function __construct(
private PhpDocTypeMapper $phpDocTypeMapper,
private PhpParserNodeMapper $phpParserNodeMapper
) {
// $this->nameScopeFactory->setStaticTypeMapper($this);
}

public function mapPHPStanTypeToPHPStanPhpDocTypeNode(Type $phpStanType): TypeNode
Expand Down Expand Up @@ -78,7 +80,16 @@ public function mapPHPStanPhpDocTypeToPHPStanType(PhpDocTagValueNode $phpDocTagV

public function mapPHPStanPhpDocTypeNodeToPHPStanType(TypeNode $typeNode, Node $node): Type
{
if ($node instanceof Param) {
$classMethod = $node->getAttribute(AttributeKey::PARENT_NODE);
if ($classMethod instanceof ClassMethod) {
// param does not hany any clue about template map, but class method has
$node = $classMethod;
}
}

$nameScope = $this->nameScopeFactory->createNameScopeFromNode($node);

return $this->phpDocTypeMapper->mapToPHPStanType($typeNode, $node, $nameScope);
}

Expand Down
3 changes: 3 additions & 0 deletions phpstan.neon
Original file line number Diff line number Diff line change
Expand Up @@ -497,3 +497,6 @@ parameters:
-
message: '#Assign in loop is not allowed#'
path: rules/RemovingStatic/Rector/ClassMethod/LocallyCalledStaticMethodToNonStaticRector.php

# generics single place
- '#Method Rector\\Php80\\NodeResolver\\ArgumentSorter\:\:sortArgsByExpectedParamOrder\(\) should return array<T of PhpParser\\Node\\Arg\|PhpParser\\Node\\Param\> but returns array<PhpParser\\Node\\Arg\|PhpParser\\Node\\Param\>#'
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php

namespace Rector\Tests\TypeDeclaration\Rector\ClassMethod\AddArrayParamDocTypeRector\Fixture;

use PhpParser\Node\Arg;
use PhpParser\Node\Param;

final class SkipTemplate
{
/**
* @template TItem as Arg|Param
* @param array<TItem> $args
* @param array<int, string> $expectedOrderedParams
* @return array<TItem>
*/
public function run(array $args): array
{
return $args;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,54 +2,33 @@

namespace Rector\Tests\TypeDeclaration\Rector\ClassMethod\AddArrayReturnDocTypeRector\Fixture;

use Rector\Tests\TypeDeclaration\Rector\ClassMethod\AddArrayReturnDocTypeRector\Source\NestedGetData;

final class AddFromChild
{
public function getData(Nested $nested)
public function getData(NestedGetData $nested)
{
return $nested->getData();
}
}

final class Nested
{
public function getData()
{
return [
'key',
'value'
];
}
}

?>
-----
<?php

namespace Rector\Tests\TypeDeclaration\Rector\ClassMethod\AddArrayReturnDocTypeRector\Fixture;

use Rector\Tests\TypeDeclaration\Rector\ClassMethod\AddArrayReturnDocTypeRector\Source\NestedGetData;

final class AddFromChild
{
/**
* @return string[]
*/
public function getData(Nested $nested)
public function getData(NestedGetData $nested)
{
return $nested->getData();
}
}

final class Nested
{
/**
* @return string[]
*/
public function getData()
{
return [
'key',
'value'
];
}
}

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

declare(strict_types=1);

namespace Rector\Tests\TypeDeclaration\Rector\ClassMethod\AddArrayReturnDocTypeRector\Source;

final class NestedGetData
{
public function getData()
{
return [
'key',
'value'
];
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

namespace Rector\Tests\TypeDeclaration\Rector\FunctionLike\ReturnTypeDeclarationRector\Fixture;

use Rector\BetterPhpDocParser\ValueObject\Parser\BetterTokenIterator;

final class PrivatePropertyReflection
{
public function getTokens(BetterTokenIterator $betterTokenIterator): array
{
return $betterTokenIterator->getTokens();
}
}
8 changes: 5 additions & 3 deletions rules/Php80/NodeResolver/ArgumentSorter.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,15 @@

use PhpParser\Node\Arg;
use PhpParser\Node\Param;
use PHPStan\Reflection\ParameterReflection;

final class ArgumentSorter
{
/**
* @param array<int, Param> $expectedOrderedParams
* @param Arg[] $args
* @return Arg[]
* @template T as Arg|Param
* @param array<int, ParameterReflection> $expectedOrderedParams
* @param T[] $args
* @return T[]
*/
public function sortArgsByExpectedParamOrder(array $args, array $expectedOrderedParams): array
{
Expand Down
22 changes: 12 additions & 10 deletions rules/Php80/NodeResolver/RequireOptionalParamResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,25 +4,27 @@

namespace Rector\Php80\NodeResolver;

use PhpParser\Node\FunctionLike;
use PhpParser\Node\Param;
use PhpParser\Node\Stmt\ClassMethod;
use PHPStan\Reflection\FunctionReflection;
use PHPStan\Reflection\MethodReflection;
use PHPStan\Reflection\ParameterReflection;

final class RequireOptionalParamResolver
{
/**
* @param ClassMethod $functionLike
* @return Param[]
* @return ParameterReflection[]
*/
public function resolve(FunctionLike $functionLike): array
public function resolveFromReflection(MethodReflection | FunctionReflection $functionLikeReflection): array
{
$parametersAcceptor = $functionLikeReflection->getVariants()[0];

$optionalParams = [];
$requireParams = [];
foreach ($functionLike->getParams() as $position => $param) {
if ($param->default === null && ! $param->variadic) {
$requireParams[$position] = $param;

foreach ($parametersAcceptor->getParameters() as $position => $parameterReflection) {
if ($parameterReflection->getDefaultValue() === null && ! $parameterReflection->isVariadic()) {
$requireParams[$position] = $parameterReflection;
} else {
$optionalParams[$position] = $param;
$optionalParams[$position] = $parameterReflection;
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,12 @@
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Expr\New_;
use PhpParser\Node\Stmt\ClassMethod;
use PHPStan\Reflection\MethodReflection;
use PHPStan\Type\TypeWithClassName;
use Rector\Core\PHPStan\Reflection\CallReflectionResolver;
use Rector\Core\PHPStan\Reflection\ClassMethodReflectionResolver;
use Rector\Core\Rector\AbstractRector;
use Rector\Core\ValueObject\MethodName;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Rector\Php80\NodeResolver\ArgumentSorter;
use Rector\Php80\NodeResolver\RequireOptionalParamResolver;
use Rector\Php80\Reflection\MethodReflectionClassMethodResolver;
Expand All @@ -28,7 +30,9 @@ final class OptionalParametersAfterRequiredRector extends AbstractRector
public function __construct(
private RequireOptionalParamResolver $requireOptionalParamResolver,
private ArgumentSorter $argumentSorter,
private MethodReflectionClassMethodResolver $methodReflectionClassMethodResolver
private MethodReflectionClassMethodResolver $methodReflectionClassMethodResolver,
private CallReflectionResolver $callReflectionResolver,
private ClassMethodReflectionResolver $classMethodReflectionResolver
) {
}

Expand Down Expand Up @@ -88,12 +92,25 @@ private function refactorClassMethod(ClassMethod $classMethod): ?ClassMethod
return null;
}

$expectedOrderParams = $this->requireOptionalParamResolver->resolve($classMethod);
if ($classMethod->params === $expectedOrderParams) {
$classMethodReflection = $this->classMethodReflectionResolver->resolve($classMethod);
if (! $classMethodReflection instanceof MethodReflection) {
return null;
}

$classMethod->params = $expectedOrderParams;
$parametersAcceptor = $classMethodReflection->getVariants()[0];

$expectedOrderParameterReflections = $this->requireOptionalParamResolver->resolveFromReflection(
$classMethodReflection
);
if ($parametersAcceptor->getParameters() === $expectedOrderParameterReflections) {
return null;
}

$newParams = $this->argumentSorter->sortArgsByExpectedParamOrder(
$classMethod->params,
$expectedOrderParameterReflections
);
$classMethod->params = $newParams;

return $classMethod;
}
Expand All @@ -117,16 +134,28 @@ private function refactorNew(New_ $new): ?New_
return null;
}

$expectedOrderedParams = $this->requireOptionalParamResolver->resolve($classMethod);
if ($expectedOrderedParams === $classMethod->getParams()) {
$classMethodReflection = $this->classMethodReflectionResolver->resolve($classMethod);
if (! $classMethodReflection instanceof MethodReflection) {
return null;
}

$parametersAcceptor = $classMethodReflection->getVariants()[0];

$expectedOrderedParameterReflections = $this->requireOptionalParamResolver->resolveFromReflection(
$classMethodReflection
);
if ($expectedOrderedParameterReflections === $parametersAcceptor->getParameters()) {
return null;
}

if (count($new->args) !== count($classMethod->getParams())) {
return null;
}

$newArgs = $this->argumentSorter->sortArgsByExpectedParamOrder($new->args, $expectedOrderedParams);
$newArgs = $this->argumentSorter->sortArgsByExpectedParamOrder(
$new->args,
$expectedOrderedParameterReflections
);
if ($new->args === $newArgs) {
return null;
}
Expand All @@ -138,32 +167,35 @@ private function refactorNew(New_ $new): ?New_

private function refactorMethodCall(MethodCall $methodCall): ?MethodCall
{
$classMethod = $this->nodeRepository->findClassMethodByMethodCall($methodCall);
if (! $classMethod instanceof ClassMethod) {
$callReflection = $this->callReflectionResolver->resolveCall($methodCall);
if ($callReflection === null) {
return null;
}

// because parameters can be already changed
$originalClassMethod = $classMethod->getAttribute(AttributeKey::ORIGINAL_NODE);
if (! $originalClassMethod instanceof ClassMethod) {
return null;
}
$parametersAcceptor = $callReflection->getVariants()[0];

$expectedOrderedParams = $this->requireOptionalParamResolver->resolve($originalClassMethod);
if ($expectedOrderedParams === $classMethod->getParams()) {
$expectedOrderedParameterReflections = $this->requireOptionalParamResolver->resolveFromReflection(
$callReflection
);
if ($expectedOrderedParameterReflections === $parametersAcceptor->getParameters()) {
return null;
}

if (count($methodCall->args) !== count($classMethod->getParams())) {
if (count($methodCall->args) !== count($parametersAcceptor->getParameters())) {
return null;
}

$newArgs = $this->argumentSorter->sortArgsByExpectedParamOrder($methodCall->args, $expectedOrderedParams);
$newArgs = $this->argumentSorter->sortArgsByExpectedParamOrder(
$methodCall->args,
$expectedOrderedParameterReflections
);

if ($methodCall->args === $newArgs) {
return null;
}

$methodCall->args = $newArgs;

return $methodCall;
}
}

0 comments on commit 29e9bf5

Please sign in to comment.