From 0650075005dfde0f277f71f809f44ff5cef54454 Mon Sep 17 00:00:00 2001 From: TomasVotruba Date: Sun, 26 Jul 2020 13:58:13 +0200 Subject: [PATCH] [Nette] Add ChangeControlArrayAccessToAnnotatedControlVariableRector --- composer.json | 1 + config/set/nette-application-code-quality.php | 3 + docs/rector_rules_overview.md | 35 +++- packages/anonymous-class/config/config.php | 15 ++ .../src/NodeAnalyzer/ClassNodeAnalyzer.php | 38 ++++ .../src/NodeTypeResolver.php | 102 +++++---- .../src/Utils/TypeUnwrapper.php | 19 ++ .../src/Collector/NodesToAddCollector.php | 6 + .../Rector/If_/SimplifyIfReturnBoolRector.php | 30 +-- .../naming/src}/NamespaceMatcher.php | 2 +- .../src/DocBlock/VarAnnotationManipulator.php | 72 +++++++ .../ArrayDimFetchControlTypeResolver.php | 109 ++++++++++ rules/nette/src/Naming/NetteControlNaming.php | 26 +++ .../NodeAnalyzer/ControlDimFetchAnalyzer.php | 50 +++++ .../FormVariableInputNameTypeResolver.php | 9 +- .../MethodNamesByInputNamesResolver.php | 1 - ...AccessToAnnotatedControlVariableRector.php | 195 ++++++++++++++++++ ...AccessToAnnotatedControlVariableRector.php | 99 ++++----- .../MakeGetComponentAssignAnnotatedRector.php | 52 ++--- ...ssToAnnotatedControlVariableRectorTest.php | 31 +++ .../Fixture/fixture.php.inc | 47 +++++ .../Fixture/rename_nested_too.php.inc | 49 +++++ .../Fixture/skip_anonymous_class.php.inc | 3 + .../Namespace_/RenameNamespaceRector.php | 2 +- src/Rector/AbstractRector.php | 20 +- .../AbstractRector/NodeTypeResolverTrait.php | 20 -- 26 files changed, 839 insertions(+), 197 deletions(-) create mode 100644 packages/anonymous-class/config/config.php create mode 100644 packages/anonymous-class/src/NodeAnalyzer/ClassNodeAnalyzer.php rename {src/Naming => rules/naming/src}/NamespaceMatcher.php (95%) create mode 100644 rules/nette/src/DocBlock/VarAnnotationManipulator.php create mode 100644 rules/nette/src/FormControlTypeResolver/ArrayDimFetchControlTypeResolver.php create mode 100644 rules/nette/src/Naming/NetteControlNaming.php create mode 100644 rules/nette/src/NodeAnalyzer/ControlDimFetchAnalyzer.php create mode 100644 rules/nette/src/Rector/ArrayDimFetch/ChangeControlArrayAccessToAnnotatedControlVariableRector.php create mode 100644 rules/nette/tests/Rector/ArrayDimFetch/ChangeControlArrayAccessToAnnotatedControlVariableRector/ChangeControlArrayAccessToAnnotatedControlVariableRectorTest.php create mode 100644 rules/nette/tests/Rector/ArrayDimFetch/ChangeControlArrayAccessToAnnotatedControlVariableRector/Fixture/fixture.php.inc create mode 100644 rules/nette/tests/Rector/ArrayDimFetch/ChangeControlArrayAccessToAnnotatedControlVariableRector/Fixture/rename_nested_too.php.inc diff --git a/composer.json b/composer.json index 21ec6d145e0..e3d9be74332 100644 --- a/composer.json +++ b/composer.json @@ -58,6 +58,7 @@ "autoload": { "psr-4": { "Rector\\Architecture\\": "rules/architecture/src", + "Rector\\AnonymousClass\\": "packages/anonymous-class/src", "Rector\\PostRector\\": "packages/post-rector/src", "Rector\\AttributeAwarePhpDoc\\": "packages/attribute-aware-php-doc/src", "Rector\\Autodiscovery\\": "rules/autodiscovery/src", diff --git a/config/set/nette-application-code-quality.php b/config/set/nette-application-code-quality.php index df6815a614c..35e8beeec01 100644 --- a/config/set/nette-application-code-quality.php +++ b/config/set/nette-application-code-quality.php @@ -2,6 +2,7 @@ declare(strict_types=1); +use Rector\Nette\Rector\ArrayDimFetch\ChangeControlArrayAccessToAnnotatedControlVariableRector; use Rector\Nette\Rector\Assign\MakeGetComponentAssignAnnotatedRector; use Rector\Nette\Rector\ClassMethod\TemplateMagicAssignToExplicitVariableArrayRector; use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator; @@ -12,4 +13,6 @@ return static function (ContainerConfigurator $containerConfigurator): void { $services->set(TemplateMagicAssignToExplicitVariableArrayRector::class); $services->set(MakeGetComponentAssignAnnotatedRector::class); + + $services->set(ChangeControlArrayAccessToAnnotatedControlVariableRector::class); }; diff --git a/docs/rector_rules_overview.md b/docs/rector_rules_overview.md index a72a57338bc..caf603e4cc3 100644 --- a/docs/rector_rules_overview.md +++ b/docs/rector_rules_overview.md @@ -1,4 +1,4 @@ -# All 534 Rectors Overview +# All 536 Rectors Overview - [Projects](#projects) - [General](#general) @@ -31,7 +31,7 @@ - [MockistaToMockery](#mockistatomockery) (2) - [MysqlToMysqli](#mysqltomysqli) (4) - [Naming](#naming) (3) -- [Nette](#nette) (14) +- [Nette](#nette) (15) - [NetteCodeQuality](#nettecodequality) (1) - [NetteKdyby](#nettekdyby) (4) - [NetteTesterToPHPUnit](#nettetestertophpunit) (3) @@ -5184,6 +5184,37 @@ Nextras/Form upgrade of addDatePicker method call to DateControl assign

+### `ChangeControlArrayAccessToAnnotatedControlVariableRector` + +- class: [`Rector\Nette\Rector\ArrayDimFetch\ChangeControlArrayAccessToAnnotatedControlVariableRector`](/../master/rules/nette/src/Rector/ArrayDimFetch/ChangeControlArrayAccessToAnnotatedControlVariableRector.php) +- [test fixtures](/../master/rules/nette/tests/Rector/ArrayDimFetch/ChangeControlArrayAccessToAnnotatedControlVariableRector/Fixture) + +Change magic `$this["some_component"]` to variable assign with @var annotation + +```diff + use Nette\Application\UI\Presenter; + use Nette\Application\UI\Form; + + final class SomePresenter extends Presenter + { + public function run() + { +- if ($this['some_form']->isSubmitted()) { ++ /** @var \Nette\Application\UI\Form $someForm */ ++ $someForm = $this['some_form']; ++ if ($someForm->isSubmitted()) { + } + } + + protected function createComponentSomeForm() + { + return new Form(); + } + } +``` + +

+ ### `ChangeFormArrayAccessToAnnotatedControlVariableRector` - class: [`Rector\Nette\Rector\ArrayDimFetch\ChangeFormArrayAccessToAnnotatedControlVariableRector`](/../master/rules/nette/src/Rector/ArrayDimFetch/ChangeFormArrayAccessToAnnotatedControlVariableRector.php) diff --git a/packages/anonymous-class/config/config.php b/packages/anonymous-class/config/config.php new file mode 100644 index 00000000000..6566daa42e2 --- /dev/null +++ b/packages/anonymous-class/config/config.php @@ -0,0 +1,15 @@ +services(); + + $services->defaults() + ->autowire() + ->public(); + + $services->load('Rector\AnonymousClass\\', __DIR__ . '/../src'); +}; diff --git a/packages/anonymous-class/src/NodeAnalyzer/ClassNodeAnalyzer.php b/packages/anonymous-class/src/NodeAnalyzer/ClassNodeAnalyzer.php new file mode 100644 index 00000000000..7bc9363d481 --- /dev/null +++ b/packages/anonymous-class/src/NodeAnalyzer/ClassNodeAnalyzer.php @@ -0,0 +1,38 @@ +nodeNameResolver = $nodeNameResolver; + } + + public function isAnonymousClass(Node $node): bool + { + if (! $node instanceof Class_) { + return false; + } + + $className = $this->nodeNameResolver->getName($node); + if ($className === null) { + return true; + } + + // match PHPStan pattern for anonymous classes + return (bool) Strings::match($className, '#AnonymousClass\w+$#'); + } +} diff --git a/packages/node-type-resolver/src/NodeTypeResolver.php b/packages/node-type-resolver/src/NodeTypeResolver.php index bbc6094c429..ce4738e59f0 100644 --- a/packages/node-type-resolver/src/NodeTypeResolver.php +++ b/packages/node-type-resolver/src/NodeTypeResolver.php @@ -12,7 +12,6 @@ use PhpParser\Node\Expr\MethodCall; use PhpParser\Node\Expr\New_; use PhpParser\Node\Param; use PhpParser\Node\Scalar; -use PhpParser\Node\Stmt\Class_; use PHPStan\Analyser\Scope; use PHPStan\Type\ArrayType; use PHPStan\Type\FloatType; @@ -25,12 +24,13 @@ use PHPStan\Type\Type; use PHPStan\Type\TypeUtils; use PHPStan\Type\TypeWithClassName; use PHPStan\Type\UnionType; +use Rector\AnonymousClass\NodeAnalyzer\ClassNodeAnalyzer; use Rector\Core\Exception\ShouldNotHappenException; -use Rector\NodeNameResolver\NodeNameResolver; use Rector\NodeTypeResolver\Contract\NodeTypeResolverInterface; use Rector\NodeTypeResolver\Node\AttributeKey; use Rector\NodeTypeResolver\NodeTypeCorrector\ParentClassesInterfacesAndUsedTraitsCorrector; use Rector\NodeTypeResolver\TypeAnalyzer\ArrayTypeAnalyzer; +use Rector\PHPStanStaticTypeMapper\Utils\TypeUnwrapper; use Rector\TypeDeclaration\PHPStan\Type\ObjectTypeSpecifier; final class NodeTypeResolver @@ -40,11 +40,6 @@ final class NodeTypeResolver */ private $nodeTypeResolvers = []; - /** - * @var NodeNameResolver - */ - private $nodeNameResolver; - /** * @var ObjectTypeSpecifier */ @@ -60,23 +55,34 @@ final class NodeTypeResolver */ private $parentClassesInterfacesAndUsedTraitsCorrector; + /** + * @var TypeUnwrapper + */ + private $typeUnwrapper; + + /** + * @var ClassNodeAnalyzer + */ + private $classNodeAnalyzer; + /** * @param NodeTypeResolverInterface[] $nodeTypeResolvers */ public function __construct( - NodeNameResolver $nodeNameResolver, ObjectTypeSpecifier $objectTypeSpecifier, ParentClassesInterfacesAndUsedTraitsCorrector $parentClassesInterfacesAndUsedTraitsCorrector, + TypeUnwrapper $typeUnwrapper, + ClassNodeAnalyzer $classNodeAnalyzer, array $nodeTypeResolvers ) { - $this->nodeNameResolver = $nodeNameResolver; - foreach ($nodeTypeResolvers as $nodeTypeResolver) { $this->addNodeTypeResolver($nodeTypeResolver); } $this->objectTypeSpecifier = $objectTypeSpecifier; $this->parentClassesInterfacesAndUsedTraitsCorrector = $parentClassesInterfacesAndUsedTraitsCorrector; + $this->typeUnwrapper = $typeUnwrapper; + $this->classNodeAnalyzer = $classNodeAnalyzer; } /** @@ -166,7 +172,7 @@ final class NodeTypeResolver return new MixedType(); } - if ($node instanceof New_ && $this->isAnonymousClass($node->class)) { + if ($node instanceof New_ && $this->classNodeAnalyzer->isAnonymousClass($node->class)) { return new ObjectWithoutClassType(); } @@ -178,6 +184,48 @@ final class NodeTypeResolver return $this->objectTypeSpecifier->narrowToFullyQualifiedOrAlaisedObjectType($node, $staticType); } + public function isNumberType(Node $node): bool + { + return $this->isStaticType($node, IntegerType::class) || $this->isStaticType($node, FloatType::class); + } + + 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); + } + + /** + * @param ObjectType|string $desiredType + */ + public function isObjectTypeOrNullableObjectType(Node $node, $desiredType): bool + { + if ($this->isObjectType($node, $desiredType)) { + return true; + } + + $nodeType = $this->getStaticType($node); + if (! $nodeType instanceof UnionType) { + return false; + } + + $unwrappedNodeType = $this->typeUnwrapper->unwrapNullableType($nodeType); + if (! $unwrappedNodeType instanceof TypeWithClassName) { + return false; + } + + $desiredTypeString = $desiredType instanceof ObjectType ? $desiredType->getClassName() : $desiredType; + return is_a($unwrappedNodeType->getClassName(), $desiredTypeString, true); + } + public function isNullableObjectType(Node $node): bool { $nodeType = $this->resolve($node); @@ -203,25 +251,6 @@ final class NodeTypeResolver return false; } - public function isNumberType(Node $node): bool - { - return $this->isStaticType($node, IntegerType::class) || $this->isStaticType($node, FloatType::class); - } - - 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); - } - private function addNodeTypeResolver(NodeTypeResolverInterface $nodeTypeResolver): void { foreach ($nodeTypeResolver->getNodeClasses() as $nodeClass) { @@ -296,7 +325,7 @@ final class NodeTypeResolver } // skip anonymous classes, ref https://github.com/rectorphp/rector/issues/1574 - if ($node instanceof New_ && $this->isAnonymousClass($node->class)) { + if ($node instanceof New_ && $this->classNodeAnalyzer->isAnonymousClass($node->class)) { return new ObjectWithoutClassType(); } @@ -331,17 +360,6 @@ final class NodeTypeResolver return new ArrayType(new MixedType(), new MixedType()); } - private function isAnonymousClass(Node $node): bool - { - if (! $node instanceof Class_) { - return false; - } - - $className = $this->nodeNameResolver->getName($node); - - return $className === null || Strings::contains($className, 'AnonymousClass'); - } - private function resolveByNodeTypeResolvers(Node $node): ?Type { foreach ($this->nodeTypeResolvers as $nodeClass => $nodeTypeResolver) { diff --git a/packages/phpstan-static-type-mapper/src/Utils/TypeUnwrapper.php b/packages/phpstan-static-type-mapper/src/Utils/TypeUnwrapper.php index 818750671b0..10972675164 100644 --- a/packages/phpstan-static-type-mapper/src/Utils/TypeUnwrapper.php +++ b/packages/phpstan-static-type-mapper/src/Utils/TypeUnwrapper.php @@ -8,6 +8,7 @@ use PHPStan\Type\NullType; use PHPStan\Type\Type; use PHPStan\Type\TypeWithClassName; use PHPStan\Type\UnionType; +use Rector\PHPStan\TypeFactoryStaticHelper; final class TypeUnwrapper { @@ -51,4 +52,22 @@ final class TypeUnwrapper return $type; } + + /** + * @return Type|UnionType + */ + public function removeNullTypeFromUnionType(UnionType $unionType): Type + { + $unionedTypesWithoutNullType = []; + + foreach ($unionType->getTypes() as $type) { + if ($type instanceof UnionType) { + continue; + } + + $unionedTypesWithoutNullType[] = $type; + } + + return TypeFactoryStaticHelper::createUnionObjectType($unionedTypesWithoutNullType); + } } diff --git a/packages/post-rector/src/Collector/NodesToAddCollector.php b/packages/post-rector/src/Collector/NodesToAddCollector.php index b1b40301455..bac96c84bb5 100644 --- a/packages/post-rector/src/Collector/NodesToAddCollector.php +++ b/packages/post-rector/src/Collector/NodesToAddCollector.php @@ -9,6 +9,7 @@ use PhpParser\Node\Expr; use PhpParser\Node\Stmt; use PhpParser\Node\Stmt\Expression; use PhpParser\Node\Stmt\If_; +use Rector\Core\Exception\ShouldNotHappenException; use Rector\Core\PhpParser\Node\BetterNodeFinder; use Rector\PostRector\Contract\Collector\NodeCollectorInterface; @@ -41,6 +42,11 @@ final class NodesToAddCollector implements NodeCollectorInterface public function addNodeBeforeNode(Node $addedNode, Node $positionNode): void { + if ($positionNode->getAttributes() === []) { + $message = sprintf('Switch arguments in "%s()" method', __METHOD__); + throw new ShouldNotHappenException($message); + } + $position = $this->resolveNearestExpressionPosition($positionNode); $this->nodesToAddBefore[$position][] = $this->wrapToExpression($addedNode); } diff --git a/rules/code-quality/src/Rector/If_/SimplifyIfReturnBoolRector.php b/rules/code-quality/src/Rector/If_/SimplifyIfReturnBoolRector.php index 6642d09e748..4fed24102e3 100644 --- a/rules/code-quality/src/Rector/If_/SimplifyIfReturnBoolRector.php +++ b/rules/code-quality/src/Rector/If_/SimplifyIfReturnBoolRector.php @@ -23,7 +23,7 @@ use Rector\Core\RectorDefinition\CodeSample; use Rector\Core\RectorDefinition\RectorDefinition; use Rector\NodeTypeResolver\Node\AttributeKey; use Rector\NodeTypeResolver\PHPStan\Type\StaticTypeAnalyzer; -use Rector\PHPStan\TypeFactoryStaticHelper; +use Rector\PHPStanStaticTypeMapper\Utils\TypeUnwrapper; /** * @see \Rector\CodeQuality\Tests\Rector\If_\SimplifyIfReturnBoolRector\SimplifyIfReturnBoolRectorTest @@ -40,12 +40,19 @@ final class SimplifyIfReturnBoolRector extends AbstractRector */ private $mergedNodeCommentPreserver; + /** + * @var TypeUnwrapper + */ + private $typeUnwrapper; + public function __construct( MergedNodeCommentPreserver $mergedNodeCommentPreserver, + TypeUnwrapper $typeUnwrapper, StaticTypeAnalyzer $staticTypeAnalyzer ) { - $this->staticTypeAnalyzer = $staticTypeAnalyzer; $this->mergedNodeCommentPreserver = $mergedNodeCommentPreserver; + $this->typeUnwrapper = $typeUnwrapper; + $this->staticTypeAnalyzer = $staticTypeAnalyzer; } public function getDefinition(): RectorDefinition @@ -205,7 +212,7 @@ PHP $exprStaticType = $this->getStaticType($expr); // if we remove null type, still has to be trueable if ($exprStaticType instanceof UnionType) { - $unionTypeWithoutNullType = $this->removeNullTypeFromUnionType($exprStaticType); + $unionTypeWithoutNullType = $this->typeUnwrapper->removeNullTypeFromUnionType($exprStaticType); if ($this->staticTypeAnalyzer->isAlwaysTruableType($unionTypeWithoutNullType)) { return new NotIdentical($expr, $this->createNull()); } @@ -221,23 +228,6 @@ PHP return new Bool_($expr); } - /** - * @return Type|UnionType - */ - private function removeNullTypeFromUnionType(UnionType $unionType): Type - { - $unionedTypesWithoutNullType = []; - foreach ($unionType->getTypes() as $type) { - if ($type instanceof UnionType) { - continue; - } - - $unionedTypesWithoutNullType[] = $type; - } - - return TypeFactoryStaticHelper::createUnionObjectType($unionedTypesWithoutNullType); - } - private function isBoolCastNeeded(Expr $expr): bool { if ($expr instanceof BooleanNot) { diff --git a/src/Naming/NamespaceMatcher.php b/rules/naming/src/NamespaceMatcher.php similarity index 95% rename from src/Naming/NamespaceMatcher.php rename to rules/naming/src/NamespaceMatcher.php index b5c20e2a52d..c9660e695b8 100644 --- a/src/Naming/NamespaceMatcher.php +++ b/rules/naming/src/NamespaceMatcher.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace Rector\Core\Naming; +namespace Rector\Naming; use Nette\Utils\Strings; use Rector\Core\ValueObject\RenamedNamespaceValueObject; diff --git a/rules/nette/src/DocBlock/VarAnnotationManipulator.php b/rules/nette/src/DocBlock/VarAnnotationManipulator.php new file mode 100644 index 00000000000..a8850c5340b --- /dev/null +++ b/rules/nette/src/DocBlock/VarAnnotationManipulator.php @@ -0,0 +1,72 @@ +phpDocInfoFactory = $phpDocInfoFactory; + } + + public function decorateNodeWithInlineVarType( + Node $node, + TypeWithClassName $controlTypeWithClassName, + string $variableName + ): void { + $phpDocInfo = $this->resolvePhpDocInfo($node); + + // already done + if ($phpDocInfo->getVarTagValue() !== null) { + return; + } + + $attributeAwareFullyQualifiedIdentifierTypeNode = new AttributeAwareFullyQualifiedIdentifierTypeNode( + $controlTypeWithClassName->getClassName() + ); + + $attributeAwareVarTagValueNode = new AttributeAwareVarTagValueNode( + $attributeAwareFullyQualifiedIdentifierTypeNode, + '$' . $variableName, + '' + ); + + $phpDocInfo->addTagValueNode($attributeAwareVarTagValueNode); + } + + private function resolvePhpDocInfo(Node $node): PhpDocInfo + { + $currentStmt = $node->getAttribute(AttributeKey::CURRENT_STATEMENT); + if ($currentStmt instanceof Expression) { + /** @var PhpDocInfo|null $phpDocInfo */ + $phpDocInfo = $currentStmt->getAttribute(AttributeKey::PHP_DOC_INFO); + } else { + /** @var PhpDocInfo|null $phpDocInfo */ + $phpDocInfo = $node->getAttribute(AttributeKey::PHP_DOC_INFO); + } + + if ($phpDocInfo === null) { + $phpDocInfo = $this->phpDocInfoFactory->createEmpty($node); + } + + $phpDocInfo->makeSingleLined(); + + return $phpDocInfo; + } +} diff --git a/rules/nette/src/FormControlTypeResolver/ArrayDimFetchControlTypeResolver.php b/rules/nette/src/FormControlTypeResolver/ArrayDimFetchControlTypeResolver.php new file mode 100644 index 00000000000..b40440c18da --- /dev/null +++ b/rules/nette/src/FormControlTypeResolver/ArrayDimFetchControlTypeResolver.php @@ -0,0 +1,109 @@ +functionLikeParsedNodesFinder = $functionLikeParsedNodesFinder; + $this->controlDimFetchAnalyzer = $controlDimFetchAnalyzer; + $this->nodeTypeResolver = $nodeTypeResolver; + $this->netteControlNaming = $netteControlNaming; + $this->returnTypeInferer = $returnTypeInferer; + } + + /** + * @return array + */ + public function resolve(Node $node): array + { + if (! $node instanceof ArrayDimFetch) { + return []; + } + + $controlShortName = $this->controlDimFetchAnalyzer->matchName($node); + if ($controlShortName === null) { + return []; + } + + $createComponentClassMethod = $this->matchCreateComponentClassMethod($node, $controlShortName); + if ($createComponentClassMethod === null) { + return []; + } + + $createComponentClassMethodReturnType = $this->returnTypeInferer->inferFunctionLike( + $createComponentClassMethod + ); + + if (! $createComponentClassMethodReturnType instanceof TypeWithClassName) { + return []; + } + + return [ + $controlShortName => $createComponentClassMethodReturnType->getClassName(), + ]; + } + + private function matchCreateComponentClassMethod( + ArrayDimFetch $arrayDimFetch, + string $controlShortName + ): ?ClassMethod { + $callerType = $this->nodeTypeResolver->getStaticType($arrayDimFetch->var); + if (! $callerType instanceof TypeWithClassName) { + return null; + } + + $createComponentClassMethodName = $this->netteControlNaming->createCreateComponentClassMethodName( + $controlShortName + ); + + return $this->functionLikeParsedNodesFinder->findClassMethod( + $createComponentClassMethodName, + $callerType->getClassName() + ); + } +} diff --git a/rules/nette/src/Naming/NetteControlNaming.php b/rules/nette/src/Naming/NetteControlNaming.php new file mode 100644 index 00000000000..f81019f7832 --- /dev/null +++ b/rules/nette/src/Naming/NetteControlNaming.php @@ -0,0 +1,26 @@ +createVariableName($shortName)); + } +} diff --git a/rules/nette/src/NodeAnalyzer/ControlDimFetchAnalyzer.php b/rules/nette/src/NodeAnalyzer/ControlDimFetchAnalyzer.php new file mode 100644 index 00000000000..a3cc0603b8c --- /dev/null +++ b/rules/nette/src/NodeAnalyzer/ControlDimFetchAnalyzer.php @@ -0,0 +1,50 @@ +nodeTypeResolver = $nodeTypeResolver; + } + + public function matchName(Node $node): ?string + { + if (! $node instanceof ArrayDimFetch) { + return null; + } + + if (! $this->isContainerVariable($node->var)) { + return null; + } + + if (! $node->dim instanceof String_) { + return null; + } + + return $node->dim->value; + } + + private function isContainerVariable(Node $node): bool + { + if (! $node instanceof Variable) { + return false; + } + + return $this->nodeTypeResolver->isObjectTypeOrNullableObjectType($node, 'Nette\ComponentModel\IContainer'); + } +} diff --git a/rules/nette/src/NodeResolver/FormVariableInputNameTypeResolver.php b/rules/nette/src/NodeResolver/FormVariableInputNameTypeResolver.php index 66e6d49db88..80a62957ef4 100644 --- a/rules/nette/src/NodeResolver/FormVariableInputNameTypeResolver.php +++ b/rules/nette/src/NodeResolver/FormVariableInputNameTypeResolver.php @@ -4,7 +4,7 @@ declare(strict_types=1); namespace Rector\Nette\NodeResolver; -use PhpParser\Node\Expr\Variable; +use PhpParser\Node\Expr; use Rector\Core\Exception\NotImplementedYetException; use Rector\Core\Exception\ShouldNotHappenException; @@ -38,14 +38,13 @@ final class FormVariableInputNameTypeResolver $this->methodNamesByInputNamesResolver = $methodNamesByInputNamesResolver; } - public function resolveControlTypeByInputName(Variable $formVariable, string $inputName): string + public function resolveControlTypeByInputName(Expr $formOrControlExpr, string $inputName): string { - $methodNamesByInputNames = $this->methodNamesByInputNamesResolver->resolveExpr($formVariable); + $methodNamesByInputNames = $this->methodNamesByInputNamesResolver->resolveExpr($formOrControlExpr); $formAddMethodName = $methodNamesByInputNames[$inputName] ?? null; - if ($formAddMethodName === null) { - $message = sprintf('Not found for "%s" input name', $inputName); + $message = sprintf('Type was not found for "%s" input name', $inputName); throw new ShouldNotHappenException($message); } diff --git a/rules/nette/src/NodeResolver/MethodNamesByInputNamesResolver.php b/rules/nette/src/NodeResolver/MethodNamesByInputNamesResolver.php index b12ec27c883..b1c328bd9ce 100644 --- a/rules/nette/src/NodeResolver/MethodNamesByInputNamesResolver.php +++ b/rules/nette/src/NodeResolver/MethodNamesByInputNamesResolver.php @@ -38,7 +38,6 @@ final class MethodNamesByInputNamesResolver foreach ($this->formControlTypeResolvers as $formControlTypeResolver) { $currentMethodNamesByInputNames = $formControlTypeResolver->resolve($node); - $methodNamesByInputNames = array_merge($methodNamesByInputNames, $currentMethodNamesByInputNames); } diff --git a/rules/nette/src/Rector/ArrayDimFetch/ChangeControlArrayAccessToAnnotatedControlVariableRector.php b/rules/nette/src/Rector/ArrayDimFetch/ChangeControlArrayAccessToAnnotatedControlVariableRector.php new file mode 100644 index 00000000000..61317ea2923 --- /dev/null +++ b/rules/nette/src/Rector/ArrayDimFetch/ChangeControlArrayAccessToAnnotatedControlVariableRector.php @@ -0,0 +1,195 @@ +controlDimFetchAnalyzer = $controlDimFetchAnalyzer; + $this->netteControlNaming = $netteControlNaming; + $this->varAnnotationManipulator = $varAnnotationManipulator; + $this->methodNamesByInputNamesResolver = $methodNamesByInputNamesResolver; + } + + public function getDefinition(): RectorDefinition + { + return new RectorDefinition('Change magic $this["some_component"] to variable assign with @var annotation', [ + new CodeSample( + <<<'PHP' +use Nette\Application\UI\Presenter; +use Nette\Application\UI\Form; + +final class SomePresenter extends Presenter +{ + public function run() + { + if ($this['some_form']->isSubmitted()) { + } + } + + protected function createComponentSomeForm() + { + return new Form(); + } +} +PHP +, + <<<'PHP' +use Nette\Application\UI\Presenter; +use Nette\Application\UI\Form; + +final class SomePresenter extends Presenter +{ + public function run() + { + /** @var \Nette\Application\UI\Form $someForm */ + $someForm = $this['some_form']; + if ($someForm->isSubmitted()) { + } + } + + protected function createComponentSomeForm() + { + return new Form(); + } +} +PHP + + ), + ]); + } + + /** + * @return string[] + */ + public function getNodeTypes(): array + { + return [ArrayDimFetch::class]; + } + + /** + * @param ArrayDimFetch $node + */ + public function refactor(Node $node): ?Node + { + $controlName = $this->controlDimFetchAnalyzer->matchName($node); + if ($controlName === null) { + return null; + } + + $variableName = $this->netteControlNaming->createVariableName($controlName); + + $controlObjectType = $this->resolveControlType($node, $controlName); + $this->addAssignExpressionForFirstCase($variableName, $node, $controlObjectType); + + return new Variable($variableName); + } + + private function createAssignExpression(string $variableName, ArrayDimFetch $arrayDimFetch): Expression + { + $variable = new Variable($variableName); + $assignedDimFetch = clone $arrayDimFetch; + $assign = new Assign($variable, $assignedDimFetch); + + return new Expression($assign); + } + + private function addAssignExpressionForFirstCase( + string $variableName, + ArrayDimFetch $arrayDimFetch, + ObjectType $controlObjectType + ): void { + /** @var ClassMethod|null $classMethod */ + $classMethod = $arrayDimFetch->getAttribute(AttributeKey::METHOD_NODE); + if ($classMethod !== null) { + $classMethodObjectHash = spl_object_hash($classMethod); + if (in_array($classMethodObjectHash, $this->alreadyInitializedAssignsClassMethodObjectHashes, true)) { + return; + } + + $this->alreadyInitializedAssignsClassMethodObjectHashes[] = $classMethodObjectHash; + } + + $assignExpression = $this->createAssignExpression($variableName, $arrayDimFetch); + + $this->varAnnotationManipulator->decorateNodeWithInlineVarType( + $assignExpression, + $controlObjectType, + $variableName + ); + + $currentStatement = $arrayDimFetch->getAttribute(AttributeKey::CURRENT_STATEMENT); + $this->addNodeBeforeNode($assignExpression, $currentStatement); + } + + private function resolveControlType(ArrayDimFetch $arrayDimFetch, string $controlName): ObjectType + { + $controlTypes = $this->methodNamesByInputNamesResolver->resolveExpr($arrayDimFetch); + if ($controlTypes === []) { + throw new NotImplementedYetException(); + } + + if (! isset($controlTypes[$controlName])) { + throw new ShouldNotHappenException(); + } + + $controlType = $controlTypes[$controlName]; + + return new ObjectType($controlType); + } +} diff --git a/rules/nette/src/Rector/ArrayDimFetch/ChangeFormArrayAccessToAnnotatedControlVariableRector.php b/rules/nette/src/Rector/ArrayDimFetch/ChangeFormArrayAccessToAnnotatedControlVariableRector.php index 46866824a73..ad9991de8f1 100644 --- a/rules/nette/src/Rector/ArrayDimFetch/ChangeFormArrayAccessToAnnotatedControlVariableRector.php +++ b/rules/nette/src/Rector/ArrayDimFetch/ChangeFormArrayAccessToAnnotatedControlVariableRector.php @@ -8,15 +8,15 @@ use PhpParser\Node; use PhpParser\Node\Expr\ArrayDimFetch; use PhpParser\Node\Expr\Assign; use PhpParser\Node\Expr\Variable; -use PhpParser\Node\Scalar\String_; use PhpParser\Node\Stmt\Expression; -use PHPStan\PhpDocParser\Ast\PhpDoc\VarTagValueNode; -use Rector\AttributeAwarePhpDoc\Ast\Type\AttributeAwareFullyQualifiedIdentifierTypeNode; -use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfo; +use PHPStan\Type\ObjectType; +use Rector\Core\Exception\ShouldNotHappenException; use Rector\Core\Rector\AbstractRector; use Rector\Core\RectorDefinition\CodeSample; use Rector\Core\RectorDefinition\RectorDefinition; -use Rector\Core\Util\StaticRectorStrings; +use Rector\Nette\DocBlock\VarAnnotationManipulator; +use Rector\Nette\Naming\NetteControlNaming; +use Rector\Nette\NodeAnalyzer\ControlDimFetchAnalyzer; use Rector\Nette\NodeResolver\FormVariableInputNameTypeResolver; use Rector\NodeTypeResolver\Node\AttributeKey; @@ -32,9 +32,31 @@ final class ChangeFormArrayAccessToAnnotatedControlVariableRector extends Abstra */ private $formVariableInputNameTypeResolver; - public function __construct(FormVariableInputNameTypeResolver $formVariableInputNameTypeResolver) - { + /** + * @var ControlDimFetchAnalyzer + */ + private $controlDimFetchAnalyzer; + + /** + * @var NetteControlNaming + */ + private $netteControlNaming; + + /** + * @var VarAnnotationManipulator + */ + private $varAnnotationManipulator; + + public function __construct( + FormVariableInputNameTypeResolver $formVariableInputNameTypeResolver, + ControlDimFetchAnalyzer $controlDimFetchAnalyzer, + NetteControlNaming $netteControlNaming, + VarAnnotationManipulator $varAnnotationManipulator + ) { $this->formVariableInputNameTypeResolver = $formVariableInputNameTypeResolver; + $this->controlDimFetchAnalyzer = $controlDimFetchAnalyzer; + $this->netteControlNaming = $netteControlNaming; + $this->varAnnotationManipulator = $varAnnotationManipulator; } public function getDefinition(): RectorDefinition @@ -90,8 +112,8 @@ PHP */ public function refactor(Node $node): ?Node { - $dimString = $this->matchNetteFormArrayDimString($node); - if ($dimString === null) { + $inputName = $this->controlDimFetchAnalyzer->matchName($node); + if ($inputName === null) { return null; } @@ -99,8 +121,7 @@ PHP return null; } - $inputName = $this->getValue($dimString); - $controlVariableName = $this->createControlVariableName($inputName); + $controlVariableName = $this->netteControlNaming->createVariableName($inputName); $controlVariableToFormDimFetchAssign = new Assign(new Variable($controlVariableName), clone $node); $assignExpression = new Expression($controlVariableToFormDimFetchAssign); @@ -114,52 +135,23 @@ PHP $inputName ); - $this->addVarTag($controlVariableToFormDimFetchAssign, $assignExpression, $controlVariableName, $controlType); + $formVariableName = $this->getName($formVariable); + if ($formVariableName === null) { + throw new ShouldNotHappenException(); + } + + $controlObjectType = new ObjectType($controlType); + $this->varAnnotationManipulator->decorateNodeWithInlineVarType( + $assignExpression, + $controlObjectType, + $controlVariableName + ); $this->addNodeBeforeNode($assignExpression, $node); return new Variable($controlVariableName); } - private function addVarTag( - Assign $assign, - Expression $assignExpression, - string $controlName, - string $controlType - ): PhpDocInfo { - $phpDocInfo = $this->phpDocInfoFactory->createEmpty($assignExpression); - - $varTagValueNode = new VarTagValueNode( - new AttributeAwareFullyQualifiedIdentifierTypeNode($controlType), - '$' . $controlName, - '' - ); - - $phpDocInfo->addTagValueNode($varTagValueNode); - $phpDocInfo->makeSingleLined(); - - $assign->setAttribute(AttributeKey::PHP_DOC_INFO, $phpDocInfo); - - return $phpDocInfo; - } - - private function matchNetteFormArrayDimString(ArrayDimFetch $arrayDimFetch): ?String_ - { - if (! $arrayDimFetch->var instanceof Variable) { - return null; - } - - if (! $this->isObjectTypeOrNullableObjectType($arrayDimFetch->var, 'Nette\ComponentModel\IComponent')) { - return null; - } - - if (! $arrayDimFetch->dim instanceof String_) { - return null; - } - - return $arrayDimFetch->dim; - } - private function isBeingAssignedOrInitialized(ArrayDimFetch $arrayDimFetch): bool { $parent = $arrayDimFetch->getAttribute(AttributeKey::PARENT_NODE); @@ -173,9 +165,4 @@ PHP return $parent->expr === $arrayDimFetch; } - - private function createControlVariableName(string $inputName): string - { - return StaticRectorStrings::underscoreToPascalCase($inputName) . 'Control'; - } } diff --git a/rules/nette/src/Rector/Assign/MakeGetComponentAssignAnnotatedRector.php b/rules/nette/src/Rector/Assign/MakeGetComponentAssignAnnotatedRector.php index 786fbefa49a..9075b043af8 100644 --- a/rules/nette/src/Rector/Assign/MakeGetComponentAssignAnnotatedRector.php +++ b/rules/nette/src/Rector/Assign/MakeGetComponentAssignAnnotatedRector.php @@ -11,20 +11,17 @@ use PhpParser\Node\Expr\Assign; use PhpParser\Node\Expr\MethodCall; use PhpParser\Node\Expr\Variable; use PhpParser\Node\Scalar\String_; -use PhpParser\Node\Stmt\Expression; use PHPStan\Analyser\Scope; -use PHPStan\PhpDocParser\Ast\PhpDoc\VarTagValueNode; use PHPStan\Reflection\ParametersAcceptorSelector; use PHPStan\Type\MixedType; use PHPStan\Type\ObjectType; use PHPStan\Type\Type; use PHPStan\Type\TypeWithClassName; -use Rector\AttributeAwarePhpDoc\Ast\Type\AttributeAwareFullyQualifiedIdentifierTypeNode; -use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfo; use Rector\Core\Exception\ShouldNotHappenException; use Rector\Core\Rector\AbstractRector; use Rector\Core\RectorDefinition\CodeSample; use Rector\Core\RectorDefinition\RectorDefinition; +use Rector\Nette\DocBlock\VarAnnotationManipulator; use Rector\NodeTypeResolver\Node\AttributeKey; /** @@ -34,6 +31,16 @@ use Rector\NodeTypeResolver\Node\AttributeKey; */ final class MakeGetComponentAssignAnnotatedRector extends AbstractRector { + /** + * @var VarAnnotationManipulator + */ + private $varAnnotationManipulator; + + public function __construct(VarAnnotationManipulator $varAnnotationManipulator) + { + $this->varAnnotationManipulator = $varAnnotationManipulator; + } + public function getDefinition(): RectorDefinition { return new RectorDefinition('Add doc type for magic $control->getComponent(...) assign', [ @@ -125,48 +132,15 @@ PHP } $controlType = $this->resolveControlType($node); - if ($controlType instanceof MixedType) { + if (! $controlType instanceof TypeWithClassName) { return null; } - $phpDocInfo = $this->resolvePhpDocInfo($node); - if ($phpDocInfo->getVarTagValue() !== null) { - return null; - } - - $attributeAwareFullyQualifiedIdentifierTypeNode = new AttributeAwareFullyQualifiedIdentifierTypeNode( - $controlType->getClassName() - ); - $varTagValueNode = new VarTagValueNode( - $attributeAwareFullyQualifiedIdentifierTypeNode, - '$' . $variableName, - '' - ); - $phpDocInfo->addTagValueNode($varTagValueNode); + $this->varAnnotationManipulator->decorateNodeWithInlineVarType($node, $controlType, $variableName); return $node; } - private function resolvePhpDocInfo(Assign $assign): PhpDocInfo - { - $currentStmt = $assign->getAttribute(AttributeKey::CURRENT_STATEMENT); - if ($currentStmt instanceof Expression) { - /** @var PhpDocInfo|null $phpDocInfo */ - $phpDocInfo = $currentStmt->getAttribute(AttributeKey::PHP_DOC_INFO); - } else { - /** @var PhpDocInfo|null $phpDocInfo */ - $phpDocInfo = $assign->getAttribute(AttributeKey::PHP_DOC_INFO); - } - - if ($phpDocInfo === null) { - $phpDocInfo = $this->phpDocInfoFactory->createEmpty($assign); - } - - $phpDocInfo->makeSingleLined(); - - return $phpDocInfo; - } - private function resolveCreateComponentMethodCallReturnType(MethodCall $methodCall): Type { /** @var Scope|null $scope */ diff --git a/rules/nette/tests/Rector/ArrayDimFetch/ChangeControlArrayAccessToAnnotatedControlVariableRector/ChangeControlArrayAccessToAnnotatedControlVariableRectorTest.php b/rules/nette/tests/Rector/ArrayDimFetch/ChangeControlArrayAccessToAnnotatedControlVariableRector/ChangeControlArrayAccessToAnnotatedControlVariableRectorTest.php new file mode 100644 index 00000000000..769e08cc805 --- /dev/null +++ b/rules/nette/tests/Rector/ArrayDimFetch/ChangeControlArrayAccessToAnnotatedControlVariableRector/ChangeControlArrayAccessToAnnotatedControlVariableRectorTest.php @@ -0,0 +1,31 @@ +doTestFileInfo($fileInfo); + } + + public function provideData(): Iterator + { + return $this->yieldFilesFromDirectory(__DIR__ . '/Fixture'); + } + + protected function getRectorClass(): string + { + return ChangeControlArrayAccessToAnnotatedControlVariableRector::class; + } +} diff --git a/rules/nette/tests/Rector/ArrayDimFetch/ChangeControlArrayAccessToAnnotatedControlVariableRector/Fixture/fixture.php.inc b/rules/nette/tests/Rector/ArrayDimFetch/ChangeControlArrayAccessToAnnotatedControlVariableRector/Fixture/fixture.php.inc new file mode 100644 index 00000000000..aa1e322a570 --- /dev/null +++ b/rules/nette/tests/Rector/ArrayDimFetch/ChangeControlArrayAccessToAnnotatedControlVariableRector/Fixture/fixture.php.inc @@ -0,0 +1,47 @@ +isSubmitted()) { + } + } + + protected function createComponentSomeForm() + { + return new Form(); + } +} + +?> +----- +isSubmitted()) { + } + } + + protected function createComponentSomeForm() + { + return new Form(); + } +} + +?> diff --git a/rules/nette/tests/Rector/ArrayDimFetch/ChangeControlArrayAccessToAnnotatedControlVariableRector/Fixture/rename_nested_too.php.inc b/rules/nette/tests/Rector/ArrayDimFetch/ChangeControlArrayAccessToAnnotatedControlVariableRector/Fixture/rename_nested_too.php.inc new file mode 100644 index 00000000000..90bc15a2092 --- /dev/null +++ b/rules/nette/tests/Rector/ArrayDimFetch/ChangeControlArrayAccessToAnnotatedControlVariableRector/Fixture/rename_nested_too.php.inc @@ -0,0 +1,49 @@ +isSubmitted()) { + return $this['some_form']->getValues(); + } + } + + protected function createComponentSomeForm() + { + return new Form(); + } +} + +?> +----- +isSubmitted()) { + return $someForm->getValues(); + } + } + + protected function createComponentSomeForm() + { + return new Form(); + } +} + +?> diff --git a/rules/privatization/tests/Rector/ClassMethod/PrivatizeLocalOnlyMethodRector/Fixture/skip_anonymous_class.php.inc b/rules/privatization/tests/Rector/ClassMethod/PrivatizeLocalOnlyMethodRector/Fixture/skip_anonymous_class.php.inc index ee1bf467c8e..0575d4e3bbd 100644 --- a/rules/privatization/tests/Rector/ClassMethod/PrivatizeLocalOnlyMethodRector/Fixture/skip_anonymous_class.php.inc +++ b/rules/privatization/tests/Rector/ClassMethod/PrivatizeLocalOnlyMethodRector/Fixture/skip_anonymous_class.php.inc @@ -6,6 +6,9 @@ use PhpParser\NodeTraverser; class SkipAnonymousClass { + /** + * @api + */ public function run() { $anonymousClass = new class() extends NodeTraverser diff --git a/rules/renaming/src/Rector/Namespace_/RenameNamespaceRector.php b/rules/renaming/src/Rector/Namespace_/RenameNamespaceRector.php index 42864368a1b..3e7fafefff5 100644 --- a/rules/renaming/src/Rector/Namespace_/RenameNamespaceRector.php +++ b/rules/renaming/src/Rector/Namespace_/RenameNamespaceRector.php @@ -11,11 +11,11 @@ use PhpParser\Node\Name; use PhpParser\Node\Name\FullyQualified; use PhpParser\Node\Stmt\Namespace_; use PhpParser\Node\Stmt\Use_; -use Rector\Core\Naming\NamespaceMatcher; use Rector\Core\Rector\AbstractRector; use Rector\Core\RectorDefinition\ConfiguredCodeSample; use Rector\Core\RectorDefinition\RectorDefinition; use Rector\Core\ValueObject\RenamedNamespaceValueObject; +use Rector\Naming\NamespaceMatcher; use Rector\NodeTypeResolver\Node\AttributeKey; /** diff --git a/src/Rector/AbstractRector.php b/src/Rector/AbstractRector.php index 89281181980..07dd8996d29 100644 --- a/src/Rector/AbstractRector.php +++ b/src/Rector/AbstractRector.php @@ -4,7 +4,6 @@ declare(strict_types=1); namespace Rector\Core\Rector; -use Nette\Utils\Strings; use PhpParser\BuilderFactory; use PhpParser\Node; use PhpParser\Node\Expr; @@ -13,11 +12,11 @@ use PhpParser\Node\Expr\Cast\Bool_; use PhpParser\Node\Expr\MethodCall; use PhpParser\Node\Name; use PhpParser\Node\Stmt; -use PhpParser\Node\Stmt\Class_; use PhpParser\Node\Stmt\Expression; use PhpParser\Node\Stmt\Return_; use PhpParser\NodeVisitorAbstract; use PHPStan\Analyser\Scope; +use Rector\AnonymousClass\NodeAnalyzer\ClassNodeAnalyzer; use Rector\Core\Configuration\Option; use Rector\Core\Contract\Rector\PhpRectorInterface; use Rector\Core\Exclusion\ExclusionManager; @@ -102,6 +101,11 @@ abstract class AbstractRector extends NodeVisitorAbstract implements PhpRectorIn */ private $currentRectorProvider; + /** + * @var ClassNodeAnalyzer + */ + private $classNodeAnalyzer; + /** * @required */ @@ -113,7 +117,8 @@ abstract class AbstractRector extends NodeVisitorAbstract implements PhpRectorIn DocBlockManipulator $docBlockManipulator, StaticTypeMapper $staticTypeMapper, ParameterProvider $parameterProvider, - CurrentRectorProvider $currentRectorProvider + CurrentRectorProvider $currentRectorProvider, + ClassNodeAnalyzer $classNodeAnalyzer ): void { $this->symfonyStyle = $symfonyStyle; $this->phpVersionProvider = $phpVersionProvider; @@ -123,6 +128,7 @@ abstract class AbstractRector extends NodeVisitorAbstract implements PhpRectorIn $this->staticTypeMapper = $staticTypeMapper; $this->parameterProvider = $parameterProvider; $this->currentRectorProvider = $currentRectorProvider; + $this->classNodeAnalyzer = $classNodeAnalyzer; } public function beforeTraverse(array $nodes) @@ -215,13 +221,7 @@ abstract class AbstractRector extends NodeVisitorAbstract implements PhpRectorIn protected function isAnonymousClass(Node $node): bool { - if (! $node instanceof Class_) { - return false; - } - - $className = $this->nodeNameResolver->getName($node); - - return $className === null || Strings::contains($className, 'AnonymousClass'); + return $this->classNodeAnalyzer->isAnonymousClass($node); } protected function createCountedValueName(string $countedValueName, ?Scope $scope): string diff --git a/src/Rector/AbstractRector/NodeTypeResolverTrait.php b/src/Rector/AbstractRector/NodeTypeResolverTrait.php index e67a9d59186..3b259761a18 100644 --- a/src/Rector/AbstractRector/NodeTypeResolverTrait.php +++ b/src/Rector/AbstractRector/NodeTypeResolverTrait.php @@ -14,7 +14,6 @@ use PhpParser\Node\Stmt\Return_; use PHPStan\Type\ObjectType; use PHPStan\Type\Type; use PHPStan\Type\TypeWithClassName; -use PHPStan\Type\UnionType; use Rector\NodeTypeResolver\Node\AttributeKey; use Rector\NodeTypeResolver\NodeTypeResolver; use Rector\NodeTypeResolver\TypeAnalyzer\ArrayTypeAnalyzer; @@ -90,25 +89,6 @@ trait NodeTypeResolverTrait return $this->nodeTypeResolver->isObjectType($node, $type); } - /** - * @param ObjectType|string $desiredType - */ - protected function isObjectTypeOrNullableObjectType(Node $node, $desiredType): bool - { - if ($this->isNullableObjectType($node)) { - /** @var UnionType $nodeType */ - $nodeType = $this->nodeTypeResolver->resolve($node); - - $nodeType = $this->typeUnwrapper->unwrapNullableType($nodeType); - if ($nodeType instanceof TypeWithClassName) { - $desiredTypeString = $desiredType instanceof ObjectType ? $desiredType->getClassName() : $desiredType; - return is_a($nodeType->getClassName(), $desiredTypeString, true); - } - } - - return $this->nodeTypeResolver->isObjectType($node, $desiredType); - } - /** * @param string[]|ObjectType[] $requiredTypes */