Skip to content

Commit 2ebec01

Browse files
committed
fix(rename): Enhance renaming logic for class constants and methods
- Introduce a renamer function that handles class constants and methods with '::' syntax. - Implement camel case and snake case transformations based on context. - Ensure proper renaming of class names and their associated constants or methods.
1 parent 379d638 commit 2ebec01

File tree

7 files changed

+160
-24
lines changed

7 files changed

+160
-24
lines changed

README.md

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,124 @@ return RectorConfig::configure()
6666
]);
6767
```
6868

69+
### Example of RenameToConventionalCaseNameRector
70+
71+
```diff
72+
/** @noinspection ALL */
73+
// @formatter:off
74+
// phpcs:ignoreFile
75+
76+
// lower snake
77+
-use function functionName;
78+
-function functionName(){}
79+
-functionName();
80+
-call_user_func('functionName');
81+
-call_user_func_array('functionName', []);
82+
-function_exists('functionName');
83+
+use function function_name;
84+
+function function_name(){}
85+
+\function_name();
86+
+call_user_func('function_name');
87+
+call_user_func_array('function_name', []);
88+
+function_exists('function_name');
89+
90+
// ucfirst camel
91+
// #[attribute_name()]
92+
-class class_name{}
93+
+class ClassName{}
94+
// enum enum_name{}
95+
// enum Enum{case case_name;}
96+
-interface interface_name{}
97+
-trait trait_name{}
98+
-class Foo extends class_name implements interface_name{}
99+
-class_name::$property;
100+
-class_name::CONST;
101+
-class_name::method();
102+
+interface InterfaceName{}
103+
+trait TraitName{}
104+
+class Foo extends \ClassName implements \InterfaceName{}
105+
+\ClassName::$property;
106+
+\ClassName::CONST;
107+
+\ClassName::method();
108+
// enum Enum implements interface_name{}
109+
-use class_name;
110+
-use trait_name;
111+
-class_alias('class_name', 'alias_class_name');
112+
-class_alias($className, 'alias_class_name');
113+
-class_exists('class_name');
114+
-class_implements('class_name');
115+
-class_parents('class_name');
116+
-class_uses('class_name');
117+
-enum_exists('enum_name');
118+
-get_class_methods('class_name');
119+
-get_class_vars('class_name');
120+
-get_parent_class('class_name');
121+
-interface_exists('interface_name');
122+
-is_subclass_of('class_name', 'parent_class_name');
123+
-is_subclass_of($className, 'parent_class_name');
124+
-trait_exists('trait_name', true);
125+
+use ClassName;
126+
+use TraitName;
127+
+class_alias('ClassName', 'AliasClassName');
128+
+class_alias($className, 'AliasClassName');
129+
+class_exists('ClassName');
130+
+class_implements('ClassName');
131+
+class_parents('ClassName');
132+
+class_uses('ClassName');
133+
+enum_exists('EnumName');
134+
+get_class_methods('ClassName');
135+
+get_class_vars('ClassName');
136+
+get_parent_class('ClassName');
137+
+interface_exists('InterfaceName');
138+
+is_subclass_of('ClassName', 'ParentClassName');
139+
+is_subclass_of($className, 'ParentClassName');
140+
+trait_exists('TraitName', true);
141+
142+
// upper snake
143+
-use const constName;
144+
-class Foo{public const constName = 'const';}
145+
-Foo::constName;
146+
-define('constName', 'const');
147+
-defined('constName');
148+
-constant('constName');
149+
-constant('Foo::constName');
150+
-constName;
151+
+use const CONST_NAME;
152+
+class Foo{public const CONST_NAME = 'const';}
153+
+Foo::CONST_NAME;
154+
+define('CONST_NAME', 'const');
155+
+defined('CONST_NAME');
156+
+constant('CONST_NAME');
157+
+constant('Foo::CONST_NAME');
158+
+\CONST_NAME;
159+
160+
// lcfirst camel
161+
-$var_name;
162+
-$object->method_name();
163+
-$object->property_name;
164+
-call_user_method('method_name', $object);
165+
-call_user_method_array('method_name', $object);
166+
-class Foo{public $property_name;}
167+
-class Foo{public function method_name(){}}
168+
-class Foo{public int $property_name;}
169+
-Foo::$property_name;
170+
-Foo::method_name();
171+
-method_exists($object, 'method_name');
172+
-property_exists($object, 'property_name');
173+
+$varName;
174+
+$object->methodName();
175+
+$object->propertyName;
176+
+call_user_method('methodName', $object);
177+
+call_user_method_array('methodName', $object);
178+
+class Foo{public $propertyName;}
179+
+class Foo{public function methodName(){}}
180+
+class Foo{public int $propertyName;}
181+
+Foo::$propertyName;
182+
+Foo::methodName();
183+
+method_exists($object, 'methodName');
184+
+property_exists($object, 'propertyName');
185+
```
186+
69187
## Composer scripts
70188

71189
```shell

baselines/loader.neon

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# total 11 errors
1+
# total 12 errors
22

33
includes:
44
- complexity.functionLike.neon
Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,13 @@
1-
# total 1 error
1+
# total 2 errors
22

33
parameters:
44
ignoreErrors:
55
-
66
message: '#^Instead of using Rector rule to setAttribute\("start_and_end"\) to be used later, create a service extending "DecoratingNodeVisitorInterface"\. This ensures attribute decoration and node changes are in 2 separated steps\.$#'
77
count: 1
88
path: ../src/Rector/FunctionLike/RenameGarbageParamNameRector.php
9+
10+
-
11+
message: '#^Instead of using Rector rule to setAttribute\("scope"\) to be used later, create a service extending "DecoratingNodeVisitorInterface"\. This ensures attribute decoration and node changes are in 2 separated steps\.$#'
12+
count: 1
13+
path: ../src/Rector/Name/RenameToConventionalCaseNameRector.php

docs/rules-overview.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -420,7 +420,7 @@ Rename to conventional case name
420420
+define('CONST_NAME', 'const');
421421
+defined('CONST_NAME');
422422
+constant('CONST_NAME');
423-
+constant('FOO::CONST_NAME');
423+
+constant('Foo::CONST_NAME');
424424
+\CONST_NAME;
425425

426426
// lcfirst camel

rector.php

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
use Rector\DowngradePhp85\Rector\FuncCall\DowngradeArrayFirstLastRector;
4141
use Rector\EarlyReturn\Rector\If_\ChangeOrIfContinueToMultiContinueRector;
4242
use Rector\EarlyReturn\Rector\Return_\ReturnBinaryOrToEarlyReturnRector;
43+
use Rector\Naming\Rector\Assign\RenameVariableToMatchMethodCallReturnTypeRector;
4344
use Rector\Naming\Rector\ClassMethod\RenameParamToMatchTypeRector;
4445
use Rector\Naming\Rector\ClassMethod\RenameVariableToMatchNewTypeRector;
4546
use Rector\Php73\Rector\FuncCall\JsonThrowOnErrorRector;
@@ -71,7 +72,7 @@
7172
// ->withoutParallel()
7273
->withParallel()
7374
// ->withImportNames(importDocBlockNames: false, importShortClasses: false)
74-
// ->withImportNames(true, false, false)
75+
->withImportNames(true, false, false)
7576
// ->withImportNames(importNames: false)
7677
// ->withEditorUrl()
7778
->withFluentCallNewLine()
@@ -196,6 +197,9 @@ classes(static fn (string $class): bool => str_starts_with($class, 'Guanguans\Re
196197
RenameParamToMatchTypeRector::class => [
197198
__DIR__.'/src/Rector/*Rector.php',
198199
],
200+
RenameVariableToMatchMethodCallReturnTypeRector::class => [
201+
__DIR__.'/src/Rector/Name/RenameToConventionalCaseNameRector.php',
202+
],
199203
RenameVariableToMatchNewTypeRector::class => [
200204
__DIR__.'/src/Rector/Namespace_/RemoveNamespaceRector.php',
201205
],

src/Rector/Name/RenameToConventionalCaseNameRector.php

Lines changed: 28 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -351,7 +351,7 @@ class Foo{public const CONST_NAME = 'const';}
351351
define('CONST_NAME', 'const');
352352
defined('CONST_NAME');
353353
constant('CONST_NAME');
354-
constant('FOO::CONST_NAME');
354+
constant('Foo::CONST_NAME');
355355
\CONST_NAME;
356356
357357
// lcfirst camel
@@ -759,20 +759,34 @@ private function shouldLcfirstCamelName(Node $node): bool
759759
*/
760760
private function wrapRenamer(callable $renamer, Node $node): \Closure
761761
{
762-
return fn (string $name): string => $renamer(
763-
(function (string $name) use ($node): string {
764-
if (Str::is($this->except, $name)) {
765-
throw new RectorErrorException($this, "The name [$name] is skipped.", $node->getAttributes());
766-
}
762+
return function (string $name) use ($node, $renamer): string {
763+
if (str_contains($name, '::')) {
764+
[$className, $constantOrMethodName] = Str::of($name)
765+
->explode('::', 2)
766+
->map(fn (string $part): string => $this->sanitizeName($part, $node))
767+
->all();
767768

768-
// if the name is all uppercase letters, convert it to lowercase letters.
769-
if (preg_match('/^[A-Z_]+$/', $name)) {
770-
return Str::lower($name);
771-
}
769+
$newClassName = Str::of($className)->camel()->ucfirst();
772770

773-
return $name;
774-
})($name)
775-
);
771+
$newConstOrMethodName = $this->isNames($node, ['define', 'defined', 'constant'])
772+
? Str::of($constantOrMethodName)->snake()->upper()
773+
: Str::of($constantOrMethodName)->camel()->pipe('lcfirst');
774+
775+
return "$newClassName::$newConstOrMethodName";
776+
}
777+
778+
return $renamer($this->sanitizeName($name, $node));
779+
};
780+
}
781+
782+
private function sanitizeName(string $name, Node $node): string
783+
{
784+
if (Str::is($this->except, $name)) {
785+
throw new RectorErrorException($this, "The name [$name] is skipped.", $node->getAttributes());
786+
}
787+
788+
// if the name is all uppercase letters, convert it to lowercase letters.
789+
return ctype_upper(preg_replace('/[^a-zA-Z]/', '', $name)) ? Str::lower($name) : $name;
776790
}
777791

778792
private function renameFuncCallIndexStringArg(Arg $argNode, callable $renamer): bool
@@ -782,12 +796,7 @@ private function renameFuncCallIndexStringArg(Arg $argNode, callable $renamer):
782796

783797
$newValue = Str::of($stringNode->value)
784798
->explode('\\')
785-
->pipe(
786-
static fn (Collection $collection): string => $collection
787-
->slice(0, -1)
788-
->push($renamer($collection->last()))
789-
->implode('\\')
790-
);
799+
->pipe(static fn (Collection $parts): string => $parts->slice(0, -1)->push($renamer($parts->last()))->implode('\\'));
791800
\assert(\is_string($newValue));
792801

793802
if ($newValue !== $stringNode->value) {

tests/Rector/Name/RenameToConventionalCaseNameRector/Fixture/fixture.php.inc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ Foo::CONST_NAME;
117117
define('CONST_NAME', 'const');
118118
defined('CONST_NAME');
119119
constant('CONST_NAME');
120-
constant('FOO::CONST_NAME');
120+
constant('Foo::CONST_NAME');
121121
\CONST_NAME;
122122

123123
// lcfirst camel

0 commit comments

Comments
 (0)