1515
1616use PhpParser \Comment \Doc ;
1717use PhpParser \Node ;
18+ use PhpParser \Node \Expr \Closure ;
1819use PhpParser \Node \Expr \Variable ;
20+ use PhpParser \Node \FunctionLike ;
1921use PhpParser \Node \Stmt \ClassMethod ;
2022use PhpParser \Node \Stmt \Function_ ;
23+ use PhpParser \Node \Stmt \Namespace_ ;
2124use Rector \Core \Php \ReservedKeywordAnalyzer ;
25+ use Rector \Core \PhpParser \Node \CustomNode \FileWithoutNamespace ;
2226use Rector \Core \Rector \AbstractRector ;
2327use Symplify \RuleDocGenerator \ValueObject \CodeSample \CodeSample ;
2428use Symplify \RuleDocGenerator \ValueObject \RuleDefinition ;
@@ -35,6 +39,7 @@ final class UnderscoreToCamelCaseVariableNameRector extends AbstractRector
3539 private const PARAM_NAME_REGEX = '#(?<paramPrefix>@param\s.*\s+\$)(?<paramName>%s)#ms ' ;
3640
3741 private ReservedKeywordAnalyzer $ reservedKeywordAnalyzer ;
42+ private bool $ hasChanged = false ;
3843
3944 public function __construct (
4045 ReservedKeywordAnalyzer $ reservedKeywordAnalyzer
@@ -74,14 +79,62 @@ public function run($aB)
7479 */
7580 public function getNodeTypes (): array
7681 {
77- return [Variable ::class];
82+ return [FileWithoutNamespace::class, Namespace_ ::class];
7883 }
7984
8085 /**
81- * @param Variable $node
86+ * @param ClassMethod|Closure|FileWithoutNamespace|Function_|Namespace_ $node
8287 */
8388 public function refactor (Node $ node ): ?Node
8489 {
90+ if ($ node ->stmts === null ) {
91+ return null ;
92+ }
93+
94+ $ this ->hasChanged = false ;
95+
96+ $ this ->traverseNodesWithCallable (
97+ $ node ->stmts ,
98+ function (Node $ subNode ) {
99+ if ($ subNode instanceof Variable || $ subNode instanceof ClassMethod || $ subNode instanceof Function_ || $ subNode instanceof Closure) {
100+ $ this ->processRenameVariable ($ subNode );
101+ }
102+
103+ return null ;
104+ }
105+ );
106+
107+ if ($ this ->hasChanged ) {
108+ return $ node ;
109+ }
110+
111+ return null ;
112+ }
113+
114+ /**
115+ * @param FunctionLike|Variable $node
116+ */
117+ private function processRenameVariable (Node $ node ): ?Variable
118+ {
119+ if ($ node instanceof FunctionLike) {
120+ if ($ node instanceof Closure) {
121+ foreach ($ node ->uses as $ closureUse ) {
122+ $ this ->processRenameVariable ($ closureUse ->var );
123+ }
124+ }
125+
126+ foreach ($ node ->params as $ key => $ param ) {
127+ $ originalVariableName = $ param ->var ->name ;
128+ $ variable = $ this ->processRenameVariable ($ param ->var );
129+ if ($ variable instanceof Variable) {
130+ $ node ->params [$ key ]->var = $ variable ;
131+ $ this ->updateDocblock ($ originalVariableName , $ variable ->name , $ node );
132+ }
133+ }
134+
135+ return null ;
136+ }
137+
85138 $ nodeName = $ this ->getName ($ node );
86139 if ($ nodeName === null ) {
87140 return null ;
@@ -105,24 +158,19 @@ public function refactor(Node $node): ?Node
105158 return null ;
106159 }
107160
108- $ node ->name = $ camelCaseName ;
109- $ this ->updateDocblock ( $ node , $ nodeName , $ camelCaseName ) ;
161+ $ node ->name = $ camelCaseName ;
162+ $ this ->hasChanged = true ;
110163
111164 return $ node ;
112165 }
113166
114- private function updateDocblock (Variable $ variable , string $ variableName , string $ camelCaseName ): void
167+ private function updateDocblock (string $ variableName , string $ camelCaseName , ? FunctionLike $ functionLike ): void
115168 {
116- $ parentFunctionLike = $ this ->betterNodeFinder ->findParentType ($ variable , ClassMethod::class);
117-
118- if ($ parentFunctionLike === null ) {
119- $ parentFunctionLike = $ this ->betterNodeFinder ->findParentType ($ variable , Function_::class);
120- if ($ parentFunctionLike === null ) {
121- return ;
122- }
169+ if ($ functionLike === null ) {
170+ return ;
123171 }
124172
125- $ docComment = $ parentFunctionLike ->getDocComment ();
173+ $ docComment = $ functionLike ->getDocComment ();
126174 if ($ docComment === null ) {
127175 return ;
128176 }
@@ -136,7 +184,7 @@ private function updateDocblock(Variable $variable, string $variableName, string
136184 return ;
137185 }
138186
139- $ phpDocInfo = $ this ->phpDocInfoFactory ->createFromNodeOrEmpty ($ parentFunctionLike );
187+ $ phpDocInfo = $ this ->phpDocInfoFactory ->createFromNodeOrEmpty ($ functionLike );
140188 $ paramTagValueNodes = $ phpDocInfo ->getParamTagValueNodes ();
141189
142190 foreach ($ paramTagValueNodes as $ paramTagValueNode ) {
@@ -146,6 +194,6 @@ private function updateDocblock(Variable $variable, string $variableName, string
146194 }
147195 }
148196
149- $ parentFunctionLike ->setDocComment (new Doc ($ phpDocInfo ->getPhpDocNode ()->__toString ()));
197+ $ functionLike ->setDocComment (new Doc ($ phpDocInfo ->getPhpDocNode ()->__toString ()));
150198 }
151199}
0 commit comments