From 9075363fef1448bf76c43ac7116f6165db537e83 Mon Sep 17 00:00:00 2001 From: TomasVotruba Date: Sun, 8 Dec 2019 22:00:38 +0100 Subject: [PATCH] bump to PHPStan 0.12 --- compiler/composer.json | 5 -- compiler/src/Console/CompileCommand.php | 3 -- composer.json | 14 +++--- config/services.yaml | 2 +- docs/AllRectorsOverview.md | 2 +- .../Fixture/fixture.php.inc | 46 ++++++++++++------ .../Fixture/fixture3.php.inc | 16 +++++++ .../Fixture/skip_required.php.inc | 2 +- .../src/AssertManipulator.php | 4 +- ...outerListToControllerAnnotationsRector.php | 2 +- .../PHPStanServicesFactory.php | 2 +- .../NodeTypeResolver/src/NodeTypeResolver.php | 24 ++++++++-- .../src/PHPStan/Scope/NodeScopeResolver.php | 6 ++- .../src/PHPStan/Scope/ScopeFactory.php | 3 +- .../Fixture/fixture.php.inc | 6 +++ .../ReduceMultipleDefaultSwitchRector.php | 2 +- .../Source/MagicEventDispatcher.php | 2 +- .../MakeDispatchFirstArgumentEventRector.php | 6 +-- .../Fixture/fixture.php.inc | 4 +- .../ReturnTypeDeclarationRector.php | 47 ++++++++++++++----- .../ReturnedNodesReturnTypeInferer.php | 3 +- .../Fixture/known_float.php.inc | 34 +------------- .../Fixture/known_float_in_variable.php.inc | 29 ++++++++++++ .../Fixture/known_float_param_type.php.inc | 27 +++++++++++ ...wn_float_param_type_with_condition.php.inc | 35 ++++++++++++++ .../Fixture/known_static.php.inc | 4 +- .../Fixture/known_static_nullable.php.inc | 4 +- .../known_static_nullable_float.php.inc | 4 +- phpstan.neon | 35 ++++++++++++-- src/Console/Application.php | 2 +- src/PhpParser/BetterNodeDumper.php | 22 ++++++++- .../NewObjectToFactoryCreateRector.php | 3 +- src/ValueObject/PhpVersionFeature.php | 6 +++ .../EventDispatcherInterface.php | 2 +- .../Fixture/fixture.php.inc | 10 ++-- ...meClassConstantsUseToStringsRectorTest.php | 4 +- .../Source/OldClassWithConstants.php | 16 +++++++ 37 files changed, 325 insertions(+), 113 deletions(-) create mode 100644 packages/TypeDeclaration/tests/Rector/FunctionLike/ReturnTypeDeclarationRector/Fixture/known_float_in_variable.php.inc create mode 100644 packages/TypeDeclaration/tests/Rector/FunctionLike/ReturnTypeDeclarationRector/Fixture/known_float_param_type.php.inc create mode 100644 packages/TypeDeclaration/tests/Rector/FunctionLike/ReturnTypeDeclarationRector/Fixture/known_float_param_type_with_condition.php.inc create mode 100644 tests/Rector/Constant/RenameClassConstantsUseToStringsRector/Source/OldClassWithConstants.php diff --git a/compiler/composer.json b/compiler/composer.json index 47c7c564e21..77d95370ba4 100644 --- a/compiler/composer.json +++ b/compiler/composer.json @@ -16,10 +16,5 @@ }, "require-dev": { "phpunit/phpunit": "^8.4" - }, - "extra": { - "cleaner-ignore": { - "phpstan/phpstan": ["conf"] - } } } diff --git a/compiler/src/Console/CompileCommand.php b/compiler/src/Console/CompileCommand.php index 3db0981cc85..af5b584cfc1 100644 --- a/compiler/src/Console/CompileCommand.php +++ b/compiler/src/Console/CompileCommand.php @@ -66,9 +66,6 @@ final class CompileCommand extends Command { $this->processFactory->setOutput($output); - // this breaks phpstan dependency by removing whole "/conf" directory - https://github.com/dg/composer-cleaner#configuration - $this->processFactory->create(['composer', 'require', '--no-update', 'dg/composer-cleaner:^2.0'], $this->buildDir); - $composerJsonFile = $this->buildDir . '/composer.json'; $this->fixComposerJson($composerJsonFile); diff --git a/composer.json b/composer.json index d86d3e76ad9..d52fb9de1a2 100644 --- a/composer.json +++ b/composer.json @@ -20,9 +20,9 @@ "nette/utils": "^3.0", "nikic/php-parser": "^4.3", "ondram/ci-detector": "^3.1", - "phpstan/phpdoc-parser": "^0.3.5", - "phpstan/phpstan": "0.11.19", - "phpstan/phpstan-phpunit": "^0.11.2", + "phpstan/phpdoc-parser": "0.4 as 0.3.5", + "phpstan/phpstan": "0.12 as 0.11.19", + "phpstan/phpstan-phpunit": "0.12 as 0.11.2", "sebastian/diff": "^3.0", "symfony/console": "^4.4|^5.0", "symfony/dependency-injection": "^4.4|^5.0", @@ -40,7 +40,7 @@ "symplify/easy-coding-standard": "^7.0", "symplify/monorepo-builder": "^7.0", "symplify/phpstan-extensions": "^7.0", - "thecodingmachine/phpstan-strict-rules": "^0.11.2", + "thecodingmachine/phpstan-strict-rules": "^0.12", "tracy/tracy": "^2.7" }, "autoload": { @@ -199,7 +199,7 @@ "ecs check bin packages src tests utils compiler --fix --ansi", "ci/clean_trailing_spaces.sh" ], - "phpstan": "phpstan analyse packages src tests compiler/src --error-format symplify --ansi", + "phpstan": "phpstan analyse packages src tests compiler/src --ansi", "changelog": [ "changelog-linker dump-merges --in-categories", "changelog-linker link", @@ -225,5 +225,7 @@ "branch-alias": { "dev-master": "0.6-dev" } - } + }, + "minimum-stability": "dev", + "prefer-stable": true } diff --git a/config/services.yaml b/config/services.yaml index c79e97b917c..7afeecf75ce 100644 --- a/config/services.yaml +++ b/config/services.yaml @@ -42,7 +42,7 @@ services: Symplify\PackageBuilder\Strings\StringFormatConverter: ~ # alises - Symfony\Component\EventDispatcher\EventDispatcherInterface: '@Rector\EventDispatcher\AutowiredEventDispatcher' + Symfony\Contracts\EventDispatcher\EventDispatcherInterface: '@Rector\EventDispatcher\AutowiredEventDispatcher' Rector\Bridge\Contract\AnalyzedApplicationContainerInterface: '@Rector\Symfony\Bridge\DefaultAnalyzedSymfonyApplicationContainer' OndraM\CiDetector\CiDetector: ~ diff --git a/docs/AllRectorsOverview.md b/docs/AllRectorsOverview.md index ad1826a64db..8d44409e22c 100644 --- a/docs/AllRectorsOverview.md +++ b/docs/AllRectorsOverview.md @@ -6768,7 +6768,7 @@ Make Symfony commands lazy Make event object a first argument of dispatch() method, event name as second ```diff - use Symfony\Component\EventDispatcher\EventDispatcherInterface; + use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; class SomeClass { diff --git a/packages/CodeQuality/tests/Rector/If_/SimplifyIfReturnBoolRector/Fixture/fixture.php.inc b/packages/CodeQuality/tests/Rector/If_/SimplifyIfReturnBoolRector/Fixture/fixture.php.inc index 833c94e06c7..89e50922f55 100644 --- a/packages/CodeQuality/tests/Rector/If_/SimplifyIfReturnBoolRector/Fixture/fixture.php.inc +++ b/packages/CodeQuality/tests/Rector/If_/SimplifyIfReturnBoolRector/Fixture/fixture.php.inc @@ -1,35 +1,53 @@ getContent(), "\n") === false) { - return true; + public function first() + { + $docToken = new Token([]); + if (strpos($docToken->getContent(), "\n") === false) { + return true; + } + + return false; } - return false; + public function second() + { + $docToken = new Token([]); + if (strpos($docToken->getContent(), "\n") !== false) { + return true; + } - - if (strpos($docToken->getContent(), "\n") !== false) { - return true; + return false; } - - return false; } ?> ----- getContent(), "\n") === false; - return strpos($docToken->getContent(), "\n") !== false; + public function first() + { + $docToken = new Token([]); + return strpos($docToken->getContent(), "\n") === false; + } + + public function second() + { + $docToken = new Token([]); + return strpos($docToken->getContent(), "\n") !== false; + } } ?> diff --git a/packages/CodeQuality/tests/Rector/Ternary/UnnecessaryTernaryExpressionRector/Fixture/fixture3.php.inc b/packages/CodeQuality/tests/Rector/Ternary/UnnecessaryTernaryExpressionRector/Fixture/fixture3.php.inc index 33f1568ece3..bb4731e073e 100644 --- a/packages/CodeQuality/tests/Rector/Ternary/UnnecessaryTernaryExpressionRector/Fixture/fixture3.php.inc +++ b/packages/CodeQuality/tests/Rector/Ternary/UnnecessaryTernaryExpressionRector/Fixture/fixture3.php.inc @@ -8,7 +8,11 @@ class EdgeCases { $order = $someQueryBuilder->getQuery()->getOneOrNullResult(); return $order ? true : false; + } + public function go(): bool + { + $order = $someQueryBuilder->getQuery()->getOneOrNullResult(); return $order ? false : true; } @@ -16,7 +20,11 @@ class EdgeCases { $order = false; return $order ? true : false; + } + public function switchBack(): bool + { + $order = false; return $order ? false : true; } } @@ -33,7 +41,11 @@ class EdgeCases { $order = $someQueryBuilder->getQuery()->getOneOrNullResult(); return (bool) $order; + } + public function go(): bool + { + $order = $someQueryBuilder->getQuery()->getOneOrNullResult(); return !(bool) $order; } @@ -41,7 +53,11 @@ class EdgeCases { $order = false; return $order; + } + public function switchBack(): bool + { + $order = false; return !$order; } } diff --git a/packages/DeadCode/tests/Rector/ClassMethod/RemoveDelegatingParentCallRector/Fixture/skip_required.php.inc b/packages/DeadCode/tests/Rector/ClassMethod/RemoveDelegatingParentCallRector/Fixture/skip_required.php.inc index dea24401a87..44cfa474f0a 100644 --- a/packages/DeadCode/tests/Rector/ClassMethod/RemoveDelegatingParentCallRector/Fixture/skip_required.php.inc +++ b/packages/DeadCode/tests/Rector/ClassMethod/RemoveDelegatingParentCallRector/Fixture/skip_required.php.inc @@ -2,7 +2,7 @@ namespace Rector\DeadCode\Tests\Rector\ClassMethod\RemoveDelegatingParentCallRector\Fixture; -use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; class SkipRequired extends ParentClassWithoutRequired { diff --git a/packages/NetteTesterToPHPUnit/src/AssertManipulator.php b/packages/NetteTesterToPHPUnit/src/AssertManipulator.php index e1525185909..3da70e98b72 100644 --- a/packages/NetteTesterToPHPUnit/src/AssertManipulator.php +++ b/packages/NetteTesterToPHPUnit/src/AssertManipulator.php @@ -219,11 +219,11 @@ final class AssertManipulator if (isset($typeToMethod[$value])) { $staticCall->name = new Identifier($typeToMethod[$value]); unset($staticCall->args[0]); - array_values($staticCall->args); + $staticCall->args = array_values($staticCall->args); } elseif ($value === 'null') { $staticCall->name = new Identifier('assertNull'); unset($staticCall->args[0]); - array_values($staticCall->args); + $staticCall->args = array_values($staticCall->args); } else { $staticCall->name = new Identifier('assertInstanceOf'); } diff --git a/packages/NetteToSymfony/src/Rector/ClassMethod/RouterListToControllerAnnotationsRector.php b/packages/NetteToSymfony/src/Rector/ClassMethod/RouterListToControllerAnnotationsRector.php index 757d63190f0..f0994e74a4d 100644 --- a/packages/NetteToSymfony/src/Rector/ClassMethod/RouterListToControllerAnnotationsRector.php +++ b/packages/NetteToSymfony/src/Rector/ClassMethod/RouterListToControllerAnnotationsRector.php @@ -347,7 +347,7 @@ PHP $presenterPart = Strings::substring($presenterPart, 0, -Strings::length('Presenter')); $presenterPart = RectorStrings::camelCaseToDashes($presenterPart); - $match = Strings::match($this->getName($classMethod), '#^(action|render)(?.*?$)#sm'); + $match = (array) Strings::match($this->getName($classMethod), '#^(action|render)(?.*?$)#sm'); $actionPart = lcfirst($match['short_action_name']); return $presenterPart . '/' . $actionPart; diff --git a/packages/NodeTypeResolver/src/DependencyInjection/PHPStanServicesFactory.php b/packages/NodeTypeResolver/src/DependencyInjection/PHPStanServicesFactory.php index 534a5ae94a3..27a22e8a320 100644 --- a/packages/NodeTypeResolver/src/DependencyInjection/PHPStanServicesFactory.php +++ b/packages/NodeTypeResolver/src/DependencyInjection/PHPStanServicesFactory.php @@ -4,11 +4,11 @@ declare(strict_types=1); namespace Rector\NodeTypeResolver\DependencyInjection; -use Nette\DI\Container; use PHPStan\Analyser\NodeScopeResolver; use PHPStan\Analyser\ScopeFactory; use PHPStan\Analyser\TypeSpecifier; use PHPStan\Broker\Broker; +use PHPStan\DependencyInjection\Container; use PHPStan\DependencyInjection\ContainerFactory; final class PHPStanServicesFactory diff --git a/packages/NodeTypeResolver/src/NodeTypeResolver.php b/packages/NodeTypeResolver/src/NodeTypeResolver.php index ba38f0dcd0a..4cb32c44be0 100644 --- a/packages/NodeTypeResolver/src/NodeTypeResolver.php +++ b/packages/NodeTypeResolver/src/NodeTypeResolver.php @@ -21,6 +21,7 @@ use PhpParser\Node\Expr\StaticCall; use PhpParser\Node\Expr\StaticPropertyFetch; use PhpParser\Node\Expr\Variable; use PhpParser\Node\Param; +use PhpParser\Node\Scalar; use PhpParser\Node\Scalar\String_; use PhpParser\Node\Stmt\Class_; use PhpParser\Node\Stmt\ClassConst; @@ -36,6 +37,8 @@ use PHPStan\Type\Accessory\HasOffsetType; use PHPStan\Type\Accessory\NonEmptyArrayType; use PHPStan\Type\ArrayType; use PHPStan\Type\Constant\ConstantBooleanType; +use PHPStan\Type\Constant\ConstantFloatType; +use PHPStan\Type\Constant\ConstantIntegerType; use PHPStan\Type\Constant\ConstantStringType; use PHPStan\Type\FloatType; use PHPStan\Type\IntegerType; @@ -326,6 +329,23 @@ final class NodeTypeResolver /** @var Scope|null $nodeScope */ $nodeScope = $node->getAttribute(AttributeKey::SCOPE); + + if ($node instanceof Scalar) { + if ($nodeScope === null) { + if ($node instanceof Node\Scalar\DNumber) { + return new ConstantFloatType($node->value); + } + + if ($node instanceof Node\Scalar\String_) { + return new ConstantStringType($node->value); + } + + if ($node instanceof Node\Scalar\LNumber) { + return new ConstantIntegerType($node->value); + } + } + } + if (! $node instanceof Expr || $nodeScope === null) { return new MixedType(); } @@ -336,9 +356,6 @@ final class NodeTypeResolver } } - // make object type specific to alias or FQN - $staticType = $nodeScope->getType($node); - // false type correction of inherited method if ($node instanceof MethodCall) { if ($this->isObjectType($node->var, SplFileInfo::class)) { @@ -349,6 +366,7 @@ final class NodeTypeResolver } } + $staticType = $nodeScope->getType($node); if (! $staticType instanceof ObjectType) { return $staticType; } diff --git a/packages/NodeTypeResolver/src/PHPStan/Scope/NodeScopeResolver.php b/packages/NodeTypeResolver/src/PHPStan/Scope/NodeScopeResolver.php index 70c88899aff..6cdfa602701 100644 --- a/packages/NodeTypeResolver/src/PHPStan/Scope/NodeScopeResolver.php +++ b/packages/NodeTypeResolver/src/PHPStan/Scope/NodeScopeResolver.php @@ -10,6 +10,7 @@ use PhpParser\Node\Stmt\ClassLike; use PhpParser\Node\Stmt\Interface_; use PhpParser\Node\Stmt\Trait_; use PhpParser\NodeTraverser; +use PHPStan\Analyser\MutatingScope; use PHPStan\Analyser\NodeScopeResolver as PHPStanNodeScopeResolver; use PHPStan\Analyser\Scope; use PHPStan\Broker\Broker; @@ -75,7 +76,7 @@ final class NodeScopeResolver $scope = $this->scopeFactory->createFromFile($filePath); // skip chain method calls, performance issue: https://github.com/phpstan/phpstan/issues/254 - $nodeCallback = function (Node $node, Scope $scope): void { + $nodeCallback = function (Node $node, MutatingScope $scope): void { // the class reflection is resolved AFTER entering to class node // so we need to get it from the first after this one if ($node instanceof Class_ || $node instanceof Interface_) { @@ -100,6 +101,7 @@ final class NodeScopeResolver } }; + /** @var MutatingScope $scope */ $this->phpStanNodeScopeResolver->processNodes($nodes, $scope, $nodeCallback); return $nodes; @@ -118,7 +120,7 @@ final class NodeScopeResolver /** * @param Class_|Interface_ $classOrInterfaceNode */ - private function resolveClassOrInterfaceScope(Node $classOrInterfaceNode, Scope $scope): Scope + private function resolveClassOrInterfaceScope(Node $classOrInterfaceNode, MutatingScope $scope): MutatingScope { $className = $this->resolveClassName($classOrInterfaceNode); $classReflection = $this->broker->getClass($className); diff --git a/packages/NodeTypeResolver/src/PHPStan/Scope/ScopeFactory.php b/packages/NodeTypeResolver/src/PHPStan/Scope/ScopeFactory.php index 0536e137da8..e0e21eef951 100644 --- a/packages/NodeTypeResolver/src/PHPStan/Scope/ScopeFactory.php +++ b/packages/NodeTypeResolver/src/PHPStan/Scope/ScopeFactory.php @@ -4,6 +4,7 @@ declare(strict_types=1); namespace Rector\NodeTypeResolver\PHPStan\Scope; +use PHPStan\Analyser\MutatingScope; use PHPStan\Analyser\Scope; use PHPStan\Analyser\ScopeContext; use PHPStan\Analyser\ScopeFactory as PHPStanScopeFactory; @@ -48,7 +49,7 @@ final class ScopeFactory public function createFromFile(string $filePath): Scope { - return new Scope( + return new MutatingScope( $this->phpStanScopeFactory, $this->broker, $this->betterStandardPrinter, diff --git a/packages/Php54/tests/Rector/Break_/RemoveZeroBreakContinueRector/Fixture/fixture.php.inc b/packages/Php54/tests/Rector/Break_/RemoveZeroBreakContinueRector/Fixture/fixture.php.inc index 8f2528ca020..895b168c51c 100644 --- a/packages/Php54/tests/Rector/Break_/RemoveZeroBreakContinueRector/Fixture/fixture.php.inc +++ b/packages/Php54/tests/Rector/Break_/RemoveZeroBreakContinueRector/Fixture/fixture.php.inc @@ -6,7 +6,10 @@ function runContinueZeroes($random) { continue 0; break 0; +} +function breakIt() +{ $five = 5; continue $five; @@ -23,7 +26,10 @@ function runContinueZeroes($random) { continue; break; +} +function breakIt() +{ $five = 5; continue 5; diff --git a/packages/Php70/src/Rector/Switch_/ReduceMultipleDefaultSwitchRector.php b/packages/Php70/src/Rector/Switch_/ReduceMultipleDefaultSwitchRector.php index 2f3c9656320..04bd6c0bd4e 100644 --- a/packages/Php70/src/Rector/Switch_/ReduceMultipleDefaultSwitchRector.php +++ b/packages/Php70/src/Rector/Switch_/ReduceMultipleDefaultSwitchRector.php @@ -69,7 +69,7 @@ PHP $defaultCases[] = $case; } - if ($defaultCases < 2) { + if (count($defaultCases) < 2) { return null; } diff --git a/packages/Php71/tests/Rector/FuncCall/RemoveExtraParametersRector/Source/MagicEventDispatcher.php b/packages/Php71/tests/Rector/FuncCall/RemoveExtraParametersRector/Source/MagicEventDispatcher.php index e8d6307bd0e..1f00c20cb7a 100644 --- a/packages/Php71/tests/Rector/FuncCall/RemoveExtraParametersRector/Source/MagicEventDispatcher.php +++ b/packages/Php71/tests/Rector/FuncCall/RemoveExtraParametersRector/Source/MagicEventDispatcher.php @@ -5,7 +5,7 @@ declare(strict_types=1); namespace Rector\Php71\Tests\Rector\FuncCall\RemoveExtraParametersRector\Source; use Symfony\Component\EventDispatcher\Event; -use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; final class MagicEventDispatcher { diff --git a/packages/Symfony/src/Rector/MethodCall/MakeDispatchFirstArgumentEventRector.php b/packages/Symfony/src/Rector/MethodCall/MakeDispatchFirstArgumentEventRector.php index e5809c14df6..5d7e81c48ce 100644 --- a/packages/Symfony/src/Rector/MethodCall/MakeDispatchFirstArgumentEventRector.php +++ b/packages/Symfony/src/Rector/MethodCall/MakeDispatchFirstArgumentEventRector.php @@ -13,7 +13,7 @@ use PHPStan\Type\ObjectType; use Rector\Rector\AbstractRector; use Rector\RectorDefinition\CodeSample; use Rector\RectorDefinition\RectorDefinition; -use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; /** * @see https://symfony.com/blog/new-in-symfony-4-3-simpler-event-dispatching @@ -26,7 +26,7 @@ final class MakeDispatchFirstArgumentEventRector extends AbstractRector return new RectorDefinition('Make event object a first argument of dispatch() method, event name as second', [ new CodeSample( <<<'PHP' -use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; class SomeClass { @@ -38,7 +38,7 @@ class SomeClass PHP , <<<'PHP' -use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; class SomeClass { diff --git a/packages/Symfony/tests/Rector/MethodCall/MakeDispatchFirstArgumentEventRector/Fixture/fixture.php.inc b/packages/Symfony/tests/Rector/MethodCall/MakeDispatchFirstArgumentEventRector/Fixture/fixture.php.inc index 267c37ab9e8..0ea2406c647 100644 --- a/packages/Symfony/tests/Rector/MethodCall/MakeDispatchFirstArgumentEventRector/Fixture/fixture.php.inc +++ b/packages/Symfony/tests/Rector/MethodCall/MakeDispatchFirstArgumentEventRector/Fixture/fixture.php.inc @@ -2,7 +2,7 @@ namespace Rector\Symfony\Tests\Rector\MethodCall\MakeDispatchFirstArgumentEventRector\Fixture; -use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; class SomeClass { @@ -20,7 +20,7 @@ class SomeClass namespace Rector\Symfony\Tests\Rector\MethodCall\MakeDispatchFirstArgumentEventRector\Fixture; -use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; class SomeClass { diff --git a/packages/TypeDeclaration/src/Rector/FunctionLike/ReturnTypeDeclarationRector.php b/packages/TypeDeclaration/src/Rector/FunctionLike/ReturnTypeDeclarationRector.php index cb4d3b763df..00dfeb187a0 100644 --- a/packages/TypeDeclaration/src/Rector/FunctionLike/ReturnTypeDeclarationRector.php +++ b/packages/TypeDeclaration/src/Rector/FunctionLike/ReturnTypeDeclarationRector.php @@ -112,6 +112,7 @@ PHP $node, [ReturnTypeDeclarationReturnTypeInferer::class] ); + if ($inferedType instanceof MixedType) { return null; } @@ -138,22 +139,15 @@ PHP $currentType = $this->staticTypeMapper->mapPhpParserNodePHPStanType($node->returnType); - // is current class implementation/subtype - if ($currentType instanceof ObjectType && $inferedType instanceof ObjectType) { - if (is_a($currentType->getClassName(), $inferedType->getClassName(), true)) { - return null; - } + if ($this->isCurrentObjectTypeSubType($currentType, $inferedType)) { + return null; } - // nullable aase - if ($currentType instanceof UnionType && $inferedType instanceof UnionType) { - if ($inferedType->isSubTypeOf($currentType)->yes()) { - return null; - } + if ($this->isNullableTypeSubType($currentType, $inferedType)) { + return null; } - // @see https://wiki.php.net/rfc/covariant-returns-and-contravariant-parameters - if ($this->isAtLeastPhpVersion('7.4') && $isSubtype) { + if ($this->isAtLeastPhpVersion(PhpVersionFeature::COVARIANT_RETURN) && $isSubtype) { $node->returnType = $inferredReturnNode; } elseif (! $isSubtype) { // type override $node->returnType = $inferredReturnNode; @@ -311,4 +305,33 @@ PHP return false; } + + /** + * E.g. current E, new type A, E extends A → true + */ + private function isCurrentObjectTypeSubType(Type $currentType, Type $inferedType): bool + { + if (! $currentType instanceof ObjectType) { + return false; + } + + if (! $inferedType instanceof ObjectType) { + return false; + } + + return is_a($currentType->getClassName(), $inferedType->getClassName(), true); + } + + private function isNullableTypeSubType(Type $currentType, Type $inferedType): bool + { + if (! $currentType instanceof UnionType) { + return false; + } + + if (! $inferedType instanceof UnionType) { + return false; + } + + return $inferedType->isSubTypeOf($currentType)->yes(); + } } diff --git a/packages/TypeDeclaration/src/TypeInferer/ReturnTypeInferer/ReturnedNodesReturnTypeInferer.php b/packages/TypeDeclaration/src/TypeInferer/ReturnTypeInferer/ReturnedNodesReturnTypeInferer.php index 7b48a27e802..8800a54ed0b 100644 --- a/packages/TypeDeclaration/src/TypeInferer/ReturnTypeInferer/ReturnedNodesReturnTypeInferer.php +++ b/packages/TypeDeclaration/src/TypeInferer/ReturnTypeInferer/ReturnedNodesReturnTypeInferer.php @@ -52,8 +52,7 @@ final class ReturnedNodesReturnTypeInferer extends AbstractTypeInferer implement continue; } - $staticType = $this->nodeTypeResolver->resolveNodeToPHPStanType($localReturnNode->expr); - $types[] = $staticType; + $types[] = $this->nodeTypeResolver->resolveNodeToPHPStanType($localReturnNode->expr); } return $this->typeFactory->createMixedPassedOrUnionType($types); diff --git a/packages/TypeDeclaration/tests/Rector/FunctionLike/ReturnTypeDeclarationRector/Fixture/known_float.php.inc b/packages/TypeDeclaration/tests/Rector/FunctionLike/ReturnTypeDeclarationRector/Fixture/known_float.php.inc index 60110847128..4868cf72a6f 100644 --- a/packages/TypeDeclaration/tests/Rector/FunctionLike/ReturnTypeDeclarationRector/Fixture/known_float.php.inc +++ b/packages/TypeDeclaration/tests/Rector/FunctionLike/ReturnTypeDeclarationRector/Fixture/known_float.php.inc @@ -10,22 +10,7 @@ class KnownFloat return 5.2; } - $value = 5.3; - return $value; - } - - public function getFloatingParam(float $float) - { - return $float; - } - - public function getFloatingTanks(float $float) - { - if (true) { - return $float; - } - - return 5.0; + return 5.3; } } @@ -43,22 +28,7 @@ class KnownFloat return 5.2; } - $value = 5.3; - return $value; - } - - public function getFloatingParam(float $float): float - { - return $float; - } - - public function getFloatingTanks(float $float): float - { - if (true) { - return $float; - } - - return 5.0; + return 5.3; } } diff --git a/packages/TypeDeclaration/tests/Rector/FunctionLike/ReturnTypeDeclarationRector/Fixture/known_float_in_variable.php.inc b/packages/TypeDeclaration/tests/Rector/FunctionLike/ReturnTypeDeclarationRector/Fixture/known_float_in_variable.php.inc new file mode 100644 index 00000000000..02039b84d46 --- /dev/null +++ b/packages/TypeDeclaration/tests/Rector/FunctionLike/ReturnTypeDeclarationRector/Fixture/known_float_in_variable.php.inc @@ -0,0 +1,29 @@ + +----- + diff --git a/packages/TypeDeclaration/tests/Rector/FunctionLike/ReturnTypeDeclarationRector/Fixture/known_float_param_type.php.inc b/packages/TypeDeclaration/tests/Rector/FunctionLike/ReturnTypeDeclarationRector/Fixture/known_float_param_type.php.inc new file mode 100644 index 00000000000..756ce68fdef --- /dev/null +++ b/packages/TypeDeclaration/tests/Rector/FunctionLike/ReturnTypeDeclarationRector/Fixture/known_float_param_type.php.inc @@ -0,0 +1,27 @@ + +----- + diff --git a/packages/TypeDeclaration/tests/Rector/FunctionLike/ReturnTypeDeclarationRector/Fixture/known_float_param_type_with_condition.php.inc b/packages/TypeDeclaration/tests/Rector/FunctionLike/ReturnTypeDeclarationRector/Fixture/known_float_param_type_with_condition.php.inc new file mode 100644 index 00000000000..8b937561feb --- /dev/null +++ b/packages/TypeDeclaration/tests/Rector/FunctionLike/ReturnTypeDeclarationRector/Fixture/known_float_param_type_with_condition.php.inc @@ -0,0 +1,35 @@ + +----- + diff --git a/packages/TypeDeclaration/tests/Rector/FunctionLike/ReturnTypeDeclarationRector/Fixture/known_static.php.inc b/packages/TypeDeclaration/tests/Rector/FunctionLike/ReturnTypeDeclarationRector/Fixture/known_static.php.inc index 545250625a9..7a9a1e6b75c 100644 --- a/packages/TypeDeclaration/tests/Rector/FunctionLike/ReturnTypeDeclarationRector/Fixture/known_static.php.inc +++ b/packages/TypeDeclaration/tests/Rector/FunctionLike/ReturnTypeDeclarationRector/Fixture/known_static.php.inc @@ -21,7 +21,7 @@ class KnownStatic public function getMoreItems() { - if (true) { + if (rand(0, 10)) { return []; } @@ -60,7 +60,7 @@ class KnownStatic public function getMoreItems(): array { - if (true) { + if (rand(0, 10)) { return []; } diff --git a/packages/TypeDeclaration/tests/Rector/FunctionLike/ReturnTypeDeclarationRector/Fixture/known_static_nullable.php.inc b/packages/TypeDeclaration/tests/Rector/FunctionLike/ReturnTypeDeclarationRector/Fixture/known_static_nullable.php.inc index a8ee2c5df7b..eb4c5121be4 100644 --- a/packages/TypeDeclaration/tests/Rector/FunctionLike/ReturnTypeDeclarationRector/Fixture/known_static_nullable.php.inc +++ b/packages/TypeDeclaration/tests/Rector/FunctionLike/ReturnTypeDeclarationRector/Fixture/known_static_nullable.php.inc @@ -6,7 +6,7 @@ class KnownStaticNullable { public function getMoreItems() { - if (true) { + if ((bool) rand(0, 100)) { return null; } @@ -32,7 +32,7 @@ class KnownStaticNullable { public function getMoreItems(): ?array { - if (true) { + if ((bool) rand(0, 100)) { return null; } diff --git a/packages/TypeDeclaration/tests/Rector/FunctionLike/ReturnTypeDeclarationRector/Fixture/known_static_nullable_float.php.inc b/packages/TypeDeclaration/tests/Rector/FunctionLike/ReturnTypeDeclarationRector/Fixture/known_static_nullable_float.php.inc index 9fa16be37f3..7b6839117c7 100644 --- a/packages/TypeDeclaration/tests/Rector/FunctionLike/ReturnTypeDeclarationRector/Fixture/known_static_nullable_float.php.inc +++ b/packages/TypeDeclaration/tests/Rector/FunctionLike/ReturnTypeDeclarationRector/Fixture/known_static_nullable_float.php.inc @@ -6,7 +6,7 @@ class KnownStaticNullableFloat { public function getFloating() { - if (true) { + if ((bool) rand(0, 10)) { return 5.2; } @@ -25,7 +25,7 @@ class KnownStaticNullableFloat { public function getFloating(): float { - if (true) { + if ((bool) rand(0, 10)) { return 5.2; } diff --git a/phpstan.neon b/phpstan.neon index e8108142026..d096f7e06ac 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -1,11 +1,13 @@ includes: - 'utils/PHPStanExtensions/config/phpstan-extensions.neon' - - 'vendor/symplify/phpstan-extensions/config/config.neon' + - 'vendor/symplify/phpstan-extensions/config/php.level.neon' + - 'vendor/symplify/phpstan-extensions/config/symfony.level.neon' + - 'vendor/thecodingmachine/phpstan-strict-rules/phpstan-strict-rules.neon' - # bleeing edge - - 'vendor/phpstan/phpstan/conf/bleedingEdge.neon' parameters: + checkGenericClassInNonGenericObjectType: false + # to allow installing with various phsptan versions without reporting old errors here reportUnmatchedIgnoredErrors: false level: max @@ -246,3 +248,30 @@ parameters: - message: "#Internal error: Cannot find function 'inlineSections#" path: utils/Composer/bin/SortNamespaces.php + + # mixed + - '#in iterable type Iterator#' + - '#with no typehint specified#' + - '#return type has no value type specified in iterable type array#' + - '#has no return typehint#' + - '#Offset int\|string\|null does not exist on array\|null#' + - '#class-string\|T of object#' + - '#with no value type specified in iterable type array#' + - '#type specified in iterable type (array|iterable)#' + + # known values + - '#Offset 0 does not exist on array\|null#' + - '#Parameter \#1 \$left of class PhpParser\\Node\\Expr\\BinaryOp\\Spaceship constructor expects PhpParser\\Node\\Expr, PhpParser\\Node\\Expr\|null given#' + - '#Parameter \#2 \$right of class PhpParser\\Node\\Expr\\BinaryOp\\Spaceship constructor expects PhpParser\\Node\\Expr, PhpParser\\Node\\Expr\|null given#' + - '#Parameter \#3 \$nodeCallback of method PHPStan\\Analyser\\NodeScopeResolver::processNodes\(\) expects Closure\(PhpParser\\Node, PHPStan\\Analyser\\Scope\): void, Closure\(PhpParser\\Node, PHPStan\\Analyser\\MutatingScope\): void given#' + + # false positive + - '#Array \(array\) does not accept key#' + - '#Array \(array\) does not accept key#' + - '#Comparison operation "<" between 0 and 2 is always true#' + - '#Property Rector\\Compiler\\Process\\SymfonyProcess::\$process type has no value type specified in iterable type Symfony\\Component\\Process\\Process#' + - '#Method Rector\\Compiler\\Process\\SymfonyProcess::getProcess\(\) return type has no value type specified in iterable type Symfony\\Component\\Process\\Process#' + - '#Method Rector\\Compiler\\Contract\\Process\\ProcessInterface::getProcess\(\) return type has no value type specified in iterable type Symfony\\Component\\Process\\Process#' + + # phpstan compiler bug + - '#Parameter \#1 \$docComment of method PhpParser\\Builder\\Property::setDocComment\(\) expects _HumbugBox3be60b26ad9d\\PhpParser\\Comment\\Doc\|string, PhpParser\\Comment\\Doc given#' diff --git a/src/Console/Application.php b/src/Console/Application.php index f99f202ea29..7a6f18c53a1 100644 --- a/src/Console/Application.php +++ b/src/Console/Application.php @@ -17,7 +17,7 @@ use Symfony\Component\Console\Input\InputDefinition; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; -use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; use Symplify\PackageBuilder\Console\Command\CommandNaming; use Symplify\SmartFileSystem\SmartFileInfo; diff --git a/src/PhpParser/BetterNodeDumper.php b/src/PhpParser/BetterNodeDumper.php index e496dfb2b47..381655298af 100644 --- a/src/PhpParser/BetterNodeDumper.php +++ b/src/PhpParser/BetterNodeDumper.php @@ -15,16 +15,34 @@ use PhpParser\NodeDumper; final class BetterNodeDumper extends NodeDumper { - private $dumpComments; + /** + * @var bool + */ + private $dumpComments = false; - private $dumpPositions; + /** + * @var bool + */ + private $dumpPositions = false; + /** + * @var int[] + */ private $printedNodes = []; + /** + * @var int + */ private $nodeIds = 0; + /** + * @var bool + */ private $skipEmpty = true; + /** + * @var string[] + */ private $filterAttributes = []; /** diff --git a/src/Rector/Architecture/Factory/NewObjectToFactoryCreateRector.php b/src/Rector/Architecture/Factory/NewObjectToFactoryCreateRector.php index c4f4a3ee658..67729e246c0 100644 --- a/src/Rector/Architecture/Factory/NewObjectToFactoryCreateRector.php +++ b/src/Rector/Architecture/Factory/NewObjectToFactoryCreateRector.php @@ -133,7 +133,8 @@ PHP private function getFactoryPropertyName(string $factoryFullQualifiedName): string { - $className = (new ReflectionClass($factoryFullQualifiedName))->getShortName(); + $reflectionClass = new ReflectionClass($factoryFullQualifiedName); + $className = $reflectionClass->getShortName(); return Strings::firstLower($className); } diff --git a/src/ValueObject/PhpVersionFeature.php b/src/ValueObject/PhpVersionFeature.php index 2d00ce90d7e..86b7f731881 100644 --- a/src/ValueObject/PhpVersionFeature.php +++ b/src/ValueObject/PhpVersionFeature.php @@ -66,6 +66,12 @@ final class PhpVersionFeature */ public const BEFORE_UNION_TYPES = '7.4'; + /** + * @see https://wiki.php.net/rfc/covariant-returns-and-contravariant-parameters + * @var string + */ + public const COVARIANT_RETURN = '7.4'; + /** * @var string */ diff --git a/stubs/Symfony/Component/EventDispatcher/EventDispatcherInterface.php b/stubs/Symfony/Component/EventDispatcher/EventDispatcherInterface.php index e20c739d538..ee6694e0fb2 100644 --- a/stubs/Symfony/Component/EventDispatcher/EventDispatcherInterface.php +++ b/stubs/Symfony/Component/EventDispatcher/EventDispatcherInterface.php @@ -4,7 +4,7 @@ declare(strict_types=1); namespace Symfony\Component\EventDispatcher; -if (interface_exists('Symfony\Component\EventDispatcher\EventDispatcherInterface')) { +if (interface_exists('Symfony\Contracts\EventDispatcher\EventDispatcherInterface')) { return; } diff --git a/tests/Rector/Constant/RenameClassConstantsUseToStringsRector/Fixture/fixture.php.inc b/tests/Rector/Constant/RenameClassConstantsUseToStringsRector/Fixture/fixture.php.inc index 510726a01af..ba90d012dc5 100644 --- a/tests/Rector/Constant/RenameClassConstantsUseToStringsRector/Fixture/fixture.php.inc +++ b/tests/Rector/Constant/RenameClassConstantsUseToStringsRector/Fixture/fixture.php.inc @@ -1,12 +1,14 @@ [ '$oldConstantsToNewValuesByType' => [ - Configurator::class => [ + OldClassWithConstants::class => [ 'DEVELOPMENT' => 'development', 'PRODUCTION' => 'production', ], diff --git a/tests/Rector/Constant/RenameClassConstantsUseToStringsRector/Source/OldClassWithConstants.php b/tests/Rector/Constant/RenameClassConstantsUseToStringsRector/Source/OldClassWithConstants.php new file mode 100644 index 00000000000..b1b2c195d21 --- /dev/null +++ b/tests/Rector/Constant/RenameClassConstantsUseToStringsRector/Source/OldClassWithConstants.php @@ -0,0 +1,16 @@ +