mirror of https://github.com/rectorphp/rector.git
Updated Rector to commit 0fe5ee02fe3527bff3a1cd1c10508e2148ea8031
0fe5ee02fe
Remove PARENT_NODE from ReadOnlyPropertyRector (#4150)
This commit is contained in:
parent
0222a6ac50
commit
9d288b9b77
|
@ -22,7 +22,6 @@ use Rector\Core\NodeAnalyzer\PropertyFetchAnalyzer;
|
|||
use Rector\Core\NodeManipulator\IfManipulator;
|
||||
use Rector\Core\Rector\AbstractRector;
|
||||
use Rector\NodeNestingScope\ContextAnalyzer;
|
||||
use Rector\NodeTypeResolver\Node\AttributeKey;
|
||||
use Rector\Php80\NodeAnalyzer\PromotedPropertyResolver;
|
||||
use Rector\TypeDeclaration\AlreadyAssignDetector\ConstructorAssignDetector;
|
||||
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
|
||||
|
@ -110,10 +109,6 @@ CODE_SAMPLE
|
|||
if ($this->contextAnalyzer->isInLoop($node)) {
|
||||
return null;
|
||||
}
|
||||
$originalCondNode = $node->cond->getAttribute(AttributeKey::ORIGINAL_NODE);
|
||||
if (!$originalCondNode instanceof Node) {
|
||||
return null;
|
||||
}
|
||||
if ($node->cond instanceof BooleanNot && $node->cond->expr instanceof Instanceof_) {
|
||||
return $this->refactorStmtAndInstanceof($node, $node->cond->expr);
|
||||
}
|
||||
|
|
|
@ -14,10 +14,10 @@ use PhpParser\Node\Stmt\Expression;
|
|||
use PhpParser\Node\Stmt\If_;
|
||||
use PhpParser\Node\Stmt\Interface_;
|
||||
use PhpParser\Node\Stmt\Trait_;
|
||||
use PhpParser\NodeTraverser;
|
||||
use PHPStan\Reflection\ClassReflection;
|
||||
use PHPStan\Type\ThisType;
|
||||
use PHPStan\Type\TypeWithClassName;
|
||||
use Rector\Core\Contract\PhpParser\Node\StmtsAwareInterface;
|
||||
use Rector\Core\NodeAnalyzer\CallAnalyzer;
|
||||
use Rector\Core\PhpParser\AstResolver;
|
||||
use Rector\Core\Rector\AbstractRector;
|
||||
|
@ -80,49 +80,34 @@ CODE_SAMPLE
|
|||
*/
|
||||
public function getNodeTypes() : array
|
||||
{
|
||||
return [StmtsAwareInterface::class];
|
||||
return [If_::class, Expression::class];
|
||||
}
|
||||
/**
|
||||
* @param StmtsAwareInterface $node
|
||||
* @param If_|Expression $node
|
||||
*/
|
||||
public function refactor(Node $node)
|
||||
{
|
||||
if ($node->stmts === null) {
|
||||
return null;
|
||||
if ($node instanceof If_) {
|
||||
return $this->refactorIf($node);
|
||||
}
|
||||
$hasChanged = \false;
|
||||
foreach ($node->stmts as $key => $stmt) {
|
||||
if ($stmt instanceof If_) {
|
||||
$if = $this->refactorIf($stmt);
|
||||
if ($if instanceof If_) {
|
||||
$hasChanged = \true;
|
||||
continue;
|
||||
}
|
||||
if ($node->expr instanceof Assign) {
|
||||
$assign = $node->expr;
|
||||
if (!$assign->expr instanceof MethodCall) {
|
||||
return null;
|
||||
}
|
||||
if (!$stmt instanceof Expression) {
|
||||
continue;
|
||||
if (!$this->shouldRemoveMethodCall($assign->expr)) {
|
||||
return null;
|
||||
}
|
||||
if ($stmt->expr instanceof Assign && $stmt->expr->expr instanceof MethodCall) {
|
||||
$methodCall = $stmt->expr->expr;
|
||||
if (!$this->shouldRemoveMethodCall($methodCall)) {
|
||||
continue;
|
||||
}
|
||||
$stmt->expr->expr = $this->nodeFactory->createFalse();
|
||||
$hasChanged = \true;
|
||||
continue;
|
||||
}
|
||||
if ($stmt->expr instanceof MethodCall) {
|
||||
$methodCall = $stmt->expr;
|
||||
if (!$this->shouldRemoveMethodCall($methodCall)) {
|
||||
continue;
|
||||
}
|
||||
unset($node->stmts[$key]);
|
||||
$hasChanged = \true;
|
||||
}
|
||||
}
|
||||
if ($hasChanged) {
|
||||
$assign->expr = $this->nodeFactory->createFalse();
|
||||
return $node;
|
||||
}
|
||||
if ($node->expr instanceof MethodCall) {
|
||||
$methodCall = $node->expr;
|
||||
if (!$this->shouldRemoveMethodCall($methodCall)) {
|
||||
return null;
|
||||
}
|
||||
return NodeTraverser::REMOVE_NODE;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
private function resolveClassLike(MethodCall $methodCall) : ?ClassLike
|
||||
|
|
|
@ -88,14 +88,18 @@ CODE_SAMPLE
|
|||
*/
|
||||
public function getNodeTypes() : array
|
||||
{
|
||||
return [FuncCall::class, Ternary::class];
|
||||
return [Trait_::class, FuncCall::class, Ternary::class];
|
||||
}
|
||||
/**
|
||||
* @param FuncCall|Ternary $node
|
||||
* @param Trait_|FuncCall|Ternary $node
|
||||
* @return int|\PhpParser\Node\Expr\Ternary|null|\PhpParser\Node\Expr\FuncCall
|
||||
*/
|
||||
public function refactorWithScope(Node $node, Scope $scope)
|
||||
{
|
||||
if ($node instanceof Trait_) {
|
||||
// skip contents in traits, as hard to analyze
|
||||
return NodeTraverser::STOP_TRAVERSAL;
|
||||
}
|
||||
if ($node instanceof Ternary) {
|
||||
if ($this->shouldSkipTernaryIfElseCountFuncCall($node)) {
|
||||
return NodeTraverser::DONT_TRAVERSE_CHILDREN;
|
||||
|
@ -152,11 +156,6 @@ CODE_SAMPLE
|
|||
if ($funcCall->isFirstClassCallable()) {
|
||||
return \true;
|
||||
}
|
||||
// skip ternary in trait, as impossible to analyse
|
||||
$trait = $this->betterNodeFinder->findParentType($funcCall, Trait_::class);
|
||||
if ($trait instanceof Trait_) {
|
||||
return \true;
|
||||
}
|
||||
$firstArg = $funcCall->getArgs()[0];
|
||||
// just added node, lets skip it to be sure we're not using mixing
|
||||
$origNode = $firstArg->value->getAttribute(AttributeKey::ORIGINAL_NODE);
|
||||
|
|
|
@ -11,7 +11,6 @@ use PhpParser\Node\Expr\PropertyFetch;
|
|||
use PhpParser\Node\Expr\Variable;
|
||||
use PhpParser\Node\Param;
|
||||
use PhpParser\Node\Stmt\Class_;
|
||||
use PhpParser\Node\Stmt\ClassLike;
|
||||
use PhpParser\Node\Stmt\ClassMethod;
|
||||
use PhpParser\Node\Stmt\Property;
|
||||
use PhpParser\NodeTraverser;
|
||||
|
@ -107,6 +106,9 @@ CODE_SAMPLE
|
|||
public function refactorWithScope(Node $node, Scope $scope) : ?Node
|
||||
{
|
||||
$hasChanged = \false;
|
||||
if ($node->isReadonly()) {
|
||||
return null;
|
||||
}
|
||||
// skip "clone $this" cases, as can create unexpected write to local constructor property
|
||||
if ($this->hasCloneThis($node)) {
|
||||
return null;
|
||||
|
@ -135,17 +137,6 @@ CODE_SAMPLE
|
|||
{
|
||||
return PhpVersionFeature::READONLY_PROPERTY;
|
||||
}
|
||||
/**
|
||||
* @param \PhpParser\Node\Stmt\Property|\PhpParser\Node\Param $node
|
||||
*/
|
||||
private function shouldSkipInReadonlyClass($node) : bool
|
||||
{
|
||||
$class = $this->betterNodeFinder->findParentType($node, Class_::class);
|
||||
if (!$class instanceof Class_) {
|
||||
return \true;
|
||||
}
|
||||
return $class->isReadonly();
|
||||
}
|
||||
private function refactorProperty(Class_ $class, Property $property, Scope $scope) : ?Property
|
||||
{
|
||||
// 1. is property read-only?
|
||||
|
@ -170,9 +161,6 @@ CODE_SAMPLE
|
|||
if ($this->propertyFetchAssignManipulator->isAssignedMultipleTimesInConstructor($class, $property)) {
|
||||
return null;
|
||||
}
|
||||
if ($this->shouldSkipInReadonlyClass($property)) {
|
||||
return null;
|
||||
}
|
||||
$this->visibilityManipulator->makeReadonly($property);
|
||||
$attributeGroups = $property->attrGroups;
|
||||
if ($attributeGroups !== []) {
|
||||
|
@ -198,22 +186,15 @@ CODE_SAMPLE
|
|||
if ($this->paramAnalyzer->isParamReassign($classMethod, $param)) {
|
||||
return null;
|
||||
}
|
||||
if ($this->isPromotedPropertyAssigned($param)) {
|
||||
return null;
|
||||
}
|
||||
if ($this->shouldSkipInReadonlyClass($param)) {
|
||||
if ($this->isPromotedPropertyAssigned($class, $param)) {
|
||||
return null;
|
||||
}
|
||||
$this->visibilityManipulator->makeReadonly($param);
|
||||
return $param;
|
||||
}
|
||||
private function isPromotedPropertyAssigned(Param $param) : bool
|
||||
private function isPromotedPropertyAssigned(Class_ $class, Param $param) : bool
|
||||
{
|
||||
$classLike = $this->betterNodeFinder->findParentType($param, ClassLike::class);
|
||||
if (!$classLike instanceof Class_) {
|
||||
return \false;
|
||||
}
|
||||
$constructClassMethod = $classLike->getMethod(MethodName::CONSTRUCT);
|
||||
$constructClassMethod = $class->getMethod(MethodName::CONSTRUCT);
|
||||
if (!$constructClassMethod instanceof ClassMethod) {
|
||||
return \false;
|
||||
}
|
||||
|
@ -221,10 +202,12 @@ CODE_SAMPLE
|
|||
return \false;
|
||||
}
|
||||
$propertyFetch = new PropertyFetch(new Variable('this'), $this->getName($param));
|
||||
$stmts = $classLike->stmts;
|
||||
$isAssigned = \false;
|
||||
$this->traverseNodesWithCallable($stmts, function (Node $node) use($propertyFetch, &$isAssigned) : ?int {
|
||||
if ($node instanceof Assign && $this->nodeComparator->areNodesEqual($propertyFetch, $node->var)) {
|
||||
$this->traverseNodesWithCallable($class->stmts, function (Node $node) use($propertyFetch, &$isAssigned) : ?int {
|
||||
if (!$node instanceof Assign) {
|
||||
return null;
|
||||
}
|
||||
if ($this->nodeComparator->areNodesEqual($propertyFetch, $node->var)) {
|
||||
$isAssigned = \true;
|
||||
return NodeTraverser::STOP_TRAVERSAL;
|
||||
}
|
||||
|
|
|
@ -100,46 +100,49 @@ CODE_SAMPLE
|
|||
*/
|
||||
public function getNodeTypes() : array
|
||||
{
|
||||
return [ClassMethod::class];
|
||||
return [Class_::class];
|
||||
}
|
||||
/**
|
||||
* @param ClassMethod $node
|
||||
* @param Class_ $node
|
||||
*/
|
||||
public function refactor(Node $node) : ?ClassMethod
|
||||
public function refactor(Node $node)
|
||||
{
|
||||
if (!$node->isPublic()) {
|
||||
return null;
|
||||
}
|
||||
if ($node->getParams() === []) {
|
||||
return null;
|
||||
}
|
||||
if (!$this->testsNodeAnalyzer->isInTestClass($node)) {
|
||||
return null;
|
||||
}
|
||||
$dataProviderPhpDocTagNode = $this->resolveDataProviderPhpDocTagNode($node);
|
||||
if (!$dataProviderPhpDocTagNode instanceof PhpDocTagNode) {
|
||||
return null;
|
||||
}
|
||||
$hasChanged = \false;
|
||||
foreach ($node->getParams() as $param) {
|
||||
if ($param->type instanceof Node) {
|
||||
foreach ($node->getMethods() as $classMethod) {
|
||||
if (!$classMethod->isPublic()) {
|
||||
continue;
|
||||
}
|
||||
$paramTypeDeclaration = $this->inferParam($param, $dataProviderPhpDocTagNode);
|
||||
if ($paramTypeDeclaration instanceof MixedType) {
|
||||
if ($classMethod->getParams() === []) {
|
||||
continue;
|
||||
}
|
||||
$param->type = $this->staticTypeMapper->mapPHPStanTypeToPhpParserNode($paramTypeDeclaration, TypeKind::PARAM);
|
||||
$hasChanged = \true;
|
||||
$dataProviderPhpDocTagNode = $this->resolveDataProviderPhpDocTagNode($classMethod);
|
||||
if (!$dataProviderPhpDocTagNode instanceof PhpDocTagNode) {
|
||||
return null;
|
||||
}
|
||||
$hasChanged = \false;
|
||||
foreach ($classMethod->getParams() as $param) {
|
||||
if ($param->type instanceof Node) {
|
||||
continue;
|
||||
}
|
||||
$paramTypeDeclaration = $this->inferParam($node, $param, $dataProviderPhpDocTagNode);
|
||||
if ($paramTypeDeclaration instanceof MixedType) {
|
||||
continue;
|
||||
}
|
||||
$param->type = $this->staticTypeMapper->mapPHPStanTypeToPhpParserNode($paramTypeDeclaration, TypeKind::PARAM);
|
||||
$hasChanged = \true;
|
||||
}
|
||||
}
|
||||
if ($hasChanged) {
|
||||
return $node;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
private function inferParam(Param $param, PhpDocTagNode $dataProviderPhpDocTagNode) : Type
|
||||
private function inferParam(Class_ $class, Param $param, PhpDocTagNode $dataProviderPhpDocTagNode) : Type
|
||||
{
|
||||
$dataProviderClassMethod = $this->resolveDataProviderClassMethod($param, $dataProviderPhpDocTagNode);
|
||||
$dataProviderClassMethod = $this->resolveDataProviderClassMethod($class, $dataProviderPhpDocTagNode);
|
||||
if (!$dataProviderClassMethod instanceof ClassMethod) {
|
||||
return new MixedType();
|
||||
}
|
||||
|
@ -156,12 +159,8 @@ CODE_SAMPLE
|
|||
$yields = $this->betterNodeFinder->findInstanceOf((array) $dataProviderClassMethod->stmts, Yield_::class);
|
||||
return $this->resolveYieldStaticArrayTypeByParameterPosition($yields, $parameterPosition);
|
||||
}
|
||||
private function resolveDataProviderClassMethod(Param $param, PhpDocTagNode $dataProviderPhpDocTagNode) : ?ClassMethod
|
||||
private function resolveDataProviderClassMethod(Class_ $class, PhpDocTagNode $dataProviderPhpDocTagNode) : ?ClassMethod
|
||||
{
|
||||
$class = $this->betterNodeFinder->findParentType($param, Class_::class);
|
||||
if (!$class instanceof Class_) {
|
||||
return null;
|
||||
}
|
||||
if (!$dataProviderPhpDocTagNode->value instanceof GenericTagValueNode) {
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -19,12 +19,12 @@ final class VersionResolver
|
|||
* @api
|
||||
* @var string
|
||||
*/
|
||||
public const PACKAGE_VERSION = 'c6a5b762dea6a71041b413554baa26f4b2400a11';
|
||||
public const PACKAGE_VERSION = '0fe5ee02fe3527bff3a1cd1c10508e2148ea8031';
|
||||
/**
|
||||
* @api
|
||||
* @var string
|
||||
*/
|
||||
public const RELEASE_DATE = '2023-06-10 07:52:38';
|
||||
public const RELEASE_DATE = '2023-06-10 06:58:05';
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
|
|
|
@ -22,4 +22,4 @@ if (PHP_VERSION_ID < 50600) {
|
|||
|
||||
require_once __DIR__ . '/composer/autoload_real.php';
|
||||
|
||||
return ComposerAutoloaderInitcba6ec738ed83b7c2fa2b12d2e80cd72::getLoader();
|
||||
return ComposerAutoloaderInit6a163f41b067be61d74c9472bd787216::getLoader();
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
// autoload_real.php @generated by Composer
|
||||
|
||||
class ComposerAutoloaderInitcba6ec738ed83b7c2fa2b12d2e80cd72
|
||||
class ComposerAutoloaderInit6a163f41b067be61d74c9472bd787216
|
||||
{
|
||||
private static $loader;
|
||||
|
||||
|
@ -22,17 +22,17 @@ class ComposerAutoloaderInitcba6ec738ed83b7c2fa2b12d2e80cd72
|
|||
return self::$loader;
|
||||
}
|
||||
|
||||
spl_autoload_register(array('ComposerAutoloaderInitcba6ec738ed83b7c2fa2b12d2e80cd72', 'loadClassLoader'), true, true);
|
||||
spl_autoload_register(array('ComposerAutoloaderInit6a163f41b067be61d74c9472bd787216', 'loadClassLoader'), true, true);
|
||||
self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__));
|
||||
spl_autoload_unregister(array('ComposerAutoloaderInitcba6ec738ed83b7c2fa2b12d2e80cd72', 'loadClassLoader'));
|
||||
spl_autoload_unregister(array('ComposerAutoloaderInit6a163f41b067be61d74c9472bd787216', 'loadClassLoader'));
|
||||
|
||||
require __DIR__ . '/autoload_static.php';
|
||||
call_user_func(\Composer\Autoload\ComposerStaticInitcba6ec738ed83b7c2fa2b12d2e80cd72::getInitializer($loader));
|
||||
call_user_func(\Composer\Autoload\ComposerStaticInit6a163f41b067be61d74c9472bd787216::getInitializer($loader));
|
||||
|
||||
$loader->setClassMapAuthoritative(true);
|
||||
$loader->register(true);
|
||||
|
||||
$filesToLoad = \Composer\Autoload\ComposerStaticInitcba6ec738ed83b7c2fa2b12d2e80cd72::$files;
|
||||
$filesToLoad = \Composer\Autoload\ComposerStaticInit6a163f41b067be61d74c9472bd787216::$files;
|
||||
$requireFile = \Closure::bind(static function ($fileIdentifier, $file) {
|
||||
if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
|
||||
$GLOBALS['__composer_autoload_files'][$fileIdentifier] = true;
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
namespace Composer\Autoload;
|
||||
|
||||
class ComposerStaticInitcba6ec738ed83b7c2fa2b12d2e80cd72
|
||||
class ComposerStaticInit6a163f41b067be61d74c9472bd787216
|
||||
{
|
||||
public static $files = array (
|
||||
'ad155f8f1cf0d418fe49e248db8c661b' => __DIR__ . '/..' . '/react/promise/src/functions_include.php',
|
||||
|
@ -3128,9 +3128,9 @@ class ComposerStaticInitcba6ec738ed83b7c2fa2b12d2e80cd72
|
|||
public static function getInitializer(ClassLoader $loader)
|
||||
{
|
||||
return \Closure::bind(function () use ($loader) {
|
||||
$loader->prefixLengthsPsr4 = ComposerStaticInitcba6ec738ed83b7c2fa2b12d2e80cd72::$prefixLengthsPsr4;
|
||||
$loader->prefixDirsPsr4 = ComposerStaticInitcba6ec738ed83b7c2fa2b12d2e80cd72::$prefixDirsPsr4;
|
||||
$loader->classMap = ComposerStaticInitcba6ec738ed83b7c2fa2b12d2e80cd72::$classMap;
|
||||
$loader->prefixLengthsPsr4 = ComposerStaticInit6a163f41b067be61d74c9472bd787216::$prefixLengthsPsr4;
|
||||
$loader->prefixDirsPsr4 = ComposerStaticInit6a163f41b067be61d74c9472bd787216::$prefixDirsPsr4;
|
||||
$loader->classMap = ComposerStaticInit6a163f41b067be61d74c9472bd787216::$classMap;
|
||||
|
||||
}, null, ClassLoader::class);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue