Skip to content

Commit

Permalink
[Performance] Reduce repetitive parent lookup on BetterNodeFinder::fi…
Browse files Browse the repository at this point in the history
…ndFirstNext() by inline search when possible (#3885)

* [Performance] Reduce repetitive parent lookup on BetterNodeFinder::findFirstNext() by inline search when possible

* exception
  • Loading branch information
samsonasik committed May 18, 2023
1 parent b064922 commit 2766aa8
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 23 deletions.
11 changes: 11 additions & 0 deletions src/Exception/StopSearchException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php

declare(strict_types=1);

namespace Rector\Core\Exception;

use Exception;

final class StopSearchException extends Exception
{
}
59 changes: 36 additions & 23 deletions src/PhpParser/Node/BetterNodeFinder.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
use PhpParser\NodeFinder;
use PhpParser\NodeTraverser;
use Rector\Core\Contract\PhpParser\Node\StmtsAwareInterface;
use Rector\Core\Exception\StopSearchException;
use Rector\Core\NodeAnalyzer\ClassAnalyzer;
use Rector\Core\PhpParser\Comparing\NodeComparator;
use Rector\Core\PhpParser\Node\CustomNode\FileWithoutNamespace;
Expand Down Expand Up @@ -345,19 +346,17 @@ public function findFirstPreviousOfTypes(Node $mainNode, array $types): ?Node
public function findFirstNext(Node $node, callable $filter): ?Node
{
$parentNode = $node->getAttribute(AttributeKey::PARENT_NODE);
$nextNode = $this->resolveNextNode($node, $parentNode);

if ($nextNode instanceof Node) {
if ($nextNode instanceof Return_ && ! $nextNode->expr instanceof Expr && ! $parentNode instanceof Case_) {
return null;
}
$newStmts = $this->resolveNewStmts($parentNode);

$found = $this->findFirst($nextNode, $filter);
if ($found instanceof Node) {
return $found;
}
try {
$foundNode = $this->findFirstInlinedNext($node, $filter, $newStmts, $parentNode);
} catch (StopSearchException) {
return null;
}

return $this->findFirstNext($nextNode, $filter);
// we found what we need
if ($foundNode instanceof Node) {
return $foundNode;
}

if ($parentNode instanceof Return_ || $parentNode instanceof FunctionLike) {
Expand Down Expand Up @@ -535,28 +534,42 @@ public function resolveCurrentStatement(Node $node): ?Stmt
return null;
}

private function resolveNextNode(Node $node, ?Node $parentNode): ?Node
/**
* Only search in next Node/Stmt
*
* @param Stmt[] $newStmts
* @param callable(Node $node): bool $filter
*/
private function findFirstInlinedNext(Node $node, callable $filter, array $newStmts, ?Node $parentNode): ?Node
{
if (! $parentNode instanceof Node) {
$newStmts = $this->resolveNewStmts($parentNode);
return $this->resolveNodeFromFile($newStmts, $node, false);
}

if ($node instanceof Stmt) {
$nextNode = $this->resolveNodeFromFile($newStmts, $node, false);
} elseif ($node instanceof Stmt) {
if (! $parentNode instanceof StmtsAwareInterface) {
return null;
}

if ($parentNode->stmts === null) {
return null;
}

// todo: use +1 key once all next node attribute reference and NodeConnectingVisitor removed
// left with add SlimNodeConnectingVisitor for only lookup parent
return $node->getAttribute(AttributeKey::NEXT_NODE);
$nextNode = $node->getAttribute(AttributeKey::NEXT_NODE);
} else {
$nextNode = $this->resolveNextNodeFromOtherNode($node);
}

if (! $nextNode instanceof Node) {
return null;
}

if ($nextNode instanceof Return_ && ! $nextNode->expr instanceof Expr && ! $parentNode instanceof Case_) {
throw new StopSearchException();
}

$found = $this->findFirst($nextNode, $filter);
if ($found instanceof Node) {
return $found;
}

return $this->resolveNextNodeFromOtherNode($node);
return $this->findFirstInlinedNext($nextNode, $filter, $newStmts, $parentNode);
}

/**
Expand Down

0 comments on commit 2766aa8

Please sign in to comment.