Updated Rector to commit 8df2120b3f546dd7f0eb89bf199a042dfc9283e7

8df2120b3f Skip void without final keyword in ReturnNeverTypeRector as could be implemented with more precise children (#5379)
This commit is contained in:
Tomas Votruba 2023-12-23 14:51:47 +00:00
parent 0ee99bfbc9
commit 94baa5fede
9 changed files with 98 additions and 36 deletions

View File

@ -0,0 +1,44 @@
<?php
declare (strict_types=1);
namespace Rector\TypeDeclaration\NodeAnalyzer;
use PhpParser\Node\Expr\Closure;
use PhpParser\Node\Stmt;
use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Stmt\Expression;
use PhpParser\Node\Stmt\Function_;
use PHPStan\Type\NeverType;
use Rector\NodeTypeResolver\NodeTypeResolver;
final class NeverFuncCallAnalyzer
{
/**
* @readonly
* @var \Rector\NodeTypeResolver\NodeTypeResolver
*/
private $nodeTypeResolver;
public function __construct(NodeTypeResolver $nodeTypeResolver)
{
$this->nodeTypeResolver = $nodeTypeResolver;
}
/**
* @param \PhpParser\Node\Stmt\ClassMethod|\PhpParser\Node\Expr\Closure|\PhpParser\Node\Stmt\Function_ $functionLike
*/
public function hasNeverFuncCall($functionLike) : bool
{
$hasNeverType = \false;
foreach ((array) $functionLike->stmts as $stmt) {
if ($stmt instanceof Expression) {
$stmt = $stmt->expr;
}
if ($stmt instanceof Stmt) {
continue;
}
$stmtType = $this->nodeTypeResolver->getNativeType($stmt);
if ($stmtType instanceof NeverType) {
$hasNeverType = \true;
}
}
return $hasNeverType;
}
}

View File

@ -7,18 +7,17 @@ use PhpParser\Node;
use PhpParser\Node\Expr\Closure;
use PhpParser\Node\Expr\Yield_;
use PhpParser\Node\Identifier;
use PhpParser\Node\Stmt;
use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Stmt\Expression;
use PhpParser\Node\Stmt\Function_;
use PhpParser\Node\Stmt\Return_;
use PhpParser\Node\Stmt\Throw_;
use PHPStan\Analyser\Scope;
use PHPStan\Type\NeverType;
use PHPStan\Reflection\ClassReflection;
use Rector\Core\PhpParser\Node\BetterNodeFinder;
use Rector\Core\Rector\AbstractScopeAwareRector;
use Rector\Core\ValueObject\PhpVersionFeature;
use Rector\NodeNestingScope\ValueObject\ControlStructure;
use Rector\TypeDeclaration\NodeAnalyzer\NeverFuncCallAnalyzer;
use Rector\VendorLocker\NodeVendorLocker\ClassMethodReturnTypeOverrideGuard;
use Rector\VersionBonding\Contract\MinPhpVersionInterface;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
@ -40,10 +39,16 @@ final class ReturnNeverTypeRector extends AbstractScopeAwareRector implements Mi
* @var \Rector\Core\PhpParser\Node\BetterNodeFinder
*/
private $betterNodeFinder;
public function __construct(ClassMethodReturnTypeOverrideGuard $classMethodReturnTypeOverrideGuard, BetterNodeFinder $betterNodeFinder)
/**
* @readonly
* @var \Rector\TypeDeclaration\NodeAnalyzer\NeverFuncCallAnalyzer
*/
private $neverFuncCallAnalyzer;
public function __construct(ClassMethodReturnTypeOverrideGuard $classMethodReturnTypeOverrideGuard, BetterNodeFinder $betterNodeFinder, NeverFuncCallAnalyzer $neverFuncCallAnalyzer)
{
$this->classMethodReturnTypeOverrideGuard = $classMethodReturnTypeOverrideGuard;
$this->betterNodeFinder = $betterNodeFinder;
$this->neverFuncCallAnalyzer = $neverFuncCallAnalyzer;
}
public function getRuleDefinition() : RuleDefinition
{
@ -97,17 +102,10 @@ CODE_SAMPLE
if ($node->returnType instanceof Node && !$this->isName($node->returnType, 'void')) {
return \true;
}
$hasReturn = $this->betterNodeFinder->hasInstancesOfInFunctionLikeScoped($node, Return_::class);
if ($hasReturn) {
if ($this->hasReturnOrYields($node)) {
return \true;
}
$hasNotNeverNodes = $this->betterNodeFinder->hasInstancesOfInFunctionLikeScoped($node, \array_merge([Yield_::class], ControlStructure::CONDITIONAL_NODE_SCOPE_TYPES));
if ($hasNotNeverNodes) {
return \true;
}
$hasNeverNodes = $this->betterNodeFinder->hasInstancesOfInFunctionLikeScoped($node, [Throw_::class]);
$hasNeverFuncCall = $this->hasNeverFuncCall($node);
if (!$hasNeverNodes && !$hasNeverFuncCall) {
if (!$this->hasNeverNodesOrNeverFuncCalls($node)) {
return \true;
}
if ($node instanceof ClassMethod && $this->classMethodReturnTypeOverrideGuard->shouldSkipClassMethod($node, $scope)) {
@ -116,26 +114,32 @@ CODE_SAMPLE
if (!$node->returnType instanceof Node) {
return \false;
}
// skip as most likely intentional
$classReflection = $scope->getClassReflection();
if ($classReflection instanceof ClassReflection && !$classReflection->isFinalByKeyword() && $this->isName($node->returnType, 'void')) {
return \true;
}
return $this->isName($node->returnType, 'never');
}
/**
* @param \PhpParser\Node\Stmt\ClassMethod|\PhpParser\Node\Expr\Closure|\PhpParser\Node\Stmt\Function_ $functionLike
* @param \PhpParser\Node\Stmt\ClassMethod|\PhpParser\Node\Stmt\Function_|\PhpParser\Node\Expr\Closure $node
*/
private function hasNeverFuncCall($functionLike) : bool
private function hasReturnOrYields($node) : bool
{
$hasNeverType = \false;
foreach ((array) $functionLike->stmts as $stmt) {
if ($stmt instanceof Expression) {
$stmt = $stmt->expr;
}
if ($stmt instanceof Stmt) {
continue;
}
$stmtType = $this->nodeTypeResolver->getNativeType($stmt);
if ($stmtType instanceof NeverType) {
$hasNeverType = \true;
}
if ($this->betterNodeFinder->hasInstancesOfInFunctionLikeScoped($node, Return_::class)) {
return \true;
}
return $hasNeverType;
return $this->betterNodeFinder->hasInstancesOfInFunctionLikeScoped($node, \array_merge([Yield_::class], ControlStructure::CONDITIONAL_NODE_SCOPE_TYPES));
}
/**
* @param \PhpParser\Node\Stmt\ClassMethod|\PhpParser\Node\Stmt\Function_|\PhpParser\Node\Expr\Closure $node
*/
private function hasNeverNodesOrNeverFuncCalls($node) : bool
{
$hasNeverNodes = $this->betterNodeFinder->hasInstancesOfInFunctionLikeScoped($node, [Throw_::class]);
if ($hasNeverNodes) {
return \true;
}
return $this->neverFuncCallAnalyzer->hasNeverFuncCall($node);
}
}

View File

@ -19,12 +19,12 @@ final class VersionResolver
* @api
* @var string
*/
public const PACKAGE_VERSION = '53ba155ab03ce7717ecef42b311880b314a40fbc';
public const PACKAGE_VERSION = '8df2120b3f546dd7f0eb89bf199a042dfc9283e7';
/**
* @api
* @var string
*/
public const RELEASE_DATE = '2023-12-23 18:31:28';
public const RELEASE_DATE = '2023-12-23 14:49:31';
/**
* @var int
*/

View File

@ -2291,6 +2291,7 @@ return array(
'Rector\\TypeDeclaration\\NodeAnalyzer\\CallerParamMatcher' => $baseDir . '/rules/TypeDeclaration/NodeAnalyzer/CallerParamMatcher.php',
'Rector\\TypeDeclaration\\NodeAnalyzer\\ClassMethodAndPropertyAnalyzer' => $baseDir . '/rules/TypeDeclaration/NodeAnalyzer/ClassMethodAndPropertyAnalyzer.php',
'Rector\\TypeDeclaration\\NodeAnalyzer\\ClassMethodParamTypeCompleter' => $baseDir . '/rules/TypeDeclaration/NodeAnalyzer/ClassMethodParamTypeCompleter.php',
'Rector\\TypeDeclaration\\NodeAnalyzer\\NeverFuncCallAnalyzer' => $baseDir . '/rules/TypeDeclaration/NodeAnalyzer/NeverFuncCallAnalyzer.php',
'Rector\\TypeDeclaration\\NodeAnalyzer\\ParamAnalyzer' => $baseDir . '/rules/TypeDeclaration/NodeAnalyzer/ParamAnalyzer.php',
'Rector\\TypeDeclaration\\NodeAnalyzer\\ReturnAnalyzer' => $baseDir . '/rules/TypeDeclaration/NodeAnalyzer/ReturnAnalyzer.php',
'Rector\\TypeDeclaration\\NodeAnalyzer\\ReturnFilter\\ExclusiveNativeCallLikeReturnMatcher' => $baseDir . '/rules/TypeDeclaration/NodeAnalyzer/ReturnFilter/ExclusiveNativeCallLikeReturnMatcher.php',

View File

@ -2509,6 +2509,7 @@ class ComposerStaticInit8339caf294dd12447c06647e5d0dc118
'Rector\\TypeDeclaration\\NodeAnalyzer\\CallerParamMatcher' => __DIR__ . '/../..' . '/rules/TypeDeclaration/NodeAnalyzer/CallerParamMatcher.php',
'Rector\\TypeDeclaration\\NodeAnalyzer\\ClassMethodAndPropertyAnalyzer' => __DIR__ . '/../..' . '/rules/TypeDeclaration/NodeAnalyzer/ClassMethodAndPropertyAnalyzer.php',
'Rector\\TypeDeclaration\\NodeAnalyzer\\ClassMethodParamTypeCompleter' => __DIR__ . '/../..' . '/rules/TypeDeclaration/NodeAnalyzer/ClassMethodParamTypeCompleter.php',
'Rector\\TypeDeclaration\\NodeAnalyzer\\NeverFuncCallAnalyzer' => __DIR__ . '/../..' . '/rules/TypeDeclaration/NodeAnalyzer/NeverFuncCallAnalyzer.php',
'Rector\\TypeDeclaration\\NodeAnalyzer\\ParamAnalyzer' => __DIR__ . '/../..' . '/rules/TypeDeclaration/NodeAnalyzer/ParamAnalyzer.php',
'Rector\\TypeDeclaration\\NodeAnalyzer\\ReturnAnalyzer' => __DIR__ . '/../..' . '/rules/TypeDeclaration/NodeAnalyzer/ReturnAnalyzer.php',
'Rector\\TypeDeclaration\\NodeAnalyzer\\ReturnFilter\\ExclusiveNativeCallLikeReturnMatcher' => __DIR__ . '/../..' . '/rules/TypeDeclaration/NodeAnalyzer/ReturnFilter/ExclusiveNativeCallLikeReturnMatcher.php',

View File

@ -1808,12 +1808,12 @@
"source": {
"type": "git",
"url": "https:\/\/github.com\/rectorphp\/rector-phpunit.git",
"reference": "669f5eed1a738fc08bb90d7dee6ba6bf72da1302"
"reference": "1cbcfcbdf5576e12e213b493db1a8813d8277c3b"
},
"dist": {
"type": "zip",
"url": "https:\/\/api.github.com\/repos\/rectorphp\/rector-phpunit\/zipball\/669f5eed1a738fc08bb90d7dee6ba6bf72da1302",
"reference": "669f5eed1a738fc08bb90d7dee6ba6bf72da1302",
"url": "https:\/\/api.github.com\/repos\/rectorphp\/rector-phpunit\/zipball\/1cbcfcbdf5576e12e213b493db1a8813d8277c3b",
"reference": "1cbcfcbdf5576e12e213b493db1a8813d8277c3b",
"shasum": ""
},
"require": {
@ -1843,7 +1843,7 @@
"tomasvotruba\/unused-public": "^0.3",
"tracy\/tracy": "^2.10"
},
"time": "2023-12-22T07:51:11+00:00",
"time": "2023-12-23T14:25:09+00:00",
"default-branch": true,
"type": "rector-extension",
"extra": {

File diff suppressed because one or more lines are too long

View File

@ -9,7 +9,7 @@ namespace Rector\RectorInstaller;
*/
final class GeneratedConfig
{
public const EXTENSIONS = array('rector/rector-doctrine' => array('install_path' => '/home/runner/work/rector-src/rector-src/rector-build/vendor/rector/rector-doctrine', 'relative_install_path' => '../../rector-doctrine', 'extra' => NULL, 'version' => 'dev-main c7ff3e5'), 'rector/rector-downgrade-php' => array('install_path' => '/home/runner/work/rector-src/rector-src/rector-build/vendor/rector/rector-downgrade-php', 'relative_install_path' => '../../rector-downgrade-php', 'extra' => NULL, 'version' => 'dev-main 917085c'), 'rector/rector-phpunit' => array('install_path' => '/home/runner/work/rector-src/rector-src/rector-build/vendor/rector/rector-phpunit', 'relative_install_path' => '../../rector-phpunit', 'extra' => NULL, 'version' => 'dev-main 669f5ee'), 'rector/rector-symfony' => array('install_path' => '/home/runner/work/rector-src/rector-src/rector-build/vendor/rector/rector-symfony', 'relative_install_path' => '../../rector-symfony', 'extra' => NULL, 'version' => 'dev-main 5f1e96d'));
public const EXTENSIONS = array('rector/rector-doctrine' => array('install_path' => '/home/runner/work/rector-src/rector-src/rector-build/vendor/rector/rector-doctrine', 'relative_install_path' => '../../rector-doctrine', 'extra' => NULL, 'version' => 'dev-main c7ff3e5'), 'rector/rector-downgrade-php' => array('install_path' => '/home/runner/work/rector-src/rector-src/rector-build/vendor/rector/rector-downgrade-php', 'relative_install_path' => '../../rector-downgrade-php', 'extra' => NULL, 'version' => 'dev-main 917085c'), 'rector/rector-phpunit' => array('install_path' => '/home/runner/work/rector-src/rector-src/rector-build/vendor/rector/rector-phpunit', 'relative_install_path' => '../../rector-phpunit', 'extra' => NULL, 'version' => 'dev-main 1cbcfcb'), 'rector/rector-symfony' => array('install_path' => '/home/runner/work/rector-src/rector-src/rector-build/vendor/rector/rector-symfony', 'relative_install_path' => '../../rector-symfony', 'extra' => NULL, 'version' => 'dev-main 5f1e96d'));
private function __construct()
{
}

View File

@ -5,6 +5,7 @@ namespace Rector\PHPUnit\PHPUnit60\Rector\MethodCall;
use PhpParser\Node;
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Expr\Variable;
use PHPStan\Type\ObjectType;
use Rector\Core\Rector\AbstractRector;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
@ -74,6 +75,10 @@ CODE_SAMPLE
if (!$currentMethodCall instanceof MethodCall) {
return null;
}
// can be only local call, as createMock() is protected method
if (!$this->isLocalScopeCaller($currentMethodCall)) {
return null;
}
// must be be test case class
if (!$this->isObjectType($currentMethodCall->var, new ObjectType('PHPUnit\\Framework\\TestCase'))) {
return null;
@ -85,4 +90,11 @@ CODE_SAMPLE
$thisVariable = $currentMethodCall->var;
return new MethodCall($thisVariable, 'createMock', $args);
}
private function isLocalScopeCaller(MethodCall $currentMethodCall) : bool
{
if (!$currentMethodCall->var instanceof Variable) {
return \false;
}
return $currentMethodCall->var->name === 'this';
}
}