mirror of
https://github.com/rectorphp/rector.git
synced 2024-05-29 07:20:52 +00:00
Updated Rector to commit 8e06627e1a34f9a48a56395943ab573681f5db4d
8e06627e1a
[Experiment][Scope] Remove dynamic Scope creation via ScopeAnalyzer on AbstractScopeAwareRector (#5102)
This commit is contained in:
parent
2a3b82f317
commit
75299a0e31
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
*/
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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() === [];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue
Block a user