mirror of
https://github.com/rectorphp/rector.git
synced 2025-04-20 23:41:57 +02:00
Updated Rector to commit 33cd52e703d44690b91106f4752b5786420fa2db
33cd52e703
Fix position of class after non-reachable stmts (#2299)
This commit is contained in:
parent
e0323c00f8
commit
bca89e29da
@ -24,37 +24,6 @@ use RectorPrefix20220512\Symplify\PackageBuilder\Reflection\PrivatesCaller;
|
||||
// Require Composer autoload.php
|
||||
$autoloadIncluder = new \RectorPrefix20220512\AutoloadIncluder();
|
||||
$autoloadIncluder->includeDependencyOrRepositoryVendorAutoloadIfExists();
|
||||
if (\file_exists(__DIR__ . '/../preload.php') && \is_dir(__DIR__ . '/../vendor')) {
|
||||
require_once __DIR__ . '/../preload.php';
|
||||
}
|
||||
require_once __DIR__ . '/../src/constants.php';
|
||||
$autoloadIncluder->loadIfExistsAndNotLoadedYet(__DIR__ . '/../vendor/scoper-autoload.php');
|
||||
$autoloadIncluder->autoloadProjectAutoloaderFile();
|
||||
$autoloadIncluder->autoloadRectorInstalledAsGlobalDependency();
|
||||
$autoloadIncluder->autoloadFromCommandLine();
|
||||
$rectorConfigsResolver = new \Rector\Core\Bootstrap\RectorConfigsResolver();
|
||||
try {
|
||||
$bootstrapConfigs = $rectorConfigsResolver->provide();
|
||||
$rectorContainerFactory = new \Rector\Core\DependencyInjection\RectorContainerFactory();
|
||||
$container = $rectorContainerFactory->createFromBootstrapConfigs($bootstrapConfigs);
|
||||
} catch (\Throwable $throwable) {
|
||||
// for json output
|
||||
$argvInput = new \RectorPrefix20220512\Symfony\Component\Console\Input\ArgvInput();
|
||||
$outputFormat = $argvInput->getParameterOption('--' . \Rector\Core\Configuration\Option::OUTPUT_FORMAT);
|
||||
// report fatal error in json format
|
||||
if ($outputFormat === \Rector\ChangesReporting\Output\JsonOutputFormatter::NAME) {
|
||||
echo \RectorPrefix20220512\Nette\Utils\Json::encode(['fatal_errors' => [$throwable->getMessage()]]);
|
||||
} else {
|
||||
// report fatal errors in console format
|
||||
$rectorConsoleOutputStyleFactory = new \Rector\Core\Console\Style\RectorConsoleOutputStyleFactory(new \RectorPrefix20220512\Symplify\PackageBuilder\Reflection\PrivatesCaller());
|
||||
$rectorConsoleOutputStyle = $rectorConsoleOutputStyleFactory->create();
|
||||
$rectorConsoleOutputStyle->error($throwable->getMessage());
|
||||
}
|
||||
exit(\RectorPrefix20220512\Symfony\Component\Console\Command\Command::FAILURE);
|
||||
}
|
||||
/** @var ConsoleApplication $application */
|
||||
$application = $container->get(\Rector\Core\Console\ConsoleApplication::class);
|
||||
exit($application->run());
|
||||
final class AutoloadIncluder
|
||||
{
|
||||
/**
|
||||
@ -94,8 +63,13 @@ final class AutoloadIncluder
|
||||
public function autoloadFromCommandLine() : void
|
||||
{
|
||||
$cliArgs = $_SERVER['argv'];
|
||||
$autoloadOptionPosition = \array_search('-a', $cliArgs, \true) ?: \array_search('--autoload-file', $cliArgs, \true);
|
||||
if (!$autoloadOptionPosition) {
|
||||
$aOptionPosition = \array_search('-a', $cliArgs, \true);
|
||||
$autoloadFileOptionPosition = \array_search('--autoload-file', $cliArgs, \true);
|
||||
if (\is_int($aOptionPosition)) {
|
||||
$autoloadOptionPosition = $aOptionPosition;
|
||||
} elseif (\is_int($autoloadFileOptionPosition)) {
|
||||
$autoloadOptionPosition = $autoloadFileOptionPosition;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
$autoloadFileValuePosition = $autoloadOptionPosition + 1;
|
||||
@ -113,8 +87,43 @@ final class AutoloadIncluder
|
||||
if (\in_array($filePath, $this->alreadyLoadedAutoloadFiles, \true)) {
|
||||
return;
|
||||
}
|
||||
$this->alreadyLoadedAutoloadFiles[] = \realpath($filePath);
|
||||
$realPath = \realpath($filePath);
|
||||
if (!\is_string($realPath)) {
|
||||
return;
|
||||
}
|
||||
$this->alreadyLoadedAutoloadFiles[] = $realPath;
|
||||
require_once $filePath;
|
||||
}
|
||||
}
|
||||
\class_alias('RectorPrefix20220512\\AutoloadIncluder', 'AutoloadIncluder', \false);
|
||||
if (\file_exists(__DIR__ . '/../preload.php') && \is_dir(__DIR__ . '/../vendor')) {
|
||||
require_once __DIR__ . '/../preload.php';
|
||||
}
|
||||
require_once __DIR__ . '/../src/constants.php';
|
||||
$autoloadIncluder->loadIfExistsAndNotLoadedYet(__DIR__ . '/../vendor/scoper-autoload.php');
|
||||
$autoloadIncluder->autoloadProjectAutoloaderFile();
|
||||
$autoloadIncluder->autoloadRectorInstalledAsGlobalDependency();
|
||||
$autoloadIncluder->autoloadFromCommandLine();
|
||||
$rectorConfigsResolver = new \Rector\Core\Bootstrap\RectorConfigsResolver();
|
||||
try {
|
||||
$bootstrapConfigs = $rectorConfigsResolver->provide();
|
||||
$rectorContainerFactory = new \Rector\Core\DependencyInjection\RectorContainerFactory();
|
||||
$container = $rectorContainerFactory->createFromBootstrapConfigs($bootstrapConfigs);
|
||||
} catch (\Throwable $throwable) {
|
||||
// for json output
|
||||
$argvInput = new \RectorPrefix20220512\Symfony\Component\Console\Input\ArgvInput();
|
||||
$outputFormat = $argvInput->getParameterOption('--' . \Rector\Core\Configuration\Option::OUTPUT_FORMAT);
|
||||
// report fatal error in json format
|
||||
if ($outputFormat === \Rector\ChangesReporting\Output\JsonOutputFormatter::NAME) {
|
||||
echo \RectorPrefix20220512\Nette\Utils\Json::encode(['fatal_errors' => [$throwable->getMessage()]]);
|
||||
} else {
|
||||
// report fatal errors in console format
|
||||
$rectorConsoleOutputStyleFactory = new \Rector\Core\Console\Style\RectorConsoleOutputStyleFactory(new \RectorPrefix20220512\Symplify\PackageBuilder\Reflection\PrivatesCaller());
|
||||
$rectorConsoleOutputStyle = $rectorConsoleOutputStyleFactory->create();
|
||||
$rectorConsoleOutputStyle->error($throwable->getMessage());
|
||||
}
|
||||
exit(\RectorPrefix20220512\Symfony\Component\Console\Command\Command::FAILURE);
|
||||
}
|
||||
/** @var ConsoleApplication $application */
|
||||
$application = $container->get(\Rector\Core\Console\ConsoleApplication::class);
|
||||
exit($application->run());
|
||||
|
@ -6294,9 +6294,10 @@ Changes Single return of && to early returns
|
||||
public function accept()
|
||||
{
|
||||
- return $this->something() && $this->somethingelse();
|
||||
+ if (!$this->something()) {
|
||||
+ if (! $this->something()) {
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+ return (bool) $this->somethingelse();
|
||||
}
|
||||
}
|
||||
|
@ -300,6 +300,7 @@ final class PhpDocInfo
|
||||
$phpDocNodeTraverser = new \RectorPrefix20220512\Symplify\Astral\PhpDocParser\PhpDocNodeTraverser();
|
||||
$phpDocNodeTraverser->traverseWithCallable($this->phpDocNode, '', function (\PHPStan\PhpDocParser\Ast\Node $node) use($typeToRemove) : ?int {
|
||||
if ($node instanceof \PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocTagNode && \is_a($node->value, $typeToRemove, \true)) {
|
||||
// keep special annotation for tools
|
||||
if (\strncmp($node->name, '@psalm-', \strlen('@psalm-')) === 0) {
|
||||
return null;
|
||||
}
|
||||
|
@ -4,12 +4,20 @@ declare (strict_types=1);
|
||||
namespace Rector\NodeTypeResolver\PHPStan\Scope;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Expr;
|
||||
use PhpParser\Node\Expr\Assign;
|
||||
use PhpParser\Node\Name;
|
||||
use PhpParser\Node\Stmt;
|
||||
use PhpParser\Node\Stmt\Class_;
|
||||
use PhpParser\Node\Stmt\Enum_;
|
||||
use PhpParser\Node\Stmt\Finally_;
|
||||
use PhpParser\Node\Stmt\Foreach_;
|
||||
use PhpParser\Node\Stmt\Interface_;
|
||||
use PhpParser\Node\Stmt\Property;
|
||||
use PhpParser\Node\Stmt\Return_;
|
||||
use PhpParser\Node\Stmt\Switch_;
|
||||
use PhpParser\Node\Stmt\Trait_;
|
||||
use PhpParser\Node\Stmt\TryCatch;
|
||||
use PhpParser\NodeTraverser;
|
||||
use PHPStan\AnalysedCodeException;
|
||||
use PHPStan\Analyser\MutatingScope;
|
||||
@ -32,6 +40,7 @@ use Rector\NodeTypeResolver\Node\AttributeKey;
|
||||
use Rector\NodeTypeResolver\PHPStan\Scope\NodeVisitor\RemoveDeepChainMethodCallNodeVisitor;
|
||||
use RectorPrefix20220512\Symplify\PackageBuilder\Reflection\PrivatesAccessor;
|
||||
use Symplify\SmartFileSystem\SmartFileInfo;
|
||||
use RectorPrefix20220512\Webmozart\Assert\Assert;
|
||||
/**
|
||||
* @inspired by https://github.com/silverstripe/silverstripe-upgrader/blob/532182b23e854d02e0b27e68ebc394f436de0682/src/UpgradeRule/PHP/Visitor/PHPStanScopeVisitor.php
|
||||
* - https://github.com/silverstripe/silverstripe-upgrader/pull/57/commits/e5c7cfa166ad940d9d4ff69537d9f7608e992359#diff-5e0807bb3dc03d6a8d8b6ad049abd774
|
||||
@ -108,38 +117,81 @@ final class PHPStanNodeScopeResolver
|
||||
* @param Stmt[] $stmts
|
||||
* @return Stmt[]
|
||||
*/
|
||||
public function processNodes(array $stmts, \Symplify\SmartFileSystem\SmartFileInfo $smartFileInfo) : array
|
||||
public function processNodes(array $stmts, \Symplify\SmartFileSystem\SmartFileInfo $smartFileInfo, ?\PHPStan\Analyser\MutatingScope $formerMutatingScope = null) : array
|
||||
{
|
||||
$isScopeRefreshing = $formerMutatingScope instanceof \PHPStan\Analyser\MutatingScope;
|
||||
/**
|
||||
* The stmts must be array of Stmt, or it will be silently skipped by PHPStan
|
||||
* @see vendor/phpstan/phpstan/phpstan.phar/src/Analyser/NodeScopeResolver.php:282
|
||||
*/
|
||||
\RectorPrefix20220512\Webmozart\Assert\Assert::allIsInstanceOf($stmts, \PhpParser\Node\Stmt::class);
|
||||
$this->removeDeepChainMethodCallNodes($stmts);
|
||||
$scope = $this->scopeFactory->createFromFile($smartFileInfo);
|
||||
$scope = $formerMutatingScope ?? $this->scopeFactory->createFromFile($smartFileInfo);
|
||||
// skip chain method calls, performance issue: https://github.com/phpstan/phpstan/issues/254
|
||||
$nodeCallback = function (\PhpParser\Node $node, \PHPStan\Analyser\MutatingScope $mutatingScope) use(&$nodeCallback) : void {
|
||||
$nodeCallback = function (\PhpParser\Node $node, \PHPStan\Analyser\MutatingScope $mutatingScope) use(&$nodeCallback, $isScopeRefreshing) : void {
|
||||
if ($node instanceof \PhpParser\Node\Stmt\Foreach_) {
|
||||
// decorate value as well
|
||||
$node->valueVar->setAttribute(\Rector\NodeTypeResolver\Node\AttributeKey::SCOPE, $mutatingScope);
|
||||
}
|
||||
if ($node instanceof \PhpParser\Node\Stmt\Property) {
|
||||
foreach ($node->props as $propertyProperty) {
|
||||
$propertyProperty->setAttribute(\Rector\NodeTypeResolver\Node\AttributeKey::SCOPE, $mutatingScope);
|
||||
if ($propertyProperty->default instanceof \PhpParser\Node\Expr) {
|
||||
$propertyProperty->default->setAttribute(\Rector\NodeTypeResolver\Node\AttributeKey::SCOPE, $mutatingScope);
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($node instanceof \PhpParser\Node\Stmt\Switch_) {
|
||||
// decorate value as well
|
||||
foreach ($node->cases as $case) {
|
||||
$case->setAttribute(\Rector\NodeTypeResolver\Node\AttributeKey::SCOPE, $mutatingScope);
|
||||
}
|
||||
}
|
||||
if ($node instanceof \PhpParser\Node\Stmt\TryCatch && $node->finally instanceof \PhpParser\Node\Stmt\Finally_) {
|
||||
$node->finally->setAttribute(\Rector\NodeTypeResolver\Node\AttributeKey::SCOPE, $mutatingScope);
|
||||
}
|
||||
if ($node instanceof \PhpParser\Node\Expr\Assign) {
|
||||
// decorate value as well
|
||||
$node->expr->setAttribute(\Rector\NodeTypeResolver\Node\AttributeKey::SCOPE, $mutatingScope);
|
||||
$node->var->setAttribute(\Rector\NodeTypeResolver\Node\AttributeKey::SCOPE, $mutatingScope);
|
||||
}
|
||||
// decorate value as well
|
||||
if ($node instanceof \PhpParser\Node\Stmt\Return_ && $node->expr instanceof \PhpParser\Node\Expr) {
|
||||
$node->expr->setAttribute(\Rector\NodeTypeResolver\Node\AttributeKey::SCOPE, $mutatingScope);
|
||||
}
|
||||
// scope is missing on attributes
|
||||
// @todo decorate parent nodes too
|
||||
if ($node instanceof \PhpParser\Node\Stmt\Property) {
|
||||
foreach ($node->attrGroups as $attrGroup) {
|
||||
foreach ($attrGroup->attrs as $attribute) {
|
||||
$attribute->setAttribute(\Rector\NodeTypeResolver\Node\AttributeKey::SCOPE, $mutatingScope);
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($node instanceof \PhpParser\Node\Stmt\Trait_) {
|
||||
$traitName = $this->resolveClassName($node);
|
||||
$traitReflectionClass = $this->reflectionProvider->getClass($traitName);
|
||||
$traitScope = clone $mutatingScope;
|
||||
$scopeContext = $this->privatesAccessor->getPrivatePropertyOfClass($traitScope, self::CONTEXT, \PHPStan\Analyser\ScopeContext::class);
|
||||
$traitContext = clone $scopeContext;
|
||||
// before entering the class/trait again, we have to tell scope no class was set, otherwise it crashes
|
||||
$this->privatesAccessor->setPrivatePropertyOfClass($traitContext, 'classReflection', $traitReflectionClass, \PHPStan\Reflection\ClassReflection::class);
|
||||
$this->privatesAccessor->setPrivatePropertyOfClass($traitScope, self::CONTEXT, $traitContext, \PHPStan\Analyser\ScopeContext::class);
|
||||
$node->setAttribute(\Rector\NodeTypeResolver\Node\AttributeKey::SCOPE, $traitScope);
|
||||
$this->nodeScopeResolver->processNodes($node->stmts, $traitScope, $nodeCallback);
|
||||
return;
|
||||
}
|
||||
// the class reflection is resolved AFTER entering to class node
|
||||
// so we need to get it from the first after this one
|
||||
if ($node instanceof \PhpParser\Node\Stmt\Class_ || $node instanceof \PhpParser\Node\Stmt\Interface_) {
|
||||
if ($node instanceof \PhpParser\Node\Stmt\Class_ || $node instanceof \PhpParser\Node\Stmt\Interface_ || $node instanceof \PhpParser\Node\Stmt\Enum_) {
|
||||
/** @var MutatingScope $mutatingScope */
|
||||
$mutatingScope = $this->resolveClassOrInterfaceScope($node, $mutatingScope);
|
||||
$mutatingScope = $this->resolveClassOrInterfaceScope($node, $mutatingScope, $isScopeRefreshing);
|
||||
}
|
||||
// special case for unreachable nodes
|
||||
if ($node instanceof \PHPStan\Node\UnreachableStatementNode) {
|
||||
$originalNode = $node->getOriginalStatement();
|
||||
$originalNode->setAttribute(\Rector\NodeTypeResolver\Node\AttributeKey::IS_UNREACHABLE, \true);
|
||||
$originalNode->setAttribute(\Rector\NodeTypeResolver\Node\AttributeKey::SCOPE, $mutatingScope);
|
||||
$originalStmt = $node->getOriginalStatement();
|
||||
$originalStmt->setAttribute(\Rector\NodeTypeResolver\Node\AttributeKey::IS_UNREACHABLE, \true);
|
||||
$originalStmt->setAttribute(\Rector\NodeTypeResolver\Node\AttributeKey::SCOPE, $mutatingScope);
|
||||
} else {
|
||||
$node->setAttribute(\Rector\NodeTypeResolver\Node\AttributeKey::SCOPE, $mutatingScope);
|
||||
}
|
||||
@ -168,9 +220,9 @@ final class PHPStanNodeScopeResolver
|
||||
$nodeTraverser->traverse($nodes);
|
||||
}
|
||||
/**
|
||||
* @param \PhpParser\Node\Stmt\Class_|\PhpParser\Node\Stmt\Interface_ $classLike
|
||||
* @param \PhpParser\Node\Stmt\Class_|\PhpParser\Node\Stmt\Interface_|\PhpParser\Node\Stmt\Enum_ $classLike
|
||||
*/
|
||||
private function resolveClassOrInterfaceScope($classLike, \PHPStan\Analyser\MutatingScope $mutatingScope) : \PHPStan\Analyser\MutatingScope
|
||||
private function resolveClassOrInterfaceScope($classLike, \PHPStan\Analyser\MutatingScope $mutatingScope, bool $isScopeRefreshing) : \PHPStan\Analyser\MutatingScope
|
||||
{
|
||||
$className = $this->resolveClassName($classLike);
|
||||
// is anonymous class? - not possible to enter it since PHPStan 0.12.33, see https://github.com/phpstan/phpstan-src/commit/e87fb0ec26f9c8552bbeef26a868b1e5d8185e91
|
||||
@ -181,10 +233,15 @@ final class PHPStanNodeScopeResolver
|
||||
} else {
|
||||
$classReflection = $this->reflectionProvider->getClass($className);
|
||||
}
|
||||
// on refresh, remove entered class avoid entering the class again
|
||||
if ($isScopeRefreshing && $mutatingScope->isInClass() && !$classReflection->isAnonymous()) {
|
||||
$context = $this->privatesAccessor->getPrivateProperty($mutatingScope, 'context');
|
||||
$this->privatesAccessor->setPrivateProperty($context, 'classReflection', null);
|
||||
}
|
||||
return $mutatingScope->enterClass($classReflection);
|
||||
}
|
||||
/**
|
||||
* @param \PhpParser\Node\Stmt\Class_|\PhpParser\Node\Stmt\Interface_|\PhpParser\Node\Stmt\Trait_ $classLike
|
||||
* @param \PhpParser\Node\Stmt\Class_|\PhpParser\Node\Stmt\Interface_|\PhpParser\Node\Stmt\Trait_|\PhpParser\Node\Stmt\Enum_ $classLike
|
||||
*/
|
||||
private function resolveClassName($classLike) : string
|
||||
{
|
||||
|
@ -9,11 +9,13 @@ use PhpParser\Node\Stmt;
|
||||
use PhpParser\Node\Stmt\Expression;
|
||||
use PhpParser\Node\Stmt\Return_;
|
||||
use Rector\ChangesReporting\Collector\RectorChangeCollector;
|
||||
use Rector\Core\Application\ChangedNodeScopeRefresher;
|
||||
use Rector\Core\Contract\PhpParser\NodePrinterInterface;
|
||||
use Rector\Core\Exception\ShouldNotHappenException;
|
||||
use Rector\Core\PhpParser\Node\BetterNodeFinder;
|
||||
use Rector\NodeTypeResolver\Node\AttributeKey;
|
||||
use Rector\PostRector\Contract\Collector\NodeCollectorInterface;
|
||||
use Symplify\SmartFileSystem\SmartFileInfo;
|
||||
final class NodesToAddCollector implements \Rector\PostRector\Contract\Collector\NodeCollectorInterface
|
||||
{
|
||||
/**
|
||||
@ -39,11 +41,17 @@ final class NodesToAddCollector implements \Rector\PostRector\Contract\Collector
|
||||
* @var \Rector\Core\Contract\PhpParser\NodePrinterInterface
|
||||
*/
|
||||
private $nodePrinter;
|
||||
public function __construct(\Rector\Core\PhpParser\Node\BetterNodeFinder $betterNodeFinder, \Rector\ChangesReporting\Collector\RectorChangeCollector $rectorChangeCollector, \Rector\Core\Contract\PhpParser\NodePrinterInterface $nodePrinter)
|
||||
/**
|
||||
* @readonly
|
||||
* @var \Rector\Core\Application\ChangedNodeScopeRefresher
|
||||
*/
|
||||
private $changedNodeScopeRefresher;
|
||||
public function __construct(\Rector\Core\PhpParser\Node\BetterNodeFinder $betterNodeFinder, \Rector\ChangesReporting\Collector\RectorChangeCollector $rectorChangeCollector, \Rector\Core\Contract\PhpParser\NodePrinterInterface $nodePrinter, \Rector\Core\Application\ChangedNodeScopeRefresher $changedNodeScopeRefresher)
|
||||
{
|
||||
$this->betterNodeFinder = $betterNodeFinder;
|
||||
$this->rectorChangeCollector = $rectorChangeCollector;
|
||||
$this->nodePrinter = $nodePrinter;
|
||||
$this->changedNodeScopeRefresher = $changedNodeScopeRefresher;
|
||||
}
|
||||
public function isActive() : bool
|
||||
{
|
||||
@ -52,12 +60,18 @@ final class NodesToAddCollector implements \Rector\PostRector\Contract\Collector
|
||||
/**
|
||||
* @deprecated Return created nodes right in refactor() method to keep context instead.
|
||||
*/
|
||||
public function addNodeBeforeNode(\PhpParser\Node $addedNode, \PhpParser\Node $positionNode) : void
|
||||
public function addNodeBeforeNode(\PhpParser\Node $addedNode, \PhpParser\Node $positionNode, ?\Symplify\SmartFileSystem\SmartFileInfo $smartFileInfo = null) : void
|
||||
{
|
||||
if ($positionNode->getAttributes() === []) {
|
||||
$message = \sprintf('Switch arguments in "%s()" method', __METHOD__);
|
||||
throw new \Rector\Core\Exception\ShouldNotHappenException($message);
|
||||
}
|
||||
// @todo the node must be returned here, so traverser can refresh it
|
||||
// this is nasty hack to verify it works
|
||||
if ($smartFileInfo instanceof \Symplify\SmartFileSystem\SmartFileInfo) {
|
||||
$currentScope = $positionNode->getAttribute(\Rector\NodeTypeResolver\Node\AttributeKey::SCOPE);
|
||||
$this->changedNodeScopeRefresher->refresh($addedNode, $smartFileInfo, $currentScope);
|
||||
}
|
||||
$position = $this->resolveNearestStmtPosition($positionNode);
|
||||
$this->nodesToAddBefore[$position][] = $this->wrapToExpression($addedNode);
|
||||
$this->rectorChangeCollector->notifyNodeFileInfo($positionNode);
|
||||
@ -119,7 +133,7 @@ final class NodesToAddCollector implements \Rector\PostRector\Contract\Collector
|
||||
public function addNodesBeforeNode(array $newNodes, \PhpParser\Node $positionNode) : void
|
||||
{
|
||||
foreach ($newNodes as $newNode) {
|
||||
$this->addNodeBeforeNode($newNode, $positionNode);
|
||||
$this->addNodeBeforeNode($newNode, $positionNode, null);
|
||||
}
|
||||
$this->rectorChangeCollector->notifyNodeFileInfo($positionNode);
|
||||
}
|
||||
|
@ -138,7 +138,7 @@ CODE_SAMPLE
|
||||
$firstArg = $funcCall->args[0];
|
||||
$assignVariable = $firstArg->value;
|
||||
$preAssign = new \PhpParser\Node\Expr\Assign($assignVariable, $array);
|
||||
$this->nodesToAddCollector->addNodeBeforeNode($preAssign, $currentStmt);
|
||||
$this->nodesToAddCollector->addNodeBeforeNode($preAssign, $currentStmt, $this->file->getSmartFileInfo());
|
||||
return $expr;
|
||||
}
|
||||
private function refactorAssignArray(\PhpParser\Node\Expr $expr, \PhpParser\Node\Expr\FuncCall $funcCall) : ?\PhpParser\Node\Expr
|
||||
|
@ -12,7 +12,7 @@ use PHPStan\Analyser\Scope;
|
||||
use PHPStan\Reflection\ParametersAcceptorSelector;
|
||||
use PHPStan\Reflection\ResolvedMethodReflection;
|
||||
use PHPStan\Type\ObjectType;
|
||||
use Rector\Core\Rector\AbstractRector;
|
||||
use Rector\Core\Rector\AbstractScopeAwareRector;
|
||||
use Rector\Core\ValueObject\MethodName;
|
||||
use Rector\NodeTypeResolver\Node\AttributeKey;
|
||||
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
|
||||
@ -25,7 +25,7 @@ use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
|
||||
*
|
||||
* @see \Rector\Tests\CodeQuality\Rector\PropertyFetch\ExplicitMethodCallOverMagicGetSetRector\ExplicitMethodCallOverMagicGetSetRectorTest
|
||||
*/
|
||||
final class ExplicitMethodCallOverMagicGetSetRector extends \Rector\Core\Rector\AbstractRector
|
||||
final class ExplicitMethodCallOverMagicGetSetRector extends \Rector\Core\Rector\AbstractScopeAwareRector
|
||||
{
|
||||
public function getRuleDefinition() : \Symplify\RuleDocGenerator\ValueObject\RuleDefinition
|
||||
{
|
||||
@ -85,11 +85,11 @@ CODE_SAMPLE
|
||||
/**
|
||||
* @param PropertyFetch|Assign $node
|
||||
*/
|
||||
public function refactor(\PhpParser\Node $node) : ?\PhpParser\Node
|
||||
public function refactorWithScope(\PhpParser\Node $node, \PHPStan\Analyser\Scope $scope) : ?\PhpParser\Node
|
||||
{
|
||||
if ($node instanceof \PhpParser\Node\Expr\Assign) {
|
||||
if ($node->var instanceof \PhpParser\Node\Expr\PropertyFetch) {
|
||||
return $this->refactorMagicSet($node->expr, $node->var);
|
||||
return $this->refactorMagicSet($node->expr, $node->var, $scope);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@ -142,7 +142,7 @@ CODE_SAMPLE
|
||||
/**
|
||||
* @return \PhpParser\Node\Expr\MethodCall|null
|
||||
*/
|
||||
private function refactorMagicSet(\PhpParser\Node\Expr $expr, \PhpParser\Node\Expr\PropertyFetch $propertyFetch)
|
||||
private function refactorMagicSet(\PhpParser\Node\Expr $expr, \PhpParser\Node\Expr\PropertyFetch $propertyFetch, \PHPStan\Analyser\Scope $scope)
|
||||
{
|
||||
$propertyCallerType = $this->getType($propertyFetch->var);
|
||||
if (!$propertyCallerType instanceof \PHPStan\Type\ObjectType) {
|
||||
@ -159,17 +159,13 @@ CODE_SAMPLE
|
||||
if (!$propertyCallerType->hasMethod($setterMethodName)->yes()) {
|
||||
return null;
|
||||
}
|
||||
if ($this->hasNoParamOrVariadic($propertyCallerType, $propertyFetch, $setterMethodName)) {
|
||||
if ($this->hasNoParamOrVariadic($propertyCallerType, $setterMethodName, $scope)) {
|
||||
return null;
|
||||
}
|
||||
return $this->nodeFactory->createMethodCall($propertyFetch->var, $setterMethodName, [$expr]);
|
||||
}
|
||||
private function hasNoParamOrVariadic(\PHPStan\Type\ObjectType $objectType, \PhpParser\Node\Expr\PropertyFetch $propertyFetch, string $setterMethodName) : bool
|
||||
private function hasNoParamOrVariadic(\PHPStan\Type\ObjectType $objectType, string $setterMethodName, \PHPStan\Analyser\Scope $scope) : bool
|
||||
{
|
||||
$scope = $propertyFetch->getAttribute(\Rector\NodeTypeResolver\Node\AttributeKey::SCOPE);
|
||||
if (!$scope instanceof \PHPStan\Analyser\Scope) {
|
||||
return \false;
|
||||
}
|
||||
$methodReflection = $objectType->getMethod($setterMethodName, $scope);
|
||||
if (!$methodReflection instanceof \PHPStan\Reflection\ResolvedMethodReflection) {
|
||||
return \false;
|
||||
|
@ -72,6 +72,7 @@ CODE_SAMPLE
|
||||
}
|
||||
if ($node->stmts === []) {
|
||||
$this->removeNode($node);
|
||||
// needed to apply removeNode(), @todo fix in AbstractRector itself
|
||||
return $node;
|
||||
}
|
||||
return $node->stmts;
|
||||
|
@ -99,7 +99,7 @@ CODE_SAMPLE
|
||||
}
|
||||
/**
|
||||
* @param If_ $node
|
||||
* @return null|mixed[]|\PhpParser\Node\Stmt\If_
|
||||
* @return \PhpParser\Node\Stmt\If_|mixed[]|null
|
||||
*/
|
||||
public function refactor(\PhpParser\Node $node)
|
||||
{
|
||||
|
@ -87,10 +87,7 @@ CODE_SAMPLE
|
||||
$this->complexNodeRemover->removePropertyAndUsages($node, $property, $this->removeAssignSideEffect);
|
||||
$hasChanged = \true;
|
||||
}
|
||||
if ($hasChanged) {
|
||||
return $node;
|
||||
}
|
||||
return null;
|
||||
return $hasChanged ? $node : null;
|
||||
}
|
||||
private function shouldSkipProperty(\PhpParser\Node\Stmt\Property $property) : bool
|
||||
{
|
||||
|
@ -17,7 +17,7 @@ use PHPStan\Reflection\ReflectionProvider;
|
||||
use Rector\Core\Enum\ObjectReference;
|
||||
use Rector\Core\NodeAnalyzer\ClassAnalyzer;
|
||||
use Rector\Core\NodeManipulator\ClassMethodManipulator;
|
||||
use Rector\Core\Rector\AbstractRector;
|
||||
use Rector\Core\Rector\AbstractScopeAwareRector;
|
||||
use Rector\NodeCollector\ScopeResolver\ParentClassScopeResolver;
|
||||
use Rector\NodeTypeResolver\Node\AttributeKey;
|
||||
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
|
||||
@ -25,7 +25,7 @@ use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
|
||||
/**
|
||||
* @see \Rector\Tests\DeadCode\Rector\StaticCall\RemoveParentCallWithoutParentRector\RemoveParentCallWithoutParentRectorTest
|
||||
*/
|
||||
final class RemoveParentCallWithoutParentRector extends \Rector\Core\Rector\AbstractRector
|
||||
final class RemoveParentCallWithoutParentRector extends \Rector\Core\Rector\AbstractScopeAwareRector
|
||||
{
|
||||
/**
|
||||
* @readonly
|
||||
@ -85,7 +85,7 @@ CODE_SAMPLE
|
||||
/**
|
||||
* @param StaticCall $node
|
||||
*/
|
||||
public function refactor(\PhpParser\Node $node) : ?\PhpParser\Node
|
||||
public function refactorWithScope(\PhpParser\Node $node, \PHPStan\Analyser\Scope $scope) : ?\PhpParser\Node
|
||||
{
|
||||
$classLike = $this->betterNodeFinder->findParentType($node, \PhpParser\Node\Stmt\Class_::class);
|
||||
if (!$classLike instanceof \PhpParser\Node\Stmt\Class_) {
|
||||
@ -94,10 +94,6 @@ CODE_SAMPLE
|
||||
if ($this->shouldSkip($node, $classLike)) {
|
||||
return null;
|
||||
}
|
||||
$scope = $node->getAttribute(\Rector\NodeTypeResolver\Node\AttributeKey::SCOPE);
|
||||
if (!$scope instanceof \PHPStan\Analyser\Scope) {
|
||||
return null;
|
||||
}
|
||||
$parentClassReflection = $this->parentClassScopeResolver->resolveParentClassReflection($scope);
|
||||
if (!$parentClassReflection instanceof \PHPStan\Reflection\ClassReflection) {
|
||||
return $this->processNoParentReflection($node);
|
||||
|
@ -90,6 +90,7 @@ CODE_SAMPLE
|
||||
continue;
|
||||
}
|
||||
$previousStmt = $stmts[$key - 1];
|
||||
// unset...
|
||||
if ($this->shouldRemove($previousStmt, $stmt)) {
|
||||
\array_splice($stmts, $key);
|
||||
return $stmts;
|
||||
@ -118,7 +119,13 @@ CODE_SAMPLE
|
||||
return \false;
|
||||
}
|
||||
$isUnreachable = $currentStmt->getAttribute(\Rector\NodeTypeResolver\Node\AttributeKey::IS_UNREACHABLE);
|
||||
return $isUnreachable === \true && $previousStmt->finally instanceof \PhpParser\Node\Stmt\Finally_ && $this->cleanNop($previousStmt->finally->stmts) !== [];
|
||||
if ($isUnreachable !== \true) {
|
||||
return \false;
|
||||
}
|
||||
if (!$previousStmt->finally instanceof \PhpParser\Node\Stmt\Finally_) {
|
||||
return \false;
|
||||
}
|
||||
return $this->cleanNop($previousStmt->finally->stmts) !== [];
|
||||
}
|
||||
/**
|
||||
* @param Stmt[] $stmts
|
||||
|
@ -96,7 +96,7 @@ CODE_SAMPLE
|
||||
}
|
||||
$selfVariable = $this->namedVariableFactory->createVariable($node, 'self');
|
||||
$expression = new \PhpParser\Node\Stmt\Expression(new \PhpParser\Node\Expr\Assign($selfVariable, new \PhpParser\Node\Expr\Variable('this')));
|
||||
$this->nodesToAddCollector->addNodeBeforeNode($expression, $node);
|
||||
$this->nodesToAddCollector->addNodeBeforeNode($expression, $node, $this->file->getSmartFileInfo());
|
||||
$this->traverseNodesWithCallable($node, function (\PhpParser\Node $subNode) use($selfVariable) : ?Closure {
|
||||
if (!$subNode instanceof \PhpParser\Node\Expr\Closure) {
|
||||
return null;
|
||||
|
@ -60,7 +60,7 @@ CODE_SAMPLE
|
||||
}
|
||||
$variable = $this->namedVariableFactory->createVariable($node, 'object');
|
||||
$expression = new \PhpParser\Node\Stmt\Expression(new \PhpParser\Node\Expr\Assign($variable, $node->var));
|
||||
$this->nodesToAddCollector->addNodeBeforeNode($expression, $node);
|
||||
$this->nodesToAddCollector->addNodeBeforeNode($expression, $node, $this->file->getSmartFileInfo());
|
||||
$node->var = $variable;
|
||||
// necessary to remove useless parentheses
|
||||
$node->setAttribute(\Rector\NodeTypeResolver\Node\AttributeKey::ORIGINAL_NODE, null);
|
||||
|
@ -104,11 +104,11 @@ CODE_SAMPLE
|
||||
}
|
||||
$scope = $funcCall->getAttribute(\Rector\NodeTypeResolver\Node\AttributeKey::SCOPE);
|
||||
$variable = new \PhpParser\Node\Expr\Variable($this->variableNaming->createCountedValueName('result', $scope));
|
||||
$this->nodesToAddCollector->addNodeBeforeNode(new \PhpParser\Node\Stmt\Expression(new \PhpParser\Node\Expr\Assign($variable, new \PhpParser\Node\Expr\Array_([]))), $funcCall);
|
||||
$this->nodesToAddCollector->addNodeBeforeNode(new \PhpParser\Node\Stmt\Expression(new \PhpParser\Node\Expr\Assign($variable, new \PhpParser\Node\Expr\Array_([]))), $funcCall, $this->file->getSmartFileInfo());
|
||||
/** @var ConstFetch $constant */
|
||||
$constant = $args[2]->value;
|
||||
$foreach = $this->nodeNameResolver->isName($constant, 'ARRAY_FILTER_USE_KEY') ? $this->applyArrayFilterUseKey($args, $closure, $variable) : $this->applyArrayFilterUseBoth($args, $closure, $variable);
|
||||
$this->nodesToAddCollector->addNodeBeforeNode($foreach, $funcCall);
|
||||
$this->nodesToAddCollector->addNodeBeforeNode($foreach, $funcCall, $this->file->getSmartFileInfo());
|
||||
return $variable;
|
||||
}
|
||||
/**
|
||||
|
@ -109,7 +109,7 @@ CODE_SAMPLE
|
||||
$funcVariable = $this->namedVariableFactory->createVariable($funcCall, 'dirnameFunc');
|
||||
$closure = $this->createClosure();
|
||||
$exprAssignClosure = $this->createExprAssign($funcVariable, $closure);
|
||||
$this->nodesToAddCollector->addNodeBeforeNode($exprAssignClosure, $funcCall);
|
||||
$this->nodesToAddCollector->addNodeBeforeNode($exprAssignClosure, $funcCall, $this->file->getSmartFileInfo());
|
||||
$funcCall->name = $funcVariable;
|
||||
return $funcCall;
|
||||
}
|
||||
|
@ -68,7 +68,7 @@ CODE_SAMPLE
|
||||
$sessionKey = new \PhpParser\Node\Scalar\String_('session.' . $option->key->value);
|
||||
$funcName = new \PhpParser\Node\Name('ini_set');
|
||||
$iniSet = new \PhpParser\Node\Expr\FuncCall($funcName, [new \PhpParser\Node\Arg($sessionKey), new \PhpParser\Node\Arg($option->value)]);
|
||||
$this->nodesToAddCollector->addNodeBeforeNode(new \PhpParser\Node\Stmt\Expression($iniSet), $node);
|
||||
$this->nodesToAddCollector->addNodeBeforeNode(new \PhpParser\Node\Stmt\Expression($iniSet), $node, $this->file->getSmartFileInfo());
|
||||
}
|
||||
unset($node->args[0]);
|
||||
return $node;
|
||||
|
@ -73,7 +73,7 @@ CODE_SAMPLE
|
||||
$variable = new \PhpParser\Node\Expr\Variable($newVariableName);
|
||||
$assign = new \PhpParser\Node\Expr\Assign($variable, $node->var);
|
||||
}
|
||||
$this->nodesToAddCollector->addNodeBeforeNode(new \PhpParser\Node\Stmt\Expression($assign), $node);
|
||||
$this->nodesToAddCollector->addNodeBeforeNode(new \PhpParser\Node\Stmt\Expression($assign), $node, $this->file->getSmartFileInfo());
|
||||
$node->var = $variable;
|
||||
$node->setAttribute(\Rector\NodeTypeResolver\Node\AttributeKey::ORIGINAL_NODE, null);
|
||||
return $node;
|
||||
|
@ -85,7 +85,7 @@ CODE_SAMPLE
|
||||
$anonymousFunction->stmts[1] = new \PhpParser\Node\Stmt\Return_($ternary);
|
||||
$assignVariable = $this->namedVariableFactory->createVariable($node, 'battleShipcompare');
|
||||
$assignExpression = $this->getAssignExpression($anonymousFunction, $assignVariable);
|
||||
$this->nodesToAddCollector->addNodeBeforeNode($assignExpression, $node);
|
||||
$this->nodesToAddCollector->addNodeBeforeNode($assignExpression, $node, $this->file->getSmartFileInfo());
|
||||
return new \PhpParser\Node\Expr\FuncCall($assignVariable, [new \PhpParser\Node\Arg($node->left), new \PhpParser\Node\Arg($node->right)]);
|
||||
}
|
||||
private function getAssignExpression(\PhpParser\Node\Expr\Closure $closure, \PhpParser\Node\Expr\Variable $variable) : \PhpParser\Node\Stmt\Expression
|
||||
|
@ -68,7 +68,7 @@ CODE_SAMPLE
|
||||
}
|
||||
$tempVariable = $this->namedVariableFactory->createVariable($node, 'callable');
|
||||
$expression = new \PhpParser\Node\Stmt\Expression(new \PhpParser\Node\Expr\Assign($tempVariable, $node->args[0]->value));
|
||||
$this->nodesToAddCollector->addNodeBeforeNode($expression, $node);
|
||||
$this->nodesToAddCollector->addNodeBeforeNode($expression, $node, $this->file->getSmartFileInfo());
|
||||
$closure = new \PhpParser\Node\Expr\Closure();
|
||||
$closure->uses[] = new \PhpParser\Node\Expr\ClosureUse($tempVariable);
|
||||
$innerFuncCall = new \PhpParser\Node\Expr\FuncCall($tempVariable, [new \PhpParser\Node\Arg($this->nodeFactory->createFuncCall('func_get_args'), \false, \true)]);
|
||||
|
@ -209,7 +209,7 @@ CODE_SAMPLE
|
||||
{
|
||||
if ($if->stmts !== []) {
|
||||
$firstStmt = $if->stmts[0];
|
||||
$this->nodesToAddCollector->addNodeBeforeNode($funcCall, $firstStmt);
|
||||
$this->nodesToAddCollector->addNodeBeforeNode($funcCall, $firstStmt, $this->file->getSmartFileInfo());
|
||||
return;
|
||||
}
|
||||
$if->stmts[0] = new \PhpParser\Node\Stmt\Expression($funcCall);
|
||||
|
@ -9,12 +9,12 @@ use PhpParser\Node\Expr\Closure;
|
||||
use PhpParser\Node\Expr\FuncCall;
|
||||
use PhpParser\Node\Expr\Variable;
|
||||
use PhpParser\Node\Stmt\Expression;
|
||||
use PHPStan\Analyser\Scope;
|
||||
use Rector\Core\Exception\ShouldNotHappenException;
|
||||
use Rector\Core\PhpParser\Parser\InlineCodeParser;
|
||||
use Rector\Core\Rector\AbstractRector;
|
||||
use Rector\Core\Rector\AbstractScopeAwareRector;
|
||||
use Rector\DowngradePhp72\NodeAnalyzer\FunctionExistsFunCallAnalyzer;
|
||||
use Rector\Naming\Naming\VariableNaming;
|
||||
use Rector\NodeTypeResolver\Node\AttributeKey;
|
||||
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
|
||||
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
|
||||
/**
|
||||
@ -22,7 +22,7 @@ use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
|
||||
*
|
||||
* @see \Rector\Tests\DowngradePhp72\Rector\FuncCall\DowngradeStreamIsattyRector\DowngradeStreamIsattyRectorTest
|
||||
*/
|
||||
final class DowngradeStreamIsattyRector extends \Rector\Core\Rector\AbstractRector
|
||||
final class DowngradeStreamIsattyRector extends \Rector\Core\Rector\AbstractScopeAwareRector
|
||||
{
|
||||
/**
|
||||
* @var \PhpParser\Node\Expr\Closure|null
|
||||
@ -100,7 +100,7 @@ CODE_SAMPLE
|
||||
/**
|
||||
* @param FuncCall $node
|
||||
*/
|
||||
public function refactor(\PhpParser\Node $node) : ?\PhpParser\Node
|
||||
public function refactorWithScope(\PhpParser\Node $node, \PHPStan\Analyser\Scope $scope) : ?\PhpParser\Node
|
||||
{
|
||||
if (!$this->isName($node, 'stream_isatty')) {
|
||||
return null;
|
||||
@ -109,10 +109,9 @@ CODE_SAMPLE
|
||||
return null;
|
||||
}
|
||||
$function = $this->createClosure();
|
||||
$scope = $node->getAttribute(\Rector\NodeTypeResolver\Node\AttributeKey::SCOPE);
|
||||
$variable = new \PhpParser\Node\Expr\Variable($this->variableNaming->createCountedValueName('streamIsatty', $scope));
|
||||
$assign = new \PhpParser\Node\Expr\Assign($variable, $function);
|
||||
$this->nodesToAddCollector->addNodeBeforeNode($assign, $node);
|
||||
$this->nodesToAddCollector->addNodeBeforeNode($assign, $node, $this->file->getSmartFileInfo());
|
||||
return new \PhpParser\Node\Expr\FuncCall($variable, $node->args);
|
||||
}
|
||||
private function createClosure() : \PhpParser\Node\Expr\Closure
|
||||
|
@ -90,7 +90,7 @@ CODE_SAMPLE
|
||||
$this->addAssignNewVariable($funcCall, $originalArray, $array);
|
||||
}
|
||||
$resetFuncCall = $this->nodeFactory->createFuncCall('reset', [$array]);
|
||||
$this->nodesToAddCollector->addNodeBeforeNode($resetFuncCall, $funcCall);
|
||||
$this->nodesToAddCollector->addNodeBeforeNode($resetFuncCall, $funcCall, $this->file->getSmartFileInfo());
|
||||
$funcCall->name = new \PhpParser\Node\Name('key');
|
||||
if ($originalArray !== $array) {
|
||||
$funcCall->args[0]->value = $array;
|
||||
@ -111,7 +111,7 @@ CODE_SAMPLE
|
||||
$this->addAssignNewVariable($funcCall, $originalArray, $array);
|
||||
}
|
||||
$resetFuncCall = $this->nodeFactory->createFuncCall('end', [$array]);
|
||||
$this->nodesToAddCollector->addNodeBeforeNode($resetFuncCall, $funcCall);
|
||||
$this->nodesToAddCollector->addNodeBeforeNode($resetFuncCall, $funcCall, $this->file->getSmartFileInfo());
|
||||
$funcCall->name = new \PhpParser\Node\Name('key');
|
||||
if ($originalArray !== $array) {
|
||||
$funcCall->args[0]->value = $array;
|
||||
@ -123,7 +123,7 @@ CODE_SAMPLE
|
||||
*/
|
||||
private function addAssignNewVariable(\PhpParser\Node\Expr\FuncCall $funcCall, \PhpParser\Node\Expr $expr, $variable) : void
|
||||
{
|
||||
$this->nodesToAddCollector->addNodeBeforeNode(new \PhpParser\Node\Stmt\Expression(new \PhpParser\Node\Expr\Assign($variable, $expr)), $funcCall);
|
||||
$this->nodesToAddCollector->addNodeBeforeNode(new \PhpParser\Node\Stmt\Expression(new \PhpParser\Node\Expr\Assign($variable, $expr)), $funcCall, $this->file->getSmartFileInfo());
|
||||
}
|
||||
/**
|
||||
* @return \PhpParser\Node\Expr|\PhpParser\Node\Expr\Variable
|
||||
|
@ -4,51 +4,34 @@ declare (strict_types=1);
|
||||
namespace Rector\DowngradePhp74\Rector\Array_;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Arg;
|
||||
use PhpParser\Node\Expr\Array_;
|
||||
use PhpParser\Node\Expr\ArrayItem;
|
||||
use PhpParser\Node\Expr\Assign;
|
||||
use PhpParser\Node\Expr\FuncCall;
|
||||
use PhpParser\Node\Expr\Ternary;
|
||||
use PhpParser\Node\Expr\Variable;
|
||||
use PhpParser\Node\Name;
|
||||
use PHPStan\Analyser\Scope;
|
||||
use PHPStan\Type\ArrayType;
|
||||
use PHPStan\Type\IterableType;
|
||||
use PHPStan\Type\ObjectType;
|
||||
use PHPStan\Type\Type;
|
||||
use Rector\Core\Exception\ShouldNotHappenException;
|
||||
use Rector\Core\Rector\AbstractRector;
|
||||
use Rector\Naming\Naming\VariableNaming;
|
||||
use Rector\NodeTypeResolver\Node\AttributeKey;
|
||||
use Rector\Core\Rector\AbstractScopeAwareRector;
|
||||
use Rector\DowngradePhp81\NodeAnalyzer\ArraySpreadAnalyzer;
|
||||
use Rector\DowngradePhp81\NodeFactory\ArrayMergeFromArraySpreadFactory;
|
||||
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
|
||||
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
|
||||
use Traversable;
|
||||
/**
|
||||
* @changelog https://wiki.php.net/rfc/spread_operator_for_array
|
||||
*
|
||||
* @see \Rector\Tests\DowngradePhp74\Rector\Array_\DowngradeArraySpreadRector\DowngradeArraySpreadRectorTest
|
||||
*/
|
||||
class DowngradeArraySpreadRector extends \Rector\Core\Rector\AbstractRector
|
||||
final class DowngradeArraySpreadRector extends \Rector\Core\Rector\AbstractScopeAwareRector
|
||||
{
|
||||
/**
|
||||
* @var bool
|
||||
* @readonly
|
||||
* @var \Rector\DowngradePhp81\NodeFactory\ArrayMergeFromArraySpreadFactory
|
||||
*/
|
||||
private $shouldIncrement = \false;
|
||||
/**
|
||||
* Handle different result in CI
|
||||
*
|
||||
* @var array<string, int>
|
||||
*/
|
||||
private $lastPositionCurrentFile = [];
|
||||
private $arrayMergeFromArraySpreadFactory;
|
||||
/**
|
||||
* @readonly
|
||||
* @var \Rector\Naming\Naming\VariableNaming
|
||||
* @var \Rector\DowngradePhp81\NodeAnalyzer\ArraySpreadAnalyzer
|
||||
*/
|
||||
private $variableNaming;
|
||||
public function __construct(\Rector\Naming\Naming\VariableNaming $variableNaming)
|
||||
private $arraySpreadAnalyzer;
|
||||
public function __construct(\Rector\DowngradePhp81\NodeFactory\ArrayMergeFromArraySpreadFactory $arrayMergeFromArraySpreadFactory, \Rector\DowngradePhp81\NodeAnalyzer\ArraySpreadAnalyzer $arraySpreadAnalyzer)
|
||||
{
|
||||
$this->variableNaming = $variableNaming;
|
||||
$this->arrayMergeFromArraySpreadFactory = $arrayMergeFromArraySpreadFactory;
|
||||
$this->arraySpreadAnalyzer = $arraySpreadAnalyzer;
|
||||
}
|
||||
public function getRuleDefinition() : \Symplify\RuleDocGenerator\ValueObject\RuleDefinition
|
||||
{
|
||||
@ -95,173 +78,17 @@ CODE_SAMPLE
|
||||
/**
|
||||
* @param Array_ $node
|
||||
*/
|
||||
public function refactor(\PhpParser\Node $node) : ?\PhpParser\Node
|
||||
public function refactorWithScope(\PhpParser\Node $node, \PHPStan\Analyser\Scope $scope) : ?\PhpParser\Node
|
||||
{
|
||||
if (!$this->shouldRefactor($node)) {
|
||||
if (!$this->arraySpreadAnalyzer->isArrayWithUnpack($node)) {
|
||||
return null;
|
||||
}
|
||||
$this->shouldIncrement = (bool) $this->betterNodeFinder->findFirstNext($node, function (\PhpParser\Node $subNode) : bool {
|
||||
$shouldIncrement = (bool) $this->betterNodeFinder->findFirstNext($node, function (\PhpParser\Node $subNode) : bool {
|
||||
if (!$subNode instanceof \PhpParser\Node\Expr\Array_) {
|
||||
return \false;
|
||||
}
|
||||
return $this->shouldRefactor($subNode);
|
||||
return $this->arraySpreadAnalyzer->isArrayWithUnpack($subNode);
|
||||
});
|
||||
return $this->refactorNode($node);
|
||||
}
|
||||
private function shouldRefactor(\PhpParser\Node\Expr\Array_ $array) : bool
|
||||
{
|
||||
// Check that any item in the array is the spread
|
||||
foreach ($array->items as $item) {
|
||||
if (!$item instanceof \PhpParser\Node\Expr\ArrayItem) {
|
||||
continue;
|
||||
}
|
||||
if ($item->unpack) {
|
||||
return \true;
|
||||
}
|
||||
}
|
||||
return \false;
|
||||
}
|
||||
private function refactorNode(\PhpParser\Node\Expr\Array_ $array) : \PhpParser\Node\Expr\FuncCall
|
||||
{
|
||||
$newItems = $this->createArrayItems($array);
|
||||
// Replace this array node with an `array_merge`
|
||||
return $this->createArrayMerge($array, $newItems);
|
||||
}
|
||||
/**
|
||||
* Iterate all array items:
|
||||
* 1. If they use the spread, remove it
|
||||
* 2. If not, make the item part of an accumulating array,
|
||||
* to be added once the next spread is found, or at the end
|
||||
* @return ArrayItem[]
|
||||
*/
|
||||
private function createArrayItems(\PhpParser\Node\Expr\Array_ $array) : array
|
||||
{
|
||||
$newItems = [];
|
||||
$accumulatedItems = [];
|
||||
foreach ($array->items as $position => $item) {
|
||||
if ($item !== null && $item->unpack) {
|
||||
// Spread operator found
|
||||
if (!$item->value instanceof \PhpParser\Node\Expr\Variable) {
|
||||
// If it is a not variable, transform it to a variable
|
||||
$item->value = $this->createVariableFromNonVariable($array, $item, $position);
|
||||
}
|
||||
if ($accumulatedItems !== []) {
|
||||
// If previous items were in the new array, add them first
|
||||
$newItems[] = $this->createArrayItem($accumulatedItems);
|
||||
// Reset the accumulated items
|
||||
$accumulatedItems = [];
|
||||
}
|
||||
// Add the current item, still with "unpack = true" (it will be removed later on)
|
||||
$newItems[] = $item;
|
||||
continue;
|
||||
}
|
||||
// Normal item, it goes into the accumulated array
|
||||
$accumulatedItems[] = $item;
|
||||
}
|
||||
// Add the remaining accumulated items
|
||||
if ($accumulatedItems !== []) {
|
||||
$newItems[] = $this->createArrayItem($accumulatedItems);
|
||||
}
|
||||
return $newItems;
|
||||
}
|
||||
/**
|
||||
* @param (ArrayItem|null)[] $items
|
||||
*/
|
||||
private function createArrayMerge(\PhpParser\Node\Expr\Array_ $array, array $items) : \PhpParser\Node\Expr\FuncCall
|
||||
{
|
||||
/** @var Scope $scope */
|
||||
$scope = $array->getAttribute(\Rector\NodeTypeResolver\Node\AttributeKey::SCOPE);
|
||||
$args = \array_map(function ($arrayItem) use($scope) : Arg {
|
||||
if ($arrayItem === null) {
|
||||
throw new \Rector\Core\Exception\ShouldNotHappenException();
|
||||
}
|
||||
if ($arrayItem->unpack) {
|
||||
// Do not unpack anymore
|
||||
$arrayItem->unpack = \false;
|
||||
return $this->createArgFromSpreadArrayItem($scope, $arrayItem);
|
||||
}
|
||||
return new \PhpParser\Node\Arg($arrayItem);
|
||||
}, $items);
|
||||
return new \PhpParser\Node\Expr\FuncCall(new \PhpParser\Node\Name('array_merge'), $args);
|
||||
}
|
||||
/**
|
||||
* If it is a variable, we add it directly
|
||||
* Otherwise it could be a function, method, ternary, traversable, etc
|
||||
* We must then first extract it into a variable,
|
||||
* as to invoke it only once and avoid potential bugs,
|
||||
* such as a method executing some side-effect
|
||||
*/
|
||||
private function createVariableFromNonVariable(\PhpParser\Node\Expr\Array_ $array, \PhpParser\Node\Expr\ArrayItem $arrayItem, int $position) : \PhpParser\Node\Expr\Variable
|
||||
{
|
||||
/** @var Scope $nodeScope */
|
||||
$nodeScope = $array->getAttribute(\Rector\NodeTypeResolver\Node\AttributeKey::SCOPE);
|
||||
// The variable name will be item0Unpacked, item1Unpacked, etc,
|
||||
// depending on their position.
|
||||
// The number can't be at the end of the var name, or it would
|
||||
// conflict with the counter (for if that name is already taken)
|
||||
$smartFileInfo = $this->file->getSmartFileInfo();
|
||||
$realPath = $smartFileInfo->getRealPath();
|
||||
$position = $this->lastPositionCurrentFile[$realPath] ?? $position;
|
||||
$variableName = $this->variableNaming->resolveFromNodeWithScopeCountAndFallbackName($array, $nodeScope, 'item' . $position . 'Unpacked');
|
||||
if ($this->shouldIncrement) {
|
||||
$this->lastPositionCurrentFile[$realPath] = ++$position;
|
||||
}
|
||||
// Assign the value to the variable, and replace the element with the variable
|
||||
$newVariable = new \PhpParser\Node\Expr\Variable($variableName);
|
||||
$newVariableAssign = new \PhpParser\Node\Expr\Assign($newVariable, $arrayItem->value);
|
||||
$this->nodesToAddCollector->addNodeBeforeNode($newVariableAssign, $array);
|
||||
return $newVariable;
|
||||
}
|
||||
/**
|
||||
* @param array<ArrayItem|null> $items
|
||||
*/
|
||||
private function createArrayItem(array $items) : \PhpParser\Node\Expr\ArrayItem
|
||||
{
|
||||
return new \PhpParser\Node\Expr\ArrayItem(new \PhpParser\Node\Expr\Array_($items));
|
||||
}
|
||||
private function createArgFromSpreadArrayItem(\PHPStan\Analyser\Scope $nodeScope, \PhpParser\Node\Expr\ArrayItem $arrayItem) : \PhpParser\Node\Arg
|
||||
{
|
||||
// By now every item is a variable
|
||||
/** @var Variable $variable */
|
||||
$variable = $arrayItem->value;
|
||||
$variableName = $this->getName($variable) ?? '';
|
||||
// If the variable is not in scope, it's one we just added.
|
||||
// Then get the type from the attribute
|
||||
if ($nodeScope->hasVariableType($variableName)->yes()) {
|
||||
$type = $nodeScope->getVariableType($variableName);
|
||||
} else {
|
||||
$originalNode = $arrayItem->getAttribute(\Rector\NodeTypeResolver\Node\AttributeKey::ORIGINAL_NODE);
|
||||
if ($originalNode instanceof \PhpParser\Node\Expr\ArrayItem) {
|
||||
$type = $nodeScope->getType($originalNode->value);
|
||||
} else {
|
||||
throw new \Rector\Core\Exception\ShouldNotHappenException();
|
||||
}
|
||||
}
|
||||
$iteratorToArrayFuncCall = new \PhpParser\Node\Expr\FuncCall(new \PhpParser\Node\Name('iterator_to_array'), [new \PhpParser\Node\Arg($arrayItem)]);
|
||||
// If we know it is an array, then print it directly
|
||||
// Otherwise PHPStan throws an error:
|
||||
// "Else branch is unreachable because ternary operator condition is always true."
|
||||
if ($type instanceof \PHPStan\Type\ArrayType) {
|
||||
return new \PhpParser\Node\Arg($arrayItem);
|
||||
}
|
||||
// If it is iterable, then directly return `iterator_to_array`
|
||||
if ($this->isIterableType($type)) {
|
||||
return new \PhpParser\Node\Arg($iteratorToArrayFuncCall);
|
||||
}
|
||||
// Print a ternary, handling either an array or an iterator
|
||||
$inArrayFuncCall = new \PhpParser\Node\Expr\FuncCall(new \PhpParser\Node\Name('is_array'), [new \PhpParser\Node\Arg($arrayItem)]);
|
||||
return new \PhpParser\Node\Arg(new \PhpParser\Node\Expr\Ternary($inArrayFuncCall, $arrayItem, $iteratorToArrayFuncCall));
|
||||
}
|
||||
/**
|
||||
* Iterables: objects declaring the interface Traversable,
|
||||
* For "iterable" type, it can be array
|
||||
*/
|
||||
private function isIterableType(\PHPStan\Type\Type $type) : bool
|
||||
{
|
||||
if ($type instanceof \PHPStan\Type\IterableType) {
|
||||
return \false;
|
||||
}
|
||||
$traversableObjectType = new \PHPStan\Type\ObjectType('Traversable');
|
||||
return $traversableObjectType->isSuperTypeOf($type)->yes();
|
||||
return $this->arrayMergeFromArraySpreadFactory->createFromArray($node, $scope, $this->file, $shouldIncrement);
|
||||
}
|
||||
}
|
||||
|
@ -107,7 +107,7 @@ CODE_SAMPLE
|
||||
$variableName = $this->variableNaming->resolveFromFuncCallFirstArgumentWithSuffix($node, 'AllowableTags', 'allowableTags', $node->getAttribute(\Rector\NodeTypeResolver\Node\AttributeKey::SCOPE));
|
||||
// Assign the value to the variable
|
||||
$newVariable = new \PhpParser\Node\Expr\Variable($variableName);
|
||||
$this->nodesToAddCollector->addNodeBeforeNode(new \PhpParser\Node\Expr\Assign($newVariable, $allowableTagsParam), $node);
|
||||
$this->nodesToAddCollector->addNodeBeforeNode(new \PhpParser\Node\Expr\Assign($newVariable, $allowableTagsParam), $node, $this->file->getSmartFileInfo());
|
||||
// Apply refactor on the variable
|
||||
$newExpr = $this->createIsArrayTernaryFromExpression($newVariable);
|
||||
}
|
||||
|
@ -118,11 +118,11 @@ CODE_SAMPLE
|
||||
$reflectionClassConstants = $this->variableNaming->createCountedValueName('reflectionClassConstants', $scope);
|
||||
$variableReflectionClassConstants = new \PhpParser\Node\Expr\Variable($this->variableNaming->createCountedValueName($reflectionClassConstants, $scope));
|
||||
$assign = new \PhpParser\Node\Expr\Assign($variableReflectionClassConstants, new \PhpParser\Node\Expr\MethodCall($methodCall->var, 'getReflectionConstants'));
|
||||
$this->nodesToAddCollector->addNodeBeforeNode(new \PhpParser\Node\Stmt\Expression($assign), $methodCall);
|
||||
$this->nodesToAddCollector->addNodeBeforeNode(new \PhpParser\Node\Stmt\Expression($assign), $methodCall, $this->file->getSmartFileInfo());
|
||||
$result = $this->variableNaming->createCountedValueName('result', $scope);
|
||||
$variableResult = new \PhpParser\Node\Expr\Variable($result);
|
||||
$assignVariableResult = new \PhpParser\Node\Expr\Assign($variableResult, new \PhpParser\Node\Expr\Array_());
|
||||
$this->nodesToAddCollector->addNodeBeforeNode(new \PhpParser\Node\Stmt\Expression($assignVariableResult), $methodCall);
|
||||
$this->nodesToAddCollector->addNodeBeforeNode(new \PhpParser\Node\Stmt\Expression($assignVariableResult), $methodCall, $this->file->getSmartFileInfo());
|
||||
$ifs = [];
|
||||
$valueVariable = new \PhpParser\Node\Expr\Variable('value');
|
||||
$key = new \PhpParser\Node\Expr\MethodCall($valueVariable, 'getName');
|
||||
@ -138,7 +138,7 @@ CODE_SAMPLE
|
||||
$closure->uses = [new \PhpParser\Node\Expr\ClosureUse($variableResult, \true)];
|
||||
$closure->stmts = $ifs;
|
||||
$funcCall = $this->nodeFactory->createFuncCall('array_walk', [$variableReflectionClassConstants, $closure]);
|
||||
$this->nodesToAddCollector->addNodeBeforeNode(new \PhpParser\Node\Stmt\Expression($funcCall), $methodCall);
|
||||
$this->nodesToAddCollector->addNodeBeforeNode(new \PhpParser\Node\Stmt\Expression($funcCall), $methodCall, $this->file->getSmartFileInfo());
|
||||
return $variableResult;
|
||||
}
|
||||
private function resolveClassConstFetchName(\PhpParser\Node\Expr\ClassConstFetch $classConstFetch) : ?string
|
||||
|
@ -87,7 +87,7 @@ CODE_SAMPLE
|
||||
$variable = $this->namedVariableFactory->createVariable($node, 'className');
|
||||
$assign = new \PhpParser\Node\Expr\Assign($variable, $node->class);
|
||||
}
|
||||
$this->nodesToAddCollector->addNodeBeforeNode($assign, $node);
|
||||
$this->nodesToAddCollector->addNodeBeforeNode($assign, $node, $this->file->getSmartFileInfo());
|
||||
$node->class = $variable;
|
||||
return $node;
|
||||
}
|
||||
|
@ -11,15 +11,15 @@ use PhpParser\Node\Expr\NullsafePropertyFetch;
|
||||
use PhpParser\Node\Expr\PropertyFetch;
|
||||
use PhpParser\Node\Expr\Ternary;
|
||||
use PhpParser\Node\Expr\Variable;
|
||||
use Rector\Core\Rector\AbstractRector;
|
||||
use PHPStan\Analyser\Scope;
|
||||
use Rector\Core\Rector\AbstractScopeAwareRector;
|
||||
use Rector\Naming\Naming\VariableNaming;
|
||||
use Rector\NodeTypeResolver\Node\AttributeKey;
|
||||
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
|
||||
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
|
||||
/**
|
||||
* @see \Rector\Tests\DowngradePhp80\Rector\NullsafeMethodCall\DowngradeNullsafeToTernaryOperatorRector\DowngradeNullsafeToTernaryOperatorRectorTest
|
||||
*/
|
||||
final class DowngradeNullsafeToTernaryOperatorRector extends \Rector\Core\Rector\AbstractRector
|
||||
final class DowngradeNullsafeToTernaryOperatorRector extends \Rector\Core\Rector\AbstractScopeAwareRector
|
||||
{
|
||||
/**
|
||||
* @readonly
|
||||
@ -52,9 +52,8 @@ CODE_SAMPLE
|
||||
/**
|
||||
* @param NullsafeMethodCall|NullsafePropertyFetch $node
|
||||
*/
|
||||
public function refactor(\PhpParser\Node $node) : \PhpParser\Node\Expr\Ternary
|
||||
public function refactorWithScope(\PhpParser\Node $node, \PHPStan\Analyser\Scope $scope) : \PhpParser\Node\Expr\Ternary
|
||||
{
|
||||
$scope = $node->getAttribute(\Rector\NodeTypeResolver\Node\AttributeKey::SCOPE);
|
||||
$tempVarName = $this->variableNaming->resolveFromNodeWithScopeCountAndFallbackName($node->var, $scope, '_');
|
||||
$variable = new \PhpParser\Node\Expr\Variable($tempVarName);
|
||||
$called = $node instanceof \PhpParser\Node\Expr\NullsafeMethodCall ? new \PhpParser\Node\Expr\MethodCall($variable, $node->name, $node->args) : new \PhpParser\Node\Expr\PropertyFetch($variable, $node->name);
|
||||
|
23
rules/DowngradePhp81/NodeAnalyzer/ArraySpreadAnalyzer.php
Normal file
23
rules/DowngradePhp81/NodeAnalyzer/ArraySpreadAnalyzer.php
Normal file
@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace Rector\DowngradePhp81\NodeAnalyzer;
|
||||
|
||||
use PhpParser\Node\Expr\Array_;
|
||||
use PhpParser\Node\Expr\ArrayItem;
|
||||
final class ArraySpreadAnalyzer
|
||||
{
|
||||
public function isArrayWithUnpack(\PhpParser\Node\Expr\Array_ $array) : bool
|
||||
{
|
||||
// Check that any item in the array is the spread
|
||||
foreach ($array->items as $item) {
|
||||
if (!$item instanceof \PhpParser\Node\Expr\ArrayItem) {
|
||||
continue;
|
||||
}
|
||||
if ($item->unpack) {
|
||||
return \true;
|
||||
}
|
||||
}
|
||||
return \false;
|
||||
}
|
||||
}
|
@ -0,0 +1,223 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace Rector\DowngradePhp81\NodeFactory;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Arg;
|
||||
use PhpParser\Node\Expr\Array_;
|
||||
use PhpParser\Node\Expr\ArrayItem;
|
||||
use PhpParser\Node\Expr\Assign;
|
||||
use PhpParser\Node\Expr\FuncCall;
|
||||
use PhpParser\Node\Expr\Ternary;
|
||||
use PhpParser\Node\Expr\Variable;
|
||||
use PhpParser\Node\Name;
|
||||
use PHPStan\Analyser\Scope;
|
||||
use PHPStan\Type\ArrayType;
|
||||
use PHPStan\Type\IterableType;
|
||||
use PHPStan\Type\ObjectType;
|
||||
use PHPStan\Type\Type;
|
||||
use Rector\Core\Exception\ShouldNotHappenException;
|
||||
use Rector\Core\PhpParser\Node\BetterNodeFinder;
|
||||
use Rector\Core\ValueObject\Application\File;
|
||||
use Rector\DowngradePhp81\NodeAnalyzer\ArraySpreadAnalyzer;
|
||||
use Rector\Naming\Naming\VariableNaming;
|
||||
use Rector\NodeNameResolver\NodeNameResolver;
|
||||
use Rector\NodeTypeResolver\Node\AttributeKey;
|
||||
use Rector\PostRector\Collector\NodesToAddCollector;
|
||||
final class ArrayMergeFromArraySpreadFactory
|
||||
{
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
private $shouldIncrement = \false;
|
||||
/**
|
||||
* Handle different result in CI
|
||||
*
|
||||
* @var array<string, int>
|
||||
*/
|
||||
private $lastPositionCurrentFile = [];
|
||||
/**
|
||||
* @readonly
|
||||
* @var \Rector\Naming\Naming\VariableNaming
|
||||
*/
|
||||
private $variableNaming;
|
||||
/**
|
||||
* @readonly
|
||||
* @var \Rector\Core\PhpParser\Node\BetterNodeFinder
|
||||
*/
|
||||
private $betterNodeFinder;
|
||||
/**
|
||||
* @readonly
|
||||
* @var \Rector\PostRector\Collector\NodesToAddCollector
|
||||
*/
|
||||
private $nodesToAddCollector;
|
||||
/**
|
||||
* @readonly
|
||||
* @var \Rector\NodeNameResolver\NodeNameResolver
|
||||
*/
|
||||
private $nodeNameResolver;
|
||||
/**
|
||||
* @readonly
|
||||
* @var \Rector\DowngradePhp81\NodeAnalyzer\ArraySpreadAnalyzer
|
||||
*/
|
||||
private $arraySpreadAnalyzer;
|
||||
public function __construct(\Rector\Naming\Naming\VariableNaming $variableNaming, \Rector\Core\PhpParser\Node\BetterNodeFinder $betterNodeFinder, \Rector\PostRector\Collector\NodesToAddCollector $nodesToAddCollector, \Rector\NodeNameResolver\NodeNameResolver $nodeNameResolver, \Rector\DowngradePhp81\NodeAnalyzer\ArraySpreadAnalyzer $arraySpreadAnalyzer)
|
||||
{
|
||||
$this->variableNaming = $variableNaming;
|
||||
$this->betterNodeFinder = $betterNodeFinder;
|
||||
$this->nodesToAddCollector = $nodesToAddCollector;
|
||||
$this->nodeNameResolver = $nodeNameResolver;
|
||||
$this->arraySpreadAnalyzer = $arraySpreadAnalyzer;
|
||||
}
|
||||
public function createFromArray(\PhpParser\Node\Expr\Array_ $array, \PHPStan\Analyser\Scope $scope, \Rector\Core\ValueObject\Application\File $file, ?bool $shouldIncrement = null) : ?\PhpParser\Node
|
||||
{
|
||||
if (!$this->arraySpreadAnalyzer->isArrayWithUnpack($array)) {
|
||||
return null;
|
||||
}
|
||||
if ($shouldIncrement !== null) {
|
||||
$this->shouldIncrement = $shouldIncrement;
|
||||
} else {
|
||||
$this->shouldIncrement = (bool) $this->betterNodeFinder->findFirstNext($array, function (\PhpParser\Node $subNode) : bool {
|
||||
if (!$subNode instanceof \PhpParser\Node\Expr\Array_) {
|
||||
return \false;
|
||||
}
|
||||
return $this->arraySpreadAnalyzer->isArrayWithUnpack($subNode);
|
||||
});
|
||||
}
|
||||
$newArrayItems = $this->disolveArrayItems($array, $scope, $file);
|
||||
return $this->createArrayMergeFuncCall($newArrayItems, $scope);
|
||||
}
|
||||
/**
|
||||
* Iterate all array items:
|
||||
*
|
||||
* 1. If they use the spread, remove it
|
||||
* 2. If not, make the item part of an accumulating array,
|
||||
* to be added once the next spread is found, or at the end
|
||||
* @return ArrayItem[]
|
||||
*/
|
||||
private function disolveArrayItems(\PhpParser\Node\Expr\Array_ $array, \PHPStan\Analyser\Scope $scope, \Rector\Core\ValueObject\Application\File $file) : array
|
||||
{
|
||||
$newItems = [];
|
||||
$accumulatedItems = [];
|
||||
foreach ($array->items as $position => $item) {
|
||||
if ($item !== null && $item->unpack) {
|
||||
// Spread operator found
|
||||
if (!$item->value instanceof \PhpParser\Node\Expr\Variable) {
|
||||
// If it is a not variable, transform it to a variable
|
||||
$item->value = $this->createVariableFromNonVariable($array, $item, $position, $scope, $file);
|
||||
}
|
||||
if ($accumulatedItems !== []) {
|
||||
// If previous items were in the new array, add them first
|
||||
$newItems[] = $this->createArrayItemFromArray($accumulatedItems);
|
||||
// Reset the accumulated items
|
||||
$accumulatedItems = [];
|
||||
}
|
||||
// Add the current item, still with "unpack = true" (it will be removed later on)
|
||||
$newItems[] = $item;
|
||||
continue;
|
||||
}
|
||||
// Normal item, it goes into the accumulated array
|
||||
$accumulatedItems[] = $item;
|
||||
}
|
||||
// Add the remaining accumulated items
|
||||
if ($accumulatedItems !== []) {
|
||||
$newItems[] = $this->createArrayItemFromArray($accumulatedItems);
|
||||
}
|
||||
return $newItems;
|
||||
}
|
||||
/**
|
||||
* @param ArrayItem[] $arrayItems
|
||||
*/
|
||||
private function createArrayMergeFuncCall(array $arrayItems, \PHPStan\Analyser\Scope $scope) : \PhpParser\Node\Expr\FuncCall
|
||||
{
|
||||
$args = \array_map(function (\PhpParser\Node\Expr\ArrayItem $arrayItem) use($scope) : Arg {
|
||||
if ($arrayItem->unpack) {
|
||||
// Do not unpack anymore
|
||||
$arrayItem->unpack = \false;
|
||||
return $this->createArgFromSpreadArrayItem($scope, $arrayItem);
|
||||
}
|
||||
return new \PhpParser\Node\Arg($arrayItem);
|
||||
}, $arrayItems);
|
||||
return new \PhpParser\Node\Expr\FuncCall(new \PhpParser\Node\Name('array_merge'), $args);
|
||||
}
|
||||
/**
|
||||
* If it is a variable, we add it directly
|
||||
* Otherwise it could be a function, method, ternary, traversable, etc
|
||||
* We must then first extract it into a variable,
|
||||
* as to invoke it only once and avoid potential bugs,
|
||||
* such as a method executing some side-effect
|
||||
*/
|
||||
private function createVariableFromNonVariable(\PhpParser\Node\Expr\Array_ $array, \PhpParser\Node\Expr\ArrayItem $arrayItem, int $position, \PHPStan\Analyser\Scope $scope, \Rector\Core\ValueObject\Application\File $file) : \PhpParser\Node\Expr\Variable
|
||||
{
|
||||
// The variable name will be item0Unpacked, item1Unpacked, etc,
|
||||
// depending on their position.
|
||||
// The number can't be at the end of the var name, or it would
|
||||
// conflict with the counter (for if that name is already taken)
|
||||
$smartFileInfo = $file->getSmartFileInfo();
|
||||
$realPath = $smartFileInfo->getRealPath();
|
||||
$position = $this->lastPositionCurrentFile[$realPath] ?? $position;
|
||||
$variableName = $this->variableNaming->resolveFromNodeWithScopeCountAndFallbackName($array, $scope, 'item' . $position . 'Unpacked');
|
||||
if ($this->shouldIncrement) {
|
||||
$this->lastPositionCurrentFile[$realPath] = ++$position;
|
||||
}
|
||||
// Assign the value to the variable, and replace the element with the variable
|
||||
$newVariable = new \PhpParser\Node\Expr\Variable($variableName);
|
||||
$newVariableAssign = new \PhpParser\Node\Expr\Assign($newVariable, $arrayItem->value);
|
||||
$this->nodesToAddCollector->addNodeBeforeNode($newVariableAssign, $array, $file->getSmartFileInfo());
|
||||
return $newVariable;
|
||||
}
|
||||
/**
|
||||
* @param array<ArrayItem|null> $items
|
||||
*/
|
||||
private function createArrayItemFromArray(array $items) : \PhpParser\Node\Expr\ArrayItem
|
||||
{
|
||||
$array = new \PhpParser\Node\Expr\Array_($items);
|
||||
return new \PhpParser\Node\Expr\ArrayItem($array);
|
||||
}
|
||||
private function createArgFromSpreadArrayItem(\PHPStan\Analyser\Scope $nodeScope, \PhpParser\Node\Expr\ArrayItem $arrayItem) : \PhpParser\Node\Arg
|
||||
{
|
||||
// By now every item is a variable
|
||||
/** @var Variable $variable */
|
||||
$variable = $arrayItem->value;
|
||||
$variableName = $this->nodeNameResolver->getName($variable) ?? '';
|
||||
// If the variable is not in scope, it's one we just added.
|
||||
// Then get the type from the attribute
|
||||
if ($nodeScope->hasVariableType($variableName)->yes()) {
|
||||
$type = $nodeScope->getVariableType($variableName);
|
||||
} else {
|
||||
$originalNode = $arrayItem->getAttribute(\Rector\NodeTypeResolver\Node\AttributeKey::ORIGINAL_NODE);
|
||||
if ($originalNode instanceof \PhpParser\Node\Expr\ArrayItem) {
|
||||
$type = $nodeScope->getType($originalNode->value);
|
||||
} else {
|
||||
throw new \Rector\Core\Exception\ShouldNotHappenException();
|
||||
}
|
||||
}
|
||||
$iteratorToArrayFuncCall = new \PhpParser\Node\Expr\FuncCall(new \PhpParser\Node\Name('iterator_to_array'), [new \PhpParser\Node\Arg($arrayItem)]);
|
||||
// If we know it is an array, then print it directly
|
||||
// Otherwise PHPStan throws an error:
|
||||
// "Else branch is unreachable because ternary operator condition is always true."
|
||||
if ($type instanceof \PHPStan\Type\ArrayType) {
|
||||
return new \PhpParser\Node\Arg($arrayItem);
|
||||
}
|
||||
// If it is iterable, then directly return `iterator_to_array`
|
||||
if ($this->isIterableType($type)) {
|
||||
return new \PhpParser\Node\Arg($iteratorToArrayFuncCall);
|
||||
}
|
||||
// Print a ternary, handling either an array or an iterator
|
||||
$inArrayFuncCall = new \PhpParser\Node\Expr\FuncCall(new \PhpParser\Node\Name('is_array'), [new \PhpParser\Node\Arg($arrayItem)]);
|
||||
return new \PhpParser\Node\Arg(new \PhpParser\Node\Expr\Ternary($inArrayFuncCall, $arrayItem, $iteratorToArrayFuncCall));
|
||||
}
|
||||
/**
|
||||
* Iterables: objects declaring the interface Traversable,
|
||||
* For "iterable" type, it can be array
|
||||
*/
|
||||
private function isIterableType(\PHPStan\Type\Type $type) : bool
|
||||
{
|
||||
if ($type instanceof \PHPStan\Type\IterableType) {
|
||||
return \false;
|
||||
}
|
||||
$traversableObjectType = new \PHPStan\Type\ObjectType('Traversable');
|
||||
return $traversableObjectType->isSuperTypeOf($type)->yes();
|
||||
}
|
||||
}
|
@ -6,42 +6,49 @@ namespace Rector\DowngradePhp81\Rector\Array_;
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Expr\Array_;
|
||||
use PhpParser\Node\Expr\ArrayItem;
|
||||
use PHPStan\Analyser\Scope;
|
||||
use PHPStan\Type\ArrayType;
|
||||
use PHPStan\Type\IntegerType;
|
||||
use Rector\DowngradePhp74\Rector\Array_\DowngradeArraySpreadRector;
|
||||
use Rector\Core\Rector\AbstractScopeAwareRector;
|
||||
use Rector\DowngradePhp81\NodeAnalyzer\ArraySpreadAnalyzer;
|
||||
use Rector\DowngradePhp81\NodeFactory\ArrayMergeFromArraySpreadFactory;
|
||||
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
|
||||
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
|
||||
/**
|
||||
* @changelog https://wiki.php.net/rfc/array_unpacking_string_keys
|
||||
*
|
||||
* @see \Rector\Tests\DowngradePhp81\Rector\Array_\DowngradeArraySpreadStringKeyRector\DowngradeArraySpreadStringKeyRectorTest
|
||||
*/
|
||||
final class DowngradeArraySpreadStringKeyRector extends \Rector\DowngradePhp74\Rector\Array_\DowngradeArraySpreadRector
|
||||
final class DowngradeArraySpreadStringKeyRector extends \Rector\Core\Rector\AbstractScopeAwareRector
|
||||
{
|
||||
/**
|
||||
* @readonly
|
||||
* @var \Rector\DowngradePhp81\NodeFactory\ArrayMergeFromArraySpreadFactory
|
||||
*/
|
||||
private $arrayMergeFromArraySpreadFactory;
|
||||
/**
|
||||
* @readonly
|
||||
* @var \Rector\DowngradePhp81\NodeAnalyzer\ArraySpreadAnalyzer
|
||||
*/
|
||||
private $arraySpreadAnalyzer;
|
||||
public function __construct(\Rector\DowngradePhp81\NodeFactory\ArrayMergeFromArraySpreadFactory $arrayMergeFromArraySpreadFactory, \Rector\DowngradePhp81\NodeAnalyzer\ArraySpreadAnalyzer $arraySpreadAnalyzer)
|
||||
{
|
||||
$this->arrayMergeFromArraySpreadFactory = $arrayMergeFromArraySpreadFactory;
|
||||
$this->arraySpreadAnalyzer = $arraySpreadAnalyzer;
|
||||
}
|
||||
public function getRuleDefinition() : \Symplify\RuleDocGenerator\ValueObject\RuleDefinition
|
||||
{
|
||||
return new \Symplify\RuleDocGenerator\ValueObject\RuleDefinition('Replace array spread with string key to array_merge function', [new \Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample(<<<'CODE_SAMPLE'
|
||||
class SomeClass
|
||||
{
|
||||
public function run()
|
||||
{
|
||||
$parts = ['a' => 'b'];
|
||||
$parts2 = ['c' => 'd'];
|
||||
$parts = ['a' => 'b'];
|
||||
$parts2 = ['c' => 'd'];
|
||||
|
||||
$result = [...$parts, ...$parts2];
|
||||
}
|
||||
}
|
||||
$result = [...$parts, ...$parts2];
|
||||
CODE_SAMPLE
|
||||
, <<<'CODE_SAMPLE'
|
||||
class SomeClass
|
||||
{
|
||||
public function run()
|
||||
{
|
||||
$parts = ['a' => 'b'];
|
||||
$parts2 = ['c' => 'd'];
|
||||
$parts = ['a' => 'b'];
|
||||
$parts2 = ['c' => 'd'];
|
||||
|
||||
$result = array_merge($parts, $parts2);
|
||||
}
|
||||
}
|
||||
$result = array_merge($parts, $parts2);
|
||||
CODE_SAMPLE
|
||||
)]);
|
||||
}
|
||||
@ -55,22 +62,22 @@ CODE_SAMPLE
|
||||
/**
|
||||
* @param Array_ $node
|
||||
*/
|
||||
public function refactor(\PhpParser\Node $node) : ?\PhpParser\Node
|
||||
public function refactorWithScope(\PhpParser\Node $node, \PHPStan\Analyser\Scope $scope) : ?\PhpParser\Node
|
||||
{
|
||||
if ($this->shouldSkip($node)) {
|
||||
if ($this->shouldSkipArray($node)) {
|
||||
return null;
|
||||
}
|
||||
return parent::refactor($node);
|
||||
return $this->arrayMergeFromArraySpreadFactory->createFromArray($node, $scope, $this->file);
|
||||
}
|
||||
private function shouldSkip(\PhpParser\Node\Expr\Array_ $array) : bool
|
||||
private function shouldSkipArray(\PhpParser\Node\Expr\Array_ $array) : bool
|
||||
{
|
||||
if (!$this->arraySpreadAnalyzer->isArrayWithUnpack($array)) {
|
||||
return \true;
|
||||
}
|
||||
foreach ($array->items as $item) {
|
||||
if (!$item instanceof \PhpParser\Node\Expr\ArrayItem) {
|
||||
continue;
|
||||
}
|
||||
if (!$item->unpack) {
|
||||
continue;
|
||||
}
|
||||
$type = $this->nodeTypeResolver->getType($item->value);
|
||||
if (!$type instanceof \PHPStan\Type\ArrayType) {
|
||||
continue;
|
||||
|
@ -9,12 +9,12 @@ use PhpParser\Node\Expr\Closure;
|
||||
use PhpParser\Node\Expr\FuncCall;
|
||||
use PhpParser\Node\Expr\Variable;
|
||||
use PhpParser\Node\Stmt\Expression;
|
||||
use PHPStan\Analyser\Scope;
|
||||
use Rector\Core\Exception\ShouldNotHappenException;
|
||||
use Rector\Core\PhpParser\Parser\InlineCodeParser;
|
||||
use Rector\Core\Rector\AbstractRector;
|
||||
use Rector\Core\Rector\AbstractScopeAwareRector;
|
||||
use Rector\DowngradePhp72\NodeAnalyzer\FunctionExistsFunCallAnalyzer;
|
||||
use Rector\Naming\Naming\VariableNaming;
|
||||
use Rector\NodeTypeResolver\Node\AttributeKey;
|
||||
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
|
||||
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
|
||||
/**
|
||||
@ -22,7 +22,7 @@ use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
|
||||
*
|
||||
* @see \Rector\Tests\DowngradePhp81\Rector\FuncCall\DowngradeArrayIsListRector\DowngradeArrayIsListRectorTest
|
||||
*/
|
||||
final class DowngradeArrayIsListRector extends \Rector\Core\Rector\AbstractRector
|
||||
final class DowngradeArrayIsListRector extends \Rector\Core\Rector\AbstractScopeAwareRector
|
||||
{
|
||||
/**
|
||||
* @var \PhpParser\Node\Expr\Closure|null
|
||||
@ -85,16 +85,15 @@ CODE_SAMPLE
|
||||
/**
|
||||
* @param FuncCall $node
|
||||
*/
|
||||
public function refactor(\PhpParser\Node $node) : ?\PhpParser\Node\Expr\FuncCall
|
||||
public function refactorWithScope(\PhpParser\Node $node, \PHPStan\Analyser\Scope $scope) : ?\PhpParser\Node\Expr\FuncCall
|
||||
{
|
||||
if ($this->shouldSkip($node)) {
|
||||
return null;
|
||||
}
|
||||
$scope = $node->getAttribute(\Rector\NodeTypeResolver\Node\AttributeKey::SCOPE);
|
||||
$variable = new \PhpParser\Node\Expr\Variable($this->variableNaming->createCountedValueName('arrayIsList', $scope));
|
||||
$function = $this->createClosure();
|
||||
$expression = new \PhpParser\Node\Stmt\Expression(new \PhpParser\Node\Expr\Assign($variable, $function));
|
||||
$this->nodesToAddCollector->addNodeBeforeNode($expression, $node);
|
||||
$this->nodesToAddCollector->addNodeBeforeNode($expression, $node, $this->file->getSmartFileInfo());
|
||||
return new \PhpParser\Node\Expr\FuncCall($variable, $node->args);
|
||||
}
|
||||
private function createClosure() : \PhpParser\Node\Expr\Closure
|
||||
|
@ -115,7 +115,7 @@ CODE_SAMPLE
|
||||
private function processEarlyReturn(\PhpParser\Node\Stmt\Expression $expression, \PhpParser\Node\Expr\Assign $assign, array $breaks, \PhpParser\Node\Stmt\Return_ $return, \PhpParser\Node\Expr\Assign $assignPreviousVariable, \PhpParser\Node\Stmt\Foreach_ $foreach) : \PhpParser\Node\Stmt\Foreach_
|
||||
{
|
||||
$this->removeNode($expression);
|
||||
$this->nodesToAddCollector->addNodeBeforeNode(new \PhpParser\Node\Stmt\Return_($assign->expr), $breaks[0]);
|
||||
$this->nodesToAddCollector->addNodeBeforeNode(new \PhpParser\Node\Stmt\Return_($assign->expr), $breaks[0], $this->file->getSmartFileInfo());
|
||||
$this->removeNode($breaks[0]);
|
||||
$return->expr = $assignPreviousVariable->expr;
|
||||
$this->removeNode($assignPreviousVariable);
|
||||
|
@ -56,9 +56,10 @@ class SomeClass
|
||||
{
|
||||
public function accept()
|
||||
{
|
||||
if (!$this->something()) {
|
||||
if (! $this->something()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (bool) $this->somethingelse();
|
||||
}
|
||||
}
|
||||
|
@ -112,7 +112,7 @@ final class NonVariableToVariableOnFunctionCallRector extends \Rector\Core\Recto
|
||||
if (!$currentStmt instanceof \PhpParser\Node\Stmt) {
|
||||
continue;
|
||||
}
|
||||
$this->nodesToAddCollector->addNodeBeforeNode($replacements->getAssign(), $currentStmt);
|
||||
$this->nodesToAddCollector->addNodeBeforeNode($replacements->getAssign(), $currentStmt, $this->file->getSmartFileInfo());
|
||||
$node->args[$key]->value = $replacements->getVariable();
|
||||
// add variable name to scope, so we prevent duplication of new variable of the same name
|
||||
$currentScope = $currentScope->assignExpression($replacements->getVariable(), $currentScope->getType($replacements->getVariable()));
|
||||
|
@ -81,6 +81,7 @@ final class RemoveExtraParametersRector extends \Rector\Core\Rector\AbstractRect
|
||||
}
|
||||
}
|
||||
$maximumAllowedParameterCount = $this->resolveMaximumAllowedParameterCount($functionLikeReflection);
|
||||
//
|
||||
$numberOfArguments = \count($node->getRawArgs());
|
||||
if ($numberOfArguments <= $maximumAllowedParameterCount) {
|
||||
return null;
|
||||
|
@ -12,7 +12,7 @@ use PhpParser\Node\Expr\Ternary;
|
||||
use PhpParser\Node\Stmt\Class_;
|
||||
use PHPStan\Analyser\Scope;
|
||||
use PHPStan\Type\NullType;
|
||||
use Rector\Core\Rector\AbstractRector;
|
||||
use Rector\Core\Rector\AbstractScopeAwareRector;
|
||||
use Rector\Core\ValueObject\PhpVersionFeature;
|
||||
use Rector\NodeTypeResolver\Node\AttributeKey;
|
||||
use Rector\VersionBonding\Contract\MinPhpVersionInterface;
|
||||
@ -23,7 +23,7 @@ use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
|
||||
*
|
||||
* @see \Rector\Tests\Php72\Rector\FuncCall\GetClassOnNullRector\GetClassOnNullRectorTest
|
||||
*/
|
||||
final class GetClassOnNullRector extends \Rector\Core\Rector\AbstractRector implements \Rector\VersionBonding\Contract\MinPhpVersionInterface
|
||||
final class GetClassOnNullRector extends \Rector\Core\Rector\AbstractScopeAwareRector implements \Rector\VersionBonding\Contract\MinPhpVersionInterface
|
||||
{
|
||||
public function provideMinPhpVersion() : int
|
||||
{
|
||||
@ -63,7 +63,7 @@ CODE_SAMPLE
|
||||
/**
|
||||
* @param FuncCall $node
|
||||
*/
|
||||
public function refactor(\PhpParser\Node $node) : ?\PhpParser\Node
|
||||
public function refactorWithScope(\PhpParser\Node $node, \PHPStan\Analyser\Scope $scope) : ?\PhpParser\Node
|
||||
{
|
||||
if (!$this->isName($node, 'get_class')) {
|
||||
return null;
|
||||
@ -75,11 +75,6 @@ CODE_SAMPLE
|
||||
return null;
|
||||
}
|
||||
$firstArgValue = $node->args[0]->value;
|
||||
// only relevant inside the class
|
||||
$scope = $node->getAttribute(\Rector\NodeTypeResolver\Node\AttributeKey::SCOPE);
|
||||
if (!$scope instanceof \PHPStan\Analyser\Scope) {
|
||||
return null;
|
||||
}
|
||||
if (!$scope->isInClass()) {
|
||||
return null;
|
||||
}
|
||||
|
@ -14,11 +14,10 @@ use PHPStan\Type\NullType;
|
||||
use PHPStan\Type\Type;
|
||||
use PHPStan\Type\UnionType;
|
||||
use Rector\Core\Contract\Rector\AllowEmptyConfigurableRectorInterface;
|
||||
use Rector\Core\Rector\AbstractRector;
|
||||
use Rector\Core\Rector\AbstractScopeAwareRector;
|
||||
use Rector\Core\ValueObject\PhpVersionFeature;
|
||||
use Rector\DeadCode\PhpDoc\TagRemover\VarTagRemover;
|
||||
use Rector\FamilyTree\Reflection\FamilyRelationsAnalyzer;
|
||||
use Rector\NodeTypeResolver\Node\AttributeKey;
|
||||
use Rector\Php74\Guard\MakePropertyTypedGuard;
|
||||
use Rector\Php74\TypeAnalyzer\ObjectTypeAnalyzer;
|
||||
use Rector\PHPStanStaticTypeMapper\DoctrineTypeAnalyzer;
|
||||
@ -37,7 +36,7 @@ use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
|
||||
* @see \Rector\Tests\Php74\Rector\Property\TypedPropertyRector\DoctrineTypedPropertyRectorTest
|
||||
* @see \Rector\Tests\Php74\Rector\Property\TypedPropertyRector\ImportedTest
|
||||
*/
|
||||
final class TypedPropertyRector extends \Rector\Core\Rector\AbstractRector implements \Rector\Core\Contract\Rector\AllowEmptyConfigurableRectorInterface, \Rector\VersionBonding\Contract\MinPhpVersionInterface
|
||||
final class TypedPropertyRector extends \Rector\Core\Rector\AbstractScopeAwareRector implements \Rector\Core\Contract\Rector\AllowEmptyConfigurableRectorInterface, \Rector\VersionBonding\Contract\MinPhpVersionInterface
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
@ -141,7 +140,7 @@ CODE_SAMPLE
|
||||
/**
|
||||
* @param Property $node
|
||||
*/
|
||||
public function refactor(\PhpParser\Node $node) : ?\PhpParser\Node
|
||||
public function refactorWithScope(\PhpParser\Node $node, \PHPStan\Analyser\Scope $scope) : ?\PhpParser\Node
|
||||
{
|
||||
if (!$this->makePropertyTypedGuard->isLegal($node, $this->inlinePublic)) {
|
||||
return null;
|
||||
@ -157,8 +156,6 @@ CODE_SAMPLE
|
||||
if ($this->isNullOrNonClassLikeTypeOrMixedOrVendorLockedIn($propertyTypeNode, $node)) {
|
||||
return null;
|
||||
}
|
||||
/** @var Scope $scope */
|
||||
$scope = $node->getAttribute(\Rector\NodeTypeResolver\Node\AttributeKey::SCOPE);
|
||||
$propertyType = $this->familyRelationsAnalyzer->getPossibleUnionPropertyType($node, $varType, $scope, $propertyTypeNode);
|
||||
$varType = $propertyType->getVarType();
|
||||
$propertyTypeNode = $propertyType->getPropertyTypeNode();
|
||||
|
@ -17,10 +17,10 @@ use PhpParser\Node\Param;
|
||||
use PhpParser\Node\Stmt\ClassMethod;
|
||||
use PhpParser\Node\Stmt\If_;
|
||||
use PhpParser\Node\UnionType;
|
||||
use PHPStan\Analyser\Scope;
|
||||
use PHPStan\Reflection\ClassReflection;
|
||||
use Rector\Core\Rector\AbstractRector;
|
||||
use Rector\Core\Rector\AbstractScopeAwareRector;
|
||||
use Rector\Core\Reflection\ReflectionResolver;
|
||||
use Rector\NodeTypeResolver\Node\AttributeKey;
|
||||
use Rector\TypeDeclaration\NodeAnalyzer\CallerParamMatcher;
|
||||
use Rector\VendorLocker\ParentClassMethodTypeOverrideGuard;
|
||||
use RectorPrefix20220512\Symplify\Astral\NodeTraverser\SimpleCallableNodeTraverser;
|
||||
@ -29,7 +29,7 @@ use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
|
||||
/**
|
||||
* @see \Rector\Tests\TypeDeclaration\Rector\ClassMethod\ParamTypeByMethodCallTypeRector\ParamTypeByMethodCallTypeRectorTest
|
||||
*/
|
||||
final class ParamTypeByMethodCallTypeRector extends \Rector\Core\Rector\AbstractRector
|
||||
final class ParamTypeByMethodCallTypeRector extends \Rector\Core\Rector\AbstractScopeAwareRector
|
||||
{
|
||||
/**
|
||||
* @readonly
|
||||
@ -114,7 +114,7 @@ CODE_SAMPLE
|
||||
/**
|
||||
* @param ClassMethod $node
|
||||
*/
|
||||
public function refactor(\PhpParser\Node $node) : ?\PhpParser\Node
|
||||
public function refactorWithScope(\PhpParser\Node $node, \PHPStan\Analyser\Scope $scope) : ?\PhpParser\Node
|
||||
{
|
||||
if ($this->shouldSkipClassMethod($node)) {
|
||||
return null;
|
||||
@ -122,7 +122,6 @@ CODE_SAMPLE
|
||||
/** @var array<StaticCall|MethodCall|FuncCall> $callers */
|
||||
$callers = $this->betterNodeFinder->findInstancesOf((array) $node->stmts, [\PhpParser\Node\Expr\StaticCall::class, \PhpParser\Node\Expr\MethodCall::class, \PhpParser\Node\Expr\FuncCall::class]);
|
||||
$hasChanged = \false;
|
||||
$scope = $node->getAttribute(\Rector\NodeTypeResolver\Node\AttributeKey::SCOPE);
|
||||
foreach ($node->params as $param) {
|
||||
if ($this->shouldSkipParam($param, $node)) {
|
||||
continue;
|
||||
|
73
src/Application/ChangedNodeScopeRefresher.php
Normal file
73
src/Application/ChangedNodeScopeRefresher.php
Normal file
@ -0,0 +1,73 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace Rector\Core\Application;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Arg;
|
||||
use PhpParser\Node\Attribute;
|
||||
use PhpParser\Node\AttributeGroup;
|
||||
use PhpParser\Node\Expr;
|
||||
use PhpParser\Node\Identifier;
|
||||
use PhpParser\Node\Param;
|
||||
use PhpParser\Node\Stmt;
|
||||
use PhpParser\Node\Stmt\Enum_;
|
||||
use PhpParser\Node\Stmt\Expression;
|
||||
use PhpParser\Node\Stmt\Property;
|
||||
use PHPStan\Analyser\MutatingScope;
|
||||
use Rector\Core\Exception\ShouldNotHappenException;
|
||||
use Rector\NodeTypeResolver\PHPStan\Scope\PHPStanNodeScopeResolver;
|
||||
use Symplify\SmartFileSystem\SmartFileInfo;
|
||||
/**
|
||||
* In case of changed node, we need to re-traverse the PHPStan Scope to make all the new nodes aware of what is going on.
|
||||
*/
|
||||
final class ChangedNodeScopeRefresher
|
||||
{
|
||||
/**
|
||||
* @readonly
|
||||
* @var \Rector\NodeTypeResolver\PHPStan\Scope\PHPStanNodeScopeResolver
|
||||
*/
|
||||
private $phpStanNodeScopeResolver;
|
||||
public function __construct(\Rector\NodeTypeResolver\PHPStan\Scope\PHPStanNodeScopeResolver $phpStanNodeScopeResolver)
|
||||
{
|
||||
$this->phpStanNodeScopeResolver = $phpStanNodeScopeResolver;
|
||||
}
|
||||
/**
|
||||
* @param \PhpParser\Node\Expr|\PhpParser\Node\Stmt|\PhpParser\Node $node
|
||||
*/
|
||||
public function refresh($node, \Symplify\SmartFileSystem\SmartFileInfo $smartFileInfo, \PHPStan\Analyser\MutatingScope $mutatingScope) : void
|
||||
{
|
||||
// nothing to refresh
|
||||
if ($node instanceof \PhpParser\Node\Identifier) {
|
||||
return;
|
||||
}
|
||||
// note from flight: when we traverse ClassMethod, the scope must be already in Class_, otherwise it crashes
|
||||
// so we need to somehow get a parent scope that is already in the same place the $node is
|
||||
if ($node instanceof \PhpParser\Node\Attribute) {
|
||||
// we'll have to fake-traverse 2 layers up, as PHPStan skips Scope for AttributeGroups and consequently Attributes
|
||||
$attributeGroup = new \PhpParser\Node\AttributeGroup([$node]);
|
||||
$node = new \PhpParser\Node\Stmt\Property(0, [], [], null, [$attributeGroup]);
|
||||
}
|
||||
// phpstan cannot process for some reason
|
||||
if ($node instanceof \PhpParser\Node\Stmt\Enum_) {
|
||||
return;
|
||||
}
|
||||
if ($node instanceof \PhpParser\Node\Stmt) {
|
||||
$stmts = [$node];
|
||||
} elseif ($node instanceof \PhpParser\Node\Expr) {
|
||||
$stmts = [new \PhpParser\Node\Stmt\Expression($node)];
|
||||
} else {
|
||||
if ($node instanceof \PhpParser\Node\Param) {
|
||||
// param type cannot be refreshed
|
||||
return;
|
||||
}
|
||||
if ($node instanceof \PhpParser\Node\Arg) {
|
||||
// arg type cannot be refreshed
|
||||
return;
|
||||
}
|
||||
$errorMessage = \sprintf('Complete parent node of "%s" be a stmt.', \get_class($node));
|
||||
throw new \Rector\Core\Exception\ShouldNotHappenException($errorMessage);
|
||||
}
|
||||
$this->phpStanNodeScopeResolver->processNodes($stmts, $smartFileInfo, $mutatingScope);
|
||||
}
|
||||
}
|
@ -16,11 +16,11 @@ final class VersionResolver
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public const PACKAGE_VERSION = '39e552c4c97dbb23ada4470fa1b89773ce5bc2a3';
|
||||
public const PACKAGE_VERSION = '33cd52e703d44690b91106f4752b5786420fa2db';
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public const RELEASE_DATE = '2022-05-12 08:07:50';
|
||||
public const RELEASE_DATE = '2022-05-12 09:05:03';
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
|
28
src/NodeAnalyzer/UnreachableStmtAnalyzer.php
Normal file
28
src/NodeAnalyzer/UnreachableStmtAnalyzer.php
Normal file
@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace Rector\Core\NodeAnalyzer;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Stmt;
|
||||
use Rector\NodeTypeResolver\Node\AttributeKey;
|
||||
final class UnreachableStmtAnalyzer
|
||||
{
|
||||
public function isStmtPHPStanUnreachable(\PhpParser\Node\Stmt $stmt) : bool
|
||||
{
|
||||
if ($stmt->getAttribute(\Rector\NodeTypeResolver\Node\AttributeKey::IS_UNREACHABLE) === \true) {
|
||||
// here the scope is never available for next stmt so we have nothing to refresh
|
||||
return \true;
|
||||
}
|
||||
$previousStmt = $stmt;
|
||||
while ($previousStmt = $previousStmt->getAttribute(\Rector\NodeTypeResolver\Node\AttributeKey::PREVIOUS_NODE)) {
|
||||
if (!$previousStmt instanceof \PhpParser\Node) {
|
||||
break;
|
||||
}
|
||||
if ($previousStmt->getAttribute(\Rector\NodeTypeResolver\Node\AttributeKey::IS_UNREACHABLE) === \true) {
|
||||
return \true;
|
||||
}
|
||||
}
|
||||
return \false;
|
||||
}
|
||||
}
|
@ -6,8 +6,11 @@ namespace Rector\Core\Rector;
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Arg;
|
||||
use PhpParser\Node\Expr;
|
||||
use PhpParser\Node\Identifier;
|
||||
use PhpParser\Node\Name;
|
||||
use PhpParser\Node\Stmt;
|
||||
use PhpParser\Node\Stmt\Expression;
|
||||
use PhpParser\Node\Stmt\Namespace_;
|
||||
use PhpParser\NodeTraverser;
|
||||
use PhpParser\NodeVisitor\ParentConnectingVisitor;
|
||||
use PhpParser\NodeVisitorAbstract;
|
||||
@ -15,14 +18,17 @@ use PHPStan\Type\ObjectType;
|
||||
use PHPStan\Type\Type;
|
||||
use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfoFactory;
|
||||
use Rector\ChangesReporting\ValueObject\RectorWithLineChange;
|
||||
use Rector\Core\Application\ChangedNodeScopeRefresher;
|
||||
use Rector\Core\Configuration\CurrentNodeProvider;
|
||||
use Rector\Core\Contract\Rector\PhpRectorInterface;
|
||||
use Rector\Core\Exception\ShouldNotHappenException;
|
||||
use Rector\Core\Exclusion\ExclusionManager;
|
||||
use Rector\Core\Logging\CurrentRectorProvider;
|
||||
use Rector\Core\NodeAnalyzer\UnreachableStmtAnalyzer;
|
||||
use Rector\Core\NodeDecorator\CreatedByRuleDecorator;
|
||||
use Rector\Core\PhpParser\Comparing\NodeComparator;
|
||||
use Rector\Core\PhpParser\Node\BetterNodeFinder;
|
||||
use Rector\Core\PhpParser\Node\CustomNode\FileWithoutNamespace;
|
||||
use Rector\Core\PhpParser\Node\NodeFactory;
|
||||
use Rector\Core\PhpParser\Node\Value\ValueResolver;
|
||||
use Rector\Core\ProcessAnalyzer\RectifiedAnalyzer;
|
||||
@ -108,6 +114,10 @@ CODE_SAMPLE;
|
||||
* @var \Rector\PostRector\Collector\NodesToAddCollector
|
||||
*/
|
||||
protected $nodesToAddCollector;
|
||||
/**
|
||||
* @var \Rector\Core\Application\ChangedNodeScopeRefresher
|
||||
*/
|
||||
protected $changedNodeScopeRefresher;
|
||||
/**
|
||||
* @var \Symplify\Astral\NodeTraverser\SimpleCallableNodeTraverser
|
||||
*/
|
||||
@ -144,10 +154,14 @@ CODE_SAMPLE;
|
||||
* @var \Rector\Core\NodeDecorator\CreatedByRuleDecorator
|
||||
*/
|
||||
private $createdByRuleDecorator;
|
||||
/**
|
||||
* @var \Rector\Core\NodeAnalyzer\UnreachableStmtAnalyzer
|
||||
*/
|
||||
private $unreachableStmtAnalyzer;
|
||||
/**
|
||||
* @required
|
||||
*/
|
||||
public function autowire(\Rector\PostRector\Collector\NodesToRemoveCollector $nodesToRemoveCollector, \Rector\PostRector\Collector\NodesToAddCollector $nodesToAddCollector, \Rector\NodeRemoval\NodeRemover $nodeRemover, \Rector\NodeNameResolver\NodeNameResolver $nodeNameResolver, \Rector\NodeTypeResolver\NodeTypeResolver $nodeTypeResolver, \RectorPrefix20220512\Symplify\Astral\NodeTraverser\SimpleCallableNodeTraverser $simpleCallableNodeTraverser, \Rector\Core\PhpParser\Node\NodeFactory $nodeFactory, \Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfoFactory $phpDocInfoFactory, \Rector\Core\Exclusion\ExclusionManager $exclusionManager, \Rector\StaticTypeMapper\StaticTypeMapper $staticTypeMapper, \Rector\Core\Logging\CurrentRectorProvider $currentRectorProvider, \Rector\Core\Configuration\CurrentNodeProvider $currentNodeProvider, \RectorPrefix20220512\Symplify\Skipper\Skipper\Skipper $skipper, \Rector\Core\PhpParser\Node\Value\ValueResolver $valueResolver, \Rector\Core\PhpParser\Node\BetterNodeFinder $betterNodeFinder, \Rector\Core\PhpParser\Comparing\NodeComparator $nodeComparator, \Rector\Core\Provider\CurrentFileProvider $currentFileProvider, \Rector\Core\ProcessAnalyzer\RectifiedAnalyzer $rectifiedAnalyzer, \Rector\Core\NodeDecorator\CreatedByRuleDecorator $createdByRuleDecorator) : void
|
||||
public function autowire(\Rector\PostRector\Collector\NodesToRemoveCollector $nodesToRemoveCollector, \Rector\PostRector\Collector\NodesToAddCollector $nodesToAddCollector, \Rector\NodeRemoval\NodeRemover $nodeRemover, \Rector\NodeNameResolver\NodeNameResolver $nodeNameResolver, \Rector\NodeTypeResolver\NodeTypeResolver $nodeTypeResolver, \RectorPrefix20220512\Symplify\Astral\NodeTraverser\SimpleCallableNodeTraverser $simpleCallableNodeTraverser, \Rector\Core\PhpParser\Node\NodeFactory $nodeFactory, \Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfoFactory $phpDocInfoFactory, \Rector\Core\Exclusion\ExclusionManager $exclusionManager, \Rector\StaticTypeMapper\StaticTypeMapper $staticTypeMapper, \Rector\Core\Logging\CurrentRectorProvider $currentRectorProvider, \Rector\Core\Configuration\CurrentNodeProvider $currentNodeProvider, \RectorPrefix20220512\Symplify\Skipper\Skipper\Skipper $skipper, \Rector\Core\PhpParser\Node\Value\ValueResolver $valueResolver, \Rector\Core\PhpParser\Node\BetterNodeFinder $betterNodeFinder, \Rector\Core\PhpParser\Comparing\NodeComparator $nodeComparator, \Rector\Core\Provider\CurrentFileProvider $currentFileProvider, \Rector\Core\ProcessAnalyzer\RectifiedAnalyzer $rectifiedAnalyzer, \Rector\Core\NodeDecorator\CreatedByRuleDecorator $createdByRuleDecorator, \Rector\Core\Application\ChangedNodeScopeRefresher $changedNodeScopeRefresher, \Rector\Core\NodeAnalyzer\UnreachableStmtAnalyzer $unreachableStmtAnalyzer) : void
|
||||
{
|
||||
$this->nodesToRemoveCollector = $nodesToRemoveCollector;
|
||||
$this->nodesToAddCollector = $nodesToAddCollector;
|
||||
@ -168,6 +182,8 @@ CODE_SAMPLE;
|
||||
$this->currentFileProvider = $currentFileProvider;
|
||||
$this->rectifiedAnalyzer = $rectifiedAnalyzer;
|
||||
$this->createdByRuleDecorator = $createdByRuleDecorator;
|
||||
$this->changedNodeScopeRefresher = $changedNodeScopeRefresher;
|
||||
$this->unreachableStmtAnalyzer = $unreachableStmtAnalyzer;
|
||||
}
|
||||
/**
|
||||
* @return Node[]|null
|
||||
@ -231,6 +247,27 @@ CODE_SAMPLE;
|
||||
// update parents relations - must run before connectParentNodes()
|
||||
/** @var Node $node */
|
||||
$this->mirrorAttributes($originalAttributes, $node);
|
||||
$currentScope = $originalNode->getAttribute(\Rector\NodeTypeResolver\Node\AttributeKey::SCOPE);
|
||||
$requiresScopeRefresh = \true;
|
||||
// names do not have scope in PHPStan
|
||||
if (!$node instanceof \PhpParser\Node\Name && !$node instanceof \PhpParser\Node\Stmt\Namespace_ && !$node instanceof \Rector\Core\PhpParser\Node\CustomNode\FileWithoutNamespace && !$node instanceof \PhpParser\Node\Identifier) {
|
||||
if ($currentScope === null) {
|
||||
$parent = $node->getAttribute(\Rector\NodeTypeResolver\Node\AttributeKey::PARENT_NODE);
|
||||
// in case of unreachable stmts, no other node will have available scope
|
||||
// loop all previous expressions, until we find nothing or is_unreachable
|
||||
$currentStmt = $this->betterNodeFinder->resolveCurrentStatement($parent);
|
||||
if ($currentStmt instanceof \PhpParser\Node\Stmt && $this->unreachableStmtAnalyzer->isStmtPHPStanUnreachable($currentStmt)) {
|
||||
$requiresScopeRefresh = \false;
|
||||
}
|
||||
if ($requiresScopeRefresh) {
|
||||
$errorMessage = \sprintf('Node "%s" with parent of "%s" is missing scope required for scope refresh.', \get_class($node), $parent instanceof \PhpParser\Node ? \get_class($parent) : null);
|
||||
throw new \Rector\Core\Exception\ShouldNotHappenException($errorMessage);
|
||||
}
|
||||
}
|
||||
if ($requiresScopeRefresh) {
|
||||
$this->changedNodeScopeRefresher->refresh($node, $this->file->getSmartFileInfo(), $currentScope);
|
||||
}
|
||||
}
|
||||
$this->connectParentNodes($node);
|
||||
// is equals node type? return node early
|
||||
if (\get_class($originalNode) === \get_class($node)) {
|
||||
|
2
vendor/autoload.php
vendored
2
vendor/autoload.php
vendored
@ -9,4 +9,4 @@ if (PHP_VERSION_ID < 50600) {
|
||||
|
||||
require_once __DIR__ . '/composer/autoload_real.php';
|
||||
|
||||
return ComposerAutoloaderInit10ed0a615d90a5e9a7d6f335d71cd385::getLoader();
|
||||
return ComposerAutoloaderInitd0878124c697db250d7bcff1ad0e5a59::getLoader();
|
||||
|
4
vendor/composer/autoload_classmap.php
vendored
4
vendor/composer/autoload_classmap.php
vendored
@ -1635,6 +1635,7 @@ return array(
|
||||
'Rector\\Composer\\ValueObject\\ReplacePackageAndVersion' => $baseDir . '/rules/Composer/ValueObject/ReplacePackageAndVersion.php',
|
||||
'Rector\\Config\\RectorConfig' => $baseDir . '/packages/Config/RectorConfig.php',
|
||||
'Rector\\Core\\Application\\ApplicationFileProcessor' => $baseDir . '/src/Application/ApplicationFileProcessor.php',
|
||||
'Rector\\Core\\Application\\ChangedNodeScopeRefresher' => $baseDir . '/src/Application/ChangedNodeScopeRefresher.php',
|
||||
'Rector\\Core\\Application\\FileDecorator\\FileDiffFileDecorator' => $baseDir . '/src/Application/FileDecorator/FileDiffFileDecorator.php',
|
||||
'Rector\\Core\\Application\\FileProcessor' => $baseDir . '/src/Application/FileProcessor.php',
|
||||
'Rector\\Core\\Application\\FileProcessor\\PhpFileProcessor' => $baseDir . '/src/Application/FileProcessor/PhpFileProcessor.php',
|
||||
@ -1711,6 +1712,7 @@ return array(
|
||||
'Rector\\Core\\NodeAnalyzer\\PropertyAnalyzer' => $baseDir . '/src/NodeAnalyzer/PropertyAnalyzer.php',
|
||||
'Rector\\Core\\NodeAnalyzer\\PropertyFetchAnalyzer' => $baseDir . '/src/NodeAnalyzer/PropertyFetchAnalyzer.php',
|
||||
'Rector\\Core\\NodeAnalyzer\\PropertyPresenceChecker' => $baseDir . '/src/NodeAnalyzer/PropertyPresenceChecker.php',
|
||||
'Rector\\Core\\NodeAnalyzer\\UnreachableStmtAnalyzer' => $baseDir . '/src/NodeAnalyzer/UnreachableStmtAnalyzer.php',
|
||||
'Rector\\Core\\NodeAnalyzer\\VariableAnalyzer' => $baseDir . '/src/NodeAnalyzer/VariableAnalyzer.php',
|
||||
'Rector\\Core\\NodeAnalyzer\\VariadicAnalyzer' => $baseDir . '/src/NodeAnalyzer/VariadicAnalyzer.php',
|
||||
'Rector\\Core\\NodeDecorator\\CreatedByRuleDecorator' => $baseDir . '/src/NodeDecorator/CreatedByRuleDecorator.php',
|
||||
@ -2087,6 +2089,8 @@ return array(
|
||||
'Rector\\DowngradePhp80\\Rector\\StaticCall\\DowngradePhpTokenRector' => $baseDir . '/rules/DowngradePhp80/Rector/StaticCall/DowngradePhpTokenRector.php',
|
||||
'Rector\\DowngradePhp80\\Reflection\\DefaultParameterValueResolver' => $baseDir . '/rules/DowngradePhp80/Reflection/DefaultParameterValueResolver.php',
|
||||
'Rector\\DowngradePhp80\\ValueObject\\DowngradeAttributeToAnnotation' => $baseDir . '/rules/DowngradePhp80/ValueObject/DowngradeAttributeToAnnotation.php',
|
||||
'Rector\\DowngradePhp81\\NodeAnalyzer\\ArraySpreadAnalyzer' => $baseDir . '/rules/DowngradePhp81/NodeAnalyzer/ArraySpreadAnalyzer.php',
|
||||
'Rector\\DowngradePhp81\\NodeFactory\\ArrayMergeFromArraySpreadFactory' => $baseDir . '/rules/DowngradePhp81/NodeFactory/ArrayMergeFromArraySpreadFactory.php',
|
||||
'Rector\\DowngradePhp81\\NodeManipulator\\ObjectToResourceReturn' => $baseDir . '/rules/DowngradePhp81/NodeManipulator/ObjectToResourceReturn.php',
|
||||
'Rector\\DowngradePhp81\\Rector\\Array_\\DowngradeArraySpreadStringKeyRector' => $baseDir . '/rules/DowngradePhp81/Rector/Array_/DowngradeArraySpreadStringKeyRector.php',
|
||||
'Rector\\DowngradePhp81\\Rector\\ClassConst\\DowngradeFinalizePublicClassConstantRector' => $baseDir . '/rules/DowngradePhp81/Rector/ClassConst/DowngradeFinalizePublicClassConstantRector.php',
|
||||
|
14
vendor/composer/autoload_real.php
vendored
14
vendor/composer/autoload_real.php
vendored
@ -2,7 +2,7 @@
|
||||
|
||||
// autoload_real.php @generated by Composer
|
||||
|
||||
class ComposerAutoloaderInit10ed0a615d90a5e9a7d6f335d71cd385
|
||||
class ComposerAutoloaderInitd0878124c697db250d7bcff1ad0e5a59
|
||||
{
|
||||
private static $loader;
|
||||
|
||||
@ -22,19 +22,19 @@ class ComposerAutoloaderInit10ed0a615d90a5e9a7d6f335d71cd385
|
||||
return self::$loader;
|
||||
}
|
||||
|
||||
spl_autoload_register(array('ComposerAutoloaderInit10ed0a615d90a5e9a7d6f335d71cd385', 'loadClassLoader'), true, true);
|
||||
spl_autoload_register(array('ComposerAutoloaderInitd0878124c697db250d7bcff1ad0e5a59', 'loadClassLoader'), true, true);
|
||||
self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__));
|
||||
spl_autoload_unregister(array('ComposerAutoloaderInit10ed0a615d90a5e9a7d6f335d71cd385', 'loadClassLoader'));
|
||||
spl_autoload_unregister(array('ComposerAutoloaderInitd0878124c697db250d7bcff1ad0e5a59', 'loadClassLoader'));
|
||||
|
||||
require __DIR__ . '/autoload_static.php';
|
||||
call_user_func(\Composer\Autoload\ComposerStaticInit10ed0a615d90a5e9a7d6f335d71cd385::getInitializer($loader));
|
||||
call_user_func(\Composer\Autoload\ComposerStaticInitd0878124c697db250d7bcff1ad0e5a59::getInitializer($loader));
|
||||
|
||||
$loader->setClassMapAuthoritative(true);
|
||||
$loader->register(true);
|
||||
|
||||
$includeFiles = \Composer\Autoload\ComposerStaticInit10ed0a615d90a5e9a7d6f335d71cd385::$files;
|
||||
$includeFiles = \Composer\Autoload\ComposerStaticInitd0878124c697db250d7bcff1ad0e5a59::$files;
|
||||
foreach ($includeFiles as $fileIdentifier => $file) {
|
||||
composerRequire10ed0a615d90a5e9a7d6f335d71cd385($fileIdentifier, $file);
|
||||
composerRequired0878124c697db250d7bcff1ad0e5a59($fileIdentifier, $file);
|
||||
}
|
||||
|
||||
return $loader;
|
||||
@ -46,7 +46,7 @@ class ComposerAutoloaderInit10ed0a615d90a5e9a7d6f335d71cd385
|
||||
* @param string $file
|
||||
* @return void
|
||||
*/
|
||||
function composerRequire10ed0a615d90a5e9a7d6f335d71cd385($fileIdentifier, $file)
|
||||
function composerRequired0878124c697db250d7bcff1ad0e5a59($fileIdentifier, $file)
|
||||
{
|
||||
if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
|
||||
$GLOBALS['__composer_autoload_files'][$fileIdentifier] = true;
|
||||
|
12
vendor/composer/autoload_static.php
vendored
12
vendor/composer/autoload_static.php
vendored
@ -4,7 +4,7 @@
|
||||
|
||||
namespace Composer\Autoload;
|
||||
|
||||
class ComposerStaticInit10ed0a615d90a5e9a7d6f335d71cd385
|
||||
class ComposerStaticInitd0878124c697db250d7bcff1ad0e5a59
|
||||
{
|
||||
public static $files = array (
|
||||
'320cde22f66dd4f5d3fd621d3e88b98f' => __DIR__ . '/..' . '/symfony/polyfill-ctype/bootstrap.php',
|
||||
@ -2004,6 +2004,7 @@ class ComposerStaticInit10ed0a615d90a5e9a7d6f335d71cd385
|
||||
'Rector\\Composer\\ValueObject\\ReplacePackageAndVersion' => __DIR__ . '/../..' . '/rules/Composer/ValueObject/ReplacePackageAndVersion.php',
|
||||
'Rector\\Config\\RectorConfig' => __DIR__ . '/../..' . '/packages/Config/RectorConfig.php',
|
||||
'Rector\\Core\\Application\\ApplicationFileProcessor' => __DIR__ . '/../..' . '/src/Application/ApplicationFileProcessor.php',
|
||||
'Rector\\Core\\Application\\ChangedNodeScopeRefresher' => __DIR__ . '/../..' . '/src/Application/ChangedNodeScopeRefresher.php',
|
||||
'Rector\\Core\\Application\\FileDecorator\\FileDiffFileDecorator' => __DIR__ . '/../..' . '/src/Application/FileDecorator/FileDiffFileDecorator.php',
|
||||
'Rector\\Core\\Application\\FileProcessor' => __DIR__ . '/../..' . '/src/Application/FileProcessor.php',
|
||||
'Rector\\Core\\Application\\FileProcessor\\PhpFileProcessor' => __DIR__ . '/../..' . '/src/Application/FileProcessor/PhpFileProcessor.php',
|
||||
@ -2080,6 +2081,7 @@ class ComposerStaticInit10ed0a615d90a5e9a7d6f335d71cd385
|
||||
'Rector\\Core\\NodeAnalyzer\\PropertyAnalyzer' => __DIR__ . '/../..' . '/src/NodeAnalyzer/PropertyAnalyzer.php',
|
||||
'Rector\\Core\\NodeAnalyzer\\PropertyFetchAnalyzer' => __DIR__ . '/../..' . '/src/NodeAnalyzer/PropertyFetchAnalyzer.php',
|
||||
'Rector\\Core\\NodeAnalyzer\\PropertyPresenceChecker' => __DIR__ . '/../..' . '/src/NodeAnalyzer/PropertyPresenceChecker.php',
|
||||
'Rector\\Core\\NodeAnalyzer\\UnreachableStmtAnalyzer' => __DIR__ . '/../..' . '/src/NodeAnalyzer/UnreachableStmtAnalyzer.php',
|
||||
'Rector\\Core\\NodeAnalyzer\\VariableAnalyzer' => __DIR__ . '/../..' . '/src/NodeAnalyzer/VariableAnalyzer.php',
|
||||
'Rector\\Core\\NodeAnalyzer\\VariadicAnalyzer' => __DIR__ . '/../..' . '/src/NodeAnalyzer/VariadicAnalyzer.php',
|
||||
'Rector\\Core\\NodeDecorator\\CreatedByRuleDecorator' => __DIR__ . '/../..' . '/src/NodeDecorator/CreatedByRuleDecorator.php',
|
||||
@ -2456,6 +2458,8 @@ class ComposerStaticInit10ed0a615d90a5e9a7d6f335d71cd385
|
||||
'Rector\\DowngradePhp80\\Rector\\StaticCall\\DowngradePhpTokenRector' => __DIR__ . '/../..' . '/rules/DowngradePhp80/Rector/StaticCall/DowngradePhpTokenRector.php',
|
||||
'Rector\\DowngradePhp80\\Reflection\\DefaultParameterValueResolver' => __DIR__ . '/../..' . '/rules/DowngradePhp80/Reflection/DefaultParameterValueResolver.php',
|
||||
'Rector\\DowngradePhp80\\ValueObject\\DowngradeAttributeToAnnotation' => __DIR__ . '/../..' . '/rules/DowngradePhp80/ValueObject/DowngradeAttributeToAnnotation.php',
|
||||
'Rector\\DowngradePhp81\\NodeAnalyzer\\ArraySpreadAnalyzer' => __DIR__ . '/../..' . '/rules/DowngradePhp81/NodeAnalyzer/ArraySpreadAnalyzer.php',
|
||||
'Rector\\DowngradePhp81\\NodeFactory\\ArrayMergeFromArraySpreadFactory' => __DIR__ . '/../..' . '/rules/DowngradePhp81/NodeFactory/ArrayMergeFromArraySpreadFactory.php',
|
||||
'Rector\\DowngradePhp81\\NodeManipulator\\ObjectToResourceReturn' => __DIR__ . '/../..' . '/rules/DowngradePhp81/NodeManipulator/ObjectToResourceReturn.php',
|
||||
'Rector\\DowngradePhp81\\Rector\\Array_\\DowngradeArraySpreadStringKeyRector' => __DIR__ . '/../..' . '/rules/DowngradePhp81/Rector/Array_/DowngradeArraySpreadStringKeyRector.php',
|
||||
'Rector\\DowngradePhp81\\Rector\\ClassConst\\DowngradeFinalizePublicClassConstantRector' => __DIR__ . '/../..' . '/rules/DowngradePhp81/Rector/ClassConst/DowngradeFinalizePublicClassConstantRector.php',
|
||||
@ -3891,9 +3895,9 @@ class ComposerStaticInit10ed0a615d90a5e9a7d6f335d71cd385
|
||||
public static function getInitializer(ClassLoader $loader)
|
||||
{
|
||||
return \Closure::bind(function () use ($loader) {
|
||||
$loader->prefixLengthsPsr4 = ComposerStaticInit10ed0a615d90a5e9a7d6f335d71cd385::$prefixLengthsPsr4;
|
||||
$loader->prefixDirsPsr4 = ComposerStaticInit10ed0a615d90a5e9a7d6f335d71cd385::$prefixDirsPsr4;
|
||||
$loader->classMap = ComposerStaticInit10ed0a615d90a5e9a7d6f335d71cd385::$classMap;
|
||||
$loader->prefixLengthsPsr4 = ComposerStaticInitd0878124c697db250d7bcff1ad0e5a59::$prefixLengthsPsr4;
|
||||
$loader->prefixDirsPsr4 = ComposerStaticInitd0878124c697db250d7bcff1ad0e5a59::$prefixDirsPsr4;
|
||||
$loader->classMap = ComposerStaticInitd0878124c697db250d7bcff1ad0e5a59::$classMap;
|
||||
|
||||
}, null, ClassLoader::class);
|
||||
}
|
||||
|
10
vendor/scoper-autoload.php
vendored
10
vendor/scoper-autoload.php
vendored
@ -9,8 +9,8 @@ $loader = require_once __DIR__.'/autoload.php';
|
||||
if (!class_exists('AutoloadIncluder', false) && !interface_exists('AutoloadIncluder', false) && !trait_exists('AutoloadIncluder', false)) {
|
||||
spl_autoload_call('RectorPrefix20220512\AutoloadIncluder');
|
||||
}
|
||||
if (!class_exists('ComposerAutoloaderInit10ed0a615d90a5e9a7d6f335d71cd385', false) && !interface_exists('ComposerAutoloaderInit10ed0a615d90a5e9a7d6f335d71cd385', false) && !trait_exists('ComposerAutoloaderInit10ed0a615d90a5e9a7d6f335d71cd385', false)) {
|
||||
spl_autoload_call('RectorPrefix20220512\ComposerAutoloaderInit10ed0a615d90a5e9a7d6f335d71cd385');
|
||||
if (!class_exists('ComposerAutoloaderInitd0878124c697db250d7bcff1ad0e5a59', false) && !interface_exists('ComposerAutoloaderInitd0878124c697db250d7bcff1ad0e5a59', false) && !trait_exists('ComposerAutoloaderInitd0878124c697db250d7bcff1ad0e5a59', false)) {
|
||||
spl_autoload_call('RectorPrefix20220512\ComposerAutoloaderInitd0878124c697db250d7bcff1ad0e5a59');
|
||||
}
|
||||
if (!class_exists('Helmich\TypoScriptParser\Parser\AST\Statement', false) && !interface_exists('Helmich\TypoScriptParser\Parser\AST\Statement', false) && !trait_exists('Helmich\TypoScriptParser\Parser\AST\Statement', false)) {
|
||||
spl_autoload_call('RectorPrefix20220512\Helmich\TypoScriptParser\Parser\AST\Statement');
|
||||
@ -59,9 +59,9 @@ if (!function_exists('print_node')) {
|
||||
return \RectorPrefix20220512\print_node(...func_get_args());
|
||||
}
|
||||
}
|
||||
if (!function_exists('composerRequire10ed0a615d90a5e9a7d6f335d71cd385')) {
|
||||
function composerRequire10ed0a615d90a5e9a7d6f335d71cd385() {
|
||||
return \RectorPrefix20220512\composerRequire10ed0a615d90a5e9a7d6f335d71cd385(...func_get_args());
|
||||
if (!function_exists('composerRequired0878124c697db250d7bcff1ad0e5a59')) {
|
||||
function composerRequired0878124c697db250d7bcff1ad0e5a59() {
|
||||
return \RectorPrefix20220512\composerRequired0878124c697db250d7bcff1ad0e5a59(...func_get_args());
|
||||
}
|
||||
}
|
||||
if (!function_exists('scanPath')) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user