mirror of
https://github.com/rectorphp/rector.git
synced 2024-06-25 20:32:35 +00:00
Updated Rector to commit 620321b3833dd450a7de79a620a07c7131342422
620321b383
Add ReturnTypeFromStrictBoolReturnExprRector support for if/else returns (#5384)
This commit is contained in:
parent
f77e8b8450
commit
3d9b6b2c99
|
@ -7,8 +7,10 @@ use PhpParser\Node;
|
|||
use PhpParser\Node\Expr\FuncCall;
|
||||
use PHPStan\Analyser\Scope;
|
||||
use Rector\Core\Enum\ObjectReference;
|
||||
use Rector\Core\Rector\AbstractScopeAwareRector;
|
||||
use Rector\Core\Rector\AbstractRector;
|
||||
use Rector\Core\Reflection\ClassModifierChecker;
|
||||
use Rector\Core\ValueObject\PhpVersionFeature;
|
||||
use Rector\NodeTypeResolver\Node\AttributeKey;
|
||||
use Rector\VersionBonding\Contract\MinPhpVersionInterface;
|
||||
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
|
||||
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
|
||||
|
@ -17,8 +19,17 @@ use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
|
|||
* @changelog https://3v4l.org/GU9dP
|
||||
* @see \Rector\Tests\Php55\Rector\FuncCall\GetCalledClassToSelfClassRector\GetCalledClassToSelfClassRectorTest
|
||||
*/
|
||||
final class GetCalledClassToSelfClassRector extends AbstractScopeAwareRector implements MinPhpVersionInterface
|
||||
final class GetCalledClassToSelfClassRector extends AbstractRector implements MinPhpVersionInterface
|
||||
{
|
||||
/**
|
||||
* @readonly
|
||||
* @var \Rector\Core\Reflection\ClassModifierChecker
|
||||
*/
|
||||
private $classModifierChecker;
|
||||
public function __construct(ClassModifierChecker $classModifierChecker)
|
||||
{
|
||||
$this->classModifierChecker = $classModifierChecker;
|
||||
}
|
||||
public function getRuleDefinition() : RuleDefinition
|
||||
{
|
||||
return new RuleDefinition('Change get_called_class() to self::class on final class', [new CodeSample(<<<'CODE_SAMPLE'
|
||||
|
@ -51,19 +62,22 @@ CODE_SAMPLE
|
|||
/**
|
||||
* @param FuncCall $node
|
||||
*/
|
||||
public function refactorWithScope(Node $node, Scope $scope) : ?Node
|
||||
public function refactor(Node $node) : ?Node
|
||||
{
|
||||
if (!$this->isName($node, 'get_called_class')) {
|
||||
return null;
|
||||
}
|
||||
$scope = $node->getAttribute(AttributeKey::SCOPE);
|
||||
if (!$scope instanceof Scope) {
|
||||
return null;
|
||||
}
|
||||
if (!$scope->isInClass()) {
|
||||
return null;
|
||||
}
|
||||
$classReflection = $scope->getClassReflection();
|
||||
if ($classReflection->isFinalByKeyword()) {
|
||||
if ($this->classModifierChecker->isInsideFinalClass($node)) {
|
||||
return $this->nodeFactory->createClassConstFetch(ObjectReference::SELF, 'class');
|
||||
}
|
||||
if ($classReflection->isAnonymous()) {
|
||||
if ($scope->isInAnonymousFunction()) {
|
||||
return $this->nodeFactory->createClassConstFetch(ObjectReference::SELF, 'class');
|
||||
}
|
||||
return null;
|
||||
|
|
|
@ -6,7 +6,9 @@ namespace Rector\TypeDeclaration\NodeAnalyzer\ReturnTypeAnalyzer;
|
|||
use PhpParser\Node\Expr\Closure;
|
||||
use PhpParser\Node\Expr\Yield_;
|
||||
use PhpParser\Node\Stmt\ClassMethod;
|
||||
use PhpParser\Node\Stmt\Else_;
|
||||
use PhpParser\Node\Stmt\Function_;
|
||||
use PhpParser\Node\Stmt\If_;
|
||||
use PhpParser\Node\Stmt\Return_;
|
||||
use Rector\Core\PhpParser\Node\BetterNodeFinder;
|
||||
use Rector\TypeDeclaration\NodeAnalyzer\ReturnAnalyzer;
|
||||
|
@ -28,30 +30,69 @@ final class AlwaysStrictReturnAnalyzer
|
|||
$this->returnAnalyzer = $returnAnalyzer;
|
||||
}
|
||||
/**
|
||||
* @return Return_[]|null
|
||||
* @return Return_[]
|
||||
* @param \PhpParser\Node\Stmt\ClassMethod|\PhpParser\Node\Expr\Closure|\PhpParser\Node\Stmt\Function_ $functionLike
|
||||
*/
|
||||
public function matchAlwaysStrictReturns($functionLike) : ?array
|
||||
public function matchAlwaysStrictReturns($functionLike) : array
|
||||
{
|
||||
if ($functionLike->stmts === null) {
|
||||
return null;
|
||||
return [];
|
||||
}
|
||||
if ($this->betterNodeFinder->hasInstancesOfInFunctionLikeScoped($functionLike, [Yield_::class])) {
|
||||
return null;
|
||||
return [];
|
||||
}
|
||||
/** @var Return_[] $returns */
|
||||
$returns = $this->betterNodeFinder->findInstancesOfInFunctionLikeScoped($functionLike, Return_::class);
|
||||
if ($returns === []) {
|
||||
return null;
|
||||
return [];
|
||||
}
|
||||
// is one statement depth 3?
|
||||
if (!$this->returnAnalyzer->areExclusiveExprReturns($returns)) {
|
||||
return null;
|
||||
return [];
|
||||
}
|
||||
// is one in ifOrElse, other in else?
|
||||
if ($this->hasOnlyStmtWithIfAndElse($functionLike)) {
|
||||
return $returns;
|
||||
}
|
||||
// has root return?
|
||||
if (!$this->returnAnalyzer->hasClassMethodRootReturn($functionLike)) {
|
||||
return null;
|
||||
return [];
|
||||
}
|
||||
return $returns;
|
||||
}
|
||||
/**
|
||||
* @param \PhpParser\Node\Stmt\If_|\PhpParser\Node\Stmt\Else_ $ifOrElse
|
||||
*/
|
||||
private function hasFirstLevelReturn($ifOrElse) : bool
|
||||
{
|
||||
foreach ($ifOrElse->stmts as $stmt) {
|
||||
if ($stmt instanceof Return_) {
|
||||
return \true;
|
||||
}
|
||||
}
|
||||
return \false;
|
||||
}
|
||||
/**
|
||||
* @param \PhpParser\Node\Stmt\ClassMethod|\PhpParser\Node\Stmt\Function_|\PhpParser\Node\Expr\Closure $functionLike
|
||||
*/
|
||||
private function hasOnlyStmtWithIfAndElse($functionLike) : bool
|
||||
{
|
||||
foreach ((array) $functionLike->stmts as $functionLikeStmt) {
|
||||
if (!$functionLikeStmt instanceof If_) {
|
||||
continue;
|
||||
}
|
||||
$if = $functionLikeStmt;
|
||||
if ($if->elseifs !== []) {
|
||||
return \false;
|
||||
}
|
||||
if (!$if->else instanceof Else_) {
|
||||
return \false;
|
||||
}
|
||||
if (!$this->hasFirstLevelReturn($if)) {
|
||||
return \false;
|
||||
}
|
||||
return $this->hasFirstLevelReturn($if->else);
|
||||
}
|
||||
return \false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,7 +31,7 @@ final class StrictBoolReturnTypeAnalyzer
|
|||
public function hasAlwaysStrictBoolReturn($functionLike) : bool
|
||||
{
|
||||
$returns = $this->alwaysStrictReturnAnalyzer->matchAlwaysStrictReturns($functionLike);
|
||||
if ($returns === null) {
|
||||
if ($returns === []) {
|
||||
return \false;
|
||||
}
|
||||
foreach ($returns as $return) {
|
||||
|
|
|
@ -7,7 +7,6 @@ use PhpParser\Node\Expr;
|
|||
use PhpParser\Node\Expr\Closure;
|
||||
use PhpParser\Node\Stmt\ClassMethod;
|
||||
use PhpParser\Node\Stmt\Function_;
|
||||
use PHPStan\Analyser\Scope;
|
||||
use PHPStan\Type\Type;
|
||||
use Rector\NodeTypeResolver\PHPStan\Type\TypeFactory;
|
||||
use Rector\TypeDeclaration\TypeAnalyzer\AlwaysStrictScalarExprAnalyzer;
|
||||
|
@ -37,10 +36,10 @@ final class StrictScalarReturnTypeAnalyzer
|
|||
/**
|
||||
* @param \PhpParser\Node\Stmt\ClassMethod|\PhpParser\Node\Expr\Closure|\PhpParser\Node\Stmt\Function_ $functionLike
|
||||
*/
|
||||
public function matchAlwaysScalarReturnType($functionLike, Scope $scope) : ?Type
|
||||
public function matchAlwaysScalarReturnType($functionLike) : ?Type
|
||||
{
|
||||
$returns = $this->alwaysStrictReturnAnalyzer->matchAlwaysStrictReturns($functionLike);
|
||||
if ($returns === null) {
|
||||
if ($returns === []) {
|
||||
return null;
|
||||
}
|
||||
$scalarTypes = [];
|
||||
|
|
|
@ -12,9 +12,9 @@ use PhpParser\Node\Stmt\Function_;
|
|||
use PhpParser\Node\Stmt\Return_;
|
||||
use PhpParser\Node\Stmt\Throw_;
|
||||
use PHPStan\Analyser\Scope;
|
||||
use PHPStan\Reflection\ClassReflection;
|
||||
use Rector\Core\PhpParser\Node\BetterNodeFinder;
|
||||
use Rector\Core\Rector\AbstractScopeAwareRector;
|
||||
use Rector\Core\Reflection\ClassModifierChecker;
|
||||
use Rector\Core\ValueObject\PhpVersionFeature;
|
||||
use Rector\NodeNestingScope\ValueObject\ControlStructure;
|
||||
use Rector\TypeDeclaration\NodeAnalyzer\NeverFuncCallAnalyzer;
|
||||
|
@ -44,11 +44,17 @@ final class ReturnNeverTypeRector extends AbstractScopeAwareRector implements Mi
|
|||
* @var \Rector\TypeDeclaration\NodeAnalyzer\NeverFuncCallAnalyzer
|
||||
*/
|
||||
private $neverFuncCallAnalyzer;
|
||||
public function __construct(ClassMethodReturnTypeOverrideGuard $classMethodReturnTypeOverrideGuard, BetterNodeFinder $betterNodeFinder, NeverFuncCallAnalyzer $neverFuncCallAnalyzer)
|
||||
/**
|
||||
* @readonly
|
||||
* @var \Rector\Core\Reflection\ClassModifierChecker
|
||||
*/
|
||||
private $classModifierChecker;
|
||||
public function __construct(ClassMethodReturnTypeOverrideGuard $classMethodReturnTypeOverrideGuard, BetterNodeFinder $betterNodeFinder, NeverFuncCallAnalyzer $neverFuncCallAnalyzer, ClassModifierChecker $classModifierChecker)
|
||||
{
|
||||
$this->classMethodReturnTypeOverrideGuard = $classMethodReturnTypeOverrideGuard;
|
||||
$this->betterNodeFinder = $betterNodeFinder;
|
||||
$this->neverFuncCallAnalyzer = $neverFuncCallAnalyzer;
|
||||
$this->classModifierChecker = $classModifierChecker;
|
||||
}
|
||||
public function getRuleDefinition() : RuleDefinition
|
||||
{
|
||||
|
@ -115,8 +121,7 @@ CODE_SAMPLE
|
|||
return \false;
|
||||
}
|
||||
// skip as most likely intentional
|
||||
$classReflection = $scope->getClassReflection();
|
||||
if ($classReflection instanceof ClassReflection && !$classReflection->isFinalByKeyword() && $this->isName($node->returnType, 'void')) {
|
||||
if (!$this->classModifierChecker->isInsideFinalClass($node) && $this->isName($node->returnType, 'void')) {
|
||||
return \true;
|
||||
}
|
||||
return $this->isName($node->returnType, 'never');
|
||||
|
|
|
@ -70,7 +70,7 @@ CODE_SAMPLE
|
|||
*/
|
||||
public function refactorWithScope(Node $node, Scope $scope) : ?Node
|
||||
{
|
||||
if ($node->returnType !== null) {
|
||||
if ($node->returnType instanceof Node) {
|
||||
return null;
|
||||
}
|
||||
if ($node instanceof ClassMethod && $this->classMethodReturnTypeOverrideGuard->shouldSkipClassMethod($node, $scope)) {
|
||||
|
|
|
@ -90,6 +90,7 @@ CODE_SAMPLE
|
|||
*/
|
||||
public function refactorWithScope(Node $node, Scope $scope) : ?Node
|
||||
{
|
||||
// already typed → skip
|
||||
if ($node->returnType instanceof Node) {
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -87,10 +87,11 @@ CODE_SAMPLE
|
|||
*/
|
||||
public function refactorWithScope(Node $node, Scope $scope) : ?Node
|
||||
{
|
||||
if ($node->returnType !== null) {
|
||||
// already added → skip
|
||||
if ($node->returnType instanceof Node) {
|
||||
return null;
|
||||
}
|
||||
$scalarReturnType = $this->strictScalarReturnTypeAnalyzer->matchAlwaysScalarReturnType($node, $scope);
|
||||
$scalarReturnType = $this->strictScalarReturnTypeAnalyzer->matchAlwaysScalarReturnType($node);
|
||||
if (!$scalarReturnType instanceof Type) {
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -35,7 +35,7 @@ final class StrictReturnClassConstReturnTypeAnalyzer
|
|||
public function matchAlwaysReturnConstFetch(ClassMethod $classMethod) : ?Type
|
||||
{
|
||||
$returns = $this->alwaysStrictReturnAnalyzer->matchAlwaysStrictReturns($classMethod);
|
||||
if ($returns === null) {
|
||||
if ($returns === []) {
|
||||
return null;
|
||||
}
|
||||
$classConstFetchTypes = [];
|
||||
|
|
|
@ -19,12 +19,12 @@ final class VersionResolver
|
|||
* @api
|
||||
* @var string
|
||||
*/
|
||||
public const PACKAGE_VERSION = '16f8d19db32108740794a68a011c78328bb69aed';
|
||||
public const PACKAGE_VERSION = '620321b3833dd450a7de79a620a07c7131342422';
|
||||
/**
|
||||
* @api
|
||||
* @var string
|
||||
*/
|
||||
public const RELEASE_DATE = '2023-12-23 20:41:53';
|
||||
public const RELEASE_DATE = '2023-12-23 21:24:27';
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
|
|
Loading…
Reference in New Issue
Block a user