Updated Rector to commit b007a8bd11ea0451b50dbafbacd5450b295f6266

b007a8bd11 [Php83] Add implements interface support on AddOverrideAttributeToOverriddenMethodsRector (#5429)
This commit is contained in:
Tomas Votruba 2024-01-04 19:14:21 +00:00
parent 5457aea4e0
commit 41a86add1d
11 changed files with 154 additions and 40 deletions

View File

@ -8,6 +8,7 @@ use PhpParser\Node\Attribute;
use PhpParser\Node\AttributeGroup;
use PhpParser\Node\Name\FullyQualified;
use PhpParser\Node\Stmt\Class_;
use PHPStan\Reflection\ClassReflection;
use PHPStan\Reflection\ReflectionProvider;
use Rector\NodeAnalyzer\ClassAnalyzer;
use Rector\Php80\NodeAnalyzer\PhpAttributeAnalyzer;
@ -37,6 +38,10 @@ final class AddOverrideAttributeToOverriddenMethodsRector extends AbstractRector
* @var \Rector\Php80\NodeAnalyzer\PhpAttributeAnalyzer
*/
private $phpAttributeAnalyzer;
/**
* @var bool
*/
private $hasChanged = \false;
public function __construct(ReflectionProvider $reflectionProvider, ClassAnalyzer $classAnalyzer, PhpAttributeAnalyzer $phpAttributeAnalyzer)
{
$this->reflectionProvider = $reflectionProvider;
@ -90,33 +95,18 @@ CODE_SAMPLE
*/
public function refactor(Node $node) : ?Node
{
// Detect if class extends a parent class
if ($this->shouldSkipClass($node)) {
$this->hasChanged = \false;
if ($this->classAnalyzer->isAnonymousClass($node)) {
return null;
}
// Fetch the parent class reflection
$parentClassReflection = $this->reflectionProvider->getClass((string) $node->extends);
$hasChanged = \false;
foreach ($node->getMethods() as $classMethod) {
if ($classMethod->name->toString() === '__construct') {
continue;
}
// Private methods should be ignored
if ($parentClassReflection->hasNativeMethod($classMethod->name->toString())) {
// ignore if it is a private method on the parent
$parentMethod = $parentClassReflection->getNativeMethod($classMethod->name->toString());
if ($parentMethod->isPrivate()) {
continue;
}
// ignore if it already uses the attribute
if ($this->phpAttributeAnalyzer->hasPhpAttribute($classMethod, 'Override')) {
continue;
}
$classMethod->attrGroups[] = new AttributeGroup([new Attribute(new FullyQualified('Override'))]);
$hasChanged = \true;
}
$className = (string) $this->getName($node);
if (!$this->reflectionProvider->hasClass($className)) {
return null;
}
if (!$hasChanged) {
$classReflection = $this->reflectionProvider->getClass($className);
$parentClassReflections = \array_merge($classReflection->getParents(), $classReflection->getInterfaces());
$this->processAddOverrideAttribute($node, $parentClassReflections);
if (!$this->hasChanged) {
return null;
}
return $node;
@ -125,14 +115,36 @@ CODE_SAMPLE
{
return PhpVersionFeature::OVERRIDE_ATTRIBUTE;
}
private function shouldSkipClass(Class_ $class) : bool
/**
* @param ClassReflection[] $parentClassReflections
*/
private function processAddOverrideAttribute(Class_ $class, array $parentClassReflections) : void
{
if ($this->classAnalyzer->isAnonymousClass($class)) {
return \true;
if ($parentClassReflections === []) {
return;
}
if (!$class->extends instanceof FullyQualified) {
return \true;
foreach ($class->getMethods() as $classMethod) {
if ($classMethod->name->toString() === '__construct') {
continue;
}
// ignore if it already uses the attribute
if ($this->phpAttributeAnalyzer->hasPhpAttribute($classMethod, 'Override')) {
continue;
}
// Private methods should be ignored
foreach ($parentClassReflections as $parentClassReflection) {
if (!$parentClassReflection->hasNativeMethod($classMethod->name->toString())) {
continue;
}
// ignore if it is a private method on the parent
$parentMethod = $parentClassReflection->getNativeMethod($classMethod->name->toString());
if ($parentMethod->isPrivate()) {
continue;
}
$classMethod->attrGroups[] = new AttributeGroup([new Attribute(new FullyQualified('Override'))]);
$this->hasChanged = \true;
continue 2;
}
}
return !$this->reflectionProvider->hasClass($class->extends->toString());
}
}

View File

@ -19,12 +19,12 @@ final class VersionResolver
* @api
* @var string
*/
public const PACKAGE_VERSION = '1f9829d2a3820f39fe0601b996c5cba71ffb42b0';
public const PACKAGE_VERSION = 'b007a8bd11ea0451b50dbafbacd5450b295f6266';
/**
* @api
* @var string
*/
public const RELEASE_DATE = '2024-01-04 22:47:15';
public const RELEASE_DATE = '2024-01-04 20:12:00';
/**
* @var int
*/

View File

@ -50,6 +50,8 @@ return array(
'PHPStan\\PhpDocParser\\Ast\\PhpDoc\\PhpDocTagValueNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/PhpDocTagValueNode.php',
'PHPStan\\PhpDocParser\\Ast\\PhpDoc\\PhpDocTextNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/PhpDocTextNode.php',
'PHPStan\\PhpDocParser\\Ast\\PhpDoc\\PropertyTagValueNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/PropertyTagValueNode.php',
'PHPStan\\PhpDocParser\\Ast\\PhpDoc\\RequireExtendsTagValueNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/RequireExtendsTagValueNode.php',
'PHPStan\\PhpDocParser\\Ast\\PhpDoc\\RequireImplementsTagValueNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/RequireImplementsTagValueNode.php',
'PHPStan\\PhpDocParser\\Ast\\PhpDoc\\ReturnTagValueNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/ReturnTagValueNode.php',
'PHPStan\\PhpDocParser\\Ast\\PhpDoc\\SelfOutTagValueNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/SelfOutTagValueNode.php',
'PHPStan\\PhpDocParser\\Ast\\PhpDoc\\TemplateTagValueNode' => $vendorDir . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/TemplateTagValueNode.php',

View File

@ -264,6 +264,8 @@ class ComposerStaticInit8c7215074e107c54fa988078cf9a09f8
'PHPStan\\PhpDocParser\\Ast\\PhpDoc\\PhpDocTagValueNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/PhpDocTagValueNode.php',
'PHPStan\\PhpDocParser\\Ast\\PhpDoc\\PhpDocTextNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/PhpDocTextNode.php',
'PHPStan\\PhpDocParser\\Ast\\PhpDoc\\PropertyTagValueNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/PropertyTagValueNode.php',
'PHPStan\\PhpDocParser\\Ast\\PhpDoc\\RequireExtendsTagValueNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/RequireExtendsTagValueNode.php',
'PHPStan\\PhpDocParser\\Ast\\PhpDoc\\RequireImplementsTagValueNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/RequireImplementsTagValueNode.php',
'PHPStan\\PhpDocParser\\Ast\\PhpDoc\\ReturnTagValueNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/ReturnTagValueNode.php',
'PHPStan\\PhpDocParser\\Ast\\PhpDoc\\SelfOutTagValueNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/SelfOutTagValueNode.php',
'PHPStan\\PhpDocParser\\Ast\\PhpDoc\\TemplateTagValueNode' => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src/Ast/PhpDoc/TemplateTagValueNode.php',

View File

@ -858,17 +858,17 @@
},
{
"name": "phpstan\/phpdoc-parser",
"version": "1.24.5",
"version_normalized": "1.24.5.0",
"version": "1.25.0",
"version_normalized": "1.25.0.0",
"source": {
"type": "git",
"url": "https:\/\/github.com\/phpstan\/phpdoc-parser.git",
"reference": "fedf211ff14ec8381c9bf5714e33a7a552dd1acc"
"reference": "bd84b629c8de41aa2ae82c067c955e06f1b00240"
},
"dist": {
"type": "zip",
"url": "https:\/\/api.github.com\/repos\/phpstan\/phpdoc-parser\/zipball\/fedf211ff14ec8381c9bf5714e33a7a552dd1acc",
"reference": "fedf211ff14ec8381c9bf5714e33a7a552dd1acc",
"url": "https:\/\/api.github.com\/repos\/phpstan\/phpdoc-parser\/zipball\/bd84b629c8de41aa2ae82c067c955e06f1b00240",
"reference": "bd84b629c8de41aa2ae82c067c955e06f1b00240",
"shasum": ""
},
"require": {
@ -885,7 +885,7 @@
"phpunit\/phpunit": "^9.5",
"symfony\/process": "^5.2"
},
"time": "2023-12-16T09:33:33+00:00",
"time": "2024-01-04T17:06:16+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
@ -902,7 +902,7 @@
"description": "PHPDoc parser with support for nullable, intersection and generic types",
"support": {
"issues": "https:\/\/github.com\/phpstan\/phpdoc-parser\/issues",
"source": "https:\/\/github.com\/phpstan\/phpdoc-parser\/tree\/1.24.5"
"source": "https:\/\/github.com\/phpstan\/phpdoc-parser\/tree\/1.25.0"
},
"install-path": "..\/phpstan\/phpdoc-parser"
},

File diff suppressed because one or more lines are too long

View File

@ -129,6 +129,24 @@ class PhpDocNode implements Node
return $value instanceof \PHPStan\PhpDocParser\Ast\PhpDoc\MixinTagValueNode;
});
}
/**
* @return RequireExtendsTagValueNode[]
*/
public function getRequireExtendsTagValues(string $tagName = '@phpstan-require-extends') : array
{
return array_filter(array_column($this->getTagsByName($tagName), 'value'), static function (\PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocTagValueNode $value) : bool {
return $value instanceof \PHPStan\PhpDocParser\Ast\PhpDoc\RequireExtendsTagValueNode;
});
}
/**
* @return RequireImplementsTagValueNode[]
*/
public function getRequireImplementsTagValues(string $tagName = '@phpstan-require-implements') : array
{
return array_filter(array_column($this->getTagsByName($tagName), 'value'), static function (\PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocTagValueNode $value) : bool {
return $value instanceof \PHPStan\PhpDocParser\Ast\PhpDoc\RequireImplementsTagValueNode;
});
}
/**
* @return DeprecatedTagValueNode[]
*/

View File

@ -0,0 +1,25 @@
<?php
declare (strict_types=1);
namespace PHPStan\PhpDocParser\Ast\PhpDoc;
use PHPStan\PhpDocParser\Ast\NodeAttributes;
use PHPStan\PhpDocParser\Ast\Type\TypeNode;
use function trim;
class RequireExtendsTagValueNode implements \PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocTagValueNode
{
use NodeAttributes;
/** @var TypeNode */
public $type;
/** @var string (may be empty) */
public $description;
public function __construct(TypeNode $type, string $description)
{
$this->type = $type;
$this->description = $description;
}
public function __toString() : string
{
return trim("{$this->type} {$this->description}");
}
}

View File

@ -0,0 +1,25 @@
<?php
declare (strict_types=1);
namespace PHPStan\PhpDocParser\Ast\PhpDoc;
use PHPStan\PhpDocParser\Ast\NodeAttributes;
use PHPStan\PhpDocParser\Ast\Type\TypeNode;
use function trim;
class RequireImplementsTagValueNode implements \PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocTagValueNode
{
use NodeAttributes;
/** @var TypeNode */
public $type;
/** @var string (may be empty) */
public $description;
public function __construct(TypeNode $type, string $description)
{
$this->type = $type;
$this->description = $description;
}
public function __toString() : string
{
return trim("{$this->type} {$this->description}");
}
}

View File

@ -301,6 +301,14 @@ class PhpDocParser
case '@mixin':
$tagValue = $this->parseMixinTagValue($tokens);
break;
case '@psalm-require-extends':
case '@phpstan-require-extends':
$tagValue = $this->parseRequireExtendsTagValue($tokens);
break;
case '@psalm-require-implements':
case '@phpstan-require-implements':
$tagValue = $this->parseRequireImplementsTagValue($tokens);
break;
case '@deprecated':
$tagValue = $this->parseDeprecatedTagValue($tokens);
break;
@ -604,6 +612,18 @@ class PhpDocParser
$description = $this->parseOptionalDescription($tokens, \true);
return new Ast\PhpDoc\MixinTagValueNode($type, $description);
}
private function parseRequireExtendsTagValue(\PHPStan\PhpDocParser\Parser\TokenIterator $tokens) : Ast\PhpDoc\RequireExtendsTagValueNode
{
$type = $this->typeParser->parse($tokens);
$description = $this->parseOptionalDescription($tokens, \true);
return new Ast\PhpDoc\RequireExtendsTagValueNode($type, $description);
}
private function parseRequireImplementsTagValue(\PHPStan\PhpDocParser\Parser\TokenIterator $tokens) : Ast\PhpDoc\RequireImplementsTagValueNode
{
$type = $this->typeParser->parse($tokens);
$description = $this->parseOptionalDescription($tokens, \true);
return new Ast\PhpDoc\RequireImplementsTagValueNode($type, $description);
}
private function parseDeprecatedTagValue(\PHPStan\PhpDocParser\Parser\TokenIterator $tokens) : Ast\PhpDoc\DeprecatedTagValueNode
{
$description = $this->parseOptionalDescription($tokens);

View File

@ -29,6 +29,8 @@ use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocTagNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocTagValueNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocTextNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\PropertyTagValueNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\RequireExtendsTagValueNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\RequireImplementsTagValueNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\ReturnTagValueNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\SelfOutTagValueNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\TemplateTagValueNode;
@ -210,6 +212,14 @@ final class Printer
$type = $this->printType($node->type);
return trim("{$type} {$node->description}");
}
if ($node instanceof RequireExtendsTagValueNode) {
$type = $this->printType($node->type);
return trim("{$type} {$node->description}");
}
if ($node instanceof RequireImplementsTagValueNode) {
$type = $this->printType($node->type);
return trim("{$type} {$node->description}");
}
if ($node instanceof ParamOutTagValueNode) {
$type = $this->printType($node->type);
return trim("{$type} {$node->parameterName} {$node->description}");