mirror of https://github.com/rectorphp/rector.git
[DX] Merge getObjectType() and getStaticType() methods to single getType() (#973)
This commit is contained in:
parent
5ba1499034
commit
f6f7431ce7
|
@ -10,7 +10,7 @@
|
|||
|
||||
- [Carbon](#carbon) (2)
|
||||
|
||||
- [CodeQuality](#codequality) (68)
|
||||
- [CodeQuality](#codequality) (69)
|
||||
|
||||
- [CodingStyle](#codingstyle) (39)
|
||||
|
||||
|
@ -90,7 +90,7 @@
|
|||
|
||||
- [Renaming](#renaming) (11)
|
||||
|
||||
- [Restoration](#restoration) (6)
|
||||
- [Restoration](#restoration) (5)
|
||||
|
||||
- [Strict](#strict) (5)
|
||||
|
||||
|
@ -845,6 +845,38 @@ Make if conditions more explicit
|
|||
|
||||
<br>
|
||||
|
||||
### ExplicitMethodCallOverMagicGetSetRector
|
||||
|
||||
Replace magic property fetch using `__get()` and `__set()` with existing method get*()/set*() calls
|
||||
|
||||
- class: [`Rector\CodeQuality\Rector\PropertyFetch\ExplicitMethodCallOverMagicGetSetRector`](../rules/CodeQuality/Rector/PropertyFetch/ExplicitMethodCallOverMagicGetSetRector.php)
|
||||
|
||||
```diff
|
||||
class MagicCallsObject
|
||||
{
|
||||
// adds magic __get() and __set() methods
|
||||
use \Nette\SmartObject;
|
||||
|
||||
private $name;
|
||||
|
||||
public function getName()
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
}
|
||||
|
||||
class SomeClass
|
||||
{
|
||||
public function run(MagicObject $magicObject)
|
||||
{
|
||||
- return $magicObject->name;
|
||||
+ return $magicObject->getName();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
<br>
|
||||
|
||||
### FixClassCaseSensitivityNameRector
|
||||
|
||||
Change miss-typed case sensitivity name to correct one
|
||||
|
@ -9651,53 +9683,6 @@ return static function (ContainerConfigurator $containerConfigurator): void {
|
|||
|
||||
<br>
|
||||
|
||||
### InferParamFromClassMethodReturnRector
|
||||
|
||||
Change `@param` doc based on another method return type
|
||||
|
||||
:wrench: **configure it!**
|
||||
|
||||
- class: [`Rector\Restoration\Rector\ClassMethod\InferParamFromClassMethodReturnRector`](../rules/Restoration/Rector/ClassMethod/InferParamFromClassMethodReturnRector.php)
|
||||
|
||||
```php
|
||||
use Rector\Restoration\Rector\ClassMethod\InferParamFromClassMethodReturnRector;
|
||||
use Rector\Restoration\ValueObject\InferParamFromClassMethodReturn;
|
||||
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
|
||||
use Symplify\SymfonyPhpConfig\ValueObjectInliner;
|
||||
|
||||
return static function (ContainerConfigurator $containerConfigurator): void {
|
||||
$services = $containerConfigurator->services();
|
||||
|
||||
$services->set(InferParamFromClassMethodReturnRector::class)
|
||||
->call('configure', [[
|
||||
InferParamFromClassMethodReturnRector::INFER_PARAMS_FROM_CLASS_METHOD_RETURNS => ValueObjectInliner::inline([
|
||||
new InferParamFromClassMethodReturn('SomeClass', 'process', 'getNodeTypes'),
|
||||
]),
|
||||
]]);
|
||||
};
|
||||
```
|
||||
|
||||
↓
|
||||
|
||||
```diff
|
||||
class SomeClass
|
||||
{
|
||||
public function getNodeTypes(): array
|
||||
{
|
||||
return [String_::class];
|
||||
}
|
||||
|
||||
+ /**
|
||||
+ * @param String_ $node
|
||||
+ */
|
||||
public function process(Node $node)
|
||||
{
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
<br>
|
||||
|
||||
### MakeTypedPropertyNullableIfCheckedRector
|
||||
|
||||
Make typed property nullable if checked
|
||||
|
|
|
@ -20,7 +20,6 @@ use PhpParser\Node\Scalar;
|
|||
use PhpParser\Node\Stmt\Class_;
|
||||
use PhpParser\Node\Stmt\Return_;
|
||||
use PHPStan\Analyser\Scope;
|
||||
use PHPStan\Reflection\ClassReflection;
|
||||
use PHPStan\Reflection\ReflectionProvider;
|
||||
use PHPStan\Type\Accessory\NonEmptyArrayType;
|
||||
use PHPStan\Type\ArrayType;
|
||||
|
@ -39,7 +38,6 @@ use PHPStan\Type\TypeCombinator;
|
|||
use PHPStan\Type\TypeWithClassName;
|
||||
use PHPStan\Type\UnionType;
|
||||
use Rector\Core\Configuration\RenamedClassesDataCollector;
|
||||
use Rector\Core\Exception\ShouldNotHappenException;
|
||||
use Rector\Core\NodeAnalyzer\ClassAnalyzer;
|
||||
use Rector\NodeTypeResolver\Contract\NodeTypeResolverInterface;
|
||||
use Rector\NodeTypeResolver\Node\AttributeKey;
|
||||
|
@ -108,7 +106,7 @@ final class NodeTypeResolver
|
|||
return false;
|
||||
}
|
||||
|
||||
$resolvedType = $this->resolve($node);
|
||||
$resolvedType = $this->getType($node);
|
||||
if ($resolvedType instanceof MixedType) {
|
||||
return false;
|
||||
}
|
||||
|
@ -124,32 +122,27 @@ final class NodeTypeResolver
|
|||
return $this->isMatchingUnionType($resolvedType, $requiredObjectType);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
* @see use NodeTypeResolver::getType() instead
|
||||
*/
|
||||
public function resolve(Node $node): Type
|
||||
{
|
||||
return $this->getType($node);
|
||||
}
|
||||
|
||||
public function getType(Node $node): Type
|
||||
{
|
||||
if ($node instanceof Ternary) {
|
||||
if ($node->if !== null) {
|
||||
$first = $this->resolve($node->if);
|
||||
$second = $this->resolve($node->else);
|
||||
|
||||
if ($this->isUnionTypeable($first, $second)) {
|
||||
return new UnionType([$first, $second]);
|
||||
}
|
||||
}
|
||||
|
||||
$condType = $this->resolve($node->cond);
|
||||
if ($this->isNullableType($node->cond) && $condType instanceof UnionType) {
|
||||
$first = $condType->getTypes()[0];
|
||||
$second = $this->resolve($node->else);
|
||||
|
||||
if ($this->isUnionTypeable($first, $second)) {
|
||||
return new UnionType([$first, $second]);
|
||||
}
|
||||
$ternaryType = $this->resolveTernaryType($node);
|
||||
if (! $ternaryType instanceof MixedType) {
|
||||
return $ternaryType;
|
||||
}
|
||||
}
|
||||
|
||||
if ($node instanceof Coalesce) {
|
||||
$first = $this->resolve($node->left);
|
||||
$second = $this->resolve($node->right);
|
||||
$first = $this->getType($node->left);
|
||||
$second = $this->getType($node->right);
|
||||
|
||||
if ($this->isUnionTypeable($first, $second)) {
|
||||
return new UnionType([$first, $second]);
|
||||
|
@ -159,6 +152,9 @@ final class NodeTypeResolver
|
|||
$type = $this->resolveByNodeTypeResolvers($node);
|
||||
if ($type !== null) {
|
||||
$type = $this->accessoryNonEmptyStringTypeCorrector->correct($type);
|
||||
|
||||
$type = $this->genericClassStringTypeCorrector->correct($type);
|
||||
|
||||
return $this->hasOffsetTypeCorrector->correct($type);
|
||||
}
|
||||
|
||||
|
@ -190,8 +186,11 @@ final class NodeTypeResolver
|
|||
}
|
||||
|
||||
$type = $scope->getType($node);
|
||||
|
||||
$type = $this->accessoryNonEmptyStringTypeCorrector->correct($type);
|
||||
|
||||
$type = $this->genericClassStringTypeCorrector->correct($type);
|
||||
|
||||
// hot fix for phpstan not resolving chain method calls
|
||||
if (! $node instanceof MethodCall) {
|
||||
return $type;
|
||||
|
@ -201,7 +200,7 @@ final class NodeTypeResolver
|
|||
return $type;
|
||||
}
|
||||
|
||||
return $this->resolve($node->var);
|
||||
return $this->getType($node->var);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -209,7 +208,7 @@ final class NodeTypeResolver
|
|||
*/
|
||||
public function isNullableType(Node $node): bool
|
||||
{
|
||||
$nodeType = $this->resolve($node);
|
||||
$nodeType = $this->getType($node);
|
||||
return TypeCombinator::containsNull($nodeType);
|
||||
}
|
||||
|
||||
|
@ -225,16 +224,8 @@ final class NodeTypeResolver
|
|||
|
||||
public function getStaticType(Node $node): Type
|
||||
{
|
||||
if ($node instanceof Param) {
|
||||
return $this->resolve($node);
|
||||
}
|
||||
|
||||
if ($node instanceof New_) {
|
||||
return $this->resolve($node);
|
||||
}
|
||||
|
||||
if ($node instanceof Return_) {
|
||||
return $this->resolve($node);
|
||||
if ($node instanceof Param || $node instanceof New_ || $node instanceof Return_) {
|
||||
return $this->getType($node);
|
||||
}
|
||||
|
||||
if (! $node instanceof Expr) {
|
||||
|
@ -246,7 +237,7 @@ final class NodeTypeResolver
|
|||
}
|
||||
|
||||
if ($node instanceof Scalar) {
|
||||
return $this->resolve($node);
|
||||
return $this->getType($node);
|
||||
}
|
||||
|
||||
$scope = $node->getAttribute(AttributeKey::SCOPE);
|
||||
|
@ -268,28 +259,12 @@ final class NodeTypeResolver
|
|||
|
||||
public function isNumberType(Node $node): bool
|
||||
{
|
||||
if ($this->isStaticType($node, IntegerType::class)) {
|
||||
$nodeType = $this->getType($node);
|
||||
if ($nodeType instanceof IntegerType) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return $this->isStaticType($node, FloatType::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param class-string<Type> $staticTypeClass
|
||||
*/
|
||||
public function isStaticType(Node $node, string $staticTypeClass): bool
|
||||
{
|
||||
if (! is_a($staticTypeClass, Type::class, true)) {
|
||||
throw new ShouldNotHappenException(sprintf(
|
||||
'"%s" in "%s()" must be type of "%s"',
|
||||
$staticTypeClass,
|
||||
__METHOD__,
|
||||
Type::class
|
||||
));
|
||||
}
|
||||
|
||||
return is_a($this->resolve($node), $staticTypeClass);
|
||||
return $nodeType instanceof FloatType;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -297,7 +272,7 @@ final class NodeTypeResolver
|
|||
*/
|
||||
public function isNullableTypeOfSpecificType(Node $node, string $desiredType): bool
|
||||
{
|
||||
$nodeType = $this->resolve($node);
|
||||
$nodeType = $this->getType($node);
|
||||
if (! $nodeType instanceof UnionType) {
|
||||
return false;
|
||||
}
|
||||
|
@ -306,17 +281,8 @@ final class NodeTypeResolver
|
|||
return false;
|
||||
}
|
||||
|
||||
if (count($nodeType->getTypes()) !== 2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach ($nodeType->getTypes() as $type) {
|
||||
if (is_a($type, $desiredType, true)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
$bareType = TypeCombinator::removeNull($nodeType);
|
||||
return is_a($bareType, $desiredType, true);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -331,21 +297,6 @@ final class NodeTypeResolver
|
|||
return $typeWithClassName->getClassName();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Type[] $desiredTypes
|
||||
*/
|
||||
public function isSameObjectTypes(ObjectType $objectType, array $desiredTypes): bool
|
||||
{
|
||||
foreach ($desiredTypes as $desiredType) {
|
||||
$desiredTypeEquals = $desiredType->equals($objectType);
|
||||
if ($desiredTypeEquals) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function isMethodStaticCallOrClassMethodObjectType(Node $node, ObjectType $objectType): bool
|
||||
{
|
||||
if ($node instanceof MethodCall) {
|
||||
|
@ -365,21 +316,6 @@ final class NodeTypeResolver
|
|||
return $this->isObjectType($classLike, $objectType);
|
||||
}
|
||||
|
||||
public function resolveObjectTypeFromScope(Scope $scope): ?ObjectType
|
||||
{
|
||||
$classReflection = $scope->getClassReflection();
|
||||
if (! $classReflection instanceof ClassReflection) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$className = $classReflection->getName();
|
||||
if (! $this->reflectionProvider->hasClass($className)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new ObjectType($className, null, $classReflection);
|
||||
}
|
||||
|
||||
private function isUnionTypeable(Type $first, Type $second): bool
|
||||
{
|
||||
return ! $first instanceof UnionType && ! $second instanceof UnionType && ! $second instanceof NullType;
|
||||
|
@ -501,4 +437,28 @@ final class NodeTypeResolver
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
private function resolveTernaryType(Ternary $ternary): MixedType|UnionType
|
||||
{
|
||||
if ($ternary->if !== null) {
|
||||
$first = $this->getType($ternary->if);
|
||||
$second = $this->getType($ternary->else);
|
||||
|
||||
if ($this->isUnionTypeable($first, $second)) {
|
||||
return new UnionType([$first, $second]);
|
||||
}
|
||||
}
|
||||
|
||||
$condType = $this->getType($ternary->cond);
|
||||
if ($this->isNullableType($ternary->cond) && $condType instanceof UnionType) {
|
||||
$first = $condType->getTypes()[0];
|
||||
$second = $this->getType($ternary->else);
|
||||
|
||||
if ($this->isUnionTypeable($first, $second)) {
|
||||
return new UnionType([$first, $second]);
|
||||
}
|
||||
}
|
||||
|
||||
return new MixedType();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -314,7 +314,7 @@ parameters:
|
|||
- '#Cognitive complexity for "Rector\\BetterPhpDocParser\\PhpDocParser\\DoctrineAnnotationDecorator\:\:mergeNestedDoctrineAnnotations\(\)" is \d+, keep it under 9#'
|
||||
|
||||
- '#Cognitive complexity for "Rector\\BetterPhpDocParser\\Printer\\PhpDocInfoPrinter\:\:printDocChildNode\(\)" is \d+, keep it under 9#'
|
||||
- '#Cognitive complexity for "Rector\\NodeTypeResolver\\NodeTypeResolver\:\:resolve\(\)" is \d+, keep it under 9#'
|
||||
- '#Cognitive complexity for "Rector\\NodeTypeResolver\\NodeTypeResolver\:\:getType\(\)" is \d+, keep it under 9#'
|
||||
|
||||
-
|
||||
message: '#Property with protected modifier is not allowed\. Use interface contract method instead#'
|
||||
|
|
11
rector.php
11
rector.php
|
@ -9,12 +9,9 @@ use Rector\CodingStyle\Rector\MethodCall\PreferThisOrSelfMethodCallRector;
|
|||
use Rector\CodingStyle\Rector\String_\SplitStringClassConstantToClassConstFetchRector;
|
||||
use Rector\CodingStyle\ValueObject\ReturnArrayClassMethodToYield;
|
||||
use Rector\Core\Configuration\Option;
|
||||
use Rector\Core\Rector\AbstractRector;
|
||||
use Rector\Nette\Set\NetteSetList;
|
||||
use Rector\Php55\Rector\String_\StringClassNameToClassConstantRector;
|
||||
use Rector\PHPUnit\Set\PHPUnitSetList;
|
||||
use Rector\Restoration\Rector\ClassMethod\InferParamFromClassMethodReturnRector;
|
||||
use Rector\Restoration\ValueObject\InferParamFromClassMethodReturn;
|
||||
use Rector\Set\ValueObject\SetList;
|
||||
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
|
||||
use Symplify\SymfonyPhpConfig\ValueObjectInliner;
|
||||
|
@ -38,15 +35,7 @@ return static function (ContainerConfigurator $containerConfigurator): void {
|
|||
$containerConfigurator->import(NetteSetList::NETTE_UTILS_CODE_QUALITY);
|
||||
$containerConfigurator->import(PHPUnitSetList::PHPUNIT_CODE_QUALITY);
|
||||
|
||||
$configuration = ValueObjectInliner::inline([
|
||||
new InferParamFromClassMethodReturn(AbstractRector::class, 'refactor', 'getNodeTypes'),
|
||||
]);
|
||||
|
||||
$services = $containerConfigurator->services();
|
||||
$services->set(InferParamFromClassMethodReturnRector::class)
|
||||
->call('configure', [[
|
||||
InferParamFromClassMethodReturnRector::INFER_PARAMS_FROM_CLASS_METHOD_RETURNS => $configuration,
|
||||
]]);
|
||||
|
||||
// phpunit
|
||||
$services->set(PreferThisOrSelfMethodCallRector::class)
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
<?php
|
||||
|
||||
namespace Rector\Tests\Php71\Rector\FuncCall\CountOnNullRector\Fixture;
|
||||
|
||||
use PhpParser\Node\Stmt\ClassMethod;
|
||||
|
||||
final class CountOnClassMethodStmts
|
||||
{
|
||||
public function run(ClassMethod $classMethod)
|
||||
{
|
||||
return count($classMethod->stmts) === 5;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
-----
|
||||
<?php
|
||||
|
||||
namespace Rector\Tests\Php71\Rector\FuncCall\CountOnNullRector\Fixture;
|
||||
|
||||
use PhpParser\Node\Stmt\ClassMethod;
|
||||
|
||||
final class CountOnClassMethodStmts
|
||||
{
|
||||
public function run(ClassMethod $classMethod)
|
||||
{
|
||||
return count((array) $classMethod->stmts) === 5;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -1,44 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Rector\Tests\Restoration\Rector\ClassMethod\InferParamFromClassMethodReturnRector\Fixture;
|
||||
|
||||
use PhpParser\Node\Scalar\String_;
|
||||
use Rector\Tests\Restoration\Rector\ClassMethod\InferParamFromClassMethodReturnRector\Source\SomeType;
|
||||
|
||||
class SomeClass extends SomeType
|
||||
{
|
||||
public function getNodeTypes(): array
|
||||
{
|
||||
return [String_::class];
|
||||
}
|
||||
|
||||
public function process(\PhpParser\Node $node)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
-----
|
||||
<?php
|
||||
|
||||
namespace Rector\Tests\Restoration\Rector\ClassMethod\InferParamFromClassMethodReturnRector\Fixture;
|
||||
|
||||
use PhpParser\Node\Scalar\String_;
|
||||
use Rector\Tests\Restoration\Rector\ClassMethod\InferParamFromClassMethodReturnRector\Source\SomeType;
|
||||
|
||||
class SomeClass extends SomeType
|
||||
{
|
||||
public function getNodeTypes(): array
|
||||
{
|
||||
return [String_::class];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \PhpParser\Node\Scalar\String_ $node
|
||||
*/
|
||||
public function process(\PhpParser\Node $node)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -1,23 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Rector\Tests\Restoration\Rector\ClassMethod\InferParamFromClassMethodReturnRector\Fixture;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Expr\AssignOp\Plus;
|
||||
use PhpParser\Node\Expr\BinaryOp\Plus as BinaryPlus;
|
||||
use Rector\Tests\Restoration\Rector\ClassMethod\InferParamFromClassMethodReturnRector\Source\SomeType;
|
||||
|
||||
class SkipAliasAlready extends SomeType
|
||||
{
|
||||
public function getNodeTypes(): array
|
||||
{
|
||||
return [Plus::class, BinaryPlus::class];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Plus|BinaryPlus $node
|
||||
*/
|
||||
public function process(Node $node)
|
||||
{
|
||||
}
|
||||
}
|
|
@ -1,21 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Rector\Tests\Restoration\Rector\ClassMethod\InferParamFromClassMethodReturnRector\Fixture;
|
||||
|
||||
use PhpParser\Node\Scalar\String_;
|
||||
use Rector\Tests\Restoration\Rector\ClassMethod\InferParamFromClassMethodReturnRector\Source\SomeType;
|
||||
|
||||
class SkipCorrect extends SomeType
|
||||
{
|
||||
public function getNodeTypes(): array
|
||||
{
|
||||
return [String_::class];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param String_ $node
|
||||
*/
|
||||
public function process(\PhpParser\Node $node)
|
||||
{
|
||||
}
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Rector\Tests\Restoration\Rector\ClassMethod\InferParamFromClassMethodReturnRector\Fixture;
|
||||
|
||||
use PhpParser\Node\Scalar\String_;
|
||||
use Rector\Tests\Restoration\Rector\ClassMethod\InferParamFromClassMethodReturnRector\Source\SomeType;
|
||||
|
||||
class SkipEmptyArray extends SomeType
|
||||
{
|
||||
public function getNodeTypes(): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
public function process(\PhpParser\Node $node)
|
||||
{
|
||||
}
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Rector\Tests\Restoration\Rector\ClassMethod\InferParamFromClassMethodReturnRector\Fixture;
|
||||
|
||||
use PhpParser\Node\Scalar\String_;
|
||||
use Rector\Tests\Restoration\Rector\ClassMethod\InferParamFromClassMethodReturnRector\Source\SomeType;
|
||||
|
||||
class SkipSameName extends SomeType
|
||||
{
|
||||
public function getNodeTypes(): array
|
||||
{
|
||||
return [String_::class];
|
||||
}
|
||||
|
||||
public function process(String_ $node)
|
||||
{
|
||||
}
|
||||
}
|
|
@ -1,46 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Rector\Tests\Restoration\Rector\ClassMethod\InferParamFromClassMethodReturnRector\Fixture;
|
||||
|
||||
use PhpParser\Node\Scalar\LNumber;
|
||||
use PhpParser\Node\Scalar\String_;
|
||||
use Rector\Tests\Restoration\Rector\ClassMethod\InferParamFromClassMethodReturnRector\Source\SomeType;
|
||||
|
||||
class UnionTypes extends SomeType
|
||||
{
|
||||
public function getNodeTypes(): array
|
||||
{
|
||||
return [String_::class, LNumber::class];
|
||||
}
|
||||
|
||||
public function process(\PhpParser\Node $node)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
-----
|
||||
<?php
|
||||
|
||||
namespace Rector\Tests\Restoration\Rector\ClassMethod\InferParamFromClassMethodReturnRector\Fixture;
|
||||
|
||||
use PhpParser\Node\Scalar\LNumber;
|
||||
use PhpParser\Node\Scalar\String_;
|
||||
use Rector\Tests\Restoration\Rector\ClassMethod\InferParamFromClassMethodReturnRector\Source\SomeType;
|
||||
|
||||
class UnionTypes extends SomeType
|
||||
{
|
||||
public function getNodeTypes(): array
|
||||
{
|
||||
return [String_::class, LNumber::class];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \PhpParser\Node\Scalar\LNumber|\PhpParser\Node\Scalar\String_ $node
|
||||
*/
|
||||
public function process(\PhpParser\Node $node)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -1,33 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Tests\Restoration\Rector\ClassMethod\InferParamFromClassMethodReturnRector;
|
||||
|
||||
use Iterator;
|
||||
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
|
||||
use Symplify\SmartFileSystem\SmartFileInfo;
|
||||
|
||||
final class InferParamFromClassMethodReturnRectorTest extends AbstractRectorTestCase
|
||||
{
|
||||
/**
|
||||
* @dataProvider provideData()
|
||||
*/
|
||||
public function test(SmartFileInfo $fileInfo): void
|
||||
{
|
||||
$this->doTestFileInfo($fileInfo);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Iterator<SmartFileInfo>
|
||||
*/
|
||||
public function provideData(): Iterator
|
||||
{
|
||||
return $this->yieldFilesFromDirectory(__DIR__ . '/Fixture');
|
||||
}
|
||||
|
||||
public function provideConfigFilePath(): string
|
||||
{
|
||||
return __DIR__ . '/config/configured_rule.php';
|
||||
}
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Tests\Restoration\Rector\ClassMethod\InferParamFromClassMethodReturnRector\Source;
|
||||
|
||||
abstract class SomeType
|
||||
{
|
||||
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Rector\Restoration\Rector\ClassMethod\InferParamFromClassMethodReturnRector;
|
||||
use Rector\Restoration\ValueObject\InferParamFromClassMethodReturn;
|
||||
use Rector\Tests\Restoration\Rector\ClassMethod\InferParamFromClassMethodReturnRector\Source\SomeType;
|
||||
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
|
||||
use Symplify\SymfonyPhpConfig\ValueObjectInliner;
|
||||
|
||||
return static function (ContainerConfigurator $containerConfigurator): void {
|
||||
$services = $containerConfigurator->services();
|
||||
|
||||
$configuration = ValueObjectInliner::inline([
|
||||
new InferParamFromClassMethodReturn(SomeType::class, 'process', 'getNodeTypes'),
|
||||
]);
|
||||
|
||||
$services->set(InferParamFromClassMethodReturnRector::class)
|
||||
->call('configure', [[
|
||||
InferParamFromClassMethodReturnRector::INFER_PARAMS_FROM_CLASS_METHOD_RETURNS => $configuration,
|
||||
]]);
|
||||
};
|
|
@ -42,7 +42,7 @@ class DFactory {}
|
|||
class ClassStringArrayItem
|
||||
{
|
||||
/**
|
||||
* @return array<string, mixed>
|
||||
* @return array<string, mixed[]>
|
||||
*/
|
||||
public function getData()
|
||||
{
|
||||
|
|
|
@ -40,7 +40,7 @@ class DFactory {}
|
|||
class ClassStringArrayItem2
|
||||
{
|
||||
/**
|
||||
* @return array<int, class-string>
|
||||
* @return class-string[]
|
||||
*/
|
||||
public function getData()
|
||||
{
|
||||
|
|
|
@ -60,7 +60,8 @@ final class ExprBoolCaster
|
|||
return false;
|
||||
}
|
||||
|
||||
if ($this->nodeTypeResolver->isStaticType($expr, BooleanType::class)) {
|
||||
$exprType = $this->nodeTypeResolver->getType($expr);
|
||||
if ($exprType instanceof BooleanType) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -65,8 +65,8 @@ CODE_SAMPLE
|
|||
*/
|
||||
public function refactor(Node $node): ?Node
|
||||
{
|
||||
$leftStaticType = $this->getStaticType($node->left);
|
||||
$rightStaticType = $this->getStaticType($node->right);
|
||||
$leftStaticType = $this->getType($node->left);
|
||||
$rightStaticType = $this->getType($node->right);
|
||||
|
||||
// objects can be different by content
|
||||
if ($leftStaticType instanceof ObjectType) {
|
||||
|
|
|
@ -92,7 +92,7 @@ CODE_SAMPLE
|
|||
/** @var BooleanAnd|BooleanOr $booleanExpr */
|
||||
$booleanExpr = $expression->expr;
|
||||
|
||||
$leftStaticType = $this->getStaticType($booleanExpr->left);
|
||||
$leftStaticType = $this->getType($booleanExpr->left);
|
||||
if (! $leftStaticType instanceof BooleanType) {
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -159,7 +159,7 @@ CODE_SAMPLE
|
|||
return true;
|
||||
}
|
||||
|
||||
$foreachValueStaticType = $this->getStaticType($foreach->expr);
|
||||
$foreachValueStaticType = $this->getType($foreach->expr);
|
||||
if ($foreachValueStaticType instanceof ObjectType) {
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -143,7 +143,7 @@ CODE_SAMPLE
|
|||
|
||||
private function isArrayType(Expr $expr): bool
|
||||
{
|
||||
$exprType = $this->getStaticType($expr);
|
||||
$exprType = $this->getType($expr);
|
||||
if ($exprType instanceof ObjectType) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -93,7 +93,7 @@ CODE_SAMPLE
|
|||
$firstArg = $node->args[0];
|
||||
|
||||
$firstValue = $firstArg->value;
|
||||
$firstValueStaticType = $this->getStaticType($firstValue);
|
||||
$firstValueStaticType = $this->getType($firstValue);
|
||||
if (! $firstValueStaticType instanceof ConstantArrayType) {
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -72,7 +72,7 @@ CODE_SAMPLE
|
|||
return null;
|
||||
}
|
||||
|
||||
$firstArgumentStaticType = $this->getStaticType($node->args[0]->value);
|
||||
$firstArgumentStaticType = $this->getType($node->args[0]->value);
|
||||
if (! $firstArgumentStaticType instanceof StringType) {
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -96,7 +96,9 @@ CODE_SAMPLE
|
|||
/** @var Arg $secondArg */
|
||||
$secondArg = $node->args[1];
|
||||
$valueArgument = $secondArg->value;
|
||||
if (! $this->nodeTypeResolver->isStaticType($valueArgument, StringType::class)) {
|
||||
|
||||
$valueType = $this->getType($valueArgument);
|
||||
if (! $valueType instanceof StringType) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
|
@ -189,7 +189,7 @@ CODE_SAMPLE
|
|||
|
||||
$defaultValue = $property->props[0]->default;
|
||||
if ($defaultValue !== null) {
|
||||
$resolvedTypes[] = $this->getStaticType($defaultValue);
|
||||
$resolvedTypes[] = $this->getType($defaultValue);
|
||||
}
|
||||
|
||||
$resolveAssignedType = $this->resolveAssignedTypeInStmtsByPropertyName($classLike->stmts, $propertyName);
|
||||
|
@ -240,7 +240,7 @@ CODE_SAMPLE
|
|||
return null;
|
||||
}
|
||||
|
||||
$resolvedTypes[] = $this->getStaticType($node->expr);
|
||||
$resolvedTypes[] = $this->getType($node->expr);
|
||||
return null;
|
||||
});
|
||||
|
||||
|
|
|
@ -78,11 +78,14 @@ CODE_SAMPLE
|
|||
|
||||
if ($node->expr instanceof Identical) {
|
||||
$identical = $node->expr;
|
||||
if (! $this->nodeTypeResolver->isStaticType($identical->left, BooleanType::class)) {
|
||||
|
||||
$leftType = $this->getType($identical->left);
|
||||
if (! $leftType instanceof BooleanType) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (! $this->nodeTypeResolver->isStaticType($identical->right, BooleanType::class)) {
|
||||
$rightType = $this->getType($identical->right);
|
||||
if (! $rightType instanceof BooleanType) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -94,11 +97,13 @@ CODE_SAMPLE
|
|||
|
||||
private function processIdentical(Identical $identical): ?NotIdentical
|
||||
{
|
||||
if (! $this->nodeTypeResolver->isStaticType($identical->left, BooleanType::class)) {
|
||||
$leftType = $this->getType($identical->left);
|
||||
if (! $leftType instanceof BooleanType) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (! $this->nodeTypeResolver->isStaticType($identical->right, BooleanType::class)) {
|
||||
$rightType = $this->getType($identical->right);
|
||||
if (! $rightType instanceof BooleanType) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
|
@ -107,7 +107,7 @@ CODE_SAMPLE
|
|||
$type = $phpDocInfo->getVarType();
|
||||
|
||||
if (! $type instanceof UnionType) {
|
||||
$type = $this->getObjectType($assign->expr);
|
||||
$type = $this->getType($assign->expr);
|
||||
}
|
||||
|
||||
if (! $type instanceof UnionType) {
|
||||
|
|
|
@ -64,14 +64,13 @@ CODE_SAMPLE
|
|||
*/
|
||||
public function refactor(Node $node): ?Node
|
||||
{
|
||||
if ($this->nodeTypeResolver->isStaticType(
|
||||
$node->left,
|
||||
BooleanType::class
|
||||
) && ! $this->valueResolver->isTrueOrFalse($node->left)) {
|
||||
$leftType = $this->getType($node->left);
|
||||
if ($leftType instanceof BooleanType && ! $this->valueResolver->isTrueOrFalse($node->left)) {
|
||||
return $this->processBoolTypeToNotBool($node, $node->left, $node->right);
|
||||
}
|
||||
|
||||
if (! $this->nodeTypeResolver->isStaticType($node->right, BooleanType::class)) {
|
||||
$rightType = $this->getType($node->right);
|
||||
if (! $rightType instanceof BooleanType) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
|
@ -112,7 +112,7 @@ CODE_SAMPLE
|
|||
return null;
|
||||
}
|
||||
|
||||
$conditionStaticType = $this->getStaticType($conditionNode);
|
||||
$conditionStaticType = $this->getType($conditionNode);
|
||||
if ($conditionStaticType instanceof BooleanType || $conditionStaticType instanceof ConstantIntegerType) {
|
||||
return null;
|
||||
}
|
||||
|
@ -152,11 +152,12 @@ CODE_SAMPLE
|
|||
return $this->resolveString($isNegated, $expr);
|
||||
}
|
||||
|
||||
if ($this->nodeTypeResolver->isStaticType($expr, IntegerType::class)) {
|
||||
$exprType = $this->getType($expr);
|
||||
if ($exprType instanceof IntegerType) {
|
||||
return $this->resolveInteger($isNegated, $expr);
|
||||
}
|
||||
|
||||
if ($this->nodeTypeResolver->isStaticType($expr, FloatType::class)) {
|
||||
if ($exprType instanceof FloatType) {
|
||||
return $this->resolveFloat($isNegated, $expr);
|
||||
}
|
||||
|
||||
|
|
|
@ -95,7 +95,7 @@ CODE_SAMPLE
|
|||
continue;
|
||||
}
|
||||
|
||||
$propertyFetchVarType = $this->getObjectType($issetVar->var);
|
||||
$propertyFetchVarType = $this->getType($issetVar->var);
|
||||
|
||||
if ($propertyFetchVarType instanceof TypeWithClassName) {
|
||||
if (! $this->reflectionProvider->hasClass($propertyFetchVarType->getClassName())) {
|
||||
|
|
|
@ -110,7 +110,7 @@ CODE_SAMPLE
|
|||
|
||||
private function refactorPropertyFetch(PropertyFetch $propertyFetch): MethodCall|null
|
||||
{
|
||||
$callerType = $this->getObjectType($propertyFetch->var);
|
||||
$callerType = $this->getType($propertyFetch->var);
|
||||
if (! $callerType instanceof TypeWithClassName) {
|
||||
return null;
|
||||
}
|
||||
|
@ -143,7 +143,7 @@ CODE_SAMPLE
|
|||
|
||||
private function refactorMagicSet(Expr $expr, PropertyFetch $propertyFetch): MethodCall|null
|
||||
{
|
||||
$propertyCallerType = $this->getObjectType($propertyFetch->var);
|
||||
$propertyCallerType = $this->getType($propertyFetch->var);
|
||||
if (! $propertyCallerType instanceof ObjectType) {
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -61,7 +61,8 @@ CODE_SAMPLE
|
|||
*/
|
||||
public function refactor(Node $node): ?Node
|
||||
{
|
||||
if (! $this->nodeTypeResolver->isStaticType($node->cond, BooleanType::class)) {
|
||||
$condType = $this->getType($node->cond);
|
||||
if (! $condType instanceof BooleanType) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
|
@ -110,7 +110,8 @@ final class UnnecessaryTernaryExpressionRector extends AbstractRector
|
|||
|
||||
private function processTrueIfExpressionWithFalseElseExpression(Expr $expr): Expr
|
||||
{
|
||||
if ($this->nodeTypeResolver->isStaticType($expr, BooleanType::class)) {
|
||||
$exprType = $this->getType($expr);
|
||||
if ($exprType instanceof BooleanType) {
|
||||
return $expr;
|
||||
}
|
||||
|
||||
|
@ -120,14 +121,16 @@ final class UnnecessaryTernaryExpressionRector extends AbstractRector
|
|||
private function processFalseIfExpressionWithTrueElseExpression(Expr $expr): Expr
|
||||
{
|
||||
if ($expr instanceof BooleanNot) {
|
||||
if ($this->nodeTypeResolver->isStaticType($expr->expr, BooleanType::class)) {
|
||||
$negatedExprType = $this->getType($expr->expr);
|
||||
if ($negatedExprType instanceof BooleanType) {
|
||||
return $expr->expr;
|
||||
}
|
||||
|
||||
return new Bool_($expr->expr);
|
||||
}
|
||||
|
||||
if ($this->nodeTypeResolver->isStaticType($expr, BooleanType::class)) {
|
||||
$exprType = $this->getType($expr);
|
||||
if ($exprType instanceof BooleanType) {
|
||||
return new BooleanNot($expr);
|
||||
}
|
||||
|
||||
|
|
|
@ -76,7 +76,7 @@ CODE_SAMPLE
|
|||
return null;
|
||||
}
|
||||
|
||||
$constType = $this->getStaticType($node->consts[0]->value);
|
||||
$constType = $this->getType($node->consts[0]->value);
|
||||
if ($constType instanceof MixedType) {
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -84,7 +84,7 @@ CODE_SAMPLE
|
|||
|
||||
private function isNullableNonScalarType(Node $node): bool
|
||||
{
|
||||
$staticType = $this->getStaticType($node);
|
||||
$staticType = $this->getType($node);
|
||||
if ($staticType instanceof MixedType) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -96,7 +96,7 @@ CODE_SAMPLE
|
|||
return null;
|
||||
}
|
||||
|
||||
$nodeType = $this->getStaticType($node->expr);
|
||||
$nodeType = $this->getType($node->expr);
|
||||
if ($nodeType instanceof MixedType) {
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -149,7 +149,7 @@ CODE_SAMPLE
|
|||
return null;
|
||||
}
|
||||
|
||||
if (count($classMethod->stmts) !== 1) {
|
||||
if (count((array) $classMethod->stmts) !== 1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
|
@ -71,7 +71,7 @@ CODE_SAMPLE
|
|||
return null;
|
||||
}
|
||||
|
||||
$conditionStaticType = $this->getStaticType($node->cond);
|
||||
$conditionStaticType = $this->getType($node->cond);
|
||||
if (! $conditionStaticType instanceof ConstantBooleanType) {
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -79,7 +79,7 @@ CODE_SAMPLE
|
|||
return null;
|
||||
}
|
||||
|
||||
$ifType = $this->getStaticType($node->if);
|
||||
$ifType = $this->getType($node->if);
|
||||
if (! $ifType instanceof BooleanType) {
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -78,7 +78,7 @@ CODE_SAMPLE
|
|||
return null;
|
||||
}
|
||||
|
||||
$classMethodStatementCount = count($node->stmts);
|
||||
$classMethodStatementCount = count((array) $node->stmts);
|
||||
|
||||
// iterate from bottom to up, so we can merge
|
||||
for ($i = $classMethodStatementCount - 1; $i >= 0; --$i) {
|
||||
|
|
|
@ -99,7 +99,7 @@ CODE_SAMPLE
|
|||
continue;
|
||||
}
|
||||
|
||||
$paramType = $this->getObjectType($paramNode);
|
||||
$paramType = $this->getType($paramNode);
|
||||
|
||||
/** @var string $paramName */
|
||||
$paramName = $this->getName($paramNode->var);
|
||||
|
@ -124,7 +124,7 @@ CODE_SAMPLE
|
|||
return false;
|
||||
}
|
||||
|
||||
$paramStaticType = $this->getObjectType($param);
|
||||
$paramStaticType = $this->getType($param);
|
||||
if (! $paramStaticType instanceof ObjectType) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -131,7 +131,7 @@ CODE_SAMPLE
|
|||
$paramName = $this->getName($param->var);
|
||||
$variable = new Variable($paramName);
|
||||
|
||||
$paramType = $this->getStaticType($param);
|
||||
$paramType = $this->getType($param);
|
||||
$recastedVariable = $this->recastVariabletIfScalarType($variable, $paramType);
|
||||
if (! $recastedVariable instanceof Cast) {
|
||||
return null;
|
||||
|
|
|
@ -127,7 +127,7 @@ CODE_SAMPLE
|
|||
return true;
|
||||
}
|
||||
|
||||
return ! $this->getStaticType($methodCall->args[0]->value) instanceof StringType;
|
||||
return ! $this->getType($methodCall->args[0]->value) instanceof StringType;
|
||||
}
|
||||
|
||||
private function updateNode(MethodCall $methodCall): MethodCall
|
||||
|
|
|
@ -160,7 +160,7 @@ CODE_SAMPLE
|
|||
return true;
|
||||
}
|
||||
|
||||
$staticType = $this->getStaticType($expr);
|
||||
$staticType = $this->getType($expr);
|
||||
$resourceType = new ResourceType();
|
||||
|
||||
if ($staticType->equals($resourceType)) {
|
||||
|
|
|
@ -206,7 +206,7 @@ CODE_SAMPLE
|
|||
|
||||
private function isClassTypeWithChildren(StaticCall | MethodCall | FuncCall $expr): bool
|
||||
{
|
||||
$callStaticType = $this->getStaticType($expr);
|
||||
$callStaticType = $this->getType($expr);
|
||||
$callStaticType = $this->typeUnwrapper->unwrapNullableType($callStaticType);
|
||||
|
||||
if (! $callStaticType instanceof ObjectType) {
|
||||
|
|
|
@ -115,7 +115,7 @@ CODE_SAMPLE
|
|||
private function isNotThisTypePropertyFetch(Expr $expr): bool
|
||||
{
|
||||
if ($expr instanceof PropertyFetch) {
|
||||
$variableType = $this->getStaticType($expr->var);
|
||||
$variableType = $this->getType($expr->var);
|
||||
return ! $variableType instanceof ThisType;
|
||||
}
|
||||
|
||||
|
|
|
@ -110,7 +110,7 @@ CODE_SAMPLE
|
|||
|
||||
private function processVariableNum(Continue_ $continue, Variable $numVariable): Continue_ | Break_
|
||||
{
|
||||
$staticType = $this->getStaticType($numVariable);
|
||||
$staticType = $this->getType($numVariable);
|
||||
if (! $staticType instanceof ConstantType) {
|
||||
return $continue;
|
||||
}
|
||||
|
|
|
@ -108,7 +108,7 @@ CODE_SAMPLE
|
|||
|
||||
private function processVariableNum(Break_ | Continue_ $stmt, Variable $numVariable): ?Node
|
||||
{
|
||||
$staticType = $this->getStaticType($numVariable);
|
||||
$staticType = $this->getType($numVariable);
|
||||
|
||||
if ($staticType instanceof ConstantType) {
|
||||
if ($staticType instanceof ConstantIntegerType) {
|
||||
|
|
|
@ -52,7 +52,8 @@ final class ListSplitStringRector extends AbstractRector implements MinPhpVersio
|
|||
return null;
|
||||
}
|
||||
|
||||
if (! $this->nodeTypeResolver->isStaticType($node->expr, StringType::class)) {
|
||||
$exprType = $this->getType($node->expr);
|
||||
if (! $exprType instanceof StringType) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
|
@ -105,13 +105,14 @@ CODE_SAMPLE
|
|||
$node->name = new Identifier(MethodName::CONSTRUCT);
|
||||
}
|
||||
|
||||
if ($node->stmts === null) {
|
||||
$stmts = $node->stmts;
|
||||
if ($stmts === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (count($node->stmts) === 1) {
|
||||
if (count($stmts) === 1) {
|
||||
/** @var Expression|Expr $stmt */
|
||||
$stmt = $node->stmts[0];
|
||||
$stmt = $stmts[0];
|
||||
if (! $stmt instanceof Expression) {
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -130,7 +130,7 @@ CODE_SAMPLE
|
|||
private function resolveStaticCallClassName(StaticCall $staticCall): ?string
|
||||
{
|
||||
if ($staticCall->class instanceof PropertyFetch) {
|
||||
$objectType = $this->getObjectType($staticCall->class);
|
||||
$objectType = $this->getType($staticCall->class);
|
||||
if ($objectType instanceof ObjectType) {
|
||||
return $objectType->getClassName();
|
||||
}
|
||||
|
|
|
@ -117,7 +117,7 @@ CODE_SAMPLE
|
|||
}
|
||||
|
||||
$value = null;
|
||||
$exprStaticType = $this->getStaticType($expr);
|
||||
$exprStaticType = $this->getType($expr);
|
||||
|
||||
if ($expr instanceof String_) {
|
||||
$value = $expr->value;
|
||||
|
|
|
@ -95,7 +95,7 @@ CODE_SAMPLE
|
|||
}
|
||||
|
||||
// this can lead to false positive by phpstan, but that's best we can do
|
||||
$onlyValueType = $this->getStaticType($countedNode);
|
||||
$onlyValueType = $this->getType($countedNode);
|
||||
if ($onlyValueType instanceof ArrayType) {
|
||||
if (! $this->countableAnalyzer->isCastableArrayType($countedNode)) {
|
||||
return null;
|
||||
|
@ -108,10 +108,9 @@ CODE_SAMPLE
|
|||
return $this->castToArray($countedNode, $node);
|
||||
}
|
||||
|
||||
if ($this->nodeTypeResolver->isNullableType($countedNode) || $this->nodeTypeResolver->isStaticType(
|
||||
$countedNode,
|
||||
NullType::class
|
||||
)) {
|
||||
$countedType = $this->getType($countedNode);
|
||||
|
||||
if ($this->nodeTypeResolver->isNullableType($countedNode) || $countedType instanceof NullType) {
|
||||
$identical = new Identical($countedNode, $this->nodeFactory->createNull());
|
||||
$ternary = new Ternary($identical, new LNumber(0), $node);
|
||||
// prevent infinity loop re-resolution
|
||||
|
|
|
@ -103,10 +103,8 @@ CODE_SAMPLE
|
|||
return null;
|
||||
}
|
||||
|
||||
if (! $this->nodeTypeResolver->isNullableType($firstArgValue) && ! $this->nodeTypeResolver->isStaticType(
|
||||
$firstArgValue,
|
||||
NullType::class
|
||||
)) {
|
||||
$firstArgType = $this->getType($firstArgValue);
|
||||
if (! $this->nodeTypeResolver->isNullableType($firstArgValue) && ! $firstArgType instanceof NullType) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
|
@ -82,7 +82,7 @@ CODE_SAMPLE
|
|||
return null;
|
||||
}
|
||||
|
||||
$firstArgStaticType = $this->getStaticType($node->args[1]->value);
|
||||
$firstArgStaticType = $this->getType($node->args[1]->value);
|
||||
if (! $firstArgStaticType instanceof ObjectType) {
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -133,7 +133,7 @@ CODE_SAMPLE
|
|||
return true;
|
||||
}
|
||||
|
||||
$arrayStaticType = $this->getStaticType($expr);
|
||||
$arrayStaticType = $this->getType($expr);
|
||||
if ($this->isConstantArrayTypeWithStringKeyType($arrayStaticType)) {
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -64,7 +64,7 @@ final class MbStrrposEncodingArgumentPositionRector extends AbstractRector imple
|
|||
return null;
|
||||
}
|
||||
|
||||
$secondArgType = $this->getStaticType($node->args[2]->value);
|
||||
$secondArgType = $this->getType($node->args[2]->value);
|
||||
if ($secondArgType instanceof IntegerType) {
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -149,7 +149,7 @@ CODE_SAMPLE
|
|||
private function processNullableType(Property $property, Param $param): void
|
||||
{
|
||||
if ($this->nodeTypeResolver->isNullableType($property)) {
|
||||
$objectType = $this->getObjectType($property);
|
||||
$objectType = $this->getType($property);
|
||||
$param->type = $this->staticTypeMapper->mapPHPStanTypeToPhpParserNode($objectType, TypeKind::PARAM());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -235,7 +235,7 @@ CODE_SAMPLE
|
|||
|
||||
$this->mirrorComments($classConst, $variable);
|
||||
|
||||
$constantType = $this->getStaticType($classConst->consts[0]->value);
|
||||
$constantType = $this->getType($classConst->consts[0]->value);
|
||||
$this->varAnnotationManipulator->decorateNodeWithType($classConst, $constantType);
|
||||
|
||||
return $classConst;
|
||||
|
|
|
@ -1,187 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Restoration\Rector\ClassMethod;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Param;
|
||||
use PhpParser\Node\Stmt\Class_;
|
||||
use PhpParser\Node\Stmt\ClassMethod;
|
||||
use PHPStan\Analyser\Scope;
|
||||
use PHPStan\Reflection\ClassReflection;
|
||||
use PHPStan\Type\MixedType;
|
||||
use PHPStan\Type\Type;
|
||||
use Rector\BetterPhpDocParser\PhpDocManipulator\PhpDocTypeChanger;
|
||||
use Rector\Core\Contract\Rector\ConfigurableRectorInterface;
|
||||
use Rector\Core\Rector\AbstractRector;
|
||||
use Rector\NodeTypeResolver\Node\AttributeKey;
|
||||
use Rector\Restoration\Type\ConstantReturnToParamTypeConverter;
|
||||
use Rector\Restoration\ValueObject\InferParamFromClassMethodReturn;
|
||||
use Rector\TypeDeclaration\TypeInferer\ReturnTypeInferer;
|
||||
use Symplify\RuleDocGenerator\ValueObject\CodeSample\ConfiguredCodeSample;
|
||||
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
|
||||
use Webmozart\Assert\Assert;
|
||||
|
||||
/**
|
||||
* @see \Rector\Tests\Restoration\Rector\ClassMethod\InferParamFromClassMethodReturnRector\InferParamFromClassMethodReturnRectorTest
|
||||
*/
|
||||
final class InferParamFromClassMethodReturnRector extends AbstractRector implements ConfigurableRectorInterface
|
||||
{
|
||||
/**
|
||||
* @api
|
||||
* @var string
|
||||
*/
|
||||
public const INFER_PARAMS_FROM_CLASS_METHOD_RETURNS = 'infer_param_from_class_method_returns';
|
||||
|
||||
/**
|
||||
* @var InferParamFromClassMethodReturn[]
|
||||
*/
|
||||
private array $inferParamFromClassMethodReturn = [];
|
||||
|
||||
public function __construct(
|
||||
private ReturnTypeInferer $returnTypeInferer,
|
||||
private ConstantReturnToParamTypeConverter $constantReturnToParamTypeConverter,
|
||||
private PhpDocTypeChanger $phpDocTypeChanger
|
||||
) {
|
||||
}
|
||||
|
||||
public function getRuleDefinition(): RuleDefinition
|
||||
{
|
||||
return new RuleDefinition('Change @param doc based on another method return type', [
|
||||
new ConfiguredCodeSample(
|
||||
<<<'CODE_SAMPLE'
|
||||
class SomeClass
|
||||
{
|
||||
public function getNodeTypes(): array
|
||||
{
|
||||
return [String_::class];
|
||||
}
|
||||
|
||||
public function process(Node $node)
|
||||
{
|
||||
}
|
||||
}
|
||||
CODE_SAMPLE
|
||||
,
|
||||
<<<'CODE_SAMPLE'
|
||||
class SomeClass
|
||||
{
|
||||
public function getNodeTypes(): array
|
||||
{
|
||||
return [String_::class];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param String_ $node
|
||||
*/
|
||||
public function process(Node $node)
|
||||
{
|
||||
}
|
||||
}
|
||||
CODE_SAMPLE
|
||||
,
|
||||
[
|
||||
self::INFER_PARAMS_FROM_CLASS_METHOD_RETURNS => [
|
||||
new InferParamFromClassMethodReturn('SomeClass', 'process', 'getNodeTypes'),
|
||||
],
|
||||
]
|
||||
),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<class-string<Node>>
|
||||
*/
|
||||
public function getNodeTypes(): array
|
||||
{
|
||||
return [ClassMethod::class];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ClassMethod $node
|
||||
*/
|
||||
public function refactor(Node $node): ?Node
|
||||
{
|
||||
// must be exactly 1 param
|
||||
if (count($node->params) !== 1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$firstParam = $node->params[0];
|
||||
$paramName = $this->getName($firstParam);
|
||||
|
||||
foreach ($this->inferParamFromClassMethodReturn as $singleInferParamFromClassMethodReturn) {
|
||||
$returnClassMethod = $this->matchReturnClassMethod($node, $singleInferParamFromClassMethodReturn);
|
||||
if (! $returnClassMethod instanceof ClassMethod) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$returnType = $this->returnTypeInferer->inferFunctionLike($returnClassMethod);
|
||||
|
||||
$currentPhpDocInfo = $this->phpDocInfoFactory->createFromNodeOrEmpty($node);
|
||||
|
||||
$paramType = $this->constantReturnToParamTypeConverter->convert($returnType);
|
||||
if ($paramType instanceof MixedType) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($this->isParamDocTypeEqualToPhpType($firstParam, $paramType)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$this->phpDocTypeChanger->changeParamType($currentPhpDocInfo, $paramType, $firstParam, $paramName);
|
||||
|
||||
return $node;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, InferParamFromClassMethodReturn[]> $configuration
|
||||
*/
|
||||
public function configure(array $configuration): void
|
||||
{
|
||||
$inferParamsFromClassMethodReturns = $configuration[self::INFER_PARAMS_FROM_CLASS_METHOD_RETURNS] ?? [];
|
||||
Assert::allIsInstanceOf($inferParamsFromClassMethodReturns, InferParamFromClassMethodReturn::class);
|
||||
|
||||
$this->inferParamFromClassMethodReturn = $inferParamsFromClassMethodReturns;
|
||||
}
|
||||
|
||||
private function matchReturnClassMethod(
|
||||
ClassMethod $classMethod,
|
||||
InferParamFromClassMethodReturn $inferParamFromClassMethodReturn
|
||||
): ?ClassMethod {
|
||||
$scope = $classMethod->getAttribute(AttributeKey::SCOPE);
|
||||
if (! $scope instanceof Scope) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$classReflection = $scope->getClassReflection();
|
||||
if (! $classReflection instanceof ClassReflection) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (! $classReflection->isSubclassOf($inferParamFromClassMethodReturn->getClass())) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (! $this->isName($classMethod->name, $inferParamFromClassMethodReturn->getParamMethod())) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$classLike = $classMethod->getAttribute(AttributeKey::CLASS_NODE);
|
||||
if (! $classLike instanceof Class_) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $classLike->getMethod($inferParamFromClassMethodReturn->getReturnMethod());
|
||||
}
|
||||
|
||||
private function isParamDocTypeEqualToPhpType(Param $param, Type $paramType): bool
|
||||
{
|
||||
$currentParamType = $this->nodeTypeResolver->getStaticType($param);
|
||||
return $currentParamType->equals($paramType);
|
||||
}
|
||||
}
|
|
@ -1,87 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Restoration\Type;
|
||||
|
||||
use PHPStan\Type\ArrayType;
|
||||
use PHPStan\Type\Constant\ConstantStringType;
|
||||
use PHPStan\Type\Generic\GenericClassStringType;
|
||||
use PHPStan\Type\MixedType;
|
||||
use PHPStan\Type\ObjectType;
|
||||
use PHPStan\Type\Type;
|
||||
use PHPStan\Type\TypeUtils;
|
||||
use PHPStan\Type\UnionType;
|
||||
use Rector\NodeTypeResolver\PHPStan\Type\TypeFactory;
|
||||
|
||||
final class ConstantReturnToParamTypeConverter
|
||||
{
|
||||
public function __construct(
|
||||
private TypeFactory $typeFactory
|
||||
) {
|
||||
}
|
||||
|
||||
public function convert(Type $type): Type
|
||||
{
|
||||
if ($type instanceof UnionType) {
|
||||
$flattenReturnTypes = TypeUtils::flattenTypes($type);
|
||||
$unionedTypes = [];
|
||||
foreach ($flattenReturnTypes as $flattenReturnType) {
|
||||
if ($flattenReturnType instanceof ArrayType) {
|
||||
$unionedTypes[] = $flattenReturnType->getItemType();
|
||||
}
|
||||
}
|
||||
|
||||
$resolvedTypes = [];
|
||||
foreach ($unionedTypes as $unionedType) {
|
||||
$resolvedTypes[] = $this->convert($unionedType);
|
||||
}
|
||||
|
||||
return new UnionType($resolvedTypes);
|
||||
}
|
||||
|
||||
if ($type instanceof ConstantStringType) {
|
||||
return $this->unwrapConstantTypeToObjectType($type);
|
||||
}
|
||||
|
||||
if ($type instanceof ArrayType) {
|
||||
return $this->unwrapConstantTypeToObjectType($type);
|
||||
}
|
||||
|
||||
return new MixedType();
|
||||
}
|
||||
|
||||
private function unwrapConstantTypeToObjectType(Type $type): Type
|
||||
{
|
||||
if ($type instanceof ArrayType) {
|
||||
return $this->unwrapConstantTypeToObjectType($type->getItemType());
|
||||
}
|
||||
|
||||
if ($type instanceof ConstantStringType) {
|
||||
return new ObjectType($type->getValue());
|
||||
}
|
||||
|
||||
if ($type instanceof GenericClassStringType && $type->getGenericType() instanceof ObjectType) {
|
||||
return $type->getGenericType();
|
||||
}
|
||||
|
||||
if ($type instanceof UnionType) {
|
||||
return $this->unwrapUnionType($type);
|
||||
}
|
||||
|
||||
return new MixedType();
|
||||
}
|
||||
|
||||
private function unwrapUnionType(UnionType $unionType): Type
|
||||
{
|
||||
$types = [];
|
||||
foreach ($unionType->getTypes() as $unionedType) {
|
||||
$unionType = $this->unwrapConstantTypeToObjectType($unionedType);
|
||||
if ($unionType !== null) {
|
||||
$types[] = $unionType;
|
||||
}
|
||||
}
|
||||
|
||||
return $this->typeFactory->createMixedPassedOrUnionType($types);
|
||||
}
|
||||
}
|
|
@ -1,30 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Restoration\ValueObject;
|
||||
|
||||
final class InferParamFromClassMethodReturn
|
||||
{
|
||||
public function __construct(
|
||||
private string $class,
|
||||
private string $paramMethod,
|
||||
private string $returnMethod
|
||||
) {
|
||||
}
|
||||
|
||||
public function getClass(): string
|
||||
{
|
||||
return $this->class;
|
||||
}
|
||||
|
||||
public function getParamMethod(): string
|
||||
{
|
||||
return $this->paramMethod;
|
||||
}
|
||||
|
||||
public function getReturnMethod(): string
|
||||
{
|
||||
return $this->returnMethod;
|
||||
}
|
||||
}
|
|
@ -105,7 +105,7 @@ CODE_SAMPLE
|
|||
}
|
||||
|
||||
$arg = $node->args[$position];
|
||||
$argValueType = $this->getStaticType($arg->value);
|
||||
$argValueType = $this->getType($arg->value);
|
||||
if (! $argValueType instanceof ClosureType) {
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -135,7 +135,7 @@ CODE_SAMPLE
|
|||
continue;
|
||||
}
|
||||
|
||||
$stmtType = $this->getStaticType($stmt);
|
||||
$stmtType = $this->getType($stmt);
|
||||
if ($stmtType instanceof NeverType) {
|
||||
$hasNeverType = true;
|
||||
}
|
||||
|
|
|
@ -64,8 +64,7 @@ final class ReturnTypeInferer
|
|||
);
|
||||
|
||||
$isAutoImport = $this->parameterProvider->provideBoolParameter(Option::AUTO_IMPORT_NAMES);
|
||||
$isAutoImportFullyQuafiedReturn = $this->isAutoImportWithFullyQualifiedReturn($isAutoImport, $functionLike);
|
||||
if ($isAutoImportFullyQuafiedReturn) {
|
||||
if ($this->isAutoImportWithFullyQualifiedReturn($isAutoImport, $functionLike)) {
|
||||
return new MixedType();
|
||||
}
|
||||
|
||||
|
@ -93,6 +92,7 @@ final class ReturnTypeInferer
|
|||
|
||||
// normalize ConstStringType to ClassStringType
|
||||
$resolvedType = $this->genericClassStringTypeNormalizer->normalize($type);
|
||||
|
||||
return $this->resolveTypeWithVoidHandling($functionLike, $resolvedType);
|
||||
}
|
||||
|
||||
|
|
|
@ -323,18 +323,30 @@ abstract class AbstractRector extends NodeVisitorAbstract implements PhpRectorIn
|
|||
return $this->nodeTypeResolver->isObjectType($node, $objectType);
|
||||
}
|
||||
|
||||
protected function getStaticType(Node $node): Type
|
||||
/**
|
||||
* Use this method for getting expr|node type
|
||||
*/
|
||||
protected function getType(Node $node): Type
|
||||
{
|
||||
return $this->nodeTypeResolver->getStaticType($node);
|
||||
return $this->nodeTypeResolver->getType($node);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
* Use getStaticType() instead, as single method to get types
|
||||
* Use @see AbstractRector::getType() instead, as single method to get types
|
||||
*/
|
||||
protected function getObjectType(Node $node): Type
|
||||
{
|
||||
return $this->nodeTypeResolver->resolve($node);
|
||||
return $this->nodeTypeResolver->getType($node);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
* Use @see AbstractRector::getType() instead, as single method to get types
|
||||
*/
|
||||
protected function getStaticType(Node $node): Type
|
||||
{
|
||||
return $this->nodeTypeResolver->getType($node);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -353,15 +365,6 @@ abstract class AbstractRector extends NodeVisitorAbstract implements PhpRectorIn
|
|||
return $this->betterStandardPrinter->print($node);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use FQN PhpVersionProvider service directly instead or implements provideMinPhpVersion, this method will be removed soon
|
||||
* Or implement \Rector\VersionBonding\Contract\MinPhpVersionInterface
|
||||
*/
|
||||
protected function isAtLeastPhpVersion(int $version): bool
|
||||
{
|
||||
return $this->phpVersionProvider->isAtLeastPhpVersion($version);
|
||||
}
|
||||
|
||||
protected function mirrorComments(Node $newNode, Node $oldNode): void
|
||||
{
|
||||
$newNode->setAttribute(AttributeKey::PHP_DOC_INFO, $oldNode->getAttribute(AttributeKey::PHP_DOC_INFO));
|
||||
|
|
Loading…
Reference in New Issue