Updated Rector to commit 93a4b2b15eec15c506ae55c25b23a40dd0390cff

93a4b2b15e [NodeTypeResolver] Remove parent attribute on PHPStanNodeScopeResolver for after UnreachableStatementNode detector (#4415)
This commit is contained in:
Tomas Votruba 2023-07-04 08:36:47 +00:00
parent 1f28e1c52a
commit 7251a47b0d
11 changed files with 99 additions and 70 deletions

View File

@ -3,15 +3,10 @@ parameters:
featureToggles:
disableRuntimeReflectionProvider: false
conditionalTags:
PhpParser\NodeVisitor\ParentConnectingVisitor:
phpstan.parser.richParserNodeVisitor: true
services:
- Rector\NodeTypeResolver\Reflection\BetterReflection\RectorBetterReflectionSourceLocatorFactory
- Rector\NodeTypeResolver\Reflection\BetterReflection\SourceLocator\IntermediateSourceLocator
- Rector\NodeTypeResolver\Reflection\BetterReflection\SourceLocatorProvider\DynamicSourceLocatorProvider
- PhpParser\NodeVisitor\ParentConnectingVisitor
# basically decorates native PHPStan source locator with a dynamic source locator that is also available in Rector DI
betterReflectionSourceLocator:

View File

@ -8,6 +8,7 @@ use PhpParser\NodeTraverser;
use PhpParser\NodeVisitor\CloningVisitor;
use PhpParser\NodeVisitor\ParentConnectingVisitor;
use Rector\Core\PhpParser\NodeTraverser\FileWithoutNamespaceNodeTraverser;
use Rector\Core\PHPStan\NodeVisitor\UnreachableStatementNodeVisitor;
use Rector\Core\ValueObject\Application\File;
use Rector\NodeTypeResolver\NodeVisitor\FunctionLikeParamArgPositionNodeVisitor;
use Rector\NodeTypeResolver\PHPStan\Scope\PHPStanNodeScopeResolver;
@ -28,7 +29,7 @@ final class NodeScopeAndMetadataDecorator
* @var \PhpParser\NodeTraverser
*/
private $nodeTraverser;
public function __construct(CloningVisitor $cloningVisitor, PHPStanNodeScopeResolver $phpStanNodeScopeResolver, ParentConnectingVisitor $parentConnectingVisitor, FunctionLikeParamArgPositionNodeVisitor $functionLikeParamArgPositionNodeVisitor, FileWithoutNamespaceNodeTraverser $fileWithoutNamespaceNodeTraverser)
public function __construct(CloningVisitor $cloningVisitor, PHPStanNodeScopeResolver $phpStanNodeScopeResolver, ParentConnectingVisitor $parentConnectingVisitor, FunctionLikeParamArgPositionNodeVisitor $functionLikeParamArgPositionNodeVisitor, UnreachableStatementNodeVisitor $unreachableStatementNodeVisitor, FileWithoutNamespaceNodeTraverser $fileWithoutNamespaceNodeTraverser)
{
$this->phpStanNodeScopeResolver = $phpStanNodeScopeResolver;
$this->fileWithoutNamespaceNodeTraverser = $fileWithoutNamespaceNodeTraverser;
@ -38,6 +39,7 @@ final class NodeScopeAndMetadataDecorator
// this one has to be run again to re-connect parent nodes with new attributes
$this->nodeTraverser->addVisitor($parentConnectingVisitor);
$this->nodeTraverser->addVisitor($functionLikeParamArgPositionNodeVisitor);
$this->nodeTraverser->addVisitor($unreachableStatementNodeVisitor);
}
/**
* @param Stmt[] $stmts

View File

@ -33,8 +33,6 @@ use PhpParser\Node\Name\FullyQualified;
use PhpParser\Node\NullableType;
use PhpParser\Node\Stmt;
use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\ClassLike;
use PhpParser\Node\Stmt\Declare_;
use PhpParser\Node\Stmt\Enum_;
use PhpParser\Node\Stmt\EnumCase;
use PhpParser\Node\Stmt\Expression;
@ -64,7 +62,6 @@ use PHPStan\Type\ObjectType;
use PHPStan\Type\TypeCombinator;
use Rector\Caching\Detector\ChangedFilesDetector;
use Rector\Caching\FileSystem\DependencyResolver;
use Rector\Core\Contract\PhpParser\Node\StmtsAwareInterface;
use Rector\Core\Exception\ShouldNotHappenException;
use Rector\Core\NodeAnalyzer\ClassAnalyzer;
use Rector\Core\PhpParser\Node\CustomNode\FileWithoutNamespace;
@ -300,9 +297,6 @@ final class PHPStanNodeScopeResolver
}
}
}
if ($node instanceof Stmt) {
$this->setChildOfUnreachableStatementNodeAttribute($node, $mutatingScope);
}
// special case for unreachable nodes
if ($node instanceof UnreachableStatementNode) {
$this->processUnreachableStatementNode($node, $filePath, $mutatingScope);
@ -369,22 +363,6 @@ final class PHPStanNodeScopeResolver
$expr = $expr->expr;
}
}
private function setChildOfUnreachableStatementNodeAttribute(Stmt $stmt, MutatingScope $mutatingScope) : void
{
if (!$stmt instanceof StmtsAwareInterface && !$stmt instanceof ClassLike && !$stmt instanceof Declare_) {
return;
}
if ($stmt->getAttribute(AttributeKey::IS_UNREACHABLE) !== \true) {
return;
}
if ($stmt->stmts === null) {
return;
}
foreach ($stmt->stmts as $childStmt) {
$childStmt->setAttribute(AttributeKey::IS_UNREACHABLE, \true);
$childStmt->setAttribute(AttributeKey::SCOPE, $mutatingScope);
}
}
private function processArray(Array_ $array, MutatingScope $mutatingScope) : void
{
foreach ($array->items as $arrayItem) {
@ -441,19 +419,6 @@ final class PHPStanNodeScopeResolver
$originalStmt->setAttribute(AttributeKey::IS_UNREACHABLE, \true);
$originalStmt->setAttribute(AttributeKey::SCOPE, $mutatingScope);
$this->processNodes([$originalStmt], $filePath, $mutatingScope);
$parentNode = $unreachableStatementNode->getAttribute(AttributeKey::PARENT_NODE);
if (!$parentNode instanceof StmtsAwareInterface && !$parentNode instanceof ClassLike && !$parentNode instanceof Declare_) {
return;
}
$stmtKey = $unreachableStatementNode->getAttribute(AttributeKey::STMT_KEY);
$totalKeys = $parentNode->stmts === null ? 0 : \count($parentNode->stmts);
for ($key = $stmtKey + 1; $key < $totalKeys; ++$key) {
if (!isset($parentNode->stmts[$key])) {
continue;
}
$parentNode->stmts[$key]->setAttribute(AttributeKey::IS_UNREACHABLE, \true);
$this->processNodes([$parentNode->stmts[$key]], $filePath, $mutatingScope);
}
}
private function processProperty(Property $property, MutatingScope $mutatingScope) : void
{

View File

@ -73,15 +73,15 @@ final class UndefinedVariableResolver
if ($node instanceof FunctionLike && !$node instanceof ArrowFunction) {
return NodeTraverser::DONT_TRAVERSE_CURRENT_AND_CHILDREN;
}
if ($node instanceof Foreach_) {
if ($node instanceof Foreach_ || $node instanceof Case_) {
// handled above
return NodeTraverser::DONT_TRAVERSE_CURRENT_AND_CHILDREN;
}
if ($node instanceof Case_) {
return NodeTraverser::DONT_TRAVERSE_CURRENT_AND_CHILDREN;
}
if ($node instanceof Stmt) {
$currentStmt = $node;
if ($currentStmt->getAttribute(AttributeKey::IS_UNREACHABLE) === \true) {
return NodeTraverser::STOP_TRAVERSAL;
}
}
if (!$node instanceof Variable) {
$checkedVariables = $this->resolveCheckedVariables($node, $checkedVariables);
@ -91,14 +91,8 @@ final class UndefinedVariableResolver
if ($node->name instanceof Variable) {
return NodeTraverser::STOP_TRAVERSAL;
}
if ($node->getAttribute(AttributeKey::IS_BEING_ASSIGNED) === \true) {
return null;
}
$variableName = (string) $this->nodeNameResolver->getName($node);
if ($this->shouldSkipVariable($node, $variableName, $checkedVariables)) {
return null;
}
if ($this->hasVariableTypeOrCurrentStmtUnreachable($node, $variableName, $currentStmt)) {
if ($this->shouldSkipVariable($node, $variableName, $checkedVariables, $currentStmt)) {
return null;
}
/** @var string $variableName */
@ -187,7 +181,7 @@ final class UndefinedVariableResolver
/**
* @param string[] $checkedVariables
*/
private function shouldSkipVariable(Variable $variable, string $variableName, array &$checkedVariables) : bool
private function shouldSkipVariable(Variable $variable, string $variableName, array &$checkedVariables, ?Stmt $currentStmt) : bool
{
$variableName = $this->nodeNameResolver->getName($variable);
// skip $this, as probably in outer scope
@ -203,7 +197,13 @@ final class UndefinedVariableResolver
if ($this->variableAnalyzer->isStaticOrGlobal($variable)) {
return \true;
}
return \in_array($variableName, $checkedVariables, \true);
if (\in_array($variableName, $checkedVariables, \true)) {
return \true;
}
if ($variable->getAttribute(AttributeKey::IS_BEING_ASSIGNED) === \true) {
return \true;
}
return $this->hasVariableTypeOrCurrentStmtUnreachable($variable, $variableName, $currentStmt);
}
private function isDifferentWithOriginalNodeOrNoScope(Variable $variable) : bool
{

View File

@ -19,12 +19,12 @@ final class VersionResolver
* @api
* @var string
*/
public const PACKAGE_VERSION = '708cc4fb49562e19a98849abd50216048b1f48ba';
public const PACKAGE_VERSION = '93a4b2b15eec15c506ae55c25b23a40dd0390cff';
/**
* @api
* @var string
*/
public const RELEASE_DATE = '2023-07-04 00:25:46';
public const RELEASE_DATE = '2023-07-04 15:32:33';
/**
* @var int
*/

View File

@ -0,0 +1,69 @@
<?php
declare (strict_types=1);
namespace Rector\Core\PHPStan\NodeVisitor;
use PhpParser\Node;
use PhpParser\Node\Stmt\ClassLike;
use PhpParser\Node\Stmt\Declare_;
use PhpParser\NodeVisitorAbstract;
use PHPStan\Analyser\MutatingScope;
use Rector\Core\Contract\PhpParser\Node\StmtsAwareInterface;
use Rector\Core\Provider\CurrentFileProvider;
use Rector\Core\ValueObject\Application\File;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Rector\NodeTypeResolver\PHPStan\Scope\PHPStanNodeScopeResolver;
use Rector\NodeTypeResolver\PHPStan\Scope\ScopeFactory;
final class UnreachableStatementNodeVisitor extends NodeVisitorAbstract
{
/**
* @readonly
* @var \Rector\Core\Provider\CurrentFileProvider
*/
private $currentFileProvider;
/**
* @readonly
* @var \Rector\NodeTypeResolver\PHPStan\Scope\PHPStanNodeScopeResolver
*/
private $phpStanNodeScopeResolver;
/**
* @readonly
* @var \Rector\NodeTypeResolver\PHPStan\Scope\ScopeFactory
*/
private $scopeFactory;
public function __construct(CurrentFileProvider $currentFileProvider, PHPStanNodeScopeResolver $phpStanNodeScopeResolver, ScopeFactory $scopeFactory)
{
$this->currentFileProvider = $currentFileProvider;
$this->phpStanNodeScopeResolver = $phpStanNodeScopeResolver;
$this->scopeFactory = $scopeFactory;
}
public function enterNode(Node $node) : ?Node
{
if (!$node instanceof StmtsAwareInterface && !$node instanceof ClassLike && !$node instanceof Declare_) {
return null;
}
if ($node->stmts === null) {
return null;
}
$file = $this->currentFileProvider->getFile();
if (!$file instanceof File) {
return null;
}
$filePath = $file->getFilePath();
$isPassedUnreachableStmt = \false;
$mutatingScope = $node->getAttribute(AttributeKey::SCOPE);
$mutatingScope = $mutatingScope instanceof MutatingScope ? $mutatingScope : $this->scopeFactory->createFromFile($filePath);
foreach ($node->stmts as $stmt) {
if ($stmt->getAttribute(AttributeKey::IS_UNREACHABLE) === \true) {
$isPassedUnreachableStmt = \true;
continue;
}
if ($isPassedUnreachableStmt) {
$stmt->setAttribute(AttributeKey::IS_UNREACHABLE, \true);
$stmt->setAttribute(AttributeKey::SCOPE, $mutatingScope);
$this->phpStanNodeScopeResolver->processNodes([$stmt], $filePath, $mutatingScope);
}
}
return null;
}
}

View File

@ -7,7 +7,6 @@ use PhpParser\Node;
use PhpParser\Node\Stmt\Namespace_;
use PhpParser\NodeTraverser;
use Rector\Core\PhpParser\Node\CustomNode\FileWithoutNamespace;
use Rector\NodeTypeResolver\Node\AttributeKey;
final class FileWithoutNamespaceNodeTraverser extends NodeTraverser
{
/**
@ -23,9 +22,6 @@ final class FileWithoutNamespaceNodeTraverser extends NodeTraverser
}
}
$fileWithoutNamespace = new FileWithoutNamespace($nodes);
foreach ($nodes as $node) {
$node->setAttribute(AttributeKey::PARENT_NODE, $fileWithoutNamespace);
}
return [$fileWithoutNamespace];
}
}

2
vendor/autoload.php vendored
View File

@ -22,4 +22,4 @@ if (PHP_VERSION_ID < 50600) {
require_once __DIR__ . '/composer/autoload_real.php';
return ComposerAutoloaderInitdf89f8040db24f1a031309888e2e2205::getLoader();
return ComposerAutoloaderInitd7f678f0c3ee659fc396d7770917fe96::getLoader();

View File

@ -1606,6 +1606,7 @@ return array(
'Rector\\Core\\NodeManipulator\\StmtsManipulator' => $baseDir . '/src/NodeManipulator/StmtsManipulator.php',
'Rector\\Core\\NonPhpFile\\NonPhpFileProcessor' => $baseDir . '/src/NonPhpFile/NonPhpFileProcessor.php',
'Rector\\Core\\NonPhpFile\\Rector\\RenameClassNonPhpRector' => $baseDir . '/src/NonPhpFile/Rector/RenameClassNonPhpRector.php',
'Rector\\Core\\PHPStan\\NodeVisitor\\UnreachableStatementNodeVisitor' => $baseDir . '/src/PHPStan/NodeVisitor/UnreachableStatementNodeVisitor.php',
'Rector\\Core\\PHPStan\\NodeVisitor\\WrappedNodeRestoringNodeVisitor' => $baseDir . '/src/PHPStan/NodeVisitor/WrappedNodeRestoringNodeVisitor.php',
'Rector\\Core\\PHPStan\\Reflection\\TypeToCallReflectionResolver\\ClosureTypeToCallReflectionResolver' => $baseDir . '/src/PHPStan/Reflection/TypeToCallReflectionResolver/ClosureTypeToCallReflectionResolver.php',
'Rector\\Core\\PHPStan\\Reflection\\TypeToCallReflectionResolver\\ConstantArrayTypeToCallReflectionResolver' => $baseDir . '/src/PHPStan/Reflection/TypeToCallReflectionResolver/ConstantArrayTypeToCallReflectionResolver.php',

View File

@ -2,7 +2,7 @@
// autoload_real.php @generated by Composer
class ComposerAutoloaderInitdf89f8040db24f1a031309888e2e2205
class ComposerAutoloaderInitd7f678f0c3ee659fc396d7770917fe96
{
private static $loader;
@ -22,17 +22,17 @@ class ComposerAutoloaderInitdf89f8040db24f1a031309888e2e2205
return self::$loader;
}
spl_autoload_register(array('ComposerAutoloaderInitdf89f8040db24f1a031309888e2e2205', 'loadClassLoader'), true, true);
spl_autoload_register(array('ComposerAutoloaderInitd7f678f0c3ee659fc396d7770917fe96', 'loadClassLoader'), true, true);
self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__));
spl_autoload_unregister(array('ComposerAutoloaderInitdf89f8040db24f1a031309888e2e2205', 'loadClassLoader'));
spl_autoload_unregister(array('ComposerAutoloaderInitd7f678f0c3ee659fc396d7770917fe96', 'loadClassLoader'));
require __DIR__ . '/autoload_static.php';
call_user_func(\Composer\Autoload\ComposerStaticInitdf89f8040db24f1a031309888e2e2205::getInitializer($loader));
call_user_func(\Composer\Autoload\ComposerStaticInitd7f678f0c3ee659fc396d7770917fe96::getInitializer($loader));
$loader->setClassMapAuthoritative(true);
$loader->register(true);
$filesToLoad = \Composer\Autoload\ComposerStaticInitdf89f8040db24f1a031309888e2e2205::$files;
$filesToLoad = \Composer\Autoload\ComposerStaticInitd7f678f0c3ee659fc396d7770917fe96::$files;
$requireFile = \Closure::bind(static function ($fileIdentifier, $file) {
if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
$GLOBALS['__composer_autoload_files'][$fileIdentifier] = true;

View File

@ -4,7 +4,7 @@
namespace Composer\Autoload;
class ComposerStaticInitdf89f8040db24f1a031309888e2e2205
class ComposerStaticInitd7f678f0c3ee659fc396d7770917fe96
{
public static $files = array (
'ad155f8f1cf0d418fe49e248db8c661b' => __DIR__ . '/..' . '/react/promise/src/functions_include.php',
@ -1858,6 +1858,7 @@ class ComposerStaticInitdf89f8040db24f1a031309888e2e2205
'Rector\\Core\\NodeManipulator\\StmtsManipulator' => __DIR__ . '/../..' . '/src/NodeManipulator/StmtsManipulator.php',
'Rector\\Core\\NonPhpFile\\NonPhpFileProcessor' => __DIR__ . '/../..' . '/src/NonPhpFile/NonPhpFileProcessor.php',
'Rector\\Core\\NonPhpFile\\Rector\\RenameClassNonPhpRector' => __DIR__ . '/../..' . '/src/NonPhpFile/Rector/RenameClassNonPhpRector.php',
'Rector\\Core\\PHPStan\\NodeVisitor\\UnreachableStatementNodeVisitor' => __DIR__ . '/../..' . '/src/PHPStan/NodeVisitor/UnreachableStatementNodeVisitor.php',
'Rector\\Core\\PHPStan\\NodeVisitor\\WrappedNodeRestoringNodeVisitor' => __DIR__ . '/../..' . '/src/PHPStan/NodeVisitor/WrappedNodeRestoringNodeVisitor.php',
'Rector\\Core\\PHPStan\\Reflection\\TypeToCallReflectionResolver\\ClosureTypeToCallReflectionResolver' => __DIR__ . '/../..' . '/src/PHPStan/Reflection/TypeToCallReflectionResolver/ClosureTypeToCallReflectionResolver.php',
'Rector\\Core\\PHPStan\\Reflection\\TypeToCallReflectionResolver\\ConstantArrayTypeToCallReflectionResolver' => __DIR__ . '/../..' . '/src/PHPStan/Reflection/TypeToCallReflectionResolver/ConstantArrayTypeToCallReflectionResolver.php',
@ -3100,9 +3101,9 @@ class ComposerStaticInitdf89f8040db24f1a031309888e2e2205
public static function getInitializer(ClassLoader $loader)
{
return \Closure::bind(function () use ($loader) {
$loader->prefixLengthsPsr4 = ComposerStaticInitdf89f8040db24f1a031309888e2e2205::$prefixLengthsPsr4;
$loader->prefixDirsPsr4 = ComposerStaticInitdf89f8040db24f1a031309888e2e2205::$prefixDirsPsr4;
$loader->classMap = ComposerStaticInitdf89f8040db24f1a031309888e2e2205::$classMap;
$loader->prefixLengthsPsr4 = ComposerStaticInitd7f678f0c3ee659fc396d7770917fe96::$prefixLengthsPsr4;
$loader->prefixDirsPsr4 = ComposerStaticInitd7f678f0c3ee659fc396d7770917fe96::$prefixDirsPsr4;
$loader->classMap = ComposerStaticInitd7f678f0c3ee659fc396d7770917fe96::$classMap;
}, null, ClassLoader::class);
}