Bump min PHP version to 7.3 (#4838)

Co-authored-by: rector-bot <tomas@getrector.org>
This commit is contained in:
Tomas Votruba 2020-12-09 23:25:53 +01:00 committed by GitHub
parent fab46dd552
commit d131d804d9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
122 changed files with 409 additions and 210 deletions

View File

@ -169,7 +169,7 @@ return static function (ContainerConfigurator $containerConfigurator): void {
]);
// is your PHP version different from the one your refactor to? [default: your PHP version], uses PHP_VERSION_ID format
$parameters->set(Option::PHP_VERSION_FEATURES, PhpVersion::PHP_7_2);
$parameters->set(Option::PHP_VERSION_FEATURES, PhpVersion::PHP_72);
// auto import fully qualified class names? [default: false]
$parameters->set(Option::AUTO_IMPORT_NAMES, true);

View File

@ -10,7 +10,7 @@
],
"bin": ["bin/rector"],
"require": {
"php": "^7.2.4|^8.0",
"php": "^7.3|^8.0",
"ext-json": "*",
"composer/xdebug-handler": "^1.4",
"doctrine/annotations": "^1.11",

View File

@ -9,6 +9,7 @@ final class AnnotationVisibilityDetector
public function isPrivate(object $annotation): bool
{
$publicPropertiesCount = count(get_object_vars($annotation));
/** @noRector special way to get public property count from object */
$propertiesCount = count((array) $annotation);
return $publicPropertiesCount !== $propertiesCount;

View File

@ -30,7 +30,8 @@ final class ArrayCallableMethodReferenceAnalyzer
*/
public function match(Array_ $array): ?ArrayCallable
{
if (count($array->items) !== 2) {
$arrayItems = (array) $array->items;
if (count($arrayItems) !== 2) {
return null;
}

View File

@ -20,14 +20,16 @@ final class BreakingRemovalGuard
return;
}
// validate the $parentNodenode can be removed
// validate the node can be removed
$parentNode = $node->getAttribute(AttributeKey::PARENT_NODE);
if (! $parentNode instanceof Node) {
throw new ShouldNotHappenException();
}
throw new ShouldNotHappenException(sprintf(
'Node "%s" on line %d is child of "%s", so it cannot be removed as it would break PHP code. Change or remove the parent node instead.',
get_class($node),
$node->getLine(),
/** @var Node $parentNode */
get_class($parentNode)
));
}
@ -35,7 +37,6 @@ final class BreakingRemovalGuard
public function isLegalNodeRemoval(Node $node): bool
{
$parent = $node->getAttribute(AttributeKey::PARENT_NODE);
if ($parent instanceof If_ && $parent->cond === $node) {
return false;
}

View File

@ -236,8 +236,17 @@ final class NodeTypeResolver
public function isNullableObjectType(Node $node): bool
{
$nodeType = $this->resolve($node);
return $this->isNullableTypeOfSpecificType($node, ObjectType::class);
}
public function isNullableArrayType(Node $node): bool
{
return $this->isNullableTypeOfSpecificType($node, ArrayType::class);
}
public function isNullableTypeOfSpecificType(Node $node, string $desiredType): bool
{
$nodeType = $this->resolve($node);
if (! $nodeType instanceof UnionType) {
return false;
}
@ -251,7 +260,7 @@ final class NodeTypeResolver
}
foreach ($nodeType->getTypes() as $type) {
if ($type instanceof ObjectType) {
if (is_a($type, $desiredType, true)) {
return true;
}
}

View File

@ -181,7 +181,7 @@ abstract class AbstractRectorTestCase extends AbstractKernelTestCase
// restore PHP version if changed
if ($this->getPhpVersion() !== self::PHP_VERSION_UNDEFINED) {
$this->setParameter(Option::PHP_VERSION_FEATURES, PhpVersion::PHP_10_0);
$this->setParameter(Option::PHP_VERSION_FEATURES, PhpVersion::PHP_10);
}
}

View File

@ -10,6 +10,15 @@ includes:
- vendor/symplify/phpstan-rules/packages/cognitive-complexity/config/cognitive-complexity-services.neon
services:
-
class: Symplify\PHPStanRules\Rules\NoParticularNodeRule
tags: [phpstan.rules.rule]
arguments:
forbiddenNodes:
- PhpParser\Node\Expr\ErrorSuppress
- PhpParser\Node\Stmt\Switch_
- PhpParser\Node\Expr\Empty_
-
class: Symplify\PHPStanRules\Rules\RequireClassTypeInClassMethodByTypeRule
tags: [phpstan.rules.rule]
@ -777,3 +786,6 @@ parameters:
- packages/better-php-doc-parser/src/PhpDocInfo/PhpDocInfoFactory.php
- rules/coding-style/src/Node/DocAliasResolver.php
- packages/better-php-doc-parser/tests/PhpDocParser/AbstractPhpDocInfoTest.php
- '#"@simplexml_load_string\(\$fileContents\)" is forbidden to use#'
- '#@ intentionally#'

View File

@ -54,6 +54,9 @@ return static function (ContainerConfigurator $containerConfigurator): void {
SetList::TYPE_DECLARATION,
SetList::PHPUNIT_CODE_QUALITY,
Setlist::SYMFONY_AUTOWIRE,
Setlist::PHP_71,
Setlist::PHP_72,
Setlist::PHP_73,
]);
$parameters->set(Option::PATHS, [
@ -86,6 +89,6 @@ return static function (ContainerConfigurator $containerConfigurator): void {
]);
# so Rector code is still PHP 7.2 compatible
$parameters->set(Option::PHP_VERSION_FEATURES, PhpVersion::PHP_7_2);
$parameters->set(Option::PHP_VERSION_FEATURES, PhpVersion::PHP_72);
$parameters->set(Option::ENABLE_CACHE, true);
};

View File

@ -4,6 +4,7 @@ declare(strict_types=1);
use Rector\Core\Configuration\Option;
use Rector\Core\ValueObject\PhpVersion;
use Rector\Set\ValueObject\SetList;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
return static function (ContainerConfigurator $containerConfigurator): void {
@ -18,11 +19,12 @@ return static function (ContainerConfigurator $containerConfigurator): void {
__DIR__ . '/bin/rector',
]);
$parameters->set(Option::SETS, [SetList::PHP_73]);
$parameters->set(Option::SKIP, [
'/Source/',
'/*Source/',
'/Fixture/',
'/Expected/',
'*/Source/*',
'*/Fixture/*',
'*/Expected/*',
__DIR__ . '/packages/doctrine-annotation-generated/src/*',
__DIR__ . '/packages/rector-generator/templates/*',
'*.php.inc',
@ -31,5 +33,5 @@ return static function (ContainerConfigurator $containerConfigurator): void {
$parameters->set(Option::AUTO_IMPORT_NAMES, true);
# so Rector code is still PHP 7.2 compatible
$parameters->set(Option::PHP_VERSION_FEATURES, PhpVersion::PHP_7_2);
$parameters->set(Option::PHP_VERSION_FEATURES, PhpVersion::PHP_72);
};

View File

@ -118,7 +118,7 @@ CODE_SAMPLE
/** @var MethodCall $methodCallNode */
$methodCallNode = $node;
if (count($methodCallNode->args) !== 1) {
if (count((array) $methodCallNode->args) !== 1) {
return null;
}

View File

@ -149,7 +149,7 @@ CODE_SAMPLE
int $argumentPosition,
ArrayToFluentCall $arrayToFluentCall
): ?MethodCall {
if (count($methodCall->args) !== $argumentPosition) {
if (count((array) $methodCall->args) !== $argumentPosition) {
return null;
}

View File

@ -120,7 +120,7 @@ CODE_SAMPLE
MethodCall $methodCall,
ModalToGetSet $modalToGetSet
): string {
if (count($methodCall->args) >= $modalToGetSet->getMinimalSetterArgumentCount()) {
if (count((array) $methodCall->args) >= $modalToGetSet->getMinimalSetterArgumentCount()) {
return $modalToGetSet->getSetMethod();
}

View File

@ -105,7 +105,7 @@ CODE_SAMPLE
continue;
}
if (count($methodCall->args) < 1) {
if (count((array) $methodCall->args) < 1) {
continue;
}

View File

@ -31,7 +31,7 @@ final class ForeachNodeAnalyzer
*/
public function matchAssignItemsOnlyForeachArrayVariable(Foreach_ $foreach): ?Expr
{
if (count($foreach->stmts) !== 1) {
if (count((array) $foreach->stmts) !== 1) {
return null;
}

View File

@ -123,7 +123,7 @@ CODE_SAMPLE
private function shouldSkipArray(Array_ $array): bool
{
// callback is exactly "[$two, 'items']"
if (count($array->items) !== 2) {
if (count((array) $array->items) !== 2) {
return true;
}

View File

@ -91,7 +91,7 @@ CODE_SAMPLE
return true;
}
if (count($assign->var->items) !== count($assign->expr->items)) {
if (count((array) $assign->var->items) !== count((array) $assign->expr->items)) {
return true;
}

View File

@ -143,7 +143,7 @@ CODE_SAMPLE
return true;
}
if (count($foreach->stmts) > 1) {
if (count((array) $foreach->stmts) > 1) {
return true;
}

View File

@ -70,11 +70,11 @@ CODE_SAMPLE
/** @var FuncCall $funcCallNode */
$funcCallNode = $ifNode->cond;
if (count($ifNode->stmts) !== 1) {
if (count((array) $ifNode->stmts) !== 1) {
return null;
}
if (count($funcCallNode->args) !== 1) {
if (count((array) $funcCallNode->args) !== 1) {
return null;
}
@ -109,7 +109,7 @@ CODE_SAMPLE
private function shouldSkip(Foreach_ $foreach): bool
{
if (count($foreach->stmts) !== 1) {
if (count((array) $foreach->stmts) !== 1) {
return true;
}

View File

@ -122,7 +122,7 @@ CODE_SAMPLE
return null;
}
if (count($node->stmts) !== 1) {
if (count((array) $node->stmts) !== 1) {
return null;
}

View File

@ -50,7 +50,7 @@ final class InArrayAndArrayKeysToArrayKeyExistsRector extends AbstractRector
return null;
}
if (count($secondArgument->args) > 1) {
if (count((array) $secondArgument->args) > 1) {
return null;
}

View File

@ -67,7 +67,7 @@ CODE_SAMPLE
return null;
}
if (count($node->args) !== 2) {
if (count((array) $node->args) !== 2) {
return null;
}

View File

@ -75,7 +75,7 @@ CODE_SAMPLE
/** @var Array_ $arrayNode */
$arrayNode = $node->args[1]->value;
if (count($arrayNode->items) !== 1) {
if (count((array) $arrayNode->items) !== 1) {
return null;
}

View File

@ -48,7 +48,7 @@ CODE_SAMPLE
return null;
}
if (count($node->args) > 1) {
if (count((array) $node->args) > 1) {
return null;
}

View File

@ -123,14 +123,14 @@ CODE_SAMPLE
}
/** @var If_ $stmt */
if (count($stmt->stmts) === 1) {
if (count((array) $stmt->stmts) === 1) {
$node->stmts[$key] = $stmt->stmts[0];
continue;
}
$haveNodeChanged = true;
// move all nodes one level up
array_splice($node->stmts, $key, count($stmt->stmts) - 1, $stmt->stmts);
array_splice($node->stmts, $key, count((array) $stmt->stmts) - 1, $stmt->stmts);
}
if ($haveNodeChanged) {
@ -147,7 +147,7 @@ CODE_SAMPLE
}
// just one if
if (count($node->elseifs) !== 0) {
if (count((array) $node->elseifs) !== 0) {
return false;
}

View File

@ -93,7 +93,7 @@ CODE_SAMPLE
return true;
}
if (count($if->stmts) !== 1) {
if (count((array) $if->stmts) !== 1) {
return true;
}

View File

@ -76,7 +76,7 @@ CODE_SAMPLE
}
$else = $node->else;
if (count($else->stmts) !== 1) {
if (count((array) $else->stmts) !== 1) {
return null;
}

View File

@ -112,7 +112,7 @@ CODE_SAMPLE
return true;
}
if (count($if->elseifs) > 1) {
if (count((array) $if->elseifs) > 1) {
return true;
}
@ -139,7 +139,7 @@ CODE_SAMPLE
*/
private function hasOnlyStatementAssign(Node $node): bool
{
if (count($node->stmts) !== 1) {
if (count((array) $node->stmts) !== 1) {
return false;
}

View File

@ -189,7 +189,7 @@ CODE_SAMPLE
return false;
}
if (count($if->else->stmts) !== 1) {
if (count((array) $if->else->stmts) !== 1) {
return false;
}
@ -200,7 +200,7 @@ CODE_SAMPLE
private function isIfWithSingleReturnExpr(If_ $if): bool
{
if (count($if->stmts) !== 1) {
if (count((array) $if->stmts) !== 1) {
return false;
}

View File

@ -54,6 +54,7 @@ final class ClassNameImportSkipper
{
/** @var Use_[] $uses */
$uses = (array) $name->getAttribute(AttributeKey::USE_NODES);
foreach ($uses as $use) {
$useUses = $use->uses;
foreach ($useUses as $useUse) {

View File

@ -194,7 +194,7 @@ final class NameImporter
return false;
}
return count($name->parts) === 1;
return count((array) $name->parts) === 1;
}
private function isNonExistingClassLikeAndFunctionFullyQualifiedName(Name $name): bool

View File

@ -325,7 +325,7 @@ CODE_SAMPLE
{
// traverse and replace placeholder by original nodes
$this->traverseNodesWithCallable($array, function (Node $node) use ($placeholderNodes): ?Expr {
if ($node instanceof Array_ && count($node->items) === 1) {
if ($node instanceof Array_ && count((array) $node->items) === 1) {
$placeholderNode = $this->matchPlaceholderNode($node->items[0]->value, $placeholderNodes);
if ($placeholderNode && $this->isImplodeToJson($placeholderNode)) {

View File

@ -73,7 +73,7 @@ CODE_SAMPLE
*/
public function refactor(Node $node): ?Node
{
if (count($node->types) !== 1) {
if (count((array) $node->types) !== 1) {
return null;
}

View File

@ -72,7 +72,7 @@ CODE_SAMPLE
public function refactor(Node $node): ?Node
{
if ($node instanceof ClassConst) {
if (count($node->consts) < 2) {
if (count((array) $node->consts) < 2) {
return null;
}
@ -89,7 +89,7 @@ CODE_SAMPLE
return $node;
}
if (count($node->props) < 2) {
if (count((array) $node->props) < 2) {
return null;
}

View File

@ -65,7 +65,7 @@ CODE_SAMPLE
*/
public function refactor(Node $node): ?Node
{
if (count($node->consts) > 1) {
if (count((array) $node->consts) > 1) {
return null;
}

View File

@ -72,7 +72,7 @@ CODE_SAMPLE
return null;
}
if (count($node->args) === 1) {
if (count((array) $node->args) === 1) {
// complete default value ''
$node->args[1] = $node->args[0];
$node->args[0] = new Arg(new String_(''));
@ -85,7 +85,7 @@ CODE_SAMPLE
return null;
}
if (count($node->args) === 2 && $this->isStringOrUnionStringOnlyType($node->args[1]->value)) {
if (count((array) $node->args) === 2 && $this->isStringOrUnionStringOnlyType($node->args[1]->value)) {
$node->args = array_reverse($node->args);
}

View File

@ -39,7 +39,7 @@ final class StrictArraySearchRector extends AbstractRector
return null;
}
if (count($node->args) === 2) {
if (count((array) $node->args) === 2) {
$node->args[2] = $this->createArg($this->createTrue());
}

View File

@ -101,7 +101,7 @@ CODE_SAMPLE
return null;
}
if (count($node->args) !== 3) {
if (count((array) $node->args) !== 3) {
return null;
}

View File

@ -62,7 +62,7 @@ CODE_SAMPLE
*/
public function refactor(Node $node): ?Node
{
if (count($node->cases) > 2) {
if (count((array) $node->cases) > 2) {
return null;
}

View File

@ -74,7 +74,7 @@ CODE_SAMPLE
private function refactorUseImport(Use_ $use): void
{
if (count($use->uses) < 2) {
if (count((array) $use->uses) < 2) {
return;
}
@ -88,7 +88,7 @@ CODE_SAMPLE
private function refactorTraitUse(TraitUse $traitUse): void
{
if (count($traitUse->traits) < 2) {
if (count((array) $traitUse->traits) < 2) {
return;
}

View File

@ -113,7 +113,7 @@ CODE_SAMPLE
return true;
}
if (count($node->consts) !== 1) {
if (count((array) $node->consts) !== 1) {
return true;
}

View File

@ -71,7 +71,7 @@ CODE_SAMPLE
return null;
}
if (count($node->consts) !== 1) {
if (count((array) $node->consts) !== 1) {
return null;
}

View File

@ -67,7 +67,7 @@ CODE_SAMPLE
}
// just one if
if (count($node->elseifs) !== 0) {
if (count((array) $node->elseifs) !== 0) {
return null;
}
@ -80,7 +80,7 @@ CODE_SAMPLE
return null;
}
if (count($node->stmts) !== 1) {
if (count((array) $node->stmts) !== 1) {
// unable to handle now
return null;
}

View File

@ -131,7 +131,7 @@ CODE_SAMPLE
private function shouldSkipProperty(Property $property): bool
{
if (count($property->props) !== 1) {
if (count((array) $property->props) !== 1) {
return true;
}

View File

@ -78,7 +78,7 @@ CODE_SAMPLE
private function shouldSkipProperty(Property $property): bool
{
if (count($property->props) !== 1) {
if (count((array) $property->props) !== 1) {
return true;
}

View File

@ -78,7 +78,7 @@ CODE_SAMPLE
*/
public function refactor(Node $node): ?Node
{
if (count($node->cases) < 2) {
if (count((array) $node->cases) < 2) {
return null;
}

View File

@ -62,13 +62,13 @@ CODE_SAMPLE
*/
public function refactor(Node $node): ?Node
{
if (count($node->catches) !== 1) {
if (count((array) $node->catches) !== 1) {
return null;
}
/** @var Catch_ $onlyCatch */
$onlyCatch = $node->catches[0];
if (count($onlyCatch->stmts) !== 1) {
if (count((array) $onlyCatch->stmts) !== 1) {
return null;
}

View File

@ -37,7 +37,7 @@ final class NewFluentChainMethodCallNodeAnalyzer
*/
public function matchNewInFluentSetterMethodCall(MethodCall $methodCall): ?New_
{
if (count($methodCall->args) !== 1) {
if (count((array) $methodCall->args) !== 1) {
return null;
}

View File

@ -117,7 +117,7 @@ final class SetterClassMethodAnalyzer
private function matchSetterOnlyPropertyFetch(ClassMethod $classMethod): ?PropertyFetch
{
if (count($classMethod->params) !== 1) {
if (count((array) $classMethod->params) !== 1) {
return null;
}

View File

@ -117,7 +117,7 @@ CODE_SAMPLE
$collectionPropertyNames = [];
foreach ($class->getProperties() as $property) {
if (count($property->props) !== 1) {
if (count((array) $property->props) !== 1) {
continue;
}

View File

@ -177,7 +177,7 @@ CODE_SAMPLE
return null;
}
if (count($classMethod->params) !== 1) {
if (count((array) $classMethod->params) !== 1) {
return null;
}

View File

@ -60,7 +60,7 @@ CODE_SAMPLE
{
$originalCatches = $node->catches;
foreach ($node->catches as $key => $catch) {
if (count($catch->types) === 1) {
if (count((array) $catch->types) === 1) {
continue;
}

View File

@ -4,14 +4,12 @@ declare(strict_types=1);
namespace Rector\DowngradePhp73\Rector\FuncCall;
use PhpParser\BuilderHelpers;
use PhpParser\Node;
use PhpParser\Node\Arg;
use PhpParser\Node\Expr\Array_;
use PhpParser\Node\Expr\ArrayItem;
use PhpParser\Node\Expr\ConstFetch;
use PhpParser\Node\Expr\FuncCall;
use PhpParser\Node\Name;
use PhpParser\Node\Scalar\LNumber;
use PhpParser\Node\Scalar\String_;
use Rector\Core\Exception\ShouldNotHappenException;
use Rector\Core\Rector\AbstractRector;
@ -27,7 +25,7 @@ final class SetCookieOptionsArrayToArgumentsRector extends AbstractRector
* Conversion table from argument index to options name
* @var array<string, int>
*/
private const ARGUMENTS_ORDER = [
private const ARGUMENT_ORDER = [
'expires' => 2,
'path' => 3,
'domain' => 4,
@ -35,16 +33,23 @@ final class SetCookieOptionsArrayToArgumentsRector extends AbstractRector
'httponly' => 6,
];
/**
* Conversion table from argument index to options name
* @var array<int, bool|int|string>
*/
private const ARGUMENT_DEFAULT_VALUES = [
2 => 0,
3 => '',
4 => '',
5 => false,
6 => false,
];
/**
* @var int
*/
private $highestIndex = 1;
/**
* @var Arg[]
*/
private $newArguments = [];
public function getRuleDefinition(): RuleDefinition
{
return new RuleDefinition(
@ -91,7 +96,7 @@ CODE_SAMPLE
return true;
}
$argsCount = count($funcCall->args);
$argsCount = count((array) $funcCall->args);
if ($argsCount <= 2) {
return true;
}
@ -104,10 +109,8 @@ CODE_SAMPLE
private function composeNewArgs(FuncCall $funcCall): array
{
$this->highestIndex = 1;
$this->newArguments = [
0 => $funcCall->args[0],
1 => $funcCall->args[1],
];
$newArgs = [$funcCall->args[0], $funcCall->args[1]];
/** @var Array_ $optionsArray */
$optionsArray = $funcCall->args[2]->value;
@ -127,49 +130,51 @@ CODE_SAMPLE
continue;
}
$order = self::ARGUMENTS_ORDER[$name];
$order = self::ARGUMENT_ORDER[$name];
if ($order > $this->highestIndex) {
$this->highestIndex = $order;
}
$this->newArguments[$order] = $value;
$newArgs[$order] = $value;
}
$this->fillMissingArgumentsWithDefaultValues();
ksort($this->newArguments);
$newArgs = $this->fillMissingArgumentsWithDefaultValues($newArgs);
ksort($newArgs);
return $this->newArguments;
return $newArgs;
}
private function isMappableArrayKey(string $key): bool
{
return isset(self::ARGUMENTS_ORDER[$key]);
return isset(self::ARGUMENT_ORDER[$key]);
}
private function fillMissingArgumentsWithDefaultValues(): void
/**
* @param Arg[] $args
* @return Arg[]
*/
private function fillMissingArgumentsWithDefaultValues(array $args): array
{
for ($i = 1; $i < $this->highestIndex; $i++) {
if (isset($this->newArguments[$i])) {
if (isset($args[$i])) {
continue;
}
$this->newArguments[$i] = $this->getDefaultValue($i);
$args[$i] = $this->createDefaultValueArg($i);
}
return $args;
}
private function getDefaultValue(int $argumentIndex): Arg
private function createDefaultValueArg(int $argumentIndex): Arg
{
switch ($argumentIndex) {
case self::ARGUMENTS_ORDER['expires']:
return new Arg(new LNumber(0));
case self::ARGUMENTS_ORDER['path']:
case self::ARGUMENTS_ORDER['domain']:
return new Arg(new String_(''));
case self::ARGUMENTS_ORDER['secure']:
case self::ARGUMENTS_ORDER['httponly']:
return new Arg(new ConstFetch(new Name('false')));
default:
throw new ShouldNotHappenException();
if (! array_key_exists($argumentIndex, self::ARGUMENT_DEFAULT_VALUES)) {
throw new ShouldNotHappenException();
}
$argumentDefaultValue = self::ARGUMENT_DEFAULT_VALUES[$argumentIndex];
$expr = BuilderHelpers::normalizeValue($argumentDefaultValue);
return new Arg($expr);
}
}

View File

@ -120,7 +120,7 @@ CODE_SAMPLE
*/
public function removeStaleParams(Node $node, int $rightSideRemovableParamsCount): ?Node
{
$nodeItemsCount = count($node->items);
$nodeItemsCount = count((array) $node->items);
if ($rightSideRemovableParamsCount === $nodeItemsCount) {
// Remove the parent Assign node
/** @var Assign */

View File

@ -146,7 +146,7 @@ CODE_SAMPLE
}
// If param not provided, do nothing
if (count($node->args) < 2) {
if (count((array) $node->args) < 2) {
return false;
}

View File

@ -77,7 +77,7 @@ CODE_SAMPLE
return null;
}
$classMethodStatementCount = count($node->stmts);
$classMethodStatementCount = count((array) $node->stmts);
// iterate from bottom to up, so we can merge
for ($i = $classMethodStatementCount - 1; $i >= 0; --$i) {

View File

@ -74,7 +74,7 @@ CODE_SAMPLE
return null;
}
if (count($node->args) === 3) {
if (count((array) $node->args) === 3) {
return null;
}

View File

@ -68,7 +68,7 @@ final class SingletonClassMethodAnalyzer
$if = $classMethod->stmts[0];
$staticPropertyFetch = $this->matchStaticPropertyFetchInIfCond($if->cond);
if (count($if->stmts) !== 1) {
if (count((array) $if->stmts) !== 1) {
return null;
}

View File

@ -28,7 +28,7 @@ final class PropertyRenameFactory
public function create(Property $property, ExpectedNameResolverInterface $expectedNameResolver): ?PropertyRename
{
if (count($property->props) !== 1) {
if (count((array) $property->props) !== 1) {
return null;
}

View File

@ -194,7 +194,7 @@ CODE_SAMPLE
return new MixedType();
}
if (count($methodCall->args) !== 1) {
if (count((array) $methodCall->args) !== 1) {
return new MixedType();
}

View File

@ -90,7 +90,7 @@ CODE_SAMPLE
return null;
}
if (count($node->args) < 2) {
if (count((array) $node->args) < 2) {
return null;
}

View File

@ -66,7 +66,7 @@ CODE_SAMPLE
return null;
}
if (count($node->args) !== 2) {
if (count((array) $node->args) !== 2) {
return null;
}

View File

@ -170,7 +170,7 @@ CODE_SAMPLE
return $args;
}
if (count($funcCall->args) !== 3) {
if (count((array) $funcCall->args) !== 3) {
return $args;
}

View File

@ -75,7 +75,7 @@ CODE_SAMPLE
return null;
}
if (count($node->args) !== 1) {
if (count((array) $node->args) !== 1) {
return null;
}

View File

@ -71,7 +71,7 @@ CODE_SAMPLE
return null;
}
if (count($node->args) !== 2) {
if (count((array) $node->args) !== 2) {
return null;
}

View File

@ -95,7 +95,7 @@ CODE_SAMPLE
continue;
}
if (count($classStmt->consts) !== 1) {
if (count((array) $classStmt->consts) !== 1) {
continue;
}

View File

@ -54,7 +54,7 @@ final class StmtOrder
{
$reorderedStmts = [];
$stmtCount = count($classLike->stmts);
$stmtCount = count((array) $classLike->stmts);
foreach ($classLike->stmts as $key => $stmt) {
if (! array_key_exists($key, $oldToNewKeys)) {

View File

@ -62,7 +62,7 @@ CODE_SAMPLE
return null;
}
if (count($node->args) === 1) {
if (count((array) $node->args) === 1) {
return null;
}

View File

@ -59,7 +59,7 @@ final class AddMockPropertiesRector extends AbstractPhpSpecToPHPUnitRector
$class = $node->getAttribute(AttributeKey::CLASS_NAME);
foreach ($classMocks as $name => $methods) {
if (count($methods) <= 1) {
if ((is_countable($methods) ? count($methods) : 0) <= 1) {
continue;
}

View File

@ -66,7 +66,7 @@ CODE_SAMPLE
return null;
}
if (count($node->args) !== 1) {
if (count((array) $node->args) !== 1) {
return null;
}

View File

@ -46,7 +46,7 @@ final class PowToExpRector extends AbstractRector
return null;
}
if (count($node->args) !== 2) {
if (count((array) $node->args) !== 2) {
return null;
}

View File

@ -91,7 +91,7 @@ CODE_SAMPLE
return null;
}
if (count($node->stmts) === 1) {
if (count((array) $node->stmts) === 1) {
/** @var Expression $stmt */
$stmt = $node->stmts[0];

View File

@ -83,12 +83,12 @@ final class MultiDirnameRector extends AbstractRector
return null;
}
if (count($funcCall->args) >= 3) {
if (count((array) $funcCall->args) >= 3) {
return null;
}
// dirname($path, <LEVEL>);
if (count($funcCall->args) === 2) {
if (count((array) $funcCall->args) === 2) {
if (! $funcCall->args[1]->value instanceof LNumber) {
return null;
}

View File

@ -66,7 +66,7 @@ CODE_SAMPLE
}
// exception handle has 1 param exactly
if (count($node->params) !== 1) {
if (count((array) $node->params) !== 1) {
return null;
}

View File

@ -192,7 +192,7 @@ CODE_SAMPLE
private function matchOnEqual(If_ $if): void
{
if (count($if->stmts) !== 1) {
if (count((array) $if->stmts) !== 1) {
return;
}
@ -209,7 +209,7 @@ CODE_SAMPLE
private function processElse(Else_ $else): void
{
if (count($else->stmts) !== 1) {
if (count((array) $else->stmts) !== 1) {
return;
}

View File

@ -0,0 +1,63 @@
<?php
declare(strict_types=1);
namespace Rector\Php71\NodeAnalyzer;
use PhpParser\Node\Expr;
use PhpParser\Node\Expr\PropertyFetch;
use PHPStan\Type\TypeWithClassName;
use PHPStan\Type\UnionType;
use Rector\NodeNameResolver\NodeNameResolver;
use Rector\NodeTypeResolver\NodeTypeResolver;
use ReflectionClass;
final class CountableAnalyzer
{
/**
* @var NodeTypeResolver
*/
private $nodeTypeResolver;
/**
* @var NodeNameResolver
*/
private $nodeNameResolver;
public function __construct(NodeTypeResolver $nodeTypeResolver, NodeNameResolver $nodeNameResolver)
{
$this->nodeTypeResolver = $nodeTypeResolver;
$this->nodeNameResolver = $nodeNameResolver;
}
public function isCastableArrayType(Expr $expr): bool
{
if (! $expr instanceof PropertyFetch) {
return false;
}
$callerObjectType = $this->nodeTypeResolver->resolve($expr->var);
$propertyName = $this->nodeNameResolver->getName($expr->name);
if (! is_string($propertyName)) {
return false;
}
if ($callerObjectType instanceof UnionType) {
$callerObjectType = $callerObjectType->getTypes()[0];
}
if (! $callerObjectType instanceof TypeWithClassName) {
return false;
}
$reflectionClass = new ReflectionClass($callerObjectType->getClassName());
$propertiesDefaults = $reflectionClass->getDefaultProperties();
if (! array_key_exists($propertyName, $propertiesDefaults)) {
return false;
}
$propertyDefaultValue = $propertiesDefaults[$propertyName];
return $propertyDefaultValue === null;
}
}

View File

@ -6,8 +6,10 @@ namespace Rector\Php71\Rector\FuncCall;
use PhpParser\Node;
use PhpParser\Node\Arg;
use PhpParser\Node\Expr;
use PhpParser\Node\Expr\BinaryOp\BooleanOr;
use PhpParser\Node\Expr\BinaryOp\Identical;
use PhpParser\Node\Expr\Cast\Array_;
use PhpParser\Node\Expr\FuncCall;
use PhpParser\Node\Expr\Instanceof_;
use PhpParser\Node\Expr\Ternary;
@ -15,10 +17,12 @@ use PhpParser\Node\Name;
use PhpParser\Node\Name\FullyQualified;
use PhpParser\Node\Scalar\LNumber;
use PhpParser\Node\Stmt\Trait_;
use PHPStan\Type\ArrayType;
use PHPStan\Type\NullType;
use Rector\Core\Rector\AbstractRector;
use Rector\Core\ValueObject\PhpVersionFeature;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Rector\Php71\NodeAnalyzer\CountableAnalyzer;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
@ -33,6 +37,15 @@ final class CountOnNullRector extends AbstractRector
* @var string
*/
private const ALREADY_CHANGED_ON_COUNT = 'already_changed_on_count';
/**
* @var CountableAnalyzer
*/
private $countableAnalyzer;
public function __construct(CountableAnalyzer $countableAnalyzer)
{
$this->countableAnalyzer = $countableAnalyzer;
}
public function getRuleDefinition(): RuleDefinition
{
@ -46,7 +59,7 @@ CODE_SAMPLE
,
<<<'CODE_SAMPLE'
$values = null;
$count = is_array($values) || $values instanceof Countable ? count($values) : 0;
$count = count((array) $values);
CODE_SAMPLE
)]
);
@ -74,27 +87,39 @@ CODE_SAMPLE
return null;
}
if ($this->isNullableType($countedNode) || $this->isStaticType($countedNode, NullType::class)) {
$identical = new Identical($countedNode, $this->createNull());
$ternaryNode = new Ternary($identical, new LNumber(0), $node);
} else {
if ($this->isAtLeastPhpVersion(PhpVersionFeature::IS_COUNTABLE)) {
$conditionNode = new FuncCall(new Name('is_countable'), [new Arg($countedNode)]);
} else {
$instanceof = new Instanceof_($countedNode, new FullyQualified('Countable'));
$conditionNode = new BooleanOr(
$this->createFuncCall('is_array', [new Arg($countedNode)]),
$instanceof
);
// this can lead to false positive by phpstan, but that's best we can do
$onlyValueType = $this->getStaticType($countedNode);
if ($onlyValueType instanceof ArrayType) {
if (! $this->countableAnalyzer->isCastableArrayType($countedNode)) {
return null;
}
$ternaryNode = new Ternary($conditionNode, $node, new LNumber(0));
return $this->castToArray($countedNode, $node);
}
if ($this->isNullableArrayType($countedNode)) {
return $this->castToArray($countedNode, $node);
}
if ($this->isNullableType($countedNode) || $this->isStaticType($countedNode, NullType::class)) {
$identical = new Identical($countedNode, $this->createNull());
$ternary = new Ternary($identical, new LNumber(0), $node);
// prevent infinity loop re-resolution
$node->setAttribute(self::ALREADY_CHANGED_ON_COUNT, true);
return $ternary;
}
if ($this->isAtLeastPhpVersion(PhpVersionFeature::IS_COUNTABLE)) {
$conditionNode = new FuncCall(new Name('is_countable'), [new Arg($countedNode)]);
} else {
$instanceof = new Instanceof_($countedNode, new FullyQualified('Countable'));
$conditionNode = new BooleanOr($this->createFuncCall('is_array', [new Arg($countedNode)]), $instanceof);
}
// prevent infinity loop re-resolution
$node->setAttribute(self::ALREADY_CHANGED_ON_COUNT, true);
return $ternaryNode;
return new Ternary($conditionNode, $node, new LNumber(0));
}
private function shouldSkip(FuncCall $funcCall): bool
@ -102,6 +127,7 @@ CODE_SAMPLE
if (! $this->isName($funcCall, 'count')) {
return true;
}
$alreadyChangedOnCount = $funcCall->getAttribute(self::ALREADY_CHANGED_ON_COUNT);
// check if it has some condition before already, if so, probably it's already handled
@ -120,7 +146,14 @@ CODE_SAMPLE
// skip node in trait, as impossible to analyse
$classLike = $funcCall->getAttribute(AttributeKey::CLASS_NODE);
return $classLike instanceof Trait_;
}
private function castToArray(Expr $countedExpr, FuncCall $funcCall): FuncCall
{
$castArray = new Array_($countedExpr);
$funcCall->args = [new Arg($castArray)];
return $funcCall;
}
}

View File

@ -72,7 +72,7 @@ final class RemoveExtraParametersRector extends AbstractRector
);
$numberOfParameters = count($parametersAcceptor->getParameters());
$numberOfArguments = count($node->args);
$numberOfArguments = count((array) $node->args);
for ($i = $numberOfParameters; $i <= $numberOfArguments; $i++) {
unset($node->args[$i]);

View File

@ -110,7 +110,7 @@ CODE_SAMPLE
// process lass part
foreach ($this->reservedKeywordsToReplacements as $reservedKeyword => $replacement) {
if (strtolower($name->getLast()) === strtolower($reservedKeyword)) {
$name->parts[count($name->parts) - 1] = $replacement;
$name->parts[count((array) $name->parts) - 1] = $replacement;
// invoke override
$name->setAttribute(AttributeKey::ORIGINAL_NODE, null);

View File

@ -64,7 +64,7 @@ CODE_SAMPLE
return null;
}
if (count($node->catches) < 2) {
if (count((array) $node->catches) < 2) {
return null;
}

View File

@ -0,0 +1,39 @@
<?php
namespace Rector\Php71\Tests\Rector\FuncCall\CountOnNullRector\Fixture;
use PhpParser\Node\Expr\MethodCall;
class CountOrArgs
{
public function run(MethodCall $methodCall)
{
if (count($methodCall->args)) {
return true;
}
return false;
}
}
?>
-----
<?php
namespace Rector\Php71\Tests\Rector\FuncCall\CountOnNullRector\Fixture;
use PhpParser\Node\Expr\MethodCall;
class CountOrArgs
{
public function run(MethodCall $methodCall)
{
if (count((array) $methodCall->args)) {
return true;
}
return false;
}
}
?>

View File

@ -20,7 +20,7 @@ final class NullableArray
{
public function number(?array $items)
{
return $items === null ? 0 : count($items);
return count((array) $items);
}
}

View File

@ -30,7 +30,7 @@ class PropertyWithDoc
public function run()
{
return is_array($this->fail) || $this->fail instanceof \Countable ? count($this->fail) : 0;
return count((array) $this->fail);
}
}

View File

@ -0,0 +1,20 @@
<?php
declare(strict_types=1);
namespace Rector\Php71\Tests\Rector\FuncCall\CountOnNullRector\Fixture;
final class SkipInitArray
{
public function run(\PHPStan\Type\Type $type, ?\PHPStan\Type\Type $resolvedType)
{
$types[] = $type;
if ($resolvedType !== null) {
$types[] = $resolvedType;
}
return $types;
}
}

View File

@ -121,7 +121,7 @@ CODE_SAMPLE
/** @var List_ $listNode */
$listNode = $assign->var;
if (count($listNode->items) !== 2) {
if (count((array) $listNode->items) !== 2) {
return true;
}

View File

@ -97,7 +97,7 @@ CODE_SAMPLE
/** @var List_ $listNode */
$listNode = $assignNode->var;
$foreachedExpr = count($listNode->items) === 1 ? $this->createFuncCall(
$foreachedExpr = count((array) $listNode->items) === 1 ? $this->createFuncCall(
'array_keys',
[$eachFuncCall->args[0]]
) : $eachFuncCall->args[0]->value;

View File

@ -98,7 +98,7 @@ CODE_SAMPLE
return true;
}
$argsCount = count($funcCall->args);
$argsCount = count((array) $funcCall->args);
if ($argsCount <= 2) {
return true;
@ -124,6 +124,7 @@ CODE_SAMPLE
$args = $funcCall->args;
$newArgs = [];
$newArgs[] = $args[0];
$newArgs[] = $args[1];

View File

@ -80,7 +80,7 @@ CODE_SAMPLE
return true;
}
if (count($property->props) > 1) {
if (count((array) $property->props) > 1) {
return true;
}

View File

@ -127,7 +127,7 @@ CODE_SAMPLE
$this->promotionCandidates = [];
foreach ($class->getProperties() as $property) {
if (count($property->props) !== 1) {
if (count((array) $property->props) !== 1) {
continue;
}

View File

@ -201,7 +201,7 @@ CODE_SAMPLE
return $beforeIf;
}
$beforeIf->stmts[count($beforeIf->stmts) - 1] = new Expression($nullSafe);
$beforeIf->stmts[count((array) $beforeIf->stmts) - 1] = new Expression($nullSafe);
return $beforeIf;
}

View File

@ -94,7 +94,7 @@ CODE_SAMPLE
*/
private function processTryCatch(TryCatch $tryCatch): ?array
{
if (count($tryCatch->catches) !== 1) {
if (count((array) $tryCatch->catches) !== 1) {
return null;
}

View File

@ -185,7 +185,7 @@ CODE_SAMPLE
return;
}
if (count($methodCall->args) !== 1) {
if (count((array) $methodCall->args) !== 1) {
throw new ShouldNotHappenException();
}

View File

@ -76,7 +76,7 @@ CODE_SAMPLE
return null;
}
if (count($node->args) !== 1) {
if (count((array) $node->args) !== 1) {
return null;
}

View File

@ -53,7 +53,7 @@ final class GetMockRector extends AbstractPHPUnitRector
}
// narrow args to one
if (count($node->args) > 1) {
if (count((array) $node->args) > 1) {
$node->args = [$node->args[0]];
}

View File

@ -13,18 +13,18 @@ final class FunctionSupportResolver
* @var array<int, string[]>
*/
private const FUNCTIONS_BY_VERSION = [
PhpVersion::PHP_5_6 => ['session_abort', 'hash_equals', 'ldap_escape'],
PhpVersion::PHP_7_0 => [
PhpVersion::PHP_56 => ['session_abort', 'hash_equals', 'ldap_escape'],
PhpVersion::PHP_70 => [
'random_int',
'random_bytes',
'intdiv',
'preg_replace_callback_array',
'error_clear_last',
],
PhpVersion::PHP_7_1 => ['is_iterable'],
PhpVersion::PHP_7_2 => ['spl_object_id', 'stream_isatty'],
PhpVersion::PHP_71 => ['is_iterable'],
PhpVersion::PHP_72 => ['spl_object_id', 'stream_isatty'],
PhpVersion::PHP_7_3 => ['array_key_first', 'array_key_last', 'hrtime', 'is_countable'],
PhpVersion::PHP_7_4 => ['get_mangled_object_vars', 'mb_str_split', 'password_algos'],
PhpVersion::PHP_74 => ['get_mangled_object_vars', 'mb_str_split', 'password_algos'],
];
/**

View File

@ -145,7 +145,7 @@ CODE_SAMPLE
return true;
}
if (count($classConst->consts) !== 1) {
if (count((array) $classConst->consts) !== 1) {
return true;
}

View File

@ -80,7 +80,7 @@ CODE_SAMPLE
private function shouldSkipProperty(Property $property): bool
{
if (count($property->props) !== 1) {
if (count((array) $property->props) !== 1) {
return true;
}

View File

@ -46,7 +46,7 @@ final class FullyQualifiedNameMatcher
}
if ($name instanceof Name) {
if (count($name->parts) !== 1) {
if (count((array) $name->parts) !== 1) {
return null;
}

View File

@ -115,7 +115,7 @@ CODE_SAMPLE
public function refactor(Node $node): ?Node
{
// must be exactly 1 param
if (count($node->params) !== 1) {
if (count((array) $node->params) !== 1) {
return null;
}

View File

@ -130,7 +130,7 @@ CODE_SAMPLE
return true;
}
return $constructorMethodReflection->getNumberOfRequiredParameters() <= count($new->args);
return $constructorMethodReflection->getNumberOfRequiredParameters() <= count((array) $new->args);
}
private function getNewNodeClassConstructorMethodReflection(New_ $new): ?ReflectionMethod

Some files were not shown because too many files have changed in this diff Show More