mirror of
https://github.com/rectorphp/rector.git
synced 2025-01-17 21:38:22 +01:00
[Naming] Make UnderscoreToCamelCasePropertyNameRector work with PropertyRenamer (#4283)
Co-authored-by: rector-bot <tomas@getrector.org>
This commit is contained in:
parent
19f83dd2b0
commit
ccb086aab7
@ -22,7 +22,6 @@ use Rector\CodingStyle\Rector\Function_\CamelCaseFunctionNamingToUnderscoreRecto
|
||||
use Rector\CodingStyle\Rector\If_\NullableCompareToNullRector;
|
||||
use Rector\CodingStyle\Rector\Include_\FollowRequireByDirRector;
|
||||
use Rector\CodingStyle\Rector\Plus\UseIncrementAssignRector;
|
||||
use Rector\CodingStyle\Rector\PropertyProperty\UnderscoreToCamelCasePropertyNameRector;
|
||||
use Rector\CodingStyle\Rector\String_\SplitStringClassConstantToClassConstFetchRector;
|
||||
use Rector\CodingStyle\Rector\String_\SymplifyQuoteEscapeRector;
|
||||
use Rector\CodingStyle\Rector\Switch_\BinarySwitchToIfElseRector;
|
||||
@ -70,7 +69,6 @@ return static function (ContainerConfigurator $containerConfigurator): void {
|
||||
|
||||
$services->set(CamelCaseFunctionNamingToUnderscoreRector::class);
|
||||
$services->set(SplitGroupedUseImportsRector::class);
|
||||
$services->set(UnderscoreToCamelCasePropertyNameRector::class);
|
||||
$services->set(UnderscoreToCamelCaseVariableNameRector::class);
|
||||
$services->set(RemoveDoubleUnderscoreInMethodNameRector::class);
|
||||
};
|
||||
|
@ -10,6 +10,7 @@ use Rector\Naming\Rector\ClassMethod\RenameParamToMatchTypeRector;
|
||||
use Rector\Naming\Rector\ClassMethod\RenameVariableToMatchNewTypeRector;
|
||||
use Rector\Naming\Rector\Foreach_\RenameForeachValueVariableToMatchMethodCallReturnTypeRector;
|
||||
use Rector\Naming\Rector\Property\MakeBoolPropertyRespectIsHasWasMethodNamingRector;
|
||||
use Rector\Naming\Rector\Property\UnderscoreToCamelCasePropertyNameRector;
|
||||
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
|
||||
|
||||
return static function (ContainerConfigurator $containerConfigurator): void {
|
||||
@ -22,4 +23,5 @@ return static function (ContainerConfigurator $containerConfigurator): void {
|
||||
$services->set(MakeIsserClassMethodNameStartWithIsRector::class);
|
||||
$services->set(RenameForeachValueVariableToMatchMethodCallReturnTypeRector::class);
|
||||
$services->set(MakeBoolPropertyRespectIsHasWasMethodNamingRector::class);
|
||||
$services->set(UnderscoreToCamelCasePropertyNameRector::class);
|
||||
};
|
||||
|
@ -10,6 +10,7 @@ use PhpParser\Node\Expr;
|
||||
use PhpParser\Node\Expr\MethodCall;
|
||||
use PhpParser\Node\Expr\PropertyFetch;
|
||||
use PhpParser\Node\Expr\StaticCall;
|
||||
use PhpParser\Node\Expr\StaticPropertyFetch;
|
||||
use PhpParser\Node\Identifier;
|
||||
use PhpParser\Node\Name;
|
||||
use PhpParser\Node\Stmt\ClassLike;
|
||||
@ -201,6 +202,15 @@ final class NodeNameResolver
|
||||
return $this->isName($node->name, $name);
|
||||
}
|
||||
|
||||
public function isLocalStaticPropertyFetchNamed(Node $node, string $name): bool
|
||||
{
|
||||
if (! $node instanceof StaticPropertyFetch) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->isName($node->name, $name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param MethodCall|StaticCall $node
|
||||
*/
|
||||
|
@ -1,104 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\CodingStyle\Rector\PropertyProperty;
|
||||
|
||||
use Nette\Utils\Strings;
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Expr\PropertyFetch;
|
||||
use PhpParser\Node\Expr\StaticPropertyFetch;
|
||||
use PhpParser\Node\Identifier;
|
||||
use PhpParser\Node\Stmt\PropertyProperty;
|
||||
use Rector\Core\Rector\AbstractRector;
|
||||
use Rector\Core\RectorDefinition\CodeSample;
|
||||
use Rector\Core\RectorDefinition\RectorDefinition;
|
||||
use Rector\Core\Util\StaticRectorStrings;
|
||||
use Rector\NodeTypeResolver\Node\AttributeKey;
|
||||
|
||||
/**
|
||||
* @see \Rector\CodingStyle\Tests\Rector\PropertyProperty\UnderscoreToCamelCasePropertyNameRector\UnderscoreToCamelCasePropertyNameRectorTest
|
||||
*/
|
||||
final class UnderscoreToCamelCasePropertyNameRector extends AbstractRector
|
||||
{
|
||||
public function getDefinition(): RectorDefinition
|
||||
{
|
||||
return new RectorDefinition('Change under_score names to camelCase', [
|
||||
new CodeSample(
|
||||
<<<'CODE_SAMPLE'
|
||||
final class SomeClass
|
||||
{
|
||||
public $property_name;
|
||||
|
||||
public function run($a)
|
||||
{
|
||||
$this->property_name = 5;
|
||||
}
|
||||
}
|
||||
CODE_SAMPLE
|
||||
,
|
||||
<<<'CODE_SAMPLE'
|
||||
final class SomeClass
|
||||
{
|
||||
public $propertyName;
|
||||
|
||||
public function run($a)
|
||||
{
|
||||
$this->propertyName = 5;
|
||||
}
|
||||
}
|
||||
CODE_SAMPLE
|
||||
),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
public function getNodeTypes(): array
|
||||
{
|
||||
return [PropertyProperty::class, PropertyFetch::class, StaticPropertyFetch::class];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param PropertyProperty|PropertyFetch|StaticPropertyFetch $node
|
||||
*/
|
||||
public function refactor(Node $node): ?Node
|
||||
{
|
||||
$nodeName = $this->getName($node);
|
||||
if ($nodeName === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/** @var string $class */
|
||||
$class = $node->getAttribute(AttributeKey::CLASS_NAME);
|
||||
// properties are accessed via magic, nothing we can do
|
||||
if (method_exists($class, '__set') || method_exists($class, '__get')) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (! Strings::contains($nodeName, '_')) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$camelCaseName = $this->createCamelName($nodeName, $node);
|
||||
|
||||
$node->name = new Identifier($camelCaseName);
|
||||
|
||||
return $node;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param PropertyProperty|PropertyFetch|StaticPropertyFetch $node
|
||||
*/
|
||||
private function createCamelName(string $nodeName, Node $node): string
|
||||
{
|
||||
$camelCaseName = StaticRectorStrings::underscoreToCamelCase($nodeName);
|
||||
|
||||
if ($node instanceof StaticPropertyFetch || $node instanceof PropertyProperty) {
|
||||
$camelCaseName = '$' . $camelCaseName;
|
||||
}
|
||||
|
||||
return $camelCaseName;
|
||||
}
|
||||
}
|
@ -0,0 +1,69 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Naming\ExpectedNameResolver;
|
||||
|
||||
use Nette\Utils\Strings;
|
||||
use PhpParser\Node\Stmt\Property;
|
||||
use Rector\Naming\Naming\PropertyNaming;
|
||||
use Rector\NodeNameResolver\NodeNameResolver;
|
||||
use Rector\NodeTypeResolver\NodeTypeResolver;
|
||||
|
||||
abstract class AbstractExpectedNameResolver implements ExpectedNameResolverInterface
|
||||
{
|
||||
/**
|
||||
* @var NodeTypeResolver
|
||||
*/
|
||||
protected $nodeTypeResolver;
|
||||
|
||||
/**
|
||||
* @var PropertyNaming
|
||||
*/
|
||||
protected $propertyNaming;
|
||||
|
||||
/**
|
||||
* @var NodeNameResolver
|
||||
*/
|
||||
protected $nodeNameResolver;
|
||||
|
||||
public function __construct(
|
||||
NodeNameResolver $nodeNameResolver,
|
||||
NodeTypeResolver $nodeTypeResolver,
|
||||
PropertyNaming $propertyNaming
|
||||
) {
|
||||
$this->nodeNameResolver = $nodeNameResolver;
|
||||
$this->nodeTypeResolver = $nodeTypeResolver;
|
||||
$this->propertyNaming = $propertyNaming;
|
||||
}
|
||||
|
||||
public function resolveIfNotYet(Property $property): ?string
|
||||
{
|
||||
$expectedName = $this->resolve($property);
|
||||
if ($expectedName === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/** @var string $propertyName */
|
||||
$propertyName = $this->nodeNameResolver->getName($property);
|
||||
if ($this->endsWith($propertyName, $expectedName)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if ($this->nodeNameResolver->isName($property, $expectedName)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $expectedName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ends with ucname
|
||||
* Starts with adjective, e.g. (Post $firstPost, Post $secondPost)
|
||||
*/
|
||||
protected function endsWith(string $currentName, string $expectedName): bool
|
||||
{
|
||||
$suffixNamePattern = '#\w+' . ucfirst($expectedName) . '#';
|
||||
return (bool) Strings::match($currentName, $suffixNamePattern);
|
||||
}
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Naming\ExpectedNameResolver;
|
||||
|
||||
use PhpParser\Node\Stmt\Property;
|
||||
|
||||
final class BoolPropertyExpectedNameResolver extends AbstractExpectedNameResolver
|
||||
{
|
||||
public function resolve(Property $property): ?string
|
||||
{
|
||||
if ($this->nodeTypeResolver->isPropertyBoolean($property)) {
|
||||
return $this->propertyNaming->getExpectedNameFromBooleanPropertyType($property);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Naming\ExpectedNameResolver;
|
||||
|
||||
use PhpParser\Node\Stmt\Property;
|
||||
|
||||
interface ExpectedNameResolverInterface
|
||||
{
|
||||
public function resolveIfNotYet(Property $property): ?string;
|
||||
|
||||
public function resolve(Property $property): ?string;
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Naming\ExpectedNameResolver;
|
||||
|
||||
use PhpParser\Node\Stmt\Property;
|
||||
use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfo;
|
||||
use Rector\NodeTypeResolver\Node\AttributeKey;
|
||||
|
||||
final class MatchPropertyTypeExpectedNameResolver extends AbstractExpectedNameResolver
|
||||
{
|
||||
public function resolve(Property $property): ?string
|
||||
{
|
||||
/** @var PhpDocInfo|null $phpDocInfo */
|
||||
$phpDocInfo = $property->getAttribute(AttributeKey::PHP_DOC_INFO);
|
||||
if ($phpDocInfo === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$expectedName = $this->propertyNaming->getExpectedNameFromType($phpDocInfo->getVarType());
|
||||
if ($expectedName === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $expectedName->getName();
|
||||
}
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Naming\ExpectedNameResolver;
|
||||
|
||||
use PhpParser\Node\Stmt\Property;
|
||||
use Rector\Core\Util\StaticRectorStrings;
|
||||
|
||||
final class UnderscoreCamelCaseExpectedNameResolver extends AbstractExpectedNameResolver
|
||||
{
|
||||
public function resolve(Property $property): string
|
||||
{
|
||||
$currentName = $this->nodeNameResolver->getName($property);
|
||||
|
||||
return StaticRectorStrings::underscoreToCamelCase($currentName);
|
||||
}
|
||||
}
|
@ -22,7 +22,6 @@ use Ramsey\Uuid\UuidInterface;
|
||||
use Rector\Core\PhpParser\Node\BetterNodeFinder;
|
||||
use Rector\Naming\Naming\ConflictingNameResolver;
|
||||
use Rector\Naming\Naming\OverridenExistingNamesResolver;
|
||||
use Rector\Naming\ValueObject\PropertyRename;
|
||||
use Rector\NodeNameResolver\NodeNameResolver;
|
||||
use Rector\NodeTypeResolver\Node\AttributeKey;
|
||||
use Rector\NodeTypeResolver\NodeTypeResolver;
|
||||
@ -125,26 +124,6 @@ final class BreakingVariableRenameGuard
|
||||
return $this->isUsedInIfAndOtherBranches($variable, $currentName);
|
||||
}
|
||||
|
||||
public function shouldSkipProperty(PropertyRename $propertyRename): bool
|
||||
{
|
||||
if (! $propertyRename->getProperty()->isPrivate()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$conflictingPropertyNames = $this->conflictingNameResolver->resolveConflictingPropertyNames(
|
||||
$propertyRename->getClassLike()
|
||||
);
|
||||
if (in_array($propertyRename->getExpectedName(), $conflictingPropertyNames, true)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($this->isRamseyUuidInterface($propertyRename->getProperty())) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return $this->isDateTimeAtNamingConvention($propertyRename->getProperty());
|
||||
}
|
||||
|
||||
public function shouldSkipParam(
|
||||
string $currentName,
|
||||
string $expectedName,
|
||||
@ -266,6 +245,7 @@ final class BreakingVariableRenameGuard
|
||||
}
|
||||
|
||||
/**
|
||||
* @TODO Remove once ParamRenamer created
|
||||
* @param Param|Property $node
|
||||
*/
|
||||
private function isRamseyUuidInterface(Node $node): bool
|
||||
@ -274,6 +254,7 @@ final class BreakingVariableRenameGuard
|
||||
}
|
||||
|
||||
/**
|
||||
* @TODO Remove once ParamRenamer created
|
||||
* @param Param|Property $node
|
||||
*/
|
||||
private function isDateTimeAtNamingConvention(Node $node): bool
|
||||
|
56
rules/naming/src/Guard/DateTimeAtNamingConventionGuard.php
Normal file
56
rules/naming/src/Guard/DateTimeAtNamingConventionGuard.php
Normal file
@ -0,0 +1,56 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Naming\Guard;
|
||||
|
||||
use DateTimeInterface;
|
||||
use Nette\Utils\Strings;
|
||||
use PHPStan\Type\TypeWithClassName;
|
||||
use Rector\Naming\ValueObject\RenameValueObjectInterface;
|
||||
use Rector\NodeTypeResolver\NodeTypeResolver;
|
||||
use Rector\PHPStanStaticTypeMapper\Utils\TypeUnwrapper;
|
||||
|
||||
final class DateTimeAtNamingConventionGuard implements GuardInterface
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private const AT_NAMING_REGEX = '#[\w+]At$#';
|
||||
|
||||
/**
|
||||
* @var NodeTypeResolver
|
||||
*/
|
||||
private $nodeTypeResolver;
|
||||
|
||||
/**
|
||||
* @var TypeUnwrapper
|
||||
*/
|
||||
private $typeUnwrapper;
|
||||
|
||||
public function __construct(NodeTypeResolver $nodeTypeResolver, TypeUnwrapper $typeUnwrapper)
|
||||
{
|
||||
$this->nodeTypeResolver = $nodeTypeResolver;
|
||||
$this->typeUnwrapper = $typeUnwrapper;
|
||||
}
|
||||
|
||||
public function check(RenameValueObjectInterface $renameValueObject): bool
|
||||
{
|
||||
return $this->isDateTimeAtNamingConvention($renameValueObject);
|
||||
}
|
||||
|
||||
private function isDateTimeAtNamingConvention(RenameValueObjectInterface $renameValueObject): bool
|
||||
{
|
||||
$type = $this->nodeTypeResolver->resolve($renameValueObject->getNode());
|
||||
$type = $this->typeUnwrapper->unwrapFirstObjectTypeFromUnionType($type);
|
||||
if (! $type instanceof TypeWithClassName) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (! is_a($type->getClassName(), DateTimeInterface::class, true)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (bool) Strings::match($renameValueObject->getCurrentName(), self::AT_NAMING_REGEX . '');
|
||||
}
|
||||
}
|
12
rules/naming/src/Guard/GuardInterface.php
Normal file
12
rules/naming/src/Guard/GuardInterface.php
Normal file
@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Naming\Guard;
|
||||
|
||||
use Rector\Naming\ValueObject\RenameValueObjectInterface;
|
||||
|
||||
interface GuardInterface
|
||||
{
|
||||
public function check(RenameValueObjectInterface $renameValueObject): bool;
|
||||
}
|
22
rules/naming/src/Guard/HasMagicGetSetGuard.php
Normal file
22
rules/naming/src/Guard/HasMagicGetSetGuard.php
Normal file
@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Naming\Guard;
|
||||
|
||||
use Rector\Naming\ValueObject\PropertyRename;
|
||||
use Rector\Naming\ValueObject\RenameValueObjectInterface;
|
||||
|
||||
final class HasMagicGetSetGuard implements GuardInterface
|
||||
{
|
||||
/**
|
||||
* @param PropertyRename $renameValueObject
|
||||
*/
|
||||
public function check(RenameValueObjectInterface $renameValueObject): bool
|
||||
{
|
||||
return method_exists($renameValueObject->getClassLikeName(), '__set') || method_exists(
|
||||
$renameValueObject->getClassLikeName(),
|
||||
'__get'
|
||||
);
|
||||
}
|
||||
}
|
19
rules/naming/src/Guard/NotPrivatePropertyGuard.php
Normal file
19
rules/naming/src/Guard/NotPrivatePropertyGuard.php
Normal file
@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Naming\Guard;
|
||||
|
||||
use Rector\Naming\ValueObject\PropertyRename;
|
||||
use Rector\Naming\ValueObject\RenameValueObjectInterface;
|
||||
|
||||
final class NotPrivatePropertyGuard implements GuardInterface
|
||||
{
|
||||
/**
|
||||
* @param PropertyRename $renameValueObject
|
||||
*/
|
||||
public function check(RenameValueObjectInterface $renameValueObject): bool
|
||||
{
|
||||
return ! $renameValueObject->getNode()->isPrivate();
|
||||
}
|
||||
}
|
@ -0,0 +1,63 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Naming\Guard\PropertyConflictingNameGuard;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Stmt\ClassLike;
|
||||
use Rector\Naming\ExpectedNameResolver\ExpectedNameResolverInterface;
|
||||
use Rector\Naming\Guard\GuardInterface;
|
||||
use Rector\Naming\PhpArray\ArrayFilter;
|
||||
use Rector\Naming\ValueObject\RenameValueObjectInterface;
|
||||
use Rector\NodeNameResolver\NodeNameResolver;
|
||||
|
||||
class AbstractPropertyConflictingNameGuard implements GuardInterface
|
||||
{
|
||||
/**
|
||||
* @var ExpectedNameResolverInterface
|
||||
*/
|
||||
protected $expectedNameResolver;
|
||||
|
||||
/**
|
||||
* @var NodeNameResolver
|
||||
*/
|
||||
private $nodeNameResolver;
|
||||
|
||||
/**
|
||||
* @var ArrayFilter
|
||||
*/
|
||||
private $arrayFilter;
|
||||
|
||||
public function __construct(NodeNameResolver $nodeNameResolver, ArrayFilter $arrayFilter)
|
||||
{
|
||||
$this->nodeNameResolver = $nodeNameResolver;
|
||||
$this->arrayFilter = $arrayFilter;
|
||||
}
|
||||
|
||||
public function check(RenameValueObjectInterface $renameValueObject): bool
|
||||
{
|
||||
$conflictingPropertyNames = $this->resolve($renameValueObject->getClassLike());
|
||||
return in_array($renameValueObject->getExpectedName(), $conflictingPropertyNames, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ClassLike $node
|
||||
* @return string[]
|
||||
*/
|
||||
public function resolve(Node $node): array
|
||||
{
|
||||
$expectedNames = [];
|
||||
foreach ($node->getProperties() as $property) {
|
||||
$expectedName = $this->expectedNameResolver->resolve($property);
|
||||
if ($expectedName === null) {
|
||||
/** @var string $expectedName */
|
||||
$expectedName = $this->nodeNameResolver->getName($property);
|
||||
}
|
||||
|
||||
$expectedNames[] = $expectedName;
|
||||
}
|
||||
|
||||
return $this->arrayFilter->filterWithAtLeastTwoOccurences($expectedNames);
|
||||
}
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Naming\Guard\PropertyConflictingNameGuard;
|
||||
|
||||
use Rector\Naming\ExpectedNameResolver\BoolPropertyExpectedNameResolver;
|
||||
|
||||
final class BoolPropertyConflictingNameGuard extends AbstractPropertyConflictingNameGuard
|
||||
{
|
||||
/**
|
||||
* @required
|
||||
*/
|
||||
public function autowireBoolPropertyConflictingNameGuard(
|
||||
BoolPropertyExpectedNameResolver $boolPropertyExpectedNameResolver
|
||||
): void {
|
||||
$this->expectedNameResolver = $boolPropertyExpectedNameResolver;
|
||||
}
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Naming\Guard\PropertyConflictingNameGuard;
|
||||
|
||||
use Rector\Naming\ExpectedNameResolver\MatchPropertyTypeExpectedNameResolver;
|
||||
|
||||
final class MatchPropertyTypeConflictingNameGuard extends AbstractPropertyConflictingNameGuard
|
||||
{
|
||||
/**
|
||||
* @required
|
||||
*/
|
||||
public function autowireMatchPropertyTypePropertyConflictingNameGuard(
|
||||
MatchPropertyTypeExpectedNameResolver $matchPropertyTypeExpectedNameResolver
|
||||
): void {
|
||||
$this->expectedNameResolver = $matchPropertyTypeExpectedNameResolver;
|
||||
}
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Naming\Guard\PropertyConflictingNameGuard;
|
||||
|
||||
use Rector\Naming\ExpectedNameResolver\UnderscoreCamelCaseExpectedNameResolver;
|
||||
|
||||
final class UnderscoreCamelCaseConflictingNameGuard extends AbstractPropertyConflictingNameGuard
|
||||
{
|
||||
/**
|
||||
* @required
|
||||
*/
|
||||
public function autowireUnderscoreCamelCasePropertyConflictingNameGuard(
|
||||
UnderscoreCamelCaseExpectedNameResolver $underscoreCamelCaseExpectedNameResolver
|
||||
): void {
|
||||
$this->expectedNameResolver = $underscoreCamelCaseExpectedNameResolver;
|
||||
}
|
||||
}
|
27
rules/naming/src/Guard/RamseyUuidInterfaceGuard.php
Normal file
27
rules/naming/src/Guard/RamseyUuidInterfaceGuard.php
Normal file
@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Naming\Guard;
|
||||
|
||||
use Ramsey\Uuid\UuidInterface;
|
||||
use Rector\Naming\ValueObject\RenameValueObjectInterface;
|
||||
use Rector\NodeTypeResolver\NodeTypeResolver;
|
||||
|
||||
final class RamseyUuidInterfaceGuard implements GuardInterface
|
||||
{
|
||||
/**
|
||||
* @var NodeTypeResolver
|
||||
*/
|
||||
private $nodeTypeResolver;
|
||||
|
||||
public function __construct(NodeTypeResolver $nodeTypeResolver)
|
||||
{
|
||||
$this->nodeTypeResolver = $nodeTypeResolver;
|
||||
}
|
||||
|
||||
public function check(RenameValueObjectInterface $renameValueObject): bool
|
||||
{
|
||||
return $this->nodeTypeResolver->isObjectType($renameValueObject->getNode(), UuidInterface::class);
|
||||
}
|
||||
}
|
@ -7,7 +7,6 @@ namespace Rector\Naming\Naming;
|
||||
use PhpParser\Node\Expr\Assign;
|
||||
use PhpParser\Node\Expr\Closure;
|
||||
use PhpParser\Node\FunctionLike;
|
||||
use PhpParser\Node\Stmt\ClassLike;
|
||||
use PhpParser\Node\Stmt\ClassMethod;
|
||||
use PhpParser\Node\Stmt\Function_;
|
||||
use Rector\Core\PhpParser\Node\BetterNodeFinder;
|
||||
@ -53,25 +52,6 @@ final class ConflictingNameResolver
|
||||
$this->arrayFilter = $arrayFilter;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
public function resolveConflictingPropertyNames(ClassLike $classLike): array
|
||||
{
|
||||
$expectedNames = [];
|
||||
foreach ($classLike->getProperties() as $property) {
|
||||
$expectedName = $this->expectedNameResolver->resolveForProperty($property);
|
||||
if ($expectedName === null) {
|
||||
/** @var string $expectedName */
|
||||
$expectedName = $this->nodeNameResolver->getName($property);
|
||||
}
|
||||
|
||||
$expectedNames[] = $expectedName;
|
||||
}
|
||||
|
||||
return $this->arrayFilter->filterWithAtLeastTwoOccurences($expectedNames);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
|
@ -15,12 +15,10 @@ use PhpParser\Node\Expr\Variable;
|
||||
use PhpParser\Node\Name;
|
||||
use PhpParser\Node\Param;
|
||||
use PhpParser\Node\Stmt\Foreach_;
|
||||
use PhpParser\Node\Stmt\Property;
|
||||
use PHPStan\Type\ArrayType;
|
||||
use PHPStan\Type\MixedType;
|
||||
use PHPStan\Type\ObjectType;
|
||||
use PHPStan\Type\Type;
|
||||
use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfo;
|
||||
use Rector\NodeNameResolver\NodeNameResolver;
|
||||
use Rector\NodeTypeResolver\Node\AttributeKey;
|
||||
use Rector\NodeTypeResolver\NodeTypeResolver;
|
||||
@ -61,26 +59,6 @@ final class ExpectedNameResolver
|
||||
$this->nodeTypeResolver = $nodeTypeResolver;
|
||||
}
|
||||
|
||||
public function resolveForPropertyIfNotYet(Property $property): ?string
|
||||
{
|
||||
$expectedName = $this->resolveForProperty($property);
|
||||
if ($expectedName === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/** @var string $propertyName */
|
||||
$propertyName = $this->nodeNameResolver->getName($property);
|
||||
if ($this->endsWith($propertyName, $expectedName)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if ($this->nodeNameResolver->isName($property, $expectedName)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $expectedName;
|
||||
}
|
||||
|
||||
public function resolveForParamIfNotYet(Param $param): ?string
|
||||
{
|
||||
$expectedName = $this->resolveForParam($param);
|
||||
@ -117,26 +95,6 @@ final class ExpectedNameResolver
|
||||
return $expectedName->getName();
|
||||
}
|
||||
|
||||
public function resolveForProperty(Property $property): ?string
|
||||
{
|
||||
/** @var PhpDocInfo|null $phpDocInfo */
|
||||
$phpDocInfo = $property->getAttribute(AttributeKey::PHP_DOC_INFO);
|
||||
if ($phpDocInfo === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if ($this->nodeTypeResolver->isPropertyBoolean($property)) {
|
||||
return $this->propertyNaming->getExpectedNameFromBooleanPropertyType($property);
|
||||
}
|
||||
|
||||
$expectedName = $this->propertyNaming->getExpectedNameFromType($phpDocInfo->getVarType());
|
||||
if ($expectedName === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $expectedName->getName();
|
||||
}
|
||||
|
||||
public function resolveForAssignNonNew(Assign $assign): ?string
|
||||
{
|
||||
if ($assign->expr instanceof New_) {
|
||||
|
@ -1,82 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Naming;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Expr\PropertyFetch;
|
||||
use PhpParser\Node\Identifier;
|
||||
use PhpParser\Node\Stmt\Property;
|
||||
use PhpParser\Node\VarLikeIdentifier;
|
||||
use Rector\Core\PhpParser\NodeTraverser\CallableNodeTraverser;
|
||||
use Rector\Naming\Guard\BreakingVariableRenameGuard;
|
||||
use Rector\Naming\ValueObject\PropertyRename;
|
||||
use Rector\NodeNameResolver\NodeNameResolver;
|
||||
|
||||
final class PropertyRenamer
|
||||
{
|
||||
/**
|
||||
* @var CallableNodeTraverser
|
||||
*/
|
||||
private $callableNodeTraverser;
|
||||
|
||||
/**
|
||||
* @var BreakingVariableRenameGuard
|
||||
*/
|
||||
private $breakingVariableRenameGuard;
|
||||
|
||||
/**
|
||||
* @var NodeNameResolver
|
||||
*/
|
||||
private $nodeNameResolver;
|
||||
|
||||
public function __construct(
|
||||
CallableNodeTraverser $callableNodeTraverser,
|
||||
BreakingVariableRenameGuard $breakingVariableRenameGuard,
|
||||
NodeNameResolver $nodeNameResolver
|
||||
) {
|
||||
$this->callableNodeTraverser = $callableNodeTraverser;
|
||||
$this->breakingVariableRenameGuard = $breakingVariableRenameGuard;
|
||||
$this->nodeNameResolver = $nodeNameResolver;
|
||||
}
|
||||
|
||||
public function rename(PropertyRename $propertyRename): ?Property
|
||||
{
|
||||
if ($this->breakingVariableRenameGuard->shouldSkipProperty($propertyRename)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if ($this->areNamesDifferent($propertyRename)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$onlyPropertyProperty = $propertyRename->getPropertyProperty();
|
||||
$onlyPropertyProperty->name = new VarLikeIdentifier($propertyRename->getExpectedName());
|
||||
$this->renamePropertyFetchesInClass($propertyRename);
|
||||
|
||||
return $propertyRename->getProperty();
|
||||
}
|
||||
|
||||
private function areNamesDifferent(PropertyRename $propertyRename): bool
|
||||
{
|
||||
return $propertyRename->getCurrentName() === $propertyRename->getExpectedName();
|
||||
}
|
||||
|
||||
private function renamePropertyFetchesInClass(PropertyRename $propertyRename): void
|
||||
{
|
||||
// 1. replace property fetch rename in whole class
|
||||
$this->callableNodeTraverser->traverseNodesWithCallable(
|
||||
[$propertyRename->getClassLike()],
|
||||
function (Node $node) use ($propertyRename): ?PropertyFetch {
|
||||
if (! $this->nodeNameResolver->isLocalPropertyFetchNamed($node, $propertyRename->getCurrentName())) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/** @var PropertyFetch $node */
|
||||
$node->name = new Identifier($propertyRename->getExpectedName());
|
||||
return $node;
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
140
rules/naming/src/PropertyRenamer/AbstractPropertyRenamer.php
Normal file
140
rules/naming/src/PropertyRenamer/AbstractPropertyRenamer.php
Normal file
@ -0,0 +1,140 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Naming\PropertyRenamer;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Expr\PropertyFetch;
|
||||
use PhpParser\Node\Expr\StaticPropertyFetch;
|
||||
use PhpParser\Node\Identifier;
|
||||
use PhpParser\Node\Stmt\Property;
|
||||
use PhpParser\Node\VarLikeIdentifier;
|
||||
use Rector\Core\PhpParser\NodeTraverser\CallableNodeTraverser;
|
||||
use Rector\Naming\Guard\DateTimeAtNamingConventionGuard;
|
||||
use Rector\Naming\Guard\GuardInterface;
|
||||
use Rector\Naming\Guard\HasMagicGetSetGuard;
|
||||
use Rector\Naming\Guard\NotPrivatePropertyGuard;
|
||||
use Rector\Naming\Guard\RamseyUuidInterfaceGuard;
|
||||
use Rector\Naming\RenameGuard\PropertyRenameGuard;
|
||||
use Rector\Naming\RenameGuard\RenameGuardInterface;
|
||||
use Rector\Naming\ValueObject\PropertyRename;
|
||||
use Rector\NodeNameResolver\NodeNameResolver;
|
||||
|
||||
abstract class AbstractPropertyRenamer
|
||||
{
|
||||
/**
|
||||
* @var RenameGuardInterface
|
||||
*/
|
||||
protected $propertyRenameGuard;
|
||||
|
||||
/**
|
||||
* @var GuardInterface
|
||||
*/
|
||||
protected $conflictingPropertyNameGuard;
|
||||
|
||||
/**
|
||||
* @var CallableNodeTraverser
|
||||
*/
|
||||
private $callableNodeTraverser;
|
||||
|
||||
/**
|
||||
* @var NodeNameResolver
|
||||
*/
|
||||
private $nodeNameResolver;
|
||||
|
||||
/**
|
||||
* @var NotPrivatePropertyGuard
|
||||
*/
|
||||
private $notPrivatePropertyGuard;
|
||||
|
||||
/**
|
||||
* @var RamseyUuidInterfaceGuard
|
||||
*/
|
||||
private $ramseyUuidInterfaceGuard;
|
||||
|
||||
/**
|
||||
* @var DateTimeAtNamingConventionGuard
|
||||
*/
|
||||
private $dateTimeAtNamingConventionGuard;
|
||||
|
||||
/**
|
||||
* @var HasMagicGetSetGuard
|
||||
*/
|
||||
private $hasMagicGetSetGuard;
|
||||
|
||||
/**
|
||||
* @required
|
||||
*/
|
||||
public function autowireAbstractPropertyRenamer(
|
||||
CallableNodeTraverser $callableNodeTraverser,
|
||||
NodeNameResolver $nodeNameResolver,
|
||||
NotPrivatePropertyGuard $notPrivatePropertyGuard,
|
||||
RamseyUuidInterfaceGuard $ramseyUuidInterfaceGuard,
|
||||
DateTimeAtNamingConventionGuard $dateTimeAtNamingConventionGuard,
|
||||
PropertyRenameGuard $propertyRenameGuard,
|
||||
HasMagicGetSetGuard $hasMagicGetSetGuard
|
||||
): void {
|
||||
$this->callableNodeTraverser = $callableNodeTraverser;
|
||||
$this->nodeNameResolver = $nodeNameResolver;
|
||||
$this->notPrivatePropertyGuard = $notPrivatePropertyGuard;
|
||||
$this->ramseyUuidInterfaceGuard = $ramseyUuidInterfaceGuard;
|
||||
$this->dateTimeAtNamingConventionGuard = $dateTimeAtNamingConventionGuard;
|
||||
$this->propertyRenameGuard = $propertyRenameGuard;
|
||||
$this->hasMagicGetSetGuard = $hasMagicGetSetGuard;
|
||||
}
|
||||
|
||||
public function rename(PropertyRename $propertyRename): ?Property
|
||||
{
|
||||
if ($this->areNamesDifferent($propertyRename)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if ($this->propertyRenameGuard->shouldSkip($propertyRename, [
|
||||
$this->notPrivatePropertyGuard,
|
||||
$this->conflictingPropertyNameGuard,
|
||||
$this->ramseyUuidInterfaceGuard,
|
||||
$this->dateTimeAtNamingConventionGuard,
|
||||
$this->hasMagicGetSetGuard,
|
||||
])) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$onlyPropertyProperty = $propertyRename->getPropertyProperty();
|
||||
$onlyPropertyProperty->name = new VarLikeIdentifier($propertyRename->getExpectedName());
|
||||
$this->renamePropertyFetchesInClass($propertyRename);
|
||||
|
||||
return $propertyRename->getNode();
|
||||
}
|
||||
|
||||
private function areNamesDifferent(PropertyRename $propertyRename): bool
|
||||
{
|
||||
return $propertyRename->getCurrentName() === $propertyRename->getExpectedName();
|
||||
}
|
||||
|
||||
private function renamePropertyFetchesInClass(PropertyRename $propertyRename): void
|
||||
{
|
||||
// 1. replace property fetch rename in whole class
|
||||
$this->callableNodeTraverser->traverseNodesWithCallable(
|
||||
[$propertyRename->getClassLike()],
|
||||
function (Node $node) use ($propertyRename): ?Node {
|
||||
if ($this->nodeNameResolver->isLocalPropertyFetchNamed($node, $propertyRename->getCurrentName())) {
|
||||
/** @var PropertyFetch $node */
|
||||
$node->name = new Identifier($propertyRename->getExpectedName());
|
||||
return $node;
|
||||
}
|
||||
|
||||
if ($this->nodeNameResolver->isLocalStaticPropertyFetchNamed(
|
||||
$node,
|
||||
$propertyRename->getCurrentName()
|
||||
)) {
|
||||
/** @var StaticPropertyFetch $node */
|
||||
$node->name = new VarLikeIdentifier($propertyRename->getExpectedName());
|
||||
return $node;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
15
rules/naming/src/PropertyRenamer/BoolPropertyRenamer.php
Normal file
15
rules/naming/src/PropertyRenamer/BoolPropertyRenamer.php
Normal file
@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Naming\PropertyRenamer;
|
||||
|
||||
use Rector\Naming\Guard\PropertyConflictingNameGuard\BoolPropertyConflictingNameGuard;
|
||||
|
||||
final class BoolPropertyRenamer extends AbstractPropertyRenamer
|
||||
{
|
||||
public function __construct(BoolPropertyConflictingNameGuard $boolPropertyConflictingNameGuard)
|
||||
{
|
||||
$this->conflictingPropertyNameGuard = $boolPropertyConflictingNameGuard;
|
||||
}
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Naming\PropertyRenamer;
|
||||
|
||||
use Rector\Naming\Guard\PropertyConflictingNameGuard\MatchPropertyTypeConflictingNameGuard;
|
||||
|
||||
final class MatchTypePropertyRenamer extends AbstractPropertyRenamer
|
||||
{
|
||||
public function __construct(MatchPropertyTypeConflictingNameGuard $matchPropertyTypeConflictingNameGuard)
|
||||
{
|
||||
$this->conflictingPropertyNameGuard = $matchPropertyTypeConflictingNameGuard;
|
||||
}
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Naming\PropertyRenamer;
|
||||
|
||||
use Rector\Naming\Guard\PropertyConflictingNameGuard\UnderscoreCamelCaseConflictingNameGuard;
|
||||
|
||||
final class UnderscoreCamelCasePropertyRenamer extends AbstractPropertyRenamer
|
||||
{
|
||||
public function __construct(UnderscoreCamelCaseConflictingNameGuard $underscoreCamelCaseConflictingNameGuard)
|
||||
{
|
||||
$this->conflictingPropertyNameGuard = $underscoreCamelCaseConflictingNameGuard;
|
||||
}
|
||||
}
|
@ -11,7 +11,8 @@ use PhpParser\Node\Stmt\Interface_;
|
||||
use Rector\Core\Rector\AbstractRector;
|
||||
use Rector\Core\RectorDefinition\CodeSample;
|
||||
use Rector\Core\RectorDefinition\RectorDefinition;
|
||||
use Rector\Naming\PropertyRenamer;
|
||||
use Rector\Naming\ExpectedNameResolver\MatchPropertyTypeExpectedNameResolver;
|
||||
use Rector\Naming\PropertyRenamer\MatchTypePropertyRenamer;
|
||||
use Rector\Naming\ValueObjectFactory\PropertyRenameFactory;
|
||||
|
||||
/**
|
||||
@ -24,20 +25,29 @@ final class RenamePropertyToMatchTypeRector extends AbstractRector
|
||||
*/
|
||||
private $hasChanged = false;
|
||||
|
||||
/**
|
||||
* @var PropertyRenamer
|
||||
*/
|
||||
private $propertyRenamer;
|
||||
|
||||
/**
|
||||
* @var PropertyRenameFactory
|
||||
*/
|
||||
private $propertyRenameFactory;
|
||||
|
||||
public function __construct(PropertyRenamer $propertyRenamer, PropertyRenameFactory $propertyRenameFactory)
|
||||
{
|
||||
$this->propertyRenamer = $propertyRenamer;
|
||||
/**
|
||||
* @var MatchTypePropertyRenamer
|
||||
*/
|
||||
private $matchTypePropertyRenamer;
|
||||
|
||||
/**
|
||||
* @var MatchPropertyTypeExpectedNameResolver
|
||||
*/
|
||||
private $matchPropertyTypeExpectedNameResolver;
|
||||
|
||||
public function __construct(
|
||||
MatchTypePropertyRenamer $matchTypePropertyRenamer,
|
||||
PropertyRenameFactory $propertyRenameFactory,
|
||||
MatchPropertyTypeExpectedNameResolver $matchPropertyTypeExpectedNameResolver
|
||||
) {
|
||||
$this->propertyRenameFactory = $propertyRenameFactory;
|
||||
$this->matchTypePropertyRenamer = $matchTypePropertyRenamer;
|
||||
$this->matchPropertyTypeExpectedNameResolver = $matchPropertyTypeExpectedNameResolver;
|
||||
}
|
||||
|
||||
public function getDefinition(): RectorDefinition
|
||||
@ -102,12 +112,15 @@ CODE_SAMPLE
|
||||
private function refactorClassProperties(ClassLike $classLike): void
|
||||
{
|
||||
foreach ($classLike->getProperties() as $property) {
|
||||
$propertyRename = $this->propertyRenameFactory->create($property);
|
||||
$propertyRename = $this->propertyRenameFactory->create(
|
||||
$property,
|
||||
$this->matchPropertyTypeExpectedNameResolver
|
||||
);
|
||||
if ($propertyRename === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($this->propertyRenamer->rename($propertyRename) !== null) {
|
||||
if ($this->matchTypePropertyRenamer->rename($propertyRename) !== null) {
|
||||
$this->hasChanged = true;
|
||||
}
|
||||
}
|
||||
|
@ -9,7 +9,8 @@ use PhpParser\Node\Stmt\Property;
|
||||
use Rector\Core\Rector\AbstractRector;
|
||||
use Rector\Core\RectorDefinition\CodeSample;
|
||||
use Rector\Core\RectorDefinition\RectorDefinition;
|
||||
use Rector\Naming\PropertyRenamer;
|
||||
use Rector\Naming\ExpectedNameResolver\BoolPropertyExpectedNameResolver;
|
||||
use Rector\Naming\PropertyRenamer\BoolPropertyRenamer;
|
||||
use Rector\Naming\ValueObjectFactory\PropertyRenameFactory;
|
||||
|
||||
/**
|
||||
@ -18,20 +19,29 @@ use Rector\Naming\ValueObjectFactory\PropertyRenameFactory;
|
||||
*/
|
||||
final class MakeBoolPropertyRespectIsHasWasMethodNamingRector extends AbstractRector
|
||||
{
|
||||
/**
|
||||
* @var PropertyRenamer
|
||||
*/
|
||||
private $propertyRenamer;
|
||||
|
||||
/**
|
||||
* @var PropertyRenameFactory
|
||||
*/
|
||||
private $propertyRenameFactory;
|
||||
|
||||
public function __construct(PropertyRenamer $propertyRenamer, PropertyRenameFactory $propertyRenameFactory)
|
||||
{
|
||||
$this->propertyRenamer = $propertyRenamer;
|
||||
/**
|
||||
* @var BoolPropertyRenamer
|
||||
*/
|
||||
private $boolPropertyRenamer;
|
||||
|
||||
/**
|
||||
* @var BoolPropertyExpectedNameResolver
|
||||
*/
|
||||
private $boolPropertyExpectedNameResolver;
|
||||
|
||||
public function __construct(
|
||||
BoolPropertyRenamer $boolPropertyRenamer,
|
||||
PropertyRenameFactory $propertyRenameFactory,
|
||||
BoolPropertyExpectedNameResolver $boolPropertyExpectedNameResolver
|
||||
) {
|
||||
$this->propertyRenameFactory = $propertyRenameFactory;
|
||||
$this->boolPropertyRenamer = $boolPropertyRenamer;
|
||||
$this->boolPropertyExpectedNameResolver = $boolPropertyExpectedNameResolver;
|
||||
}
|
||||
|
||||
public function getDefinition(): RectorDefinition
|
||||
@ -85,12 +95,13 @@ CODE_SAMPLE
|
||||
return null;
|
||||
}
|
||||
|
||||
$propertyRename = $this->propertyRenameFactory->create($node);
|
||||
$propertyRename = $this->propertyRenameFactory->create($node, $this->boolPropertyExpectedNameResolver);
|
||||
if ($propertyRename === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if ($this->propertyRenamer->rename($propertyRename) === null) {
|
||||
// dd($propertyRename->getClassLike());
|
||||
if ($this->boolPropertyRenamer->rename($propertyRename) === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,111 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Naming\Rector\Property;
|
||||
|
||||
use Nette\Utils\Strings;
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Stmt\Property;
|
||||
use Rector\Core\Rector\AbstractRector;
|
||||
use Rector\Core\RectorDefinition\CodeSample;
|
||||
use Rector\Core\RectorDefinition\RectorDefinition;
|
||||
use Rector\Naming\ExpectedNameResolver\UnderscoreCamelCaseExpectedNameResolver;
|
||||
use Rector\Naming\PropertyRenamer\UnderscoreCamelCasePropertyRenamer;
|
||||
use Rector\Naming\ValueObjectFactory\PropertyRenameFactory;
|
||||
|
||||
/**
|
||||
* @see \Rector\Naming\Tests\Rector\Property\UnderscoreToCamelCasePropertyNameRector\UnderscoreToCamelCasePropertyNameRectorTest
|
||||
*/
|
||||
final class UnderscoreToCamelCasePropertyNameRector extends AbstractRector
|
||||
{
|
||||
/**
|
||||
* @var PropertyRenameFactory
|
||||
*/
|
||||
private $propertyRenameFactory;
|
||||
|
||||
/**
|
||||
* @var UnderscoreCamelCasePropertyRenamer
|
||||
*/
|
||||
private $underscoreCamelCasePropertyRenamer;
|
||||
|
||||
/**
|
||||
* @var UnderscoreCamelCaseExpectedNameResolver
|
||||
*/
|
||||
private $underscoreCamelCaseExpectedNameResolver;
|
||||
|
||||
public function __construct(
|
||||
UnderscoreCamelCasePropertyRenamer $underscoreCamelCasePropertyRenamer,
|
||||
PropertyRenameFactory $propertyRenameFactory,
|
||||
UnderscoreCamelCaseExpectedNameResolver $underscoreCamelCaseExpectedNameResolver
|
||||
) {
|
||||
$this->underscoreCamelCasePropertyRenamer = $underscoreCamelCasePropertyRenamer;
|
||||
$this->propertyRenameFactory = $propertyRenameFactory;
|
||||
$this->underscoreCamelCaseExpectedNameResolver = $underscoreCamelCaseExpectedNameResolver;
|
||||
}
|
||||
|
||||
public function getDefinition(): RectorDefinition
|
||||
{
|
||||
return new RectorDefinition('Change under_score names to camelCase', [
|
||||
new CodeSample(
|
||||
<<<'CODE_SAMPLE'
|
||||
final class SomeClass
|
||||
{
|
||||
public $property_name;
|
||||
|
||||
public function run($a)
|
||||
{
|
||||
$this->property_name = 5;
|
||||
}
|
||||
}
|
||||
CODE_SAMPLE
|
||||
,
|
||||
<<<'CODE_SAMPLE'
|
||||
final class SomeClass
|
||||
{
|
||||
public $propertyName;
|
||||
|
||||
public function run($a)
|
||||
{
|
||||
$this->propertyName = 5;
|
||||
}
|
||||
}
|
||||
CODE_SAMPLE
|
||||
),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
public function getNodeTypes(): array
|
||||
{
|
||||
return [Property::class];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Property $node
|
||||
*/
|
||||
public function refactor(Node $node): ?Node
|
||||
{
|
||||
$nodeName = $this->getName($node);
|
||||
if ($nodeName === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (! Strings::contains($nodeName, '_')) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$propertyRename = $this->propertyRenameFactory->create($node, $this->underscoreCamelCaseExpectedNameResolver);
|
||||
if ($propertyRename === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if ($this->underscoreCamelCasePropertyRenamer->rename($propertyRename) === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $node;
|
||||
}
|
||||
}
|
25
rules/naming/src/RenameGuard/PropertyRenameGuard.php
Normal file
25
rules/naming/src/RenameGuard/PropertyRenameGuard.php
Normal file
@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Naming\RenameGuard;
|
||||
|
||||
use Rector\Naming\Guard\GuardInterface;
|
||||
use Rector\Naming\ValueObject\RenameValueObjectInterface;
|
||||
|
||||
final class PropertyRenameGuard implements RenameGuardInterface
|
||||
{
|
||||
/**
|
||||
* @param GuardInterface[] $guards
|
||||
*/
|
||||
public function shouldSkip(RenameValueObjectInterface $renameValueObject, array $guards): bool
|
||||
{
|
||||
foreach ($guards as $guard) {
|
||||
if ($guard->check($renameValueObject)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
16
rules/naming/src/RenameGuard/RenameGuardInterface.php
Normal file
16
rules/naming/src/RenameGuard/RenameGuardInterface.php
Normal file
@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Naming\RenameGuard;
|
||||
|
||||
use Rector\Naming\Guard\GuardInterface;
|
||||
use Rector\Naming\ValueObject\RenameValueObjectInterface;
|
||||
|
||||
interface RenameGuardInterface
|
||||
{
|
||||
/**
|
||||
* @param GuardInterface[] $guards
|
||||
*/
|
||||
public function shouldSkip(RenameValueObjectInterface $renameValueObject, array $guards): bool;
|
||||
}
|
@ -4,11 +4,12 @@ declare(strict_types=1);
|
||||
|
||||
namespace Rector\Naming\ValueObject;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Stmt\ClassLike;
|
||||
use PhpParser\Node\Stmt\Property;
|
||||
use PhpParser\Node\Stmt\PropertyProperty;
|
||||
|
||||
final class PropertyRename
|
||||
final class PropertyRename implements RenameValueObjectInterface
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
@ -20,6 +21,11 @@ final class PropertyRename
|
||||
*/
|
||||
private $currentName;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $classLikeName;
|
||||
|
||||
/**
|
||||
* @var Property
|
||||
*/
|
||||
@ -36,20 +42,20 @@ final class PropertyRename
|
||||
private $propertyProperty;
|
||||
|
||||
public function __construct(
|
||||
Property $property,
|
||||
string $expectedName,
|
||||
string $currentName,
|
||||
ClassLike $classLike,
|
||||
PropertyProperty $propertyProperty
|
||||
Property $property, string $expectedName, string $currentName, ClassLike $classLike, string $classLikeName, PropertyProperty $propertyProperty
|
||||
) {
|
||||
$this->property = $property;
|
||||
$this->expectedName = $expectedName;
|
||||
$this->currentName = $currentName;
|
||||
$this->classLike = $classLike;
|
||||
$this->classLikeName = $classLikeName;
|
||||
$this->propertyProperty = $propertyProperty;
|
||||
}
|
||||
|
||||
public function getProperty(): Property
|
||||
/**
|
||||
* @return Property
|
||||
*/
|
||||
public function getNode(): Node
|
||||
{
|
||||
return $this->property;
|
||||
}
|
||||
@ -69,6 +75,11 @@ final class PropertyRename
|
||||
return $this->classLike;
|
||||
}
|
||||
|
||||
public function getClassLikeName(): string
|
||||
{
|
||||
return $this->classLikeName;
|
||||
}
|
||||
|
||||
public function getPropertyProperty(): PropertyProperty
|
||||
{
|
||||
return $this->propertyProperty;
|
||||
|
19
rules/naming/src/ValueObject/RenameValueObjectInterface.php
Normal file
19
rules/naming/src/ValueObject/RenameValueObjectInterface.php
Normal file
@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Naming\ValueObject;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Stmt\ClassLike;
|
||||
|
||||
interface RenameValueObjectInterface
|
||||
{
|
||||
public function getNode(): Node;
|
||||
|
||||
public function getCurrentName(): string;
|
||||
|
||||
public function getExpectedName(): string;
|
||||
|
||||
public function getClassLike(): ClassLike;
|
||||
}
|
@ -6,7 +6,7 @@ namespace Rector\Naming\ValueObjectFactory;
|
||||
|
||||
use PhpParser\Node\Stmt\Property;
|
||||
use Rector\Core\Exception\ShouldNotHappenException;
|
||||
use Rector\Naming\Naming\ExpectedNameResolver;
|
||||
use Rector\Naming\ExpectedNameResolver\ExpectedNameResolverInterface;
|
||||
use Rector\Naming\ValueObject\PropertyRename;
|
||||
use Rector\NodeNameResolver\NodeNameResolver;
|
||||
use Rector\NodeTypeResolver\Node\AttributeKey;
|
||||
@ -16,29 +16,23 @@ use Rector\NodeTypeResolver\Node\AttributeKey;
|
||||
*/
|
||||
final class PropertyRenameFactory
|
||||
{
|
||||
/**
|
||||
* @var ExpectedNameResolver
|
||||
*/
|
||||
private $expectedNameResolver;
|
||||
|
||||
/**
|
||||
* @var NodeNameResolver
|
||||
*/
|
||||
private $nodeNameResolver;
|
||||
|
||||
public function __construct(ExpectedNameResolver $expectedNameResolver, NodeNameResolver $nodeNameResolver)
|
||||
public function __construct(NodeNameResolver $nodeNameResolver)
|
||||
{
|
||||
$this->expectedNameResolver = $expectedNameResolver;
|
||||
$this->nodeNameResolver = $nodeNameResolver;
|
||||
}
|
||||
|
||||
public function create(Property $property): ?PropertyRename
|
||||
public function create(Property $property, ExpectedNameResolverInterface $expectedNameResolver): ?PropertyRename
|
||||
{
|
||||
if (count($property->props) !== 1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$expectedName = $this->expectedNameResolver->resolveForPropertyIfNotYet($property);
|
||||
$expectedName = $expectedNameResolver->resolveIfNotYet($property);
|
||||
if ($expectedName === null) {
|
||||
return null;
|
||||
}
|
||||
@ -47,9 +41,21 @@ final class PropertyRenameFactory
|
||||
|
||||
$propertyClassLike = $property->getAttribute(AttributeKey::CLASS_NODE);
|
||||
if ($propertyClassLike === null) {
|
||||
throw new ShouldNotHappenException("There shouldn't be a property without Class Node");
|
||||
throw new ShouldNotHappenException("There shouldn't be a property without AttributeKey::CLASS_NODE");
|
||||
}
|
||||
|
||||
return new PropertyRename($property, $expectedName, $currentName, $propertyClassLike, $property->props[0]);
|
||||
$propertyClassLikeName = $property->getAttribute(AttributeKey::CLASS_NAME);
|
||||
if ($propertyClassLikeName === null) {
|
||||
throw new ShouldNotHappenException("There shouldn't be a property without AttributeKey::CLASS_NAME");
|
||||
}
|
||||
|
||||
return new PropertyRename(
|
||||
$property,
|
||||
$expectedName,
|
||||
$currentName,
|
||||
$propertyClassLike,
|
||||
$propertyClassLikeName,
|
||||
$property->props[0]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -1,16 +1,16 @@
|
||||
<?php
|
||||
|
||||
namespace Rector\CodingStyle\Tests\Rector\Property\UnderscoreToCamelCasePropertyNameRector\Fixture;
|
||||
namespace Rector\Naming\Tests\Rector\Property\UnderscoreToCamelCasePropertyNameRector\Fixture;
|
||||
|
||||
final class Property
|
||||
{
|
||||
public $some_property;
|
||||
private $some_property;
|
||||
|
||||
public static $some_static_property;
|
||||
private static $some_static_property;
|
||||
|
||||
public $_first_and_multiple_underscore_property;
|
||||
private $_first_and_multiple_underscore_property;
|
||||
|
||||
public $_underscore;
|
||||
private $_underscore;
|
||||
|
||||
public function run()
|
||||
{
|
||||
@ -26,17 +26,17 @@ final class Property
|
||||
-----
|
||||
<?php
|
||||
|
||||
namespace Rector\CodingStyle\Tests\Rector\Property\UnderscoreToCamelCasePropertyNameRector\Fixture;
|
||||
namespace Rector\Naming\Tests\Rector\Property\UnderscoreToCamelCasePropertyNameRector\Fixture;
|
||||
|
||||
final class Property
|
||||
{
|
||||
public $someProperty;
|
||||
private $someProperty;
|
||||
|
||||
public static $someStaticProperty;
|
||||
private static $someStaticProperty;
|
||||
|
||||
public $firstAndMultipleUnderscoreProperty;
|
||||
private $firstAndMultipleUnderscoreProperty;
|
||||
|
||||
public $underscore;
|
||||
private $underscore;
|
||||
|
||||
public function run()
|
||||
{
|
@ -1,9 +1,11 @@
|
||||
<?php
|
||||
|
||||
namespace Rector\CodingStyle\Tests\Rector\PropertyProperty\UnderscoreToCamelCasePropertyNameRector\Fixture;
|
||||
namespace Rector\Naming\Tests\Rector\Property\UnderscoreToCamelCasePropertyNameRector\Fixture;
|
||||
|
||||
class SkipMagicGet
|
||||
{
|
||||
private $underscore_value;
|
||||
|
||||
public function get()
|
||||
{
|
||||
$this->underscore_value = 5;
|
@ -1,9 +1,11 @@
|
||||
<?php
|
||||
|
||||
namespace Rector\CodingStyle\Tests\Rector\PropertyProperty\UnderscoreToCamelCasePropertyNameRector\Fixture;
|
||||
namespace Rector\Naming\Tests\Rector\Property\UnderscoreToCamelCasePropertyNameRector\Fixture;
|
||||
|
||||
class SkipMagicSet
|
||||
{
|
||||
private $underscore_value;
|
||||
|
||||
public function set()
|
||||
{
|
||||
$this->underscore_value = 5;
|
@ -2,11 +2,11 @@
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\CodingStyle\Tests\Rector\PropertyProperty\UnderscoreToCamelCasePropertyNameRector;
|
||||
namespace Rector\Naming\Tests\Rector\Property\UnderscoreToCamelCasePropertyNameRector;
|
||||
|
||||
use Iterator;
|
||||
use Rector\CodingStyle\Rector\PropertyProperty\UnderscoreToCamelCasePropertyNameRector;
|
||||
use Rector\Core\Testing\PHPUnit\AbstractRectorTestCase;
|
||||
use Rector\Naming\Rector\Property\UnderscoreToCamelCasePropertyNameRector;
|
||||
use Symplify\SmartFileSystem\SmartFileInfo;
|
||||
|
||||
final class UnderscoreToCamelCasePropertyNameRectorTest extends AbstractRectorTestCase
|
@ -10,6 +10,7 @@ use Rector\Core\Exception\ShouldNotHappenException;
|
||||
use Rector\Core\HttpKernel\RectorKernel;
|
||||
use Rector\Core\PhpParser\Node\BetterNodeFinder;
|
||||
use Rector\FileSystemRector\Parser\FileInfoParser;
|
||||
use Rector\Naming\ExpectedNameResolver\MatchPropertyTypeExpectedNameResolver;
|
||||
use Rector\Naming\ValueObject\PropertyRename;
|
||||
use Rector\Naming\ValueObjectFactory\PropertyRenameFactory;
|
||||
use Symplify\PackageBuilder\Tests\AbstractKernelTestCase;
|
||||
@ -32,11 +33,20 @@ final class PropertyRenameFactoryTest extends AbstractKernelTestCase
|
||||
*/
|
||||
private $betterNodeFinder;
|
||||
|
||||
/**
|
||||
* @var MatchPropertyTypeExpectedNameResolver
|
||||
*/
|
||||
private $matchPropertyTypeExpectedNameResolver;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
$this->bootKernel(RectorKernel::class);
|
||||
|
||||
$this->propertyRenameFactory = self::$container->get(PropertyRenameFactory::class);
|
||||
$this->matchPropertyTypeExpectedNameResolver = self::$container->get(
|
||||
MatchPropertyTypeExpectedNameResolver::class
|
||||
);
|
||||
|
||||
$this->fileInfoParser = self::$container->get(FileInfoParser::class);
|
||||
$this->betterNodeFinder = self::$container->get(BetterNodeFinder::class);
|
||||
}
|
||||
@ -48,11 +58,14 @@ final class PropertyRenameFactoryTest extends AbstractKernelTestCase
|
||||
{
|
||||
$property = $this->getPropertyFromFileInfo($fileInfoWithProperty);
|
||||
|
||||
$actualPropertyRename = $this->propertyRenameFactory->create($property);
|
||||
$actualPropertyRename = $this->propertyRenameFactory->create(
|
||||
$property,
|
||||
$this->matchPropertyTypeExpectedNameResolver
|
||||
);
|
||||
$this->assertNotNull($actualPropertyRename);
|
||||
|
||||
/** @var PropertyRename $actualPropertyRename */
|
||||
$this->assertSame($property, $actualPropertyRename->getProperty());
|
||||
$this->assertSame($property, $actualPropertyRename->getNode());
|
||||
$this->assertSame($expectedName, $actualPropertyRename->getExpectedName());
|
||||
$this->assertSame($currentName, $actualPropertyRename->getCurrentName());
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user