diff --git a/config/set/phpstan/phpstan.yaml b/config/set/phpstan/phpstan.yaml index 15e5a02cfa06..3af4a7a0e954 100644 --- a/config/set/phpstan/phpstan.yaml +++ b/config/set/phpstan/phpstan.yaml @@ -1,3 +1,4 @@ services: Rector\PHPStan\Rector\Cast\RecastingRemovalRector: ~ Rector\PHPStan\Rector\Assign\PHPStormVarAnnotationRector: ~ + Rector\PHPStan\Rector\Node\RemoveNonExistingVarAnnotationRector: ~ diff --git a/ecs.yaml b/ecs.yaml index 739d6fba979e..8d71439cb9c6 100644 --- a/ecs.yaml +++ b/ecs.yaml @@ -102,6 +102,7 @@ parameters: Symplify\CodingStandard\Sniffs\CleanCode\CognitiveComplexitySniff: # tough logic + - 'packages/PHPStan/src/Rector/Node/RemoveNonExistingVarAnnotationRector.php' - 'packages/Architecture/src/Rector/Class_/ConstructorInjectionToActionInjectionRector.php' - 'src/PhpParser/Node/Commander/NodeRemovingCommander.php' - 'packages/BetterPhpDocParser/src/*' diff --git a/packages/Architecture/src/Rector/Class_/RemoveRepositoryFromEntityAnnotationRector.php b/packages/Architecture/src/Rector/Class_/RemoveRepositoryFromEntityAnnotationRector.php index ada3b238dc32..67903a0ab1dc 100644 --- a/packages/Architecture/src/Rector/Class_/RemoveRepositoryFromEntityAnnotationRector.php +++ b/packages/Architecture/src/Rector/Class_/RemoveRepositoryFromEntityAnnotationRector.php @@ -70,7 +70,7 @@ public function getNodeTypes(): array } /** - * @param Node\Stmt\Class_ $node + * @param Class_ $node */ public function refactor(Node $node): ?Node { diff --git a/packages/Architecture/tests/Rector/Class_/RemoveRepositoryFromEntityAnnotationRector/RemoveRepositoryFromEntityAnnotationRectorTest.php b/packages/Architecture/tests/Rector/Class_/RemoveRepositoryFromEntityAnnotationRector/RemoveRepositoryFromEntityAnnotationRectorTest.php index 19f5775b4dae..390bce494f26 100644 --- a/packages/Architecture/tests/Rector/Class_/RemoveRepositoryFromEntityAnnotationRector/RemoveRepositoryFromEntityAnnotationRectorTest.php +++ b/packages/Architecture/tests/Rector/Class_/RemoveRepositoryFromEntityAnnotationRector/RemoveRepositoryFromEntityAnnotationRectorTest.php @@ -9,10 +9,7 @@ final class RemoveRepositoryFromEntityAnnotationRectorTest extends AbstractRecto { public function test(): void { - $this->doTestFiles([ - __DIR__ . '/Fixture/fixture.php.inc', - __DIR__ . '/Fixture/skip_done.php.inc', - ]); + $this->doTestFiles([__DIR__ . '/Fixture/fixture.php.inc', __DIR__ . '/Fixture/skip_done.php.inc']); } protected function getRectorClass(): string diff --git a/packages/CodeQuality/src/Rector/FuncCall/IsAWithStringWithThirdArgumentRector.php b/packages/CodeQuality/src/Rector/FuncCall/IsAWithStringWithThirdArgumentRector.php index 31f1c5245104..938d377dac92 100644 --- a/packages/CodeQuality/src/Rector/FuncCall/IsAWithStringWithThirdArgumentRector.php +++ b/packages/CodeQuality/src/Rector/FuncCall/IsAWithStringWithThirdArgumentRector.php @@ -3,6 +3,7 @@ namespace Rector\CodeQuality\Rector\FuncCall; use PhpParser\Node; +use PhpParser\Node\Arg; use PhpParser\Node\Expr\FuncCall; use PHPStan\Type\StringType; use Rector\Rector\AbstractRector; @@ -64,7 +65,7 @@ public function refactor(Node $node): ?Node return null; } - $node->args[2] = new Node\Arg($this->createTrue()); + $node->args[2] = new Arg($this->createTrue()); return $node; } diff --git a/packages/CodeQuality/src/Rector/FuncCall/StrlenZeroToIdenticalEmptyStringRector.php b/packages/CodeQuality/src/Rector/FuncCall/StrlenZeroToIdenticalEmptyStringRector.php index 8cb5a76c6549..7a1dea13e28c 100644 --- a/packages/CodeQuality/src/Rector/FuncCall/StrlenZeroToIdenticalEmptyStringRector.php +++ b/packages/CodeQuality/src/Rector/FuncCall/StrlenZeroToIdenticalEmptyStringRector.php @@ -3,8 +3,10 @@ namespace Rector\CodeQuality\Rector\FuncCall; use PhpParser\Node; +use PhpParser\Node\Expr; use PhpParser\Node\Expr\BinaryOp\Identical; use PhpParser\Node\Expr\FuncCall; +use PhpParser\Node\Scalar\String_; use Rector\Rector\AbstractRector; use Rector\RectorDefinition\CodeSample; use Rector\RectorDefinition\RectorDefinition; @@ -76,7 +78,7 @@ public function refactor(Node $node): ?Node $variable = $node->right->args[0]->value; } - /** @var Node\Expr $variable */ - return new Identical($variable, new Node\Scalar\String_('')); + /** @var Expr $variable */ + return new Identical($variable, new String_('')); } } diff --git a/packages/ContributorTools/src/Command/DumpNodesCommand.php b/packages/ContributorTools/src/Command/DumpNodesCommand.php index 90643fc0c3e1..c100d04af1b8 100644 --- a/packages/ContributorTools/src/Command/DumpNodesCommand.php +++ b/packages/ContributorTools/src/Command/DumpNodesCommand.php @@ -172,7 +172,6 @@ protected function execute(InputInterface $input, OutputInterface $output): int continue; } - /** @var Node $node */ $contructorReflection = $nodeClassReflection->getConstructor(); if ($contructorReflection->getNumberOfRequiredParameters() === 0) { diff --git a/packages/ContributorTools/templates/packages/_Package_/src/Rector/_Category_/_Name_.php.inc b/packages/ContributorTools/templates/packages/_Package_/src/Rector/_Category_/_Name_.php.inc index 25879053e611..ccf617269c3c 100644 --- a/packages/ContributorTools/templates/packages/_Package_/src/Rector/_Category_/_Name_.php.inc +++ b/packages/ContributorTools/templates/packages/_Package_/src/Rector/_Category_/_Name_.php.inc @@ -6,7 +6,12 @@ use PhpParser\Node; use Rector\Rector\AbstractRector; use Rector\RectorDefinition\CodeSample; use Rector\RectorDefinition\RectorDefinition; + _Source_ + +/** + * @see \Rector\_Package_\Tests\Rector\_Category_\_Name_\_Name_Test + */ final class _Name_ extends AbstractRector { public function getDefinition(): RectorDefinition diff --git a/packages/NodeTypeResolver/src/PerNodeTypeResolver/NameTypeResolver.php b/packages/NodeTypeResolver/src/PerNodeTypeResolver/NameTypeResolver.php index d14f76afdb42..1ea1359ed2fc 100644 --- a/packages/NodeTypeResolver/src/PerNodeTypeResolver/NameTypeResolver.php +++ b/packages/NodeTypeResolver/src/PerNodeTypeResolver/NameTypeResolver.php @@ -65,9 +65,7 @@ private function resolveFullyQualifiedName(Node $nameNode, string $name): ?strin return $class; } - // @todo add "parent" - - /** @var Name|null $name */ + /** @var Name|null $resolvedNameNode */ $resolvedNameNode = $nameNode->getAttribute(AttributeKey::RESOLVED_NAME); if ($resolvedNameNode instanceof Name) { return $resolvedNameNode->toString(); diff --git a/packages/PHPStan/src/Rector/Node/RemoveNonExistingVarAnnotationRector.php b/packages/PHPStan/src/Rector/Node/RemoveNonExistingVarAnnotationRector.php new file mode 100644 index 000000000000..05cc7a50cd55 --- /dev/null +++ b/packages/PHPStan/src/Rector/Node/RemoveNonExistingVarAnnotationRector.php @@ -0,0 +1,131 @@ +docBlockManipulator = $docBlockManipulator; + } + + public function getDefinition(): RectorDefinition + { + return new RectorDefinition('Removes non-existing @var annotations above the code', [ + new CodeSample( + <<<'CODE_SAMPLE' +class SomeClass +{ + public function get() + { + /** @var Training[] $trainings */ + return $this->getData(); + } +} +CODE_SAMPLE + , + <<<'CODE_SAMPLE' +class SomeClass +{ + public function get() + { + return $this->getData(); + } +} +CODE_SAMPLE + ), + ]); + } + + /** + * @return string[] + */ + public function getNodeTypes(): array + { + return [Node::class]; + } + + /** + * @param Node $node + */ + public function refactor(Node $node): ?Node + { + if ($this->shouldSkip($node)) { + return null; + } + + $variableName = $this->getVarTagVariableName($node); + if ($variableName === null) { + return null; + } + + // it's there + if (Strings::match($this->print($node), '#' . preg_quote($variableName, '#') . '\b#')) { + return null; + } + + $this->docBlockManipulator->removeTagFromNode($node, 'var'); + + return $node; + } + + private function shouldSkip(Node $node): bool + { + return ! $node instanceof Assign + && ! $node instanceof AssignRef + && ! $node instanceof Foreach_ + && ! $node instanceof Static_ + && ! $node instanceof Echo_ + && ! $node instanceof Return_ + && ! $node instanceof Expression + && ! $node instanceof Throw_ + && ! $node instanceof If_ + && ! $node instanceof While_ + && ! $node instanceof Switch_ + && ! $node instanceof Nop; + } + + private function getVarTagVariableName(Node $node): ?string + { + if (! $this->docBlockManipulator->hasTag($node, 'var')) { + return null; + } + + $varTag = $this->docBlockManipulator->getTagByName($node, 'var'); + + /** @var AttributeAwareVarTagValueNode $varTagValue */ + $varTagValue = $varTag->value; + + return $varTagValue->variableName; + } +} diff --git a/packages/PHPStan/tests/Rector/Node/RemoveNonExistingVarAnnotationRector/Fixture/fixture.php.inc b/packages/PHPStan/tests/Rector/Node/RemoveNonExistingVarAnnotationRector/Fixture/fixture.php.inc new file mode 100644 index 000000000000..91b6be680238 --- /dev/null +++ b/packages/PHPStan/tests/Rector/Node/RemoveNonExistingVarAnnotationRector/Fixture/fixture.php.inc @@ -0,0 +1,28 @@ +getData(); + } +} + +?> +----- +getData(); + } +} + +?> diff --git a/packages/PHPStan/tests/Rector/Node/RemoveNonExistingVarAnnotationRector/Fixture/if_case.php.inc b/packages/PHPStan/tests/Rector/Node/RemoveNonExistingVarAnnotationRector/Fixture/if_case.php.inc new file mode 100644 index 000000000000..93c9ad5edcd3 --- /dev/null +++ b/packages/PHPStan/tests/Rector/Node/RemoveNonExistingVarAnnotationRector/Fixture/if_case.php.inc @@ -0,0 +1,38 @@ + +----- + diff --git a/packages/PHPStan/tests/Rector/Node/RemoveNonExistingVarAnnotationRector/Fixture/keep.php.inc b/packages/PHPStan/tests/Rector/Node/RemoveNonExistingVarAnnotationRector/Fixture/keep.php.inc new file mode 100644 index 000000000000..0ad15b9608da --- /dev/null +++ b/packages/PHPStan/tests/Rector/Node/RemoveNonExistingVarAnnotationRector/Fixture/keep.php.inc @@ -0,0 +1,19 @@ +getAnotherData(); + + return $trainings; + } +} diff --git a/packages/PHPStan/tests/Rector/Node/RemoveNonExistingVarAnnotationRector/Fixture/subcontent.php.inc b/packages/PHPStan/tests/Rector/Node/RemoveNonExistingVarAnnotationRector/Fixture/subcontent.php.inc new file mode 100644 index 000000000000..25ff3cf289fc --- /dev/null +++ b/packages/PHPStan/tests/Rector/Node/RemoveNonExistingVarAnnotationRector/Fixture/subcontent.php.inc @@ -0,0 +1,32 @@ +getAnotherData(); + + return $trainings; + } +} + +?> +----- +getAnotherData(); + + return $trainings; + } +} + +?> diff --git a/packages/PHPStan/tests/Rector/Node/RemoveNonExistingVarAnnotationRector/RemoveNonExistingVarAnnotationRectorTest.php b/packages/PHPStan/tests/Rector/Node/RemoveNonExistingVarAnnotationRector/RemoveNonExistingVarAnnotationRectorTest.php new file mode 100644 index 000000000000..20f3182e921e --- /dev/null +++ b/packages/PHPStan/tests/Rector/Node/RemoveNonExistingVarAnnotationRector/RemoveNonExistingVarAnnotationRectorTest.php @@ -0,0 +1,24 @@ +doTestFiles([ + __DIR__ . '/Fixture/subcontent.php.inc', + __DIR__ . '/Fixture/fixture.php.inc', + __DIR__ . '/Fixture/if_case.php.inc', + __DIR__ . '/Fixture/keep.php.inc', + ]); + } + + protected function getRectorClass(): string + { + return RemoveNonExistingVarAnnotationRector::class; + } +} diff --git a/packages/Php/src/Rector/FuncCall/RenameMktimeWithoutArgsToTimeRector.php b/packages/Php/src/Rector/FuncCall/RenameMktimeWithoutArgsToTimeRector.php index 4a931e83e2f9..56ea32b94e7a 100644 --- a/packages/Php/src/Rector/FuncCall/RenameMktimeWithoutArgsToTimeRector.php +++ b/packages/Php/src/Rector/FuncCall/RenameMktimeWithoutArgsToTimeRector.php @@ -4,6 +4,7 @@ use PhpParser\Node; use PhpParser\Node\Expr\FuncCall; +use PhpParser\Node\Name; use Rector\Rector\AbstractRector; use Rector\RectorDefinition\CodeSample; use Rector\RectorDefinition\RectorDefinition; @@ -63,7 +64,7 @@ public function refactor(Node $node): ?Node return null; } - $node->name = new Node\Name('time'); + $node->name = new Name('time'); return $node; } diff --git a/packages/TypeDeclaration/src/Rector/FunctionLike/ParamTypeDeclarationRector.php b/packages/TypeDeclaration/src/Rector/FunctionLike/ParamTypeDeclarationRector.php index 22fee31d74f5..42cfc5eb835c 100644 --- a/packages/TypeDeclaration/src/Rector/FunctionLike/ParamTypeDeclarationRector.php +++ b/packages/TypeDeclaration/src/Rector/FunctionLike/ParamTypeDeclarationRector.php @@ -3,6 +3,7 @@ namespace Rector\TypeDeclaration\Rector\FunctionLike; use PhpParser\Node; +use PhpParser\Node\Name; use PhpParser\Node\Stmt\Class_; use PhpParser\Node\Stmt\ClassLike; use PhpParser\Node\Stmt\ClassMethod; @@ -153,7 +154,7 @@ public function refactor(Node $node): ?Node $paramNode->type = $paramTypeInfo->getTypeNode(); // "resource" is valid phpdoc type, but it's not implemented in PHP - if ($paramNode->type instanceof Node\Name && reset($paramNode->type->parts) === 'resource') { + if ($paramNode->type instanceof Name && reset($paramNode->type->parts) === 'resource') { $paramNode->type = null; continue; diff --git a/rector.yaml b/rector.yaml index 5a4d0af1e249..399369c358ba 100644 --- a/rector.yaml +++ b/rector.yaml @@ -17,4 +17,4 @@ parameters: php_version_features: '7.1' services: -# Rector\CodingStyle\Rector\Namespace_\ImportFullyQualifiedNamesRector: ~ + Rector\CodingStyle\Rector\Namespace_\ImportFullyQualifiedNamesRector: ~ diff --git a/src/PhpParser/Node/Manipulator/ClassManipulator.php b/src/PhpParser/Node/Manipulator/ClassManipulator.php index 73d394aaad87..c91ccd6c446a 100644 --- a/src/PhpParser/Node/Manipulator/ClassManipulator.php +++ b/src/PhpParser/Node/Manipulator/ClassManipulator.php @@ -264,7 +264,7 @@ public function hasPropertyFetchAsProperty(Class_ $class, PropertyFetch $propert public function removeProperty(Class_ $class, string $propertyName): void { foreach ($class->stmts as $key => $classStmt) { - if (! $classStmt instanceof Node\Stmt\Property) { + if (! $classStmt instanceof Property) { continue; }