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,59 @@ 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+ private function processRenameVariable (FunctionLike |Variable $ node ): ?Variable
115+ {
116+ if ($ node instanceof FunctionLike) {
117+ if ($ node instanceof Closure) {
118+ foreach ($ node ->uses as $ closureUse ) {
119+ $ this ->processRenameVariable ($ closureUse ->var );
120+ }
121+ }
122+
123+ foreach ($ node ->params as $ key => $ param ) {
124+ $ originalVariableName = $ param ->var ->name ;
125+ $ variable = $ this ->processRenameVariable ($ param ->var );
126+ if ($ variable instanceof Variable) {
127+ $ node ->params [$ key ]->var = $ variable ;
128+ $ this ->updateDocblock ($ originalVariableName , $ variable ->name , $ node );
129+ }
130+ }
131+
132+ return null ;
133+ }
134+
85135 $ nodeName = $ this ->getName ($ node );
86136 if ($ nodeName === null ) {
87137 return null ;
@@ -105,24 +155,19 @@ public function refactor(Node $node): ?Node
105155 return null ;
106156 }
107157
108- $ node ->name = $ camelCaseName ;
109- $ this ->updateDocblock ( $ node , $ nodeName , $ camelCaseName ) ;
158+ $ node ->name = $ camelCaseName ;
159+ $ this ->hasChanged = true ;
110160
111161 return $ node ;
112162 }
113163
114- private function updateDocblock (Variable $ variable , string $ variableName , string $ camelCaseName ): void
164+ private function updateDocblock (string $ variableName , string $ camelCaseName , ? FunctionLike $ functionLike ): void
115165 {
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- }
166+ if ($ functionLike === null ) {
167+ return ;
123168 }
124169
125- $ docComment = $ parentFunctionLike ->getDocComment ();
170+ $ docComment = $ functionLike ->getDocComment ();
126171 if ($ docComment === null ) {
127172 return ;
128173 }
@@ -136,7 +181,7 @@ private function updateDocblock(Variable $variable, string $variableName, string
136181 return ;
137182 }
138183
139- $ phpDocInfo = $ this ->phpDocInfoFactory ->createFromNodeOrEmpty ($ parentFunctionLike );
184+ $ phpDocInfo = $ this ->phpDocInfoFactory ->createFromNodeOrEmpty ($ functionLike );
140185 $ paramTagValueNodes = $ phpDocInfo ->getParamTagValueNodes ();
141186
142187 foreach ($ paramTagValueNodes as $ paramTagValueNode ) {
@@ -146,6 +191,6 @@ private function updateDocblock(Variable $variable, string $variableName, string
146191 }
147192 }
148193
149- $ parentFunctionLike ->setDocComment (new Doc ($ phpDocInfo ->getPhpDocNode ()->__toString ()));
194+ $ functionLike ->setDocComment (new Doc ($ phpDocInfo ->getPhpDocNode ()->__toString ()));
150195 }
151196}
0 commit comments