[DeadCode] Improve parent and current type comparison on RemoveDelegatingParentCallRector (#4409)

* decouple CurrentAndParentClassMethodComparator

* fix param reflections

* [rector] fix param reflections

* [cs] fix param reflections

* composer: bump assert

* [rector] composer: bump assert

* [cs] composer: bump assert

* static fixes

Co-authored-by: rector-bot <tomas@getrector.org>
This commit is contained in:
Tomas Votruba 2020-10-14 19:14:55 +02:00 committed by GitHub
parent 15600516af
commit e085f52f86
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 619 additions and 227 deletions

View File

@ -12,7 +12,7 @@ Rector helps you with 2 areas - major code changes and in daily work.
It's a tool that [we develop](https://getrector.org/) and share for free, so you anyone can automate their refactoring.
Would you like to skip learning Rector, AST and nodes, educate your team about Rectors benefits and setup Rector in your CI that will speedup your development by 300 %, [hire us](https://getrector.org/contact)?
[Hire us](https://getrector.org/contact) to skip learning Rector, AST and nodes, to educate your team about Rectors benefits and to setup Rector in your project - so you can enjoy the 300 % development speed :+1:
[![Coverage Status](https://img.shields.io/coveralls/rectorphp/rector/master.svg?style=flat-square)](https://coveralls.io/github/rectorphp/rector?branch=master)
[![Downloads](https://img.shields.io/packagist/dt/rector/rector.svg?style=flat-square)](https://packagist.org/packages/rector/rector)

View File

@ -39,7 +39,7 @@
"symplify/package-builder": "^8.3.35",
"symplify/set-config-resolver": "^8.3.35",
"symplify/smart-file-system": "^8.3.35",
"webmozart/assert": "^1.8"
"webmozart/assert": "^1.9"
},
"require-dev": {
"friendsofphp/php-cs-fixer": "^2.16",

View File

@ -0,0 +1,159 @@
<?php
declare(strict_types=1);
namespace Rector\NodeCollector\Reflection;
use PhpParser\Node\Expr\StaticCall;
use PhpParser\Node\Stmt\ClassMethod;
use PHPStan\Analyser\Scope;
use PHPStan\Reflection\MethodReflection;
use PHPStan\Reflection\Native\NativeMethodReflection;
use PHPStan\Reflection\ParameterReflection;
use PHPStan\Reflection\ParametersAcceptorSelector;
use PHPStan\Reflection\ReflectionProvider;
use PHPStan\Type\Type;
use PHPStan\Type\TypeUtils;
use Rector\Core\Exception\ShouldNotHappenException;
use Rector\NodeNameResolver\NodeNameResolver;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Rector\NodeTypeResolver\NodeTypeResolver;
final class MethodReflectionProvider
{
/**
* @var NodeTypeResolver
*/
private $nodeTypeResolver;
/**
* @var ReflectionProvider
*/
private $reflectionProvider;
/**
* @var NodeNameResolver
*/
private $nodeNameResolver;
public function __construct(
NodeTypeResolver $nodeTypeResolver,
NodeNameResolver $nodeNameResolver,
ReflectionProvider $reflectionProvider
) {
$this->nodeTypeResolver = $nodeTypeResolver;
$this->reflectionProvider = $reflectionProvider;
$this->nodeNameResolver = $nodeNameResolver;
}
/**
* @return Type[]
*/
public function provideParameterTypesFromMethodReflection(MethodReflection $methodReflection): array
{
if ($methodReflection instanceof NativeMethodReflection) {
// method "getParameters()" does not exist there
return [];
}
$parameterTypes = [];
$parameterReflections = $this->getParameterReflectionsFromMethodReflection($methodReflection);
foreach ($parameterReflections as $phpParameterReflection) {
$parameterTypes[] = $phpParameterReflection->getType();
}
return $parameterTypes;
}
public function provideByClassAndMethodName(string $class, string $method, Scope $scope): ?MethodReflection
{
$classReflection = $this->reflectionProvider->getClass($class);
if (! $classReflection->hasMethod($method)) {
return null;
}
return $classReflection->getMethod($method, $scope);
}
/**
* @return Type[]
*/
public function provideParameterTypesByStaticCall(StaticCall $staticCall): array
{
$methodReflection = $this->provideByStaticCall($staticCall);
if ($methodReflection === null) {
return [];
}
return $this->provideParameterTypesFromMethodReflection($methodReflection);
}
public function provideByStaticCall(StaticCall $staticCall): ?MethodReflection
{
$objectType = $this->nodeTypeResolver->resolve($staticCall->class);
$classes = TypeUtils::getDirectClassNames($objectType);
$methodName = $this->nodeNameResolver->getName($staticCall->name);
if ($methodName === null) {
return null;
}
/** @var Scope|null $scope */
$scope = $staticCall->getAttribute(AttributeKey::SCOPE);
if (! $scope instanceof Scope) {
throw new ShouldNotHappenException();
}
foreach ($classes as $class) {
$methodReflection = $this->provideByClassAndMethodName($class, $methodName, $scope);
if ($methodReflection instanceof MethodReflection) {
return $methodReflection;
}
}
return null;
}
/**
* @return Type[]
*/
public function provideParameterTypesByClassMethod(ClassMethod $classMethod): array
{
$methodReflection = $this->provideByClassMethod($classMethod);
if ($methodReflection === null) {
return [];
}
return $this->provideParameterTypesFromMethodReflection($methodReflection);
}
public function provideByClassMethod(ClassMethod $classMethod): ?MethodReflection
{
$class = $classMethod->getAttribute(AttributeKey::CLASS_NAME);
if (! is_string($class)) {
return null;
}
$method = $this->nodeNameResolver->getName($classMethod->name);
if (! is_string($method)) {
return null;
}
$scope = $classMethod->getAttribute(AttributeKey::SCOPE);
if (! $scope instanceof Scope) {
return null;
}
return $this->provideByClassAndMethodName($class, $method, $scope);
}
/**
* @return ParameterReflection[]
*/
public function getParameterReflectionsFromMethodReflection(MethodReflection $methodReflection): array
{
$methodReflectionVariant = ParametersAcceptorSelector::selectSingle($methodReflection->getVariants());
return $methodReflectionVariant->getParameters();
}
}

View File

@ -7,11 +7,11 @@
"symfony/dependency-injection": "^4.4.8|^5.1",
"symfony/config": "^4.4.8|^5.1",
"symfony/http-kernel": "^4.4.8|^5.1",
"symplify/package-builder": "^8.3.33"
"symplify/package-builder": "^8.3.35"
},
"require-dev": {
"phpunit/phpunit": "^8.5|^9.2",
"symplify/easy-testing": "^8.3.33"
"symplify/easy-testing": "^8.3.35"
},
"autoload": {
"psr-4": {

View File

@ -6,7 +6,7 @@
"php": "^7.2.4|^8.0",
"symfony/dependency-injection": "^4.4.8|^5.1",
"symfony/http-kernel": "^4.4.8|^5.1",
"symplify/package-builder": "^8.3.33"
"symplify/package-builder": "^8.3.35"
},
"require-dev": {
"phpunit/phpunit": "^8.5|^9.2"

View File

@ -898,17 +898,6 @@ parameters:
paths:
- tests/debug_functions.php
-
message: '#Do not use @method tag in class docblock#'
paths:
- src/PhpParser/Builder/ClassBuilder.php # 15
- src/PhpParser/Builder/MethodBuilder.php # 15
- src/PhpParser/Builder/NamespaceBuilder.php # 15
- src/PhpParser/Builder/ParamBuilder.php # 15
- src/PhpParser/Builder/PropertyBuilder.php # 15
- src/PhpParser/Builder/TraitUseBuilder.php # 15
- src/PhpParser/Builder/UseBuilder.php # 15
-
message: '#Property with protected modifier is not allowed\. Use interface instead#'
paths:
@ -993,3 +982,11 @@ parameters:
- src/Testing/PHPUnit/AbstractNodeVisitorTestCase.php # 30
- src/Testing/PHPUnit/AbstractRectorTestCase.php # 24
- utils/doctrine-annotation-parser-syncer/src/FileSyncer/AbstractClassSyncer.php # 19
- '#Method Rector\\Core\\PhpParser\\Builder\\NamespaceBuilder\:\:getNode\(\) should return PhpParser\\Node\\Stmt\\Namespace_ but returns PhpParser\\Node#'
- '#Method Rector\\Core\\PhpParser\\Builder\\TraitUseBuilder\:\:getNode\(\) should return PhpParser\\Node\\Stmt\\TraitUse but returns PhpParser\\Node#'
- '#Method Rector\\Core\\PhpParser\\Builder\\UseBuilder\:\:getNode\(\) should return PhpParser\\Node\\Stmt\\Use_ but returns PhpParser\\Node#'
- '#Method Rector\\Utils\\PHPStanAttributeTypeSyncer\\NodeFactory\\AttributeAwareClassFactoryFactory\:\:createFromPhpDocParserNodeClass\(\) should return PhpParser\\Node\\Stmt\\Namespace_ but returns PhpParser\\Node#'
- '#Method Rector\\Utils\\PHPStanAttributeTypeSyncer\\NodeFactory\\AttributeAwareClassFactory\:\:createFromPhpDocParserNodeClass\(\) should return PhpParser\\Node\\Stmt\\Namespace_ but returns PhpParser\\Node#'
- '#Method Rector\\NetteKdyby\\NodeFactory\\EventValueObjectClassFactory\:\:wrapClassToNamespace\(\) should return PhpParser\\Node\\Stmt\\Namespace_ but returns PhpParser\\Node#'

View File

@ -0,0 +1,213 @@
<?php
declare(strict_types=1);
namespace Rector\DeadCode\Comparator;
use PhpParser\Node\Arg;
use PhpParser\Node\Expr\StaticCall;
use PhpParser\Node\Param;
use PhpParser\Node\Stmt\ClassMethod;
use PHPStan\Analyser\Scope;
use PHPStan\Reflection\MethodReflection;
use Rector\Core\Exception\ShouldNotHappenException;
use Rector\Core\PhpParser\Printer\BetterStandardPrinter;
use Rector\DeadCode\Comparator\Parameter\ParameterDefaultsComparator;
use Rector\DeadCode\Comparator\Parameter\ParameterTypeComparator;
use Rector\NodeCollector\NodeCollector\NodeRepository;
use Rector\NodeCollector\Reflection\MethodReflectionProvider;
use Rector\NodeNameResolver\NodeNameResolver;
use Rector\NodeTypeResolver\Node\AttributeKey;
final class CurrentAndParentClassMethodComparator
{
/**
* @var NodeNameResolver
*/
private $nodeNameResolver;
/**
* @var BetterStandardPrinter
*/
private $betterStandardPrinter;
/**
* @var NodeRepository
*/
private $nodeRepository;
/**
* @var MethodReflectionProvider
*/
private $methodReflectionProvider;
/**
* @var ParameterDefaultsComparator
*/
private $parameterDefaultsComparator;
/**
* @var ParameterTypeComparator
*/
private $parameterTypeComparator;
public function __construct(
NodeNameResolver $nodeNameResolver,
BetterStandardPrinter $betterStandardPrinter,
NodeRepository $nodeRepository,
MethodReflectionProvider $methodReflectionProvider,
ParameterDefaultsComparator $parameterDefaultsComparator,
ParameterTypeComparator $parameterTypeComparator
) {
$this->nodeNameResolver = $nodeNameResolver;
$this->betterStandardPrinter = $betterStandardPrinter;
$this->nodeRepository = $nodeRepository;
$this->methodReflectionProvider = $methodReflectionProvider;
$this->parameterDefaultsComparator = $parameterDefaultsComparator;
$this->parameterTypeComparator = $parameterTypeComparator;
}
public function isParentCallMatching(ClassMethod $classMethod, StaticCall $staticCall): bool
{
if (! $this->isSameMethodParentCall($classMethod, $staticCall)) {
return false;
}
if (! $this->areArgsAndParamsEqual($staticCall->args, $classMethod->params)) {
return false;
}
if (! $this->parameterTypeComparator->compareCurrentClassMethodAndParentStaticCall($classMethod, $staticCall)) {
return false;
}
return ! $this->isParentClassMethodVisibilityOrDefaultOverride($classMethod, $staticCall);
}
private function isSameMethodParentCall(ClassMethod $classMethod, StaticCall $staticCall): bool
{
if (! $this->nodeNameResolver->areNamesEqual($staticCall->name, $classMethod->name)) {
return false;
}
return $this->nodeNameResolver->isName($staticCall->class, 'parent');
}
/**
* @param Arg[] $parentStaticCallArgs
* @param Param[] $currentClassMethodParams
*/
private function areArgsAndParamsEqual(array $parentStaticCallArgs, array $currentClassMethodParams): bool
{
if (count($parentStaticCallArgs) !== count($currentClassMethodParams)) {
return false;
}
if (count($parentStaticCallArgs) === 0) {
return true;
}
foreach ($parentStaticCallArgs as $key => $arg) {
if (! isset($currentClassMethodParams[$key])) {
return false;
}
// this only compares variable name, but those can be differnt, so its kinda useless
$param = $currentClassMethodParams[$key];
if (! $this->betterStandardPrinter->areNodesEqual($param->var, $arg->value)) {
return false;
}
}
return true;
}
private function isParentClassMethodVisibilityOrDefaultOverride(
ClassMethod $classMethod,
StaticCall $staticCall
): bool {
/** @var string $className */
$className = $staticCall->getAttribute(AttributeKey::CLASS_NAME);
$parentClassName = get_parent_class($className);
if (! $parentClassName) {
throw new ShouldNotHappenException();
}
/** @var string $methodName */
$methodName = $this->nodeNameResolver->getName($staticCall->name);
$parentClassMethod = $this->nodeRepository->findClassMethod($parentClassName, $methodName);
if ($parentClassMethod !== null && $parentClassMethod->isProtected() && $classMethod->isPublic()) {
return true;
}
return $this->checkOverrideUsingReflection($classMethod, $parentClassName, $methodName);
}
private function checkOverrideUsingReflection(
ClassMethod $classMethod,
string $parentClassName,
string $methodName
): bool {
// @todo use phpstan reflecoitn
$scope = $classMethod->getAttribute(AttributeKey::SCOPE);
if (! $scope instanceof Scope) {
throw new ShouldNotHappenException();
}
$parentMethodReflection = $this->methodReflectionProvider->provideByClassAndMethodName(
$parentClassName,
$methodName,
$scope
);
// 3rd party code
if ($parentMethodReflection !== null) {
if (! $parentMethodReflection->isPrivate() && ! $parentMethodReflection->isPublic() && $classMethod->isPublic()) {
return true;
}
if ($parentMethodReflection->isInternal()->yes()) {
// we can't know for certain so we assume its a override with purpose
return true;
}
if ($this->areParameterDefaultsDifferent($classMethod, $parentMethodReflection)) {
return true;
}
}
return false;
}
private function areParameterDefaultsDifferent(
ClassMethod $classMethod,
MethodReflection $methodReflection
): bool {
$parameterReflections = $this->methodReflectionProvider->getParameterReflectionsFromMethodReflection(
$methodReflection
);
foreach ($parameterReflections as $key => $parameterReflection) {
if (! isset($classMethod->params[$key])) {
if ($parameterReflection->getDefaultValue() !== null) {
continue;
}
return true;
}
$methodParam = $classMethod->params[$key];
if ($this->parameterDefaultsComparator->areDefaultValuesDifferent(
$parameterReflection,
$methodParam
)) {
return true;
}
}
return false;
}
}

View File

@ -0,0 +1,77 @@
<?php
declare(strict_types=1);
namespace Rector\DeadCode\Comparator\Parameter;
use PhpParser\Node\Expr;
use PhpParser\Node\Param;
use PHPStan\Reflection\ParameterReflection;
use PHPStan\Type\Constant\ConstantArrayType;
use PHPStan\Type\Constant\ConstantBooleanType;
use PHPStan\Type\Constant\ConstantFloatType;
use PHPStan\Type\Constant\ConstantIntegerType;
use PHPStan\Type\Constant\ConstantStringType;
use PHPStan\Type\ConstantType;
use PHPStan\Type\NullType;
use Rector\Core\Exception\ShouldNotHappenException;
use Rector\Core\PhpParser\Node\Value\ValueResolver;
final class ParameterDefaultsComparator
{
/**
* @var ValueResolver
*/
private $valueResolver;
public function __construct(ValueResolver $valueResolver)
{
$this->valueResolver = $valueResolver;
}
public function areDefaultValuesDifferent(ParameterReflection $parameterReflection, Param $param): bool
{
if ($parameterReflection->getDefaultValue() === null && $param->default === null) {
return false;
}
if ($this->isMutuallyExclusiveNull($parameterReflection, $param)) {
return true;
}
/** @var Expr $paramDefault */
$paramDefault = $param->default;
$firstParameterValue = $this->resolveParameterReflectionDefaultValue($parameterReflection);
$secondParameterValue = $this->valueResolver->getValue($paramDefault);
return $firstParameterValue !== $secondParameterValue;
}
private function isMutuallyExclusiveNull(ParameterReflection $parameterReflection, Param $param): bool
{
if ($parameterReflection->getDefaultValue() === null && $param->default !== null) {
return true;
}
return $parameterReflection->getDefaultValue() !== null && $param->default === null;
}
/**
* @return bool|float|int|string|mixed[]|null
*/
private function resolveParameterReflectionDefaultValue(ParameterReflection $parameterReflection)
{
$defaultValue = $parameterReflection->getDefaultValue();
if (! $defaultValue instanceof ConstantType) {
throw new ShouldNotHappenException();
}
if ($defaultValue instanceof ConstantArrayType) {
return $defaultValue->getAllArrays();
}
/** @var ConstantStringType|ConstantIntegerType|ConstantFloatType|ConstantBooleanType|NullType $defaultValue */
return $defaultValue->getValue();
}
}

View File

@ -0,0 +1,43 @@
<?php
declare(strict_types=1);
namespace Rector\DeadCode\Comparator\Parameter;
use PhpParser\Node\Expr\StaticCall;
use PhpParser\Node\Stmt\ClassMethod;
use Rector\NodeCollector\Reflection\MethodReflectionProvider;
final class ParameterTypeComparator
{
/**
* @var MethodReflectionProvider
*/
private $methodReflectionProvider;
public function __construct(MethodReflectionProvider $methodReflectionProvider)
{
$this->methodReflectionProvider = $methodReflectionProvider;
}
public function compareCurrentClassMethodAndParentStaticCall(
ClassMethod $classMethod,
StaticCall $staticCall
): bool {
$currentParameterTypes = $this->methodReflectionProvider->provideParameterTypesByClassMethod($classMethod);
$parentParameterTypes = $this->methodReflectionProvider->provideParameterTypesByStaticCall($staticCall);
foreach ($currentParameterTypes as $key => $currentParameterType) {
if (! isset($parentParameterTypes[$key])) {
continue;
}
$parentParameterType = $parentParameterTypes[$key];
if (! $currentParameterType->equals($parentParameterType)) {
return false;
}
}
return true;
}
}

View File

@ -5,7 +5,6 @@ declare(strict_types=1);
namespace Rector\DeadCode\Rector\ClassMethod;
use PhpParser\Node;
use PhpParser\Node\Arg;
use PhpParser\Node\Expr\StaticCall;
use PhpParser\Node\Param;
use PhpParser\Node\Stmt\Class_;
@ -14,21 +13,27 @@ use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Stmt\Expression;
use PhpParser\Node\Stmt\Return_;
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\Core\ValueObject\MethodName;
use Rector\DeadCode\Comparator\CurrentAndParentClassMethodComparator;
use Rector\NodeTypeResolver\Node\AttributeKey;
use ReflectionClass;
use ReflectionMethod;
use ReflectionParameter;
/**
* @see \Rector\DeadCode\Tests\Rector\ClassMethod\RemoveDelegatingParentCallRector\RemoveDelegatingParentCallRectorTest
*/
final class RemoveDelegatingParentCallRector extends AbstractRector
{
/**
* @var CurrentAndParentClassMethodComparator
*/
private $currentAndParentClassMethodComparator;
public function __construct(CurrentAndParentClassMethodComparator $currentAndParentClassMethodComparator)
{
$this->currentAndParentClassMethodComparator = $currentAndParentClassMethodComparator;
}
public function getDefinition(): RectorDefinition
{
return new RectorDefinition('Removed dead parent call, that does not change anything', [
@ -83,7 +88,11 @@ CODE_SAMPLE
}
$staticCall = $this->matchStaticCall($onlyStmt);
if (! $this->isParentCallMatching($node, $staticCall)) {
if ($staticCall === null) {
return null;
}
if (! $this->currentAndParentClassMethodComparator->isParentCallMatching($node, $staticCall)) {
return null;
}
@ -144,26 +153,6 @@ CODE_SAMPLE
return null;
}
private function isParentCallMatching(ClassMethod $classMethod, ?StaticCall $staticCall): bool
{
if ($staticCall === null) {
return false;
}
if (! $this->areNamesEqual($staticCall->name, $classMethod->name)) {
return false;
}
if (! $this->isName($staticCall->class, 'parent')) {
return false;
}
if (! $this->areArgsAndParamsEqual($staticCall->args, $classMethod->params)) {
return false;
}
return ! $this->isParentClassMethodVisibilityOrDefaultOverride($classMethod, $staticCall);
}
private function hasRequiredAnnotation(Node $node): bool
{
/** @var PhpDocInfo|null $phpDocInfo */
@ -172,120 +161,6 @@ CODE_SAMPLE
return false;
}
return (bool) $phpDocInfo->hasByName('required');
}
/**
* @param Arg[] $args
* @param Param[] $params
*/
private function areArgsAndParamsEqual(array $args, array $params): bool
{
if (count($args) !== count($params)) {
return false;
}
foreach ($args as $key => $arg) {
if (! isset($params[$key])) {
return false;
}
$param = $params[$key];
if (! $this->areNodesEqual($param->var, $arg->value)) {
return false;
}
}
return true;
}
private function isParentClassMethodVisibilityOrDefaultOverride(
ClassMethod $classMethod,
StaticCall $staticCall
): bool {
/** @var string $className */
$className = $staticCall->getAttribute(AttributeKey::CLASS_NAME);
$parentClassName = get_parent_class($className);
if (! $parentClassName) {
throw new ShouldNotHappenException();
}
/** @var string $methodName */
$methodName = $this->getName($staticCall->name);
$parentClassMethod = $this->nodeRepository->findClassMethod($parentClassName, $methodName);
if ($parentClassMethod !== null && $parentClassMethod->isProtected() && $classMethod->isPublic()) {
return true;
}
return $this->checkOverrideUsingReflection($classMethod, $parentClassName, $methodName);
}
private function checkOverrideUsingReflection(
ClassMethod $classMethod,
string $parentClassName,
string $methodName
): bool {
$parentMethodReflection = $this->getReflectionMethod($parentClassName, $methodName);
// 3rd party code
if ($parentMethodReflection !== null) {
if ($parentMethodReflection->isProtected() && $classMethod->isPublic()) {
return true;
}
if ($parentMethodReflection->isInternal()) {
//we can't know for certain so we assume its an override
return true;
}
if ($this->areParameterDefaultsDifferent($classMethod, $parentMethodReflection)) {
return true;
}
}
return false;
}
private function getReflectionMethod(string $className, string $methodName): ?ReflectionMethod
{
if (! method_exists($className, $methodName)) {
//internal classes don't have __construct method
if ($methodName === MethodName::CONSTRUCT && class_exists($className)) {
return (new ReflectionClass($className))->getConstructor();
}
return null;
}
return new ReflectionMethod($className, $methodName);
}
private function areParameterDefaultsDifferent(
ClassMethod $classMethod,
ReflectionMethod $reflectionMethod
): bool {
foreach ($reflectionMethod->getParameters() as $key => $reflectionParameter) {
if (! isset($classMethod->params[$key])) {
if ($reflectionParameter->isDefaultValueAvailable()) {
continue;
}
return true;
}
$methodParam = $classMethod->params[$key];
if ($this->areDefaultValuesDifferent($reflectionParameter, $methodParam)) {
return true;
}
}
return false;
}
private function areDefaultValuesDifferent(ReflectionParameter $reflectionParameter, Param $methodParam): bool
{
if ($reflectionParameter->isDefaultValueAvailable() !== isset($methodParam->default)) {
return true;
}
return $reflectionParameter->isDefaultValueAvailable() && $methodParam->default !== null &&
! $this->isValue($methodParam->default, $reflectionParameter->getDefaultValue());
return $phpDocInfo->hasByName('required');
}
}

View File

@ -1,49 +0,0 @@
<?php
namespace Rector\DeadCode\Tests\Rector\ClassMethod\RemoveDelegatingParentCallRector\DifferentDefaults;
Class Base {
public function __construct($message = "")
{
}
}
class DefaultOverride extends Base
{
public function __construct($message = "My special message")
{
parent::__construct($message);
}
}
class NoOverride extends Base
{
public function __construct($message = "")
{
parent::__construct($message);
}
}
?>
-----
<?php
namespace Rector\DeadCode\Tests\Rector\ClassMethod\RemoveDelegatingParentCallRector\DifferentDefaults;
Class Base {
public function __construct($message = "")
{
}
}
class DefaultOverride extends Base
{
public function __construct($message = "My special message")
{
parent::__construct($message);
}
}
class NoOverride extends Base
{
}
?>

View File

@ -0,0 +1,27 @@
<?php
namespace Rector\DeadCode\Tests\Rector\ClassMethod\RemoveDelegatingParentCallRector\Fixture;
use Rector\DeadCode\Tests\Rector\ClassMethod\RemoveDelegatingParentCallRector\Source\ClassWithStringDefaultParameter;
final class IdenticalDefaults extends ClassWithStringDefaultParameter
{
public function __construct($message = '')
{
parent::__construct($message);
}
}
?>
-----
<?php
namespace Rector\DeadCode\Tests\Rector\ClassMethod\RemoveDelegatingParentCallRector\Fixture;
use Rector\DeadCode\Tests\Rector\ClassMethod\RemoveDelegatingParentCallRector\Source\ClassWithStringDefaultParameter;
final class IdenticalDefaults extends ClassWithStringDefaultParameter
{
}
?>

View File

@ -0,0 +1,13 @@
<?php
namespace Rector\DeadCode\Tests\Rector\ClassMethod\RemoveDelegatingParentCallRector\Fixture;
use Rector\DeadCode\Tests\Rector\ClassMethod\RemoveDelegatingParentCallRector\Source\ClassWithStringDefaultParameter;
final class SkipDifferentDefaults extends ClassWithStringDefaultParameter
{
public function __construct($message = 'My special message')
{
parent::__construct($message);
}
}

View File

@ -0,0 +1,14 @@
<?php
namespace Rector\DeadCode\Tests\Rector\ClassMethod\RemoveDelegatingParentCallRector\Fixture;
use Rector\DeadCode\Tests\Rector\ClassMethod\RemoveDelegatingParentCallRector\Source\ChildOfToBeImplementedInterface;
use Rector\DeadCode\Tests\Rector\ClassMethod\RemoveDelegatingParentCallRector\Source\ParentClassWithInterfaceType;
class SkipParentDifferentType extends ParentClassWithInterfaceType
{
public function __construct(ChildOfToBeImplementedInterface $toBeImplemented)
{
parent::__construct($toBeImplemented);
}
}

View File

@ -0,0 +1,9 @@
<?php
declare(strict_types=1);
namespace Rector\DeadCode\Tests\Rector\ClassMethod\RemoveDelegatingParentCallRector\Source;
final class ChildOfToBeImplementedInterface implements ToBeImplementedInterface
{
}

View File

@ -0,0 +1,12 @@
<?php
declare(strict_types=1);
namespace Rector\DeadCode\Tests\Rector\ClassMethod\RemoveDelegatingParentCallRector\Source;
class ClassWithStringDefaultParameter
{
public function __construct($message = '')
{
}
}

View File

@ -0,0 +1,12 @@
<?php
declare(strict_types=1);
namespace Rector\DeadCode\Tests\Rector\ClassMethod\RemoveDelegatingParentCallRector\Source;
class ParentClassWithInterfaceType
{
public function __construct(ToBeImplementedInterface $toBeImplemented)
{
}
}

View File

@ -0,0 +1,10 @@
<?php
declare(strict_types=1);
namespace Rector\DeadCode\Tests\Rector\ClassMethod\RemoveDelegatingParentCallRector\Source;
interface ToBeImplementedInterface
{
}

View File

@ -5,12 +5,9 @@ declare(strict_types=1);
namespace Rector\Core\PhpParser\Builder;
use PhpParser\Builder\Class_;
use PhpParser\Node\Stmt\Class_ as ClassStmt;
/**
* Fixed duplicated naming in php-parser and prevents confusion
*
* @method ClassStmt getNode()
*/
final class ClassBuilder extends Class_
{

View File

@ -5,12 +5,9 @@ declare(strict_types=1);
namespace Rector\Core\PhpParser\Builder;
use PhpParser\Builder\Method;
use PhpParser\Node\Stmt\ClassMethod;
/**
* Fixed duplicated naming in php-parser and prevents confusion
*
* @method ClassMethod getNode()
*/
final class MethodBuilder extends Method
{

View File

@ -5,12 +5,9 @@ declare(strict_types=1);
namespace Rector\Core\PhpParser\Builder;
use PhpParser\Builder\Namespace_;
use PhpParser\Node\Stmt\Namespace_ as NamespaceStmt;
/**
* Fixed duplicated naming in php-parser and prevents confusion
*
* @method NamespaceStmt getNode()
*/
final class NamespaceBuilder extends Namespace_
{

View File

@ -5,12 +5,9 @@ declare(strict_types=1);
namespace Rector\Core\PhpParser\Builder;
use PhpParser\Builder\Param;
use PhpParser\Node\Param as ParamNode;
/**
* Fixed duplicated naming in php-parser and prevents confusion
*
* @method ParamNode getNode()
*/
final class ParamBuilder extends Param
{

View File

@ -5,12 +5,9 @@ declare(strict_types=1);
namespace Rector\Core\PhpParser\Builder;
use PhpParser\Builder\Property;
use PhpParser\Node\Stmt\Property as PropertyNode;
/**
* Fixed duplicated naming in php-parser and prevents confusion
*
* @method PropertyNode getNode()
*/
final class PropertyBuilder extends Property
{

View File

@ -5,12 +5,9 @@ declare(strict_types=1);
namespace Rector\Core\PhpParser\Builder;
use PhpParser\Builder\TraitUse;
use PhpParser\Node\Stmt\TraitUse as TraitUseStmt;
/**
* Fixed duplicated naming in php-parser and prevents confusion
*
* @method TraitUseStmt getNode()
*/
final class TraitUseBuilder extends TraitUse
{

View File

@ -9,8 +9,6 @@ use PhpParser\Node\Stmt\Use_ as UseStmt;
/**
* Fixed duplicated naming in php-parser and prevents confusion
*
* @method UseStmt getNode()
*/
final class UseBuilder extends Use_
{