1212use PhpParser \Node \Stmt \Interface_ ;
1313use PhpParser \Node \Stmt \Property ;
1414use PhpParser \Node \Stmt \Trait_ ;
15+ use PhpParser \NodeTraverser ;
1516use PhpParser \NodeVisitor ;
1617use PhpParser \NodeVisitorAbstract ;
1718use PHPStan \Analyser \MutatingScope ;
@@ -122,6 +123,9 @@ public function beforeTraverse(array $nodes): ?array
122123 return null ;
123124 }
124125
126+ /**
127+ * @return NodeTraverser::REMOVE_NODE|Node|null
128+ */
125129 final public function enterNode (Node $ node ): int |Node |null
126130 {
127131 if (! $ this ->isMatchingNodeType ($ node )) {
@@ -140,52 +144,41 @@ final public function enterNode(Node $node): int|Node|null
140144 // ensure origNode pulled before refactor to avoid changed during refactor, ref https://3v4l.org/YMEGN
141145 $ originalNode = $ node ->getAttribute (AttributeKey::ORIGINAL_NODE ) ?? $ node ;
142146
143- $ refactoredNode = $ this ->refactor ($ node );
147+ $ refactoredNodeOrState = $ this ->refactor ($ node );
144148
145149 // nothing to change → continue
146- if ($ refactoredNode === null ) {
150+ if ($ refactoredNodeOrState === null ) {
147151 return null ;
148152 }
149153
150- if ($ refactoredNode === []) {
154+ if ($ refactoredNodeOrState === []) {
151155 $ errorMessage = sprintf (self ::EMPTY_NODE_ARRAY_MESSAGE , static ::class);
152156 throw new ShouldNotHappenException ($ errorMessage );
153157 }
154158
155- $ isIntRefactoredNode = is_int ($ refactoredNode );
159+ $ isState = is_int ($ refactoredNodeOrState );
156160
157- /**
158- * If below node and/or its children not traversed on current rule
159- * early return null with decorate current and children node with skipped by "only" current rule
160- */
161- if ($ isIntRefactoredNode ) {
161+ if ($ isState ) {
162162 $ this ->createdByRuleDecorator ->decorate ($ node , $ originalNode , static ::class);
163163
164- if (in_array (
165- $ refactoredNode ,
166- [NodeVisitor::DONT_TRAVERSE_CHILDREN , NodeVisitor::DONT_TRAVERSE_CURRENT_AND_CHILDREN ],
167- true
168- )) {
169- $ this ->decorateCurrentAndChildren ($ node );
164+ // only remove node is supported
165+ if ($ refactoredNodeOrState !== NodeVisitor::REMOVE_NODE ) {
166+ // @todo warn about unsupported state in the future
170167 return null ;
171168 }
172169
173- // @see NodeVisitor::* codes, e.g. removal of node of stopping the traversing
174- if ($ refactoredNode === NodeVisitor::REMOVE_NODE ) {
175- // log here, so we can remove the node in leaveNode() method
176- $ this ->toBeRemovedNodeId = spl_object_id ($ originalNode );
177- }
170+ // log here, so we can remove the node in leaveNode() method
171+ $ this ->toBeRemovedNodeId = spl_object_id ($ originalNode );
178172
179- // notify this rule changing code
173+ // notify this rule changed code
180174 $ rectorWithLineChange = new RectorWithLineChange (static ::class, $ originalNode ->getStartLine ());
181175 $ this ->file ->addRectorClassWithLine ($ rectorWithLineChange );
182176
183- return $ refactoredNode === NodeVisitor::REMOVE_NODE
184- ? $ originalNode
185- : $ refactoredNode ;
177+ // keep original node as node will be removed in leaveNode()
178+ return $ originalNode ;
186179 }
187180
188- return $ this ->postRefactorProcess ($ originalNode , $ node , $ refactoredNode , $ filePath );
181+ return $ this ->postRefactorProcess ($ originalNode , $ node , $ refactoredNodeOrState , $ filePath );
189182 }
190183
191184 /**
@@ -275,35 +268,6 @@ protected function mirrorComments(Node $newNode, Node $oldNode): void
275268 $ this ->commentsMerger ->mirrorComments ($ newNode , $ oldNode );
276269 }
277270
278- private function decorateCurrentAndChildren (Node $ node ): void
279- {
280- // skip sole type, as no other nodes to filter out
281- if (count ($ this ->getNodeTypes ()) === 1 ) {
282- return ;
283- }
284-
285- // filter only types that
286- // 1. registered in getNodesTypes() method
287- // 2. different with current node type, as already decorated above
288- //
289- $ otherTypes = array_filter (
290- $ this ->getNodeTypes (),
291- static fn (string $ nodeType ): bool => $ nodeType !== $ node ::class
292- );
293-
294- if ($ otherTypes === []) {
295- return ;
296- }
297-
298- $ this ->traverseNodesWithCallable ($ node , static function (Node $ subNode ) use ($ otherTypes ): null {
299- if (in_array ($ subNode ::class, $ otherTypes , true )) {
300- $ subNode ->setAttribute (AttributeKey::SKIPPED_BY_RECTOR_RULE , static ::class);
301- }
302-
303- return null ;
304- });
305- }
306-
307271 /**
308272 * @param Node|Node[] $refactoredNode
309273 */
0 commit comments