Skip to content

Commit

Permalink
[Php80] Add implements interface support on single file on AddParamBa…
Browse files Browse the repository at this point in the history
…sedOnParentClassMethodRector (#2660)
  • Loading branch information
samsonasik committed Jul 15, 2022
1 parent 84012e4 commit db7012e
Show file tree
Hide file tree
Showing 6 changed files with 143 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
use Rector\Core\Reflection\ReflectionResolver;
use Rector\FamilyTree\Reflection\FamilyRelationsAnalyzer;
use Rector\NodeNameResolver\NodeNameResolver;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Rector\StaticTypeMapper\PhpDoc\CustomPHPStanDetector;

final class ClassMethodReturnTypeOverrideGuard
Expand Down Expand Up @@ -69,7 +68,7 @@ public function shouldSkipClassMethod(ClassMethod $classMethod): bool
return true;
}

if ($this->shouldSkipHasChildNoReturn($childrenClassReflections, $classMethod)) {
if ($this->shouldSkipHasChildHasReturnType($childrenClassReflections, $classMethod)) {
return true;
}

Expand Down Expand Up @@ -98,24 +97,22 @@ public function shouldSkipClassMethodOldTypeWithNewType(Type $oldType, Type $new
/**
* @param ClassReflection[] $childrenClassReflections
*/
private function shouldSkipHasChildNoReturn(array $childrenClassReflections, ClassMethod $classMethod): bool
private function shouldSkipHasChildHasReturnType(array $childrenClassReflections, ClassMethod $classMethod): bool
{
$methodName = $this->nodeNameResolver->getName($classMethod);
$scope = $classMethod->getAttribute(AttributeKey::SCOPE);

foreach ($childrenClassReflections as $childClassReflection) {
if (! $childClassReflection->hasMethod($methodName)) {
if (! $childClassReflection->hasNativeMethod($methodName)) {
continue;
}

$methodReflection = $childClassReflection->getMethod($methodName, $scope);
$methodReflection = $childClassReflection->getNativeMethod($methodName);
$method = $this->astResolver->resolveClassMethodFromMethodReflection($methodReflection);

if (! $method instanceof ClassMethod) {
continue;
}

if ($method->returnType === null) {
if ($method->returnType instanceof Node) {
return true;
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<?php

namespace Rector\Tests\Php80\Rector\ClassMethod\AddParamBasedOnParentClassMethodRector\Fixture;

/**
* Both interface and class on same file on purpose to ensure locate
* parent interface bug
*/
interface InterfaceWithParam
{
public function execute($foo);
}

class ImplementsInterface implements InterfaceWithParam {
public function execute()
{
}
}

?>
-----
<?php

namespace Rector\Tests\Php80\Rector\ClassMethod\AddParamBasedOnParentClassMethodRector\Fixture;

/**
* Both interface and class on same file on purpose to ensure locate
* parent interface bug
*/
interface InterfaceWithParam
{
public function execute($foo);
}

class ImplementsInterface implements InterfaceWithParam {
public function execute($foo)
{
}
}

?>
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<?php

namespace Rector\Tests\Php80\Rector\ClassMethod\AddParamBasedOnParentClassMethodRector\Fixture;

class ImplementsInterfaceFlipped implements InterfaceWithParamFlipped {
public function execute()
{
}
}

/**
* Both interface and class on same file on purpose to ensure locate
* parent interface bug
*/
interface InterfaceWithParamFlipped
{
public function execute($foo);
}

?>
-----
<?php

namespace Rector\Tests\Php80\Rector\ClassMethod\AddParamBasedOnParentClassMethodRector\Fixture;

class ImplementsInterfaceFlipped implements InterfaceWithParamFlipped {
public function execute($foo)
{
}
}

/**
* Both interface and class on same file on purpose to ensure locate
* parent interface bug
*/
interface InterfaceWithParamFlipped
{
public function execute($foo);
}

?>
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php

namespace Rector\Tests\Php80\Rector\ClassMethod\AddParamBasedOnParentClassMethodRector\Fixture;

use Rector\Tests\Php80\Rector\ClassMethod\AddParamBasedOnParentClassMethodRector\Source\InterfaceWithParam;

class ImplementsInterfaceFromSource implements InterfaceWithParam {
public function execute()
{
}
}

?>
-----
<?php

namespace Rector\Tests\Php80\Rector\ClassMethod\AddParamBasedOnParentClassMethodRector\Fixture;

use Rector\Tests\Php80\Rector\ClassMethod\AddParamBasedOnParentClassMethodRector\Source\InterfaceWithParam;

class ImplementsInterfaceFromSource implements InterfaceWithParam {
public function execute($foo)
{
}
}

?>
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?php

namespace Rector\Tests\Php80\Rector\ClassMethod\AddParamBasedOnParentClassMethodRector\Source;

interface InterfaceWithParam
{
public function execute($foo);
}
30 changes: 21 additions & 9 deletions src/PhpParser/AstResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
use PhpParser\Node\Param;
use PhpParser\Node\Stmt;
use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\ClassLike;
use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Stmt\Enum_;
use PhpParser\Node\Stmt\Function_;
Expand Down Expand Up @@ -105,17 +106,28 @@ public function resolveClassMethodFromMethodReflection(MethodReflection $methodR
return null;
}

$class = $this->betterNodeFinder->findFirstInstanceOf($nodes, Class_::class);
if (! $class instanceof Class_) {
// avoids looking for a class in a file where is not present
$this->classMethodsByClassAndMethod[$classReflection->getName()][$methodReflection->getName()] = null;
return null;
}
/** @var ClassLike[] $classLikes */
$classLikes = $this->betterNodeFinder->findInstanceOf($nodes, ClassLike::class);
$classLikeName = $classReflection->getName();
$methodReflectionName = $methodReflection->getName();

$classMethod = $class->getMethod($methodReflection->getName());
$this->classMethodsByClassAndMethod[$classReflection->getName()][$methodReflection->getName()] = $classMethod;
foreach ($classLikes as $classLike) {
if (! $this->nodeNameResolver->isName($classLike, $classLikeName)) {
continue;
}

return $classMethod;
$classMethod = $classLike->getMethod($methodReflectionName);
if (! $classMethod instanceof ClassMethod) {
continue;
}

$this->classMethodsByClassAndMethod[$classLikeName][$methodReflectionName] = $classMethod;
return $classMethod;
}

// avoids looking for a class in a file where is not present
$this->classMethodsByClassAndMethod[$classLikeName][$methodReflectionName] = null;
return null;
}

public function resolveClassMethodOrFunctionFromCall(
Expand Down

0 comments on commit db7012e

Please sign in to comment.