[Core] Avoid hang on file has template-extends (#1034)

* [Core] Avoid hang on file has template-extends

* check with regex

* phpstan

* [ci-review] Rector Rectify

* add comment to PHPStan issue

* add comment for why oldTokens only that filled when newStmts equal to oldStmts

* add comment for why oldTokens only that filled when newStmts equal to oldStmts

* final touch: linking issue

* final touch: typo fix

* [ci-review] Rector Rectify

Co-authored-by: GitHub Action <action@github.com>
This commit is contained in:
Abdul Malik Ikhsan 2021-10-22 10:16:03 +07:00 committed by GitHub
parent c5426f60d6
commit 06994b8ff3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 42 additions and 2 deletions

View File

@ -27,6 +27,7 @@ use PhpParser\Node\Scalar\LNumber;
use PhpParser\Node\Scalar\String_;
use PhpParser\Node\Stmt;
use PhpParser\Node\Stmt\Expression;
use PhpParser\Node\Stmt\Foreach_;
use PhpParser\Node\Stmt\Return_;
use PhpParser\Node\UnionType;
use PhpParser\Parser;
@ -206,7 +207,7 @@ final class AnonymousFunctionFactory
$parentNode = $variableNode->getAttribute(AttributeKey::PARENT_NODE);
if (
$parentNode instanceof Assign
|| $parentNode instanceof Stmt\Foreach_
|| $parentNode instanceof Foreach_
|| $parentNode instanceof Param
) {
$alreadyAssignedVariables[] = $variableName;

View File

@ -4,21 +4,31 @@ declare(strict_types=1);
namespace Rector\Core\Application;
use Nette\Utils\Strings;
use PhpParser\Lexer;
use PhpParser\Node;
use Rector\ChangesReporting\Collector\AffectedFilesCollector;
use Rector\Core\PhpParser\NodeTraverser\RectorNodeTraverser;
use Rector\Core\PhpParser\Parser\Parser;
use Rector\Core\PhpParser\Printer\BetterStandardPrinter;
use Rector\Core\ValueObject\Application\File;
use Rector\NodeTypeResolver\NodeScopeAndMetadataDecorator;
final class FileProcessor
{
/**
* @var string
* @see https://regex101.com/r/ozPuC9/1
*/
private const TEMPLATE_EXTENDS_REGEX = '#(\*|\/\/)\s+\@template-extends\s+\\\\?\w+#';
public function __construct(
private AffectedFilesCollector $affectedFilesCollector,
private Lexer $lexer,
private NodeScopeAndMetadataDecorator $nodeScopeAndMetadataDecorator,
private Parser $parser,
private RectorNodeTraverser $rectorNodeTraverser
private RectorNodeTraverser $rectorNodeTraverser,
private BetterStandardPrinter $betterStandardPrinter
) {
}
@ -29,6 +39,17 @@ final class FileProcessor
$oldStmts = $this->parser->parseFileInfo($smartFileInfo);
$oldTokens = $this->lexer->getTokens();
/**
* Tweak PHPStan internal issue for has @template-extends that cause endless loop in the process
*
* @see https://github.com/phpstan/phpstan/issues/3865
* @see https://github.com/rectorphp/rector/issues/6758
*/
if ($this->isTemplateExtendsInSource($oldStmts)) {
$file->hydrateStmtsAndTokens($oldStmts, $oldStmts, $oldTokens);
return;
}
// @todo may need tweak to refresh PHPStan types to avoid issue like in https://github.com/rectorphp/rector/issues/6561
$newStmts = $this->nodeScopeAndMetadataDecorator->decorateNodesFromFile($file, $oldStmts);
$file->hydrateStmtsAndTokens($newStmts, $oldStmts, $oldTokens);
@ -44,4 +65,13 @@ final class FileProcessor
$this->refactor($otherTouchedFile);
}
}
/**
* @param Node[] $nodes
*/
private function isTemplateExtendsInSource(array $nodes): bool
{
$print = $this->betterStandardPrinter->print($nodes);
return (bool) Strings::match($print, self::TEMPLATE_EXTENDS_REGEX);
}
}

View File

@ -114,6 +114,15 @@ final class File
throw new ShouldNotHappenException('Double stmts override');
}
/*
* If newStmts is equal to $oldStmts,
* it is necessary to fill oldTokens only to avoid content of the file removed or spacing changed
*/
if ($newStmts === $oldStmts) {
$this->oldTokens = $oldTokens;
return;
}
$this->oldStmts = $oldStmts;
$this->newStmts = $newStmts;
$this->oldTokens = $oldTokens;