diff --git a/rules-tests/Php83/Rector/ClassMethod/AddOverrideAttributeToOverriddenMethodsRector/Fixture/extends_parent_consume_trait.php.inc b/rules-tests/Php83/Rector/ClassMethod/AddOverrideAttributeToOverriddenMethodsRector/Fixture/extends_parent_consume_trait.php.inc new file mode 100644 index 00000000000..1b066a10590 --- /dev/null +++ b/rules-tests/Php83/Rector/ClassMethod/AddOverrideAttributeToOverriddenMethodsRector/Fixture/extends_parent_consume_trait.php.inc @@ -0,0 +1,32 @@ + +----- + diff --git a/rules-tests/Php83/Rector/ClassMethod/AddOverrideAttributeToOverriddenMethodsRector/Source/ParentConsumeTrait.php b/rules-tests/Php83/Rector/ClassMethod/AddOverrideAttributeToOverriddenMethodsRector/Source/ParentConsumeTrait.php new file mode 100644 index 00000000000..d00165a85b8 --- /dev/null +++ b/rules-tests/Php83/Rector/ClassMethod/AddOverrideAttributeToOverriddenMethodsRector/Source/ParentConsumeTrait.php @@ -0,0 +1,8 @@ + $arg) { if ($arg instanceof Arg && ( - ($arg->name !== null && $arg->name->toString() === 'associative') || - ($arg->name === null && $index === 1) + ($arg->name instanceof Identifier && $arg->name->toString() === 'associative') || + (!$arg->name instanceof Identifier && $index === 1) )) { unset($funcCall->args[$index]); break; diff --git a/rules/Php83/Rector/ClassMethod/AddOverrideAttributeToOverriddenMethodsRector.php b/rules/Php83/Rector/ClassMethod/AddOverrideAttributeToOverriddenMethodsRector.php index 5abcb0252af..165fae46d03 100644 --- a/rules/Php83/Rector/ClassMethod/AddOverrideAttributeToOverriddenMethodsRector.php +++ b/rules/Php83/Rector/ClassMethod/AddOverrideAttributeToOverriddenMethodsRector.php @@ -16,6 +16,7 @@ use PhpParser\Node\Stmt\ClassMethod; use PhpParser\Node\Stmt\Expression; use PhpParser\Node\Stmt\Return_; +use PhpParser\Node\Stmt\Trait_; use PHPStan\Reflection\ClassReflection; use PHPStan\Reflection\ReflectionProvider; use Rector\Contract\Rector\ConfigurableRectorInterface; @@ -261,6 +262,10 @@ private function shouldSkipParentClassMethod(ClassReflection $parentClassReflect } $parentClassMethod = $parentClass->getMethod($classMethod->name->toString()); + if (! $parentClassMethod instanceof ClassMethod) { + $parentClassMethod = $this->resolveClassMethodFromTraitUse($parentClass, $classMethod->name->toString()); + } + if (! $parentClassMethod instanceof ClassMethod) { return true; } @@ -298,6 +303,25 @@ private function shouldSkipParentClassMethod(ClassReflection $parentClassReflect return false; } + private function resolveClassMethodFromTraitUse(ClassLike $classLike, string $methodName): ?ClassMethod + { + foreach ($classLike->getTraitUses() as $traitUse) { + foreach ($traitUse->traits as $traitName) { + $traitClass = $this->astResolver->resolveClassFromName($traitName->__toString()); + if (! $traitClass instanceof Trait_) { + continue; + } + + $traitClassMethod = $traitClass->getMethod($methodName); + if ($traitClassMethod instanceof ClassMethod) { + return $traitClassMethod; + } + } + } + + return null; + } + private function implementsStringable(Class_ $class): bool { foreach ($class->implements as $implement) {