mirror of
https://github.com/rectorphp/rector.git
synced 2025-01-19 14:27:14 +01:00
[DeadCode] Fix RemoveSetterOnlyPropertyAndMethodCallRector for interface contract
This commit is contained in:
parent
c7c5de8ab5
commit
6cec5bf890
@ -92,29 +92,33 @@ PHP
|
||||
return null;
|
||||
}
|
||||
|
||||
if ($this->propertyManipulator->isPropertyUsedInReadContext($node)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$propertyFetches = $this->propertyManipulator->getAllPropertyFetch($node);
|
||||
|
||||
/** @var ClassMethod[] $methodsToCheck */
|
||||
$methodsToCheck = [];
|
||||
foreach ($propertyFetches as $propertyFetch) {
|
||||
$methodName = $propertyFetch->getAttribute(AttributeKey::METHOD_NAME);
|
||||
if ($methodName !== '__construct') {
|
||||
//this rector does not remove empty constructors
|
||||
$methodsToCheck[$methodName] =
|
||||
$propertyFetch->getAttribute(AttributeKey::METHOD_NODE);
|
||||
$methodsToCheck[$methodName] = $propertyFetch->getAttribute(AttributeKey::METHOD_NODE);
|
||||
}
|
||||
}
|
||||
|
||||
$this->removePropertyAndUsages($node);
|
||||
$vendorLockedClassMethodNames = $this->getVendorLockedClassMethodNames($methodsToCheck);
|
||||
$this->removePropertyAndUsages($node, $vendorLockedClassMethodNames);
|
||||
|
||||
/** @var ClassMethod $method */
|
||||
foreach ($methodsToCheck as $method) {
|
||||
if ($this->methodHasNoStmtsLeft($method)) {
|
||||
$this->removeClassMethodAndUsages($method);
|
||||
if (! $this->methodHasNoStmtsLeft($method)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$classMethodName = $this->getName($method->name);
|
||||
if (in_array($classMethodName, $vendorLockedClassMethodNames, true)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->removeClassMethodAndUsages($method);
|
||||
}
|
||||
|
||||
return $node;
|
||||
@ -138,6 +142,68 @@ PHP
|
||||
|
||||
/** @var Class_|Interface_|Trait_|null $classNode */
|
||||
$classNode = $propertyProperty->getAttribute(AttributeKey::CLASS_NODE);
|
||||
return $classNode === null || $classNode instanceof Trait_ || $classNode instanceof Interface_;
|
||||
if ($classNode === null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($classNode instanceof Trait_) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($classNode instanceof Interface_) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($this->propertyManipulator->isPropertyUsedInReadContext($propertyProperty)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private function isClassMethodRemovalVendorLocked(ClassMethod $classMethod): bool
|
||||
{
|
||||
$classMethodName = $this->getName($classMethod);
|
||||
|
||||
/** @var Class_|null $class */
|
||||
$class = $classMethod->getAttribute(AttributeKey::CLASS_NODE);
|
||||
if ($class === null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// required by interface?
|
||||
foreach ($class->implements as $implement) {
|
||||
$implementedInterfaceName = $this->getName($implement);
|
||||
|
||||
if (interface_exists($implementedInterfaceName)) {
|
||||
$interfaceMethods = get_class_methods($implementedInterfaceName);
|
||||
if (in_array($classMethodName, $interfaceMethods, true)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// required by abstract class?
|
||||
// @todo
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ClassMethod[] $methodsToCheck
|
||||
* @return string[]
|
||||
*/
|
||||
private function getVendorLockedClassMethodNames(array $methodsToCheck): array
|
||||
{
|
||||
$vendorLockedClassMethodsNames = [];
|
||||
foreach ($methodsToCheck as $method) {
|
||||
if (! $this->isClassMethodRemovalVendorLocked($method)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$vendorLockedClassMethodsNames[] = $this->getName($method);
|
||||
}
|
||||
|
||||
return $vendorLockedClassMethodsNames;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace Rector\DeadCode\Tests\Rector\Property\RemoveSetterOnlyPropertyAndMethodCallRector\StaticProperty;
|
||||
|
||||
class SkipInterfaceRequired implements ParentInterface
|
||||
{
|
||||
private $name;
|
||||
public function setName(string $name): void
|
||||
{
|
||||
$this->name = $name;
|
||||
}
|
||||
}
|
||||
|
||||
interface ParentInterface
|
||||
{
|
||||
public function setName(string $name): void;
|
||||
}
|
@ -87,10 +87,22 @@ trait ComplexRemovalTrait
|
||||
}
|
||||
}
|
||||
|
||||
protected function removePropertyAndUsages(PropertyProperty $propertyProperty): void
|
||||
{
|
||||
/**
|
||||
* @param string[] $classMethodNamesToSkip
|
||||
*/
|
||||
protected function removePropertyAndUsages(
|
||||
PropertyProperty $propertyProperty,
|
||||
array $classMethodNamesToSkip = []
|
||||
): void {
|
||||
$shouldKeepProperty = false;
|
||||
|
||||
$propertyFetches = $this->propertyManipulator->getAllPropertyFetch($propertyProperty);
|
||||
foreach ($propertyFetches as $propertyFetch) {
|
||||
if ($this->shouldSkipPropertyForClassMethod($propertyFetch, $classMethodNamesToSkip)) {
|
||||
$shouldKeepProperty = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
$assign = $propertyFetch->getAttribute(AttributeKey::PARENT_NODE);
|
||||
|
||||
while ($assign !== null && ! $assign instanceof Assign) {
|
||||
@ -104,6 +116,10 @@ trait ComplexRemovalTrait
|
||||
$this->removeAssignNode($assign);
|
||||
}
|
||||
|
||||
if ($shouldKeepProperty) {
|
||||
return;
|
||||
}
|
||||
|
||||
/** @var Property $property */
|
||||
$property = $propertyProperty->getAttribute(AttributeKey::PARENT_NODE);
|
||||
$this->removeNode($propertyProperty);
|
||||
@ -223,4 +239,23 @@ trait ComplexRemovalTrait
|
||||
}
|
||||
$this->removeNode($node);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string[] $classMethodNamesToSkip
|
||||
*/
|
||||
private function shouldSkipPropertyForClassMethod(PropertyFetch $propertyFetch, array $classMethodNamesToSkip): bool
|
||||
{
|
||||
/** @var ClassMethod|null $methodNode */
|
||||
$classMethodNode = $propertyFetch->getAttribute(AttributeKey::METHOD_NODE);
|
||||
if ($classMethodNode === null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$classMethodName = $this->getName($classMethodNode);
|
||||
if ($classMethodName === null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return in_array($classMethodName, $classMethodNamesToSkip, true);
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user