[DeadCode] Make private property removal dependent on local property fetches (#311)

This commit is contained in:
Tomas Votruba 2021-06-27 18:08:24 +02:00 committed by GitHub
parent 46843ec495
commit e3727aad81
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
27 changed files with 61 additions and 712 deletions

View File

@ -11,7 +11,6 @@ use Rector\Privatization\Rector\ClassMethod\PrivatizeFinalClassMethodRector;
use Rector\Privatization\Rector\MethodCall\PrivatizeLocalGetterToPropertyRector;
use Rector\Privatization\Rector\Property\ChangeReadOnlyPropertyWithDefaultValueToConstantRector;
use Rector\Privatization\Rector\Property\PrivatizeFinalClassPropertyRector;
use Rector\Privatization\Rector\Property\PrivatizeLocalPropertyToPrivatePropertyRector;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
return static function (ContainerConfigurator $containerConfigurator): void {
@ -22,7 +21,6 @@ return static function (ContainerConfigurator $containerConfigurator): void {
$services->set(ChangeReadOnlyVariableWithDefaultValueToConstantRector::class);
$services->set(RepeatedLiteralToClassConstantRector::class);
$services->set(PrivatizeLocalGetterToPropertyRector::class);
$services->set(PrivatizeLocalPropertyToPrivatePropertyRector::class);
$services->set(PrivatizeFinalClassPropertyRector::class);
$services->set(PrivatizeFinalClassMethodRector::class);

View File

@ -25,7 +25,6 @@ use Rector\NodeTypeResolver\NodeTypeResolver;
final class NodeRepository
{
public function __construct(
private ParsedPropertyFetchNodeCollector $parsedPropertyFetchNodeCollector,
private NodeNameResolver $nodeNameResolver,
private ParsedNodeCollector $parsedNodeCollector,
private ReflectionProvider $reflectionProvider,
@ -33,39 +32,6 @@ final class NodeRepository
) {
}
/**
* @return PropertyFetch[]
*/
public function findPropertyFetchesByProperty(Property $property): array
{
/** @var string|null $className */
$className = $property->getAttribute(AttributeKey::CLASS_NAME);
if ($className === null) {
return [];
}
$propertyName = $this->nodeNameResolver->getName($property);
return $this->parsedPropertyFetchNodeCollector->findPropertyFetchesByTypeAndName($className, $propertyName);
}
/**
* @return PropertyFetch[]
*/
public function findPropertyFetchesByPropertyFetch(PropertyFetch $propertyFetch): array
{
$propertyFetcheeType = $this->nodeTypeResolver->getStaticType($propertyFetch->var);
if (! $propertyFetcheeType instanceof TypeWithClassName) {
return [];
}
$className = $this->nodeTypeResolver->getFullyQualifiedClassName($propertyFetcheeType);
/** @var string $propertyName */
$propertyName = $this->nodeNameResolver->getName($propertyFetch);
return $this->parsedPropertyFetchNodeCollector->findPropertyFetchesByTypeAndName($className, $propertyName);
}
public function hasClassChildren(Class_ $desiredClass): bool
{
$desiredClassName = $desiredClass->getAttribute(AttributeKey::CLASS_NAME);
@ -90,6 +56,7 @@ final class NodeRepository
}
/**
* @deprecated Use ReflectionProvider instead to resolve all the traits
* @return Trait_[]
*/
public function findUsedTraitsInClass(ClassLike $classLike): array

View File

@ -1,97 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\NodeCollector\NodeCollector;
use PhpParser\Node;
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Expr\PropertyFetch;
use PhpParser\Node\Expr\StaticCall;
use PhpParser\Node\Expr\StaticPropertyFetch;
use PHPStan\Type\MixedType;
use PHPStan\Type\Type;
use PHPStan\Type\TypeWithClassName;
use PHPStan\Type\UnionType;
use Rector\NodeNameResolver\NodeNameResolver;
use Rector\NodeTypeResolver\NodeTypeResolver;
/**
* All parsed nodes grouped type
*/
final class ParsedPropertyFetchNodeCollector
{
/**
* @var array<string, array<string, PropertyFetch[]>>
*/
private array $propertyFetchesByTypeAndName = [];
public function __construct(
private NodeNameResolver $nodeNameResolver,
private NodeTypeResolver $nodeTypeResolver
) {
}
public function collect(Node $node): void
{
if (! $node instanceof PropertyFetch && ! $node instanceof StaticPropertyFetch) {
return;
}
$propertyType = $this->resolvePropertyCallerType($node);
if ($propertyType instanceof MixedType) {
return;
}
// make sure name is valid
if ($node->name instanceof StaticCall || $node->name instanceof MethodCall) {
return;
}
$propertyName = $this->nodeNameResolver->getName($node->name);
if ($propertyName === null) {
return;
}
$this->addPropertyFetchWithTypeAndName($propertyType, $node, $propertyName);
}
/**
* @return PropertyFetch[]
*/
public function findPropertyFetchesByTypeAndName(string $className, string $propertyName): array
{
return $this->propertyFetchesByTypeAndName[$className][$propertyName] ?? [];
}
/**
* @param PropertyFetch|StaticPropertyFetch $node
*/
private function resolvePropertyCallerType(Node $node): Type
{
if ($node instanceof PropertyFetch) {
return $this->nodeTypeResolver->resolve($node->var);
}
return $this->nodeTypeResolver->resolve($node->class);
}
/**
* @param PropertyFetch|StaticPropertyFetch $propertyFetchNode
*/
private function addPropertyFetchWithTypeAndName(
Type $propertyType,
Node $propertyFetchNode,
string $propertyName
): void {
if ($propertyType instanceof TypeWithClassName) {
$this->propertyFetchesByTypeAndName[$propertyType->getClassName()][$propertyName][] = $propertyFetchNode;
}
if ($propertyType instanceof UnionType) {
foreach ($propertyType->getTypes() as $unionedType) {
$this->addPropertyFetchWithTypeAndName($unionedType, $propertyFetchNode, $propertyName);
}
}
}
}

View File

@ -7,13 +7,11 @@ namespace Rector\NodeCollector\NodeVisitor;
use PhpParser\Node;
use PhpParser\NodeVisitorAbstract;
use Rector\NodeCollector\NodeCollector\ParsedNodeCollector;
use Rector\NodeCollector\NodeCollector\ParsedPropertyFetchNodeCollector;
final class NodeCollectorNodeVisitor extends NodeVisitorAbstract
{
public function __construct(
private ParsedNodeCollector $parsedNodeCollector,
private ParsedPropertyFetchNodeCollector $parsedPropertyFetchNodeCollector
) {
}
@ -23,8 +21,6 @@ final class NodeCollectorNodeVisitor extends NodeVisitorAbstract
$this->parsedNodeCollector->collect($node);
}
$this->parsedPropertyFetchNodeCollector->collect($node);
return null;
}
}

View File

@ -32,13 +32,8 @@ final class ReadWritePropertyAnalyzer
) {
}
/**
* @param PropertyFetch|StaticPropertyFetch $node
*/
public function isRead(Node $node): bool
public function isRead(PropertyFetch|StaticPropertyFetch $node): bool
{
Assert::isAnyOf($node, [PropertyFetch::class, StaticPropertyFetch::class]);
$parent = $node->getAttribute(AttributeKey::PARENT_NODE);
if (! $parent instanceof Node) {
throw new ShouldNotHappenException();

View File

@ -6,12 +6,10 @@ namespace Rector\ReadWrite\NodeFinder;
use PhpParser\Node;
use PhpParser\Node\Expr;
use PhpParser\Node\Expr\PropertyFetch;
use PhpParser\Node\Expr\Variable;
use PhpParser\Node\Stmt\Foreach_;
use Rector\Core\PhpParser\Comparing\NodeComparator;
use Rector\Core\PhpParser\Node\BetterNodeFinder;
use Rector\NodeCollector\NodeCollector\NodeRepository;
use Rector\NodeNameResolver\NodeNameResolver;
use Rector\NodeNestingScope\NodeFinder\ScopeAwareNodeFinder;
@ -20,7 +18,6 @@ final class NodeUsageFinder
public function __construct(
private NodeNameResolver $nodeNameResolver,
private BetterNodeFinder $betterNodeFinder,
private NodeRepository $nodeRepository,
private ScopeAwareNodeFinder $scopeAwareNodeFinder,
private NodeComparator $nodeComparator
) {
@ -50,25 +47,6 @@ final class NodeUsageFinder
});
}
/**
* @return PropertyFetch[]
*/
public function findPropertyFetchUsages(PropertyFetch $desiredPropertyFetch): array
{
$propertyFetches = $this->nodeRepository->findPropertyFetchesByPropertyFetch($desiredPropertyFetch);
$propertyFetchesWithoutPropertyFetch = [];
foreach ($propertyFetches as $propertyFetch) {
if ($propertyFetch === $desiredPropertyFetch) {
continue;
}
$propertyFetchesWithoutPropertyFetch[] = $propertyFetch;
}
return $propertyFetchesWithoutPropertyFetch;
}
public function findPreviousForeachNodeUsage(Foreach_ $foreach, Expr $expr): ?Node
{
return $this->scopeAwareNodeFinder->findParent($foreach, function (Node $node) use ($expr): bool {

View File

@ -0,0 +1,55 @@
<?php
declare(strict_types=1);
namespace Rector\ReadWrite\ReadNodeAnalyzer;
use PhpParser\Node;
use PhpParser\Node\Expr\PropertyFetch;
use PhpParser\Node\Stmt\Class_;
use Rector\Core\PhpParser\NodeFinder\PropertyFetchFinder;
use Rector\NodeNameResolver\NodeNameResolver;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Rector\ReadWrite\Contract\ReadNodeAnalyzerInterface;
final class LocalPropertyFetchReadNodeAnalyzer implements ReadNodeAnalyzerInterface
{
public function __construct(
private JustReadExprAnalyzer $justReadExprAnalyzer,
private PropertyFetchFinder $propertyFetchFinder,
private NodeNameResolver $nodeNameResolver
) {
}
public function supports(Node $node): bool
{
return $node instanceof PropertyFetch;
}
/**
* @param PropertyFetch $node
*/
public function isRead(Node $node): bool
{
$class = $node->getAttribute(AttributeKey::CLASS_NODE);
if (! $class instanceof Class_) {
// assume worse to keep node protected
return true;
}
$propertyName = $this->nodeNameResolver->getName($node->name);
if ($propertyName === null) {
// assume worse to keep node protected
return true;
}
$propertyFetches = $this->propertyFetchFinder->findLocalPropertyFetchesByName($class, $propertyName);
foreach ($propertyFetches as $propertyFetch) {
if ($this->justReadExprAnalyzer->isReadContext($propertyFetch)) {
return true;
}
}
return false;
}
}

View File

@ -1,39 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\ReadWrite\ReadNodeAnalyzer;
use PhpParser\Node;
use PhpParser\Node\Expr\PropertyFetch;
use Rector\ReadWrite\Contract\ReadNodeAnalyzerInterface;
use Rector\ReadWrite\NodeFinder\NodeUsageFinder;
final class PropertyFetchReadNodeAnalyzer implements ReadNodeAnalyzerInterface
{
public function __construct(
private JustReadExprAnalyzer $justReadExprAnalyzer,
private NodeUsageFinder $nodeUsageFinder
) {
}
public function supports(Node $node): bool
{
return $node instanceof PropertyFetch;
}
/**
* @param PropertyFetch $node
*/
public function isRead(Node $node): bool
{
$propertyFetchUsages = $this->nodeUsageFinder->findPropertyFetchUsages($node);
foreach ($propertyFetchUsages as $propertyFetchUsage) {
if ($this->justReadExprAnalyzer->isReadContext($propertyFetchUsage)) {
return true;
}
}
return false;
}
}

View File

@ -14,7 +14,6 @@ use Rector\Php55\Rector\String_\StringClassNameToClassConstantRector;
use Rector\Php74\Rector\MethodCall\ChangeReflectionTypeToStringToGetNameRector;
use Rector\PHPUnit\Rector\Class_\AddSeeTestAnnotationRector;
use Rector\PHPUnit\Set\PHPUnitSetList;
use Rector\Privatization\Rector\Property\PrivatizeLocalPropertyToPrivatePropertyRector;
use Rector\Restoration\Rector\ClassMethod\InferParamFromClassMethodReturnRector;
use Rector\Restoration\ValueObject\InferParamFromClassMethodReturn;
use Rector\Set\ValueObject\SetList;
@ -88,8 +87,6 @@ return static function (ContainerConfigurator $containerConfigurator): void {
__DIR__ . '/rules/Php70/Rector/FuncCall/MultiDirnameRector.php',
],
PrivatizeLocalPropertyToPrivatePropertyRector::class => [__DIR__ . '/src/Rector/AbstractRector.php'],
ReturnTypeDeclarationRector::class => [
__DIR__ . '/packages/PHPStanStaticTypeMapper/TypeMapper/ArrayTypeMapper.php',
__DIR__ . '/packages/PHPStanStaticTypeMapper/TypeMapper/ObjectTypeMapper.php',

View File

@ -1,31 +0,0 @@
<?php
namespace Rector\Tests\Privatization\Rector\Property\PrivatizeLocalPropertyToPrivatePropertyRector\Fixture;
class Fixture
{
public $value;
public function run()
{
return $this->value;
}
}
?>
-----
<?php
namespace Rector\Tests\Privatization\Rector\Property\PrivatizeLocalPropertyToPrivatePropertyRector\Fixture;
class Fixture
{
private $value;
public function run()
{
return $this->value;
}
}
?>

View File

@ -1,8 +0,0 @@
<?php
namespace Rector\Tests\Privatization\Rector\Property\PrivatizeLocalPropertyToPrivatePropertyRector\Fixture;
abstract class SkipAbstract
{
public $property;
}

View File

@ -1,8 +0,0 @@
<?php
namespace Rector\Tests\Privatization\Rector\Property\PrivatizeLocalPropertyToPrivatePropertyRector\Fixture;
abstract class SkipAbstractClass
{
public $some;
}

View File

@ -1,16 +0,0 @@
<?php
namespace Rector\Tests\Privatization\Rector\Property\PrivatizeLocalPropertyToPrivatePropertyRector\Fixture;
use PhpParser\NodeTraverser;
class SkipAnonymousClass
{
public function run()
{
$anonymousClass = new class() extends NodeTraverser
{
public $property;
};
}
}

View File

@ -1,19 +0,0 @@
<?php
namespace Rector\Tests\Privatization\Rector\Property\PrivatizeLocalPropertyToPrivatePropertyRector\Fixture;
class SkipClassExtended extends AbstractParentClass
{
/**
* @api
*/
public function stop()
{
$this->value;
}
}
abstract class AbstractParentClass
{
public $value;
}

View File

@ -1,28 +0,0 @@
<?php
namespace Rector\Tests\Privatization\Rector\Property\PrivatizeLocalPropertyToPrivatePropertyRector\Fixture;
use Rector\Tests\Privatization\Rector\Property\PrivatizeLocalPropertyToPrivatePropertyRector\Source\EventInterface;
final class SkipDimFetchDispatcher
{
/**
* @var EventInterface[]
*/
private $dispatched = [];
public function dispatch(EventInterface $event)
{
$this->dispatched[] = $event;
return $event;
}
/**
* @return EventInterface[]
*/
public function getDispatchedEvents(): array
{
return $this->dispatched;
}
}

View File

@ -1,29 +0,0 @@
<?php
namespace Rector\Tests\Privatization\Rector\Property\PrivatizeLocalPropertyToPrivatePropertyRector\Fixture;
class SkipExternalFetch
{
/**
* @var ExternalClass
*/
private $externalClass;
public function __construct(ExternalClass $externalClass)
{
$this->externalClass = $externalClass;
}
/**
* @api
*/
public function run()
{
$this->externalClass->externalProperty;
}
}
class ExternalClass
{
public $externalProperty;
}

View File

@ -1,36 +0,0 @@
<?php
namespace Rector\Tests\Privatization\Rector\Property\PrivatizeLocalPropertyToPrivatePropertyRector\Fixture;
class SkipInterfaceImplemented
{
/**
* @var SomeInterface
*/
private $classImplementing;
public function __construct(SomeInterface $classImplementing)
{
$this->classImplementing = $classImplementing;
}
/**
* @api
*/
public function run()
{
$this->classImplementing->run();
}
}
class ClassImplementingInterface implements SomeInterface
{
public function run()
{
}
}
interface SomeInterface
{
public function run();
}

View File

@ -1,14 +0,0 @@
<?php
namespace Rector\Tests\Privatization\Rector\Property\PrivatizeLocalPropertyToPrivatePropertyRector\Fixture;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
class SkipParentClassProtected extends Command
{
protected function execute(InputInterface $input, OutputInterface $output)
{
}
}

View File

@ -1,37 +0,0 @@
<?php
namespace Rector\Tests\Privatization\Rector\Property\PrivatizeLocalPropertyToPrivatePropertyRector\Fixture;
use PHP_CodeSniffer\Files\File;
use PHP_CodeSniffer\Sniffs\Sniff;
final class SkipSniff implements Sniff
{
public $sniffConfigProperty;
public function shouldSkip(string $methodName, string $className): bool
{
// not really a setter, but usually test "setup" method
if ($methodName === 'setUp') {
return true;
}
foreach ($this->sniffConfigProperty as $allowedClass) {
if (fnmatch($allowedClass, $className, FNM_NOESCAPE)) {
return true;
}
}
return false;
}
public function register()
{
// TODO: Implement register() method.
}
public function process(File $phpcsFile, $stackPtr)
{
// TODO: Implement process() method.
}
}

View File

@ -1,8 +0,0 @@
<?php
namespace Rector\Tests\Privatization\Rector\Property\PrivatizeLocalPropertyToPrivatePropertyRector\Fixture;
trait SkipTrait
{
public $value;
}

View File

@ -1,26 +0,0 @@
<?php
namespace Rector\Tests\Privatization\Rector\Property\PrivatizeLocalPropertyToPrivatePropertyRector\Fixture;
final class SkipUsedInTrait
{
public $go;
}
trait SomeTrait
{
/**
* @var SkipUsedInTrait
*/
private $skipUsedInTrait;
public function run()
{
$this->skipUsedInTrait->go;
}
}
class AnotherClassUsingTheTraitJustToMakePHPStanWork
{
use SomeTrait;
}

View File

@ -1,33 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Tests\Privatization\Rector\Property\PrivatizeLocalPropertyToPrivatePropertyRector;
use Iterator;
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
use Symplify\SmartFileSystem\SmartFileInfo;
final class PrivatizeLocalPropertyToPrivatePropertyRectorTest extends AbstractRectorTestCase
{
/**
* @dataProvider provideData()
*/
public function test(SmartFileInfo $fileInfo): void
{
$this->doTestFileInfo($fileInfo);
}
/**
* @return Iterator<SmartFileInfo>
*/
public function provideData(): Iterator
{
return $this->yieldFilesFromDirectory(__DIR__ . '/Fixture');
}
public function provideConfigFilePath(): string
{
return __DIR__ . '/config/configured_rule.php';
}
}

View File

@ -1,10 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Tests\Privatization\Rector\Property\PrivatizeLocalPropertyToPrivatePropertyRector\Source;
interface EventInterface
{
}

View File

@ -1,11 +0,0 @@
<?php
declare(strict_types=1);
use Rector\Privatization\Rector\Property\PrivatizeLocalPropertyToPrivatePropertyRector;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
return static function (ContainerConfigurator $containerConfigurator): void {
$services = $containerConfigurator->services();
$services->set(PrivatizeLocalPropertyToPrivatePropertyRector::class);
};

View File

@ -10,6 +10,7 @@ use PhpParser\Node\Stmt\Interface_;
use PhpParser\Node\Stmt\Property;
use PhpParser\Node\Stmt\Trait_;
use Rector\Core\NodeManipulator\PropertyManipulator;
use Rector\Core\PhpParser\NodeFinder\PropertyFetchFinder;
use Rector\Core\Rector\AbstractRector;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Rector\Removing\NodeManipulator\ComplexNodeRemover;
@ -23,7 +24,7 @@ final class RemoveUnusedPrivatePropertyRector extends AbstractRector
{
public function __construct(
private PropertyManipulator $propertyManipulator,
private ComplexNodeRemover $complexNodeRemover
private ComplexNodeRemover $complexNodeRemover,
) {
}

View File

@ -1,174 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Privatization\Rector\Property;
use PhpParser\Node;
use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\ClassLike;
use PhpParser\Node\Stmt\Property;
use PHPStan\Type\ObjectType;
use Rector\Core\NodeAnalyzer\ClassAnalyzer;
use Rector\Core\Rector\AbstractRector;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Rector\VendorLocker\NodeVendorLocker\PropertyVisibilityVendorLockResolver;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
/**
* @see \Rector\Tests\Privatization\Rector\Property\PrivatizeLocalPropertyToPrivatePropertyRector\PrivatizeLocalPropertyToPrivatePropertyRectorTest
*/
final class PrivatizeLocalPropertyToPrivatePropertyRector extends AbstractRector
{
/**
* @var string[]
*/
private const TAGS_REQUIRING_PUBLIC_PROPERTY = [
'api',
// Symfony DI
'required',
// Nette + other DI
'inject',
];
/**
* @var ObjectType[]
*/
private array $excludedObjectTypes = [];
public function __construct(
private PropertyVisibilityVendorLockResolver $propertyVisibilityVendorLockResolver,
private ClassAnalyzer $classAnalyzer
) {
$this->excludedObjectTypes = [
new ObjectType('PHPUnit\Framework\TestCase'),
new ObjectType('PHP_CodeSniffer\Sniffs\Sniff'),
];
}
public function getRuleDefinition(): RuleDefinition
{
return new RuleDefinition('Privatize local-only property to private property', [
new CodeSample(
<<<'CODE_SAMPLE'
class SomeClass
{
public $value;
public function run()
{
return $this->value;
}
}
CODE_SAMPLE
,
<<<'CODE_SAMPLE'
class SomeClass
{
private $value;
public function run()
{
return $this->value;
}
}
CODE_SAMPLE
),
]);
}
/**
* @return array<class-string<Node>>
*/
public function getNodeTypes(): array
{
return [Property::class];
}
/**
* @param Property $node
*/
public function refactor(Node $node): ?Node
{
if ($this->shouldSkip($node)) {
return null;
}
$propertyFetches = $this->nodeRepository->findPropertyFetchesByProperty($node);
$usedPropertyFetchClassNames = [];
foreach ($propertyFetches as $propertyFetch) {
$usedPropertyFetchClassNames[] = $propertyFetch->getAttribute(AttributeKey::CLASS_NAME);
}
$usedPropertyFetchClassNames = array_unique($usedPropertyFetchClassNames);
$propertyClassName = $node->getAttribute(AttributeKey::CLASS_NAME);
// has external usage
if ($usedPropertyFetchClassNames !== [] && [$propertyClassName] !== $usedPropertyFetchClassNames) {
return null;
}
$this->visibilityManipulator->makePrivate($node);
return $node;
}
private function shouldSkip(Property $property): bool
{
$classLike = $property->getAttribute(AttributeKey::CLASS_NODE);
if (! $classLike instanceof ClassLike) {
return true;
}
if ($this->shouldSkipClass($classLike)) {
return true;
}
if ($this->shouldSkipProperty($property)) {
return true;
}
// is parent required property? skip it
if ($this->propertyVisibilityVendorLockResolver->isParentLockedProperty($property)) {
return true;
}
if ($this->propertyVisibilityVendorLockResolver->isChildLockedProperty($property)) {
return true;
}
$phpDocInfo = $this->phpDocInfoFactory->createFromNodeOrEmpty($property);
return $phpDocInfo->hasByNames(self::TAGS_REQUIRING_PUBLIC_PROPERTY);
}
private function shouldSkipClass(ClassLike $classLike): bool
{
if (! $classLike instanceof Class_) {
return true;
}
if ($this->classAnalyzer->isAnonymousClass($classLike)) {
return true;
}
if ($this->nodeTypeResolver->isObjectTypes($classLike, $this->excludedObjectTypes)) {
return true;
}
return $classLike->isAbstract();
}
private function shouldSkipProperty(Property $property): bool
{
// already private
if ($property->isPrivate()) {
return true;
}
// skip for now
return $property->isStatic();
}
}

View File

@ -29,15 +29,10 @@ final class IdentifierManipulator
}
/**
* @param ClassConstFetch|MethodCall|PropertyFetch|StaticCall|ClassMethod $node
* @param string[] $renameMethodMap
*/
public function renameNodeWithMap(Node $node, array $renameMethodMap): void
public function renameNodeWithMap(ClassConstFetch|MethodCall|PropertyFetch|StaticCall|ClassMethod $node, array $renameMethodMap): void
{
Assert::isAnyOf($node, [
ClassConstFetch::class, MethodCall::class, PropertyFetch::class, StaticCall::class, ClassMethod::class,
]);
$oldNodeMethodName = $this->resolveOldMethodName($node);
if ($oldNodeMethodName === null) {
return;
@ -46,23 +41,14 @@ final class IdentifierManipulator
$node->name = new Identifier($renameMethodMap[$oldNodeMethodName]);
}
/**
* @param ClassConstFetch|MethodCall|PropertyFetch|StaticCall|ClassMethod $node
*/
public function removeSuffix(Node $node, string $suffixToRemove): void
public function removeSuffix(ClassConstFetch|MethodCall|PropertyFetch|StaticCall|ClassMethod $node, string $suffixToRemove): void
{
Assert::isAnyOf(
$node,
[ClassConstFetch::class, MethodCall::class, PropertyFetch::class, StaticCall::class, ClassMethod::class]
);
$name = $this->nodeNameResolver->getName($node);
if ($name === null) {
return;
}
$newName = Strings::replace($name, sprintf('#%s$#', $suffixToRemove), '');
$node->name = new Identifier($newName);
}