Updated Rector to commit 8e06627e1a34f9a48a56395943ab573681f5db4d

8e06627e1a [Experiment][Scope] Remove dynamic Scope creation via ScopeAnalyzer on AbstractScopeAwareRector (#5102)
This commit is contained in:
Tomas Votruba 2023-10-05 12:57:01 +00:00
parent 2a3b82f317
commit 75299a0e31
7 changed files with 16 additions and 54 deletions

View File

@ -13,8 +13,6 @@ use Rector\Core\Contract\Rector\ConfigurableRectorInterface;
use Rector\Core\Contract\Rector\RectorInterface;
use Rector\Core\DependencyInjection\Laravel\ContainerMemento;
use Rector\Core\Exception\ShouldNotHappenException;
use Rector\Core\NodeAnalyzer\ScopeAnalyzer;
use Rector\Core\Rector\AbstractScopeAwareRector;
use Rector\Core\ValueObject\PhpVersion;
use Rector\Skipper\SkipCriteriaResolver\SkippedClassResolver;
use RectorPrefix202310\Webmozart\Assert\Assert;
@ -182,13 +180,6 @@ final class RectorConfig extends Container
if (\is_a($rectorClass, CollectorRectorInterface::class, \true)) {
$this->tag($rectorClass, CollectorRectorInterface::class);
}
if (\is_a($rectorClass, AbstractScopeAwareRector::class, \true)) {
$this->extend($rectorClass, static function (AbstractScopeAwareRector $scopeAwareRector, Container $container) : AbstractScopeAwareRector {
$scopeAnalyzer = $container->make(ScopeAnalyzer::class);
$scopeAwareRector->autowireAbstractScopeAwareRector($scopeAnalyzer);
return $scopeAwareRector;
});
}
// for cache invalidation in case of change
SimpleParameterProvider::addParameter(Option::REGISTERED_RECTOR_RULES, $rectorClass);
}

View File

@ -141,6 +141,7 @@ final class PHPStanNodeScopeResolver
// skip chain method calls, performance issue: https://github.com/phpstan/phpstan/issues/254
$nodeCallback = function (Node $node, MutatingScope $mutatingScope) use(&$nodeCallback, $filePath) : void {
if ($node instanceof FileWithoutNamespace) {
$node->setAttribute(AttributeKey::SCOPE, $mutatingScope);
$this->nodeScopeResolver->processNodes($node->stmts, $mutatingScope, $nodeCallback);
return;
}

View File

@ -50,7 +50,6 @@ final class ChangedNodeScopeRefresher
if (!$this->scopeAnalyzer->isRefreshable($node)) {
return;
}
$mutatingScope = $mutatingScope instanceof MutatingScope ? $mutatingScope : $this->scopeAnalyzer->resolveScope($node, $filePath);
if (!$mutatingScope instanceof MutatingScope) {
$errorMessage = \sprintf('Node "%s" with is missing scope required for scope refresh', \get_class($node));
throw new ShouldNotHappenException($errorMessage);

View File

@ -19,12 +19,12 @@ final class VersionResolver
* @api
* @var string
*/
public const PACKAGE_VERSION = '0.18.5';
public const PACKAGE_VERSION = '8e06627e1a34f9a48a56395943ab573681f5db4d';
/**
* @api
* @var string
*/
public const RELEASE_DATE = '2023-10-05 08:18:12';
public const RELEASE_DATE = '2023-10-05 14:54:01';
/**
* @var int
*/

View File

@ -9,25 +9,12 @@ use PhpParser\Node\Expr\Variable;
use PhpParser\Node\Identifier;
use PhpParser\Node\Name;
use PhpParser\Node\Param;
use PhpParser\Node\Stmt;
use PHPStan\Analyser\Scope;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Rector\NodeTypeResolver\PHPStan\Scope\ScopeFactory;
final class ScopeAnalyzer
{
/**
* @readonly
* @var \Rector\NodeTypeResolver\PHPStan\Scope\ScopeFactory
*/
private $scopeFactory;
/**
* @var array<class-string<Node>>
*/
private const NON_REFRESHABLE_NODES = [Name::class, Identifier::class, Param::class, Arg::class, Variable::class];
public function __construct(ScopeFactory $scopeFactory)
{
$this->scopeFactory = $scopeFactory;
}
public function isRefreshable(Node $node) : bool
{
foreach (self::NON_REFRESHABLE_NODES as $noScopeNode) {
@ -37,19 +24,4 @@ final class ScopeAnalyzer
}
return \true;
}
public function resolveScope(Node $node, string $filePath) : ?Scope
{
// on File level
if ($node instanceof Stmt && $node->getAttribute(AttributeKey::STATEMENT_DEPTH) === 0) {
return $this->scopeFactory->createFromFile($filePath);
}
/**
* Node and parent Node doesn't has Scope, and Node Start token pos is < 0,
* it means the node and parent node just re-printed, the Scope need to be resolved from file
*/
if ($node->getStartTokenPos() < 0) {
return $this->scopeFactory->createFromFile($filePath);
}
return null;
}
}

View File

@ -11,6 +11,7 @@ use Rector\NodeTypeResolver\Node\AttributeKey;
* This service verify if the Node:
*
* - already applied same Rector rule before current Rector rule on last previous Rector rule.
* - Just added as new Stmt
* - just re-printed but token start still >= 0
* - has above node skipped traverse children on current rule
*/
@ -25,11 +26,18 @@ final class RectifiedAnalyzer
if ($this->hasConsecutiveCreatedByRule($rectorClass, $node, $originalNode)) {
return \true;
}
if ($this->isJustAddedAsNewStmt($node, $originalNode)) {
return \true;
}
if ($this->isJustReprintedOverlappedTokenStart($node, $originalNode)) {
return \true;
}
return $node->getAttribute(AttributeKey::SKIPPED_BY_RECTOR_RULE) === $rectorClass;
}
private function isJustAddedAsNewStmt(Node $node, ?Node $originalNode) : bool
{
return !$originalNode instanceof Node && $node instanceof Stmt && \array_keys($node->getAttributes()) === [AttributeKey::SCOPE];
}
/**
* @param class-string<RectorInterface> $rectorClass
*/
@ -39,7 +47,7 @@ final class RectifiedAnalyzer
/** @var class-string<RectorInterface>[] $createdByRule */
$createdByRule = $createdByRuleNode->getAttribute(AttributeKey::CREATED_BY_RULE) ?? [];
if ($createdByRule === []) {
return !$originalNode instanceof Node && $node instanceof Stmt && \count($node->getAttributes()) <= 1;
return \false;
}
return \end($createdByRule) === $rectorClass;
}
@ -55,6 +63,9 @@ final class RectifiedAnalyzer
* - Parent Node's original node is null
*/
$startTokenPos = $node->getStartTokenPos();
return $startTokenPos >= 0;
if ($startTokenPos >= 0) {
return \true;
}
return !$node instanceof Stmt && $node->getAttributes() === [];
}
}

View File

@ -9,18 +9,9 @@ use PHPStan\Analyser\MutatingScope;
use PHPStan\Analyser\Scope;
use Rector\Core\Contract\Rector\ScopeAwareRectorInterface;
use Rector\Core\Exception\ShouldNotHappenException;
use Rector\Core\NodeAnalyzer\ScopeAnalyzer;
use Rector\NodeTypeResolver\Node\AttributeKey;
abstract class AbstractScopeAwareRector extends \Rector\Core\Rector\AbstractRector implements ScopeAwareRectorInterface
{
/**
* @var \Rector\Core\NodeAnalyzer\ScopeAnalyzer
*/
private $scopeAnalyzer;
public function autowireAbstractScopeAwareRector(ScopeAnalyzer $scopeAnalyzer) : void
{
$this->scopeAnalyzer = $scopeAnalyzer;
}
/**
* Process Node of matched type with its PHPStan scope
* @return Node|Node[]|null|NodeTraverser::*
@ -29,9 +20,6 @@ abstract class AbstractScopeAwareRector extends \Rector\Core\Rector\AbstractRect
{
/** @var MutatingScope|null $currentScope */
$currentScope = $node->getAttribute(AttributeKey::SCOPE);
if (!$currentScope instanceof MutatingScope) {
$currentScope = $this->scopeAnalyzer->resolveScope($node, $this->file->getFilePath());
}
if (!$currentScope instanceof Scope) {
$errorMessage = \sprintf('Scope not available on "%s" node, but is required by a refactorWithScope() method of "%s" rule. Fix scope refresh on changed nodes first', \get_class($node), static::class);
throw new ShouldNotHappenException($errorMessage);