mirror of
https://github.com/rectorphp/rector.git
synced 2024-05-31 16:30:51 +00:00
[PHP 8.0] Make Downgrade widening union depend on ClassMethod, the narrow scope (#375)
Co-authored-by: GitHub Action <action@github.com>
This commit is contained in:
parent
ae71516150
commit
a9b1bbba88
|
@ -4766,7 +4766,7 @@ Remove the "object" param and return type, add a `@param` and `@return` tags ins
|
|||
|
||||
Change param type to match the lowest type in whole family tree
|
||||
|
||||
- class: [`Rector\DowngradePhp72\Rector\Class_\DowngradeParameterTypeWideningRector`](../rules/DowngradePhp72/Rector/Class_/DowngradeParameterTypeWideningRector.php)
|
||||
- class: [`Rector\DowngradePhp72\Rector\ClassMethod\DowngradeParameterTypeWideningRector`](../rules/DowngradePhp72/Rector/Class_/DowngradeParameterTypeWideningRector.php)
|
||||
|
||||
```diff
|
||||
interface SomeInterface
|
||||
|
|
|
@ -4,7 +4,7 @@ declare(strict_types=1);
|
|||
|
||||
use Rector\Core\Configuration\Option;
|
||||
use Rector\Core\ValueObject\PhpVersion;
|
||||
use Rector\DowngradePhp72\Rector\Class_\DowngradeParameterTypeWideningRector;
|
||||
use Rector\DowngradePhp72\Rector\ClassMethod\DowngradeParameterTypeWideningRector;
|
||||
use Rector\DowngradePhp72\Rector\FuncCall\DowngradePregUnmatchedAsNullConstantRector;
|
||||
use Rector\DowngradePhp72\Rector\FuncCall\DowngradeStreamIsattyRector;
|
||||
use Rector\DowngradePhp72\Rector\FunctionLike\DowngradeObjectTypeDeclarationRector;
|
||||
|
|
|
@ -77,6 +77,7 @@ final class PhpDocTypeChanger
|
|||
$newType,
|
||||
TypeKind::RETURN()
|
||||
);
|
||||
|
||||
$currentReturnTagValueNode = $phpDocInfo->getReturnTagValue();
|
||||
|
||||
if ($currentReturnTagValueNode !== null) {
|
||||
|
|
|
@ -67,8 +67,7 @@ final class PropertyFetchTypeResolver implements NodeTypeResolverInterface
|
|||
if ($classNode instanceof Trait_) {
|
||||
/** @var string $traitName */
|
||||
$traitName = $classNode->getAttribute(AttributeKey::CLASS_NAME);
|
||||
|
||||
$scope = $this->traitNodeScopeCollector->getScopeForTraitAndNode($traitName, $node);
|
||||
$scope = $this->traitNodeScopeCollector->getScopeForTrait($traitName);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -90,7 +90,7 @@ final class VariableTypeResolver implements NodeTypeResolverInterface
|
|||
if ($classLike instanceof Trait_) {
|
||||
/** @var string $traitName */
|
||||
$traitName = $variable->getAttribute(AttributeKey::CLASS_NAME);
|
||||
$traitNodeScope = $this->traitNodeScopeCollector->getScopeForTraitAndNode($traitName, $variable);
|
||||
$traitNodeScope = $this->traitNodeScopeCollector->getScopeForTrait($traitName);
|
||||
|
||||
if ($traitNodeScope !== null) {
|
||||
return $traitNodeScope;
|
||||
|
|
|
@ -4,10 +4,7 @@ declare(strict_types=1);
|
|||
|
||||
namespace Rector\NodeTypeResolver\PHPStan\Collector;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PHPStan\Analyser\Scope;
|
||||
use PHPStan\Node\VirtualNode;
|
||||
use Rector\Core\PhpParser\Printer\BetterStandardPrinter;
|
||||
|
||||
final class TraitNodeScopeCollector
|
||||
{
|
||||
|
@ -16,38 +13,18 @@ final class TraitNodeScopeCollector
|
|||
*/
|
||||
private array $scopeByTraitNodeHash = [];
|
||||
|
||||
public function __construct(
|
||||
private BetterStandardPrinter $betterStandardPrinter
|
||||
) {
|
||||
}
|
||||
|
||||
public function addForTraitAndNode(string $traitName, Node $node, Scope $scope): void
|
||||
public function addForTrait(string $traitName, Scope $scope): void
|
||||
{
|
||||
if ($node instanceof VirtualNode) {
|
||||
return;
|
||||
}
|
||||
|
||||
$traitNodeHash = $this->createHash($traitName, $node);
|
||||
|
||||
// probably set from another class
|
||||
if (isset($this->scopeByTraitNodeHash[$traitNodeHash])) {
|
||||
if (isset($this->scopeByTraitNodeHash[$traitName])) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->scopeByTraitNodeHash[$traitNodeHash] = $scope;
|
||||
$this->scopeByTraitNodeHash[$traitName] = $scope;
|
||||
}
|
||||
|
||||
public function getScopeForTraitAndNode(string $traitName, Node $node): ?Scope
|
||||
public function getScopeForTrait(string $traitName): ?Scope
|
||||
{
|
||||
$traitNodeHash = $this->createHash($traitName, $node);
|
||||
|
||||
return $this->scopeByTraitNodeHash[$traitNodeHash] ?? null;
|
||||
}
|
||||
|
||||
private function createHash(string $traitName, Node $node): string
|
||||
{
|
||||
$printedNode = $this->betterStandardPrinter->print($node);
|
||||
|
||||
return sha1($traitName . $printedNode);
|
||||
return $this->scopeByTraitNodeHash[$traitName] ?? null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ use PhpParser\Node;
|
|||
use PhpParser\Node\Stmt;
|
||||
use PhpParser\Node\Stmt\Class_;
|
||||
use PhpParser\Node\Stmt\Interface_;
|
||||
use PhpParser\Node\Stmt\Trait_;
|
||||
use PhpParser\NodeTraverser;
|
||||
use PHPStan\AnalysedCodeException;
|
||||
use PHPStan\Analyser\MutatingScope;
|
||||
|
@ -71,10 +72,15 @@ final class PHPStanNodeScopeResolver
|
|||
$nodeCallback = function (Node $node, Scope $scope): void {
|
||||
// traversing trait inside class that is using it scope (from referenced) - the trait traversed by Rector is different (directly from parsed file)
|
||||
if ($scope->isInTrait()) {
|
||||
/** @var ClassReflection $classReflection */
|
||||
$classReflection = $scope->getTraitReflection();
|
||||
$traitName = $classReflection->getName();
|
||||
$this->traitNodeScopeCollector->addForTraitAndNode($traitName, $node, $scope);
|
||||
// has just entereted trait, to avoid adding it for ever ynode
|
||||
$parentNode = $node->getAttribute(AttributeKey::PARENT_NODE);
|
||||
if ($parentNode instanceof Trait_) {
|
||||
/** @var ClassReflection $classReflection */
|
||||
$classReflection = $scope->getTraitReflection();
|
||||
$traitName = $classReflection->getName();
|
||||
|
||||
$this->traitNodeScopeCollector->addForTrait($traitName, $scope);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -543,3 +543,8 @@ parameters:
|
|||
-
|
||||
message: '#foreach\(\.\.\.\), while\(\), for\(\) or if\(\.\.\.\) cannot contains a complex expression\. Extract it to a new variable assign on line before#'
|
||||
path: src/Application/ApplicationFileProcessor.php
|
||||
|
||||
|
||||
- '#Callable callable\(PHPStan\\Type\\Type\)\: PHPStan\\Type\\Type invoked with 2 parameters, 1 required#'
|
||||
# leave for now
|
||||
- '#Cognitive complexity for "Rector\\TypeDeclaration\\TypeNormalizer\:\:normalizeArrayTypeAndArrayNever\(\)" is 14, keep it under 9#'
|
||||
|
|
|
@ -1,41 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Rector\Tests\CodingStyle\Rector\Namespace_\ImportFullyQualifiedNamesRector\Fixture;
|
||||
|
||||
use Rector\Tests\CodingStyle\Rector\Namespace_\ImportFullyQualifiedNamesRector\Source\Another;
|
||||
use Rector\Tests\CodingStyle\Rector\Namespace_\ImportFullyQualifiedNamesRector\Source\Some\Trait_;
|
||||
|
||||
final class SameEnd
|
||||
{
|
||||
/**
|
||||
* @param \Rector\Tests\CodingStyle\Rector\Namespace_\ImportFullyQualifiedNamesRector\Source\Some\Trait_ $firstTrait
|
||||
* @param Another\Trait_ $secondTrait
|
||||
* @param \Rector\Tests\CodingStyle\Rector\Namespace_\ImportFullyQualifiedNamesRector\Source\Some\Trait_ $thirdTrait
|
||||
*/
|
||||
public function __construct(\Rector\Tests\CodingStyle\Rector\Namespace_\ImportFullyQualifiedNamesRector\Source\Some\Trait_ $firstTrait, Another\Trait_ $secondTrait, \Rector\CodingStyle\Rector\Namespace_\ImportFullyQualifiedNamesRector\Source\Some\Trait_ $thirdTrait)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
-----
|
||||
<?php
|
||||
|
||||
namespace Rector\Tests\CodingStyle\Rector\Namespace_\ImportFullyQualifiedNamesRector\Fixture;
|
||||
|
||||
use Rector\Tests\CodingStyle\Rector\Namespace_\ImportFullyQualifiedNamesRector\Source\Another;
|
||||
use Rector\Tests\CodingStyle\Rector\Namespace_\ImportFullyQualifiedNamesRector\Source\Some\Trait_;
|
||||
|
||||
final class SameEnd
|
||||
{
|
||||
/**
|
||||
* @param Trait_ $firstTrait
|
||||
* @param Another\Trait_ $secondTrait
|
||||
* @param Trait_ $thirdTrait
|
||||
*/
|
||||
public function __construct(Trait_ $firstTrait, Another\Trait_ $secondTrait, \Rector\CodingStyle\Rector\Namespace_\ImportFullyQualifiedNamesRector\Source\Some\Trait_ $thirdTrait)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -2,11 +2,11 @@
|
|||
|
||||
namespace Rector\Tests\CodingStyle\Rector\Namespace_\ImportFullyQualifiedNamesRector\Fixture;
|
||||
|
||||
use Rector\Tests\CodingStyle\Rector\Namespace_\ImportFullyQualifiedNamesRector\Source\Some\Trait_;
|
||||
use Rector\Tests\CodingStyle\Rector\Namespace_\ImportFullyQualifiedNamesRector\Source\Some\SomeTrait;
|
||||
|
||||
final class SameEndWithExistingImport
|
||||
{
|
||||
public function __construct(\Rector\Tests\CodingStyle\Rector\Namespace_\ImportFullyQualifiedNamesRector\Source\Some\Trait_ $firstTrait)
|
||||
public function __construct(\Rector\Tests\CodingStyle\Rector\Namespace_\ImportFullyQualifiedNamesRector\Source\Some\SomeTrait $firstTrait)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
@ -17,11 +17,11 @@ final class SameEndWithExistingImport
|
|||
|
||||
namespace Rector\Tests\CodingStyle\Rector\Namespace_\ImportFullyQualifiedNamesRector\Fixture;
|
||||
|
||||
use Rector\Tests\CodingStyle\Rector\Namespace_\ImportFullyQualifiedNamesRector\Source\Some\Trait_;
|
||||
use Rector\Tests\CodingStyle\Rector\Namespace_\ImportFullyQualifiedNamesRector\Source\Some\SomeTrait;
|
||||
|
||||
final class SameEndWithExistingImport
|
||||
{
|
||||
public function __construct(Trait_ $firstTrait)
|
||||
public function __construct(SomeTrait $firstTrait)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ declare(strict_types=1);
|
|||
|
||||
namespace Rector\Tests\CodingStyle\Rector\Namespace_\ImportFullyQualifiedNamesRector\Source\Another;
|
||||
|
||||
final class Trait_
|
||||
final class NestedTrait
|
||||
{
|
||||
|
||||
}
|
|
@ -4,7 +4,7 @@ declare(strict_types=1);
|
|||
|
||||
namespace Rector\Tests\CodingStyle\Rector\Namespace_\ImportFullyQualifiedNamesRector\Source\Some;
|
||||
|
||||
final class Trait_
|
||||
final class SomeTrait
|
||||
{
|
||||
|
||||
}
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Tests\DowngradePhp72\Rector\Class_\DowngradeParameterTypeWideningRector;
|
||||
namespace Rector\Tests\DowngradePhp72\Rector\ClassMethod\DowngradeParameterTypeWideningRector;
|
||||
|
||||
use Iterator;
|
||||
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
|
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
|
||||
namespace Rector\Tests\DowngradePhp72\Rector\Class_\DowngradeParameterTypeWideningRector\Fixture;
|
||||
namespace Rector\Tests\DowngradePhp72\Rector\ClassMethod\DowngradeParameterTypeWideningRector\Fixture;
|
||||
|
||||
/**
|
||||
* @see https://3v4l.org/8B03D
|
||||
|
@ -21,7 +21,7 @@ final class Asker implements SomeAskingInterface
|
|||
-----
|
||||
<?php
|
||||
|
||||
namespace Rector\Tests\DowngradePhp72\Rector\Class_\DowngradeParameterTypeWideningRector\Fixture;
|
||||
namespace Rector\Tests\DowngradePhp72\Rector\ClassMethod\DowngradeParameterTypeWideningRector\Fixture;
|
||||
|
||||
/**
|
||||
* @see https://3v4l.org/8B03D
|
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
|
||||
namespace Rector\Tests\DowngradePhp72\Rector\Class_\DowngradeParameterTypeWideningRector\Fixture;
|
||||
namespace Rector\Tests\DowngradePhp72\Rector\ClassMethod\DowngradeParameterTypeWideningRector\Fixture;
|
||||
|
||||
interface SomeContainerInterface
|
||||
{
|
||||
|
@ -25,7 +25,7 @@ class SomeUniqueContainer implements SomeContainerInterface
|
|||
-----
|
||||
<?php
|
||||
|
||||
namespace Rector\Tests\DowngradePhp72\Rector\Class_\DowngradeParameterTypeWideningRector\Fixture;
|
||||
namespace Rector\Tests\DowngradePhp72\Rector\ClassMethod\DowngradeParameterTypeWideningRector\Fixture;
|
||||
|
||||
interface SomeContainerInterface
|
||||
{
|
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
|
||||
namespace Rector\Tests\DowngradePhp72\Rector\Class_\DowngradeParameterTypeWideningRector\Fixture;
|
||||
namespace Rector\Tests\DowngradePhp72\Rector\ClassMethod\DowngradeParameterTypeWideningRector\Fixture;
|
||||
|
||||
interface A
|
||||
{
|
||||
|
@ -25,7 +25,7 @@ final class MostChild implements A
|
|||
-----
|
||||
<?php
|
||||
|
||||
namespace Rector\Tests\DowngradePhp72\Rector\Class_\DowngradeParameterTypeWideningRector\Fixture;
|
||||
namespace Rector\Tests\DowngradePhp72\Rector\ClassMethod\DowngradeParameterTypeWideningRector\Fixture;
|
||||
|
||||
interface A
|
||||
{
|
|
@ -1,6 +1,8 @@
|
|||
<?php
|
||||
|
||||
namespace Rector\Tests\DowngradePhp72\Rector\Class_\DowngradeParameterTypeWideningRector\Fixture;
|
||||
namespace Rector\Tests\DowngradePhp72\Rector\ClassMethod\DowngradeParameterTypeWideningRector\Fixture;
|
||||
|
||||
use Rector\Tests\DowngradePhp72\Rector\ClassMethod\DowngradeParameterTypeWideningRector\Source\AnotherContainerInterface;
|
||||
|
||||
final class YetAnotherContainer implements AnotherContainerInterface
|
||||
{
|
||||
|
@ -14,16 +16,13 @@ trait AnotherServiceLocatorTrait
|
|||
}
|
||||
}
|
||||
|
||||
interface AnotherContainerInterface
|
||||
{
|
||||
public function get($name);
|
||||
}
|
||||
|
||||
?>
|
||||
-----
|
||||
<?php
|
||||
|
||||
namespace Rector\Tests\DowngradePhp72\Rector\Class_\DowngradeParameterTypeWideningRector\Fixture;
|
||||
namespace Rector\Tests\DowngradePhp72\Rector\ClassMethod\DowngradeParameterTypeWideningRector\Fixture;
|
||||
|
||||
use Rector\Tests\DowngradePhp72\Rector\ClassMethod\DowngradeParameterTypeWideningRector\Source\AnotherContainerInterface;
|
||||
|
||||
final class YetAnotherContainer implements AnotherContainerInterface
|
||||
{
|
||||
|
@ -40,9 +39,4 @@ trait AnotherServiceLocatorTrait
|
|||
}
|
||||
}
|
||||
|
||||
interface AnotherContainerInterface
|
||||
{
|
||||
public function get($name);
|
||||
}
|
||||
|
||||
?>
|
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
|
||||
namespace Rector\Tests\DowngradePhp72\Rector\Class_\DowngradeParameterTypeWideningRector\Fixture;
|
||||
namespace Rector\Tests\DowngradePhp72\Rector\ClassMethod\DowngradeParameterTypeWideningRector\Fixture;
|
||||
|
||||
interface WhateverInterface
|
||||
{
|
||||
|
@ -23,7 +23,7 @@ class SomeChildClass extends AbstractSomeAncestorClass
|
|||
-----
|
||||
<?php
|
||||
|
||||
namespace Rector\Tests\DowngradePhp72\Rector\Class_\DowngradeParameterTypeWideningRector\Fixture;
|
||||
namespace Rector\Tests\DowngradePhp72\Rector\ClassMethod\DowngradeParameterTypeWideningRector\Fixture;
|
||||
|
||||
interface WhateverInterface
|
||||
{
|
|
@ -0,0 +1,12 @@
|
|||
<?php
|
||||
|
||||
namespace Rector\Tests\DowngradePhp72\Rector\ClassMethod\DowngradeParameterTypeWideningRector\Fixture;
|
||||
|
||||
use Rector\Tests\DowngradePhp72\Rector\ClassMethod\DowngradeParameterTypeWideningRector\Source\SomeExternalContainerInterface;
|
||||
|
||||
class KeepInterfaceDonwgraded implements SomeExternalContainerInterface
|
||||
{
|
||||
public function get($id)
|
||||
{
|
||||
}
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
|
||||
namespace Rector\Tests\DowngradePhp72\Rector\Class_\DowngradeParameterTypeWideningRector\Fixture;
|
||||
namespace Rector\Tests\DowngradePhp72\Rector\ClassMethod\DowngradeParameterTypeWideningRector\Fixture;
|
||||
|
||||
final class KeepTraitAndInterfaceSame implements AnyContainerInterface
|
||||
{
|
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
|
||||
namespace Rector\Tests\DowngradePhp72\Rector\Class_\DowngradeParameterTypeWideningRector\Fixture;
|
||||
namespace Rector\Tests\DowngradePhp72\Rector\ClassMethod\DowngradeParameterTypeWideningRector\Fixture;
|
||||
|
||||
interface SomeAskingInterfaceWithNullable
|
||||
{
|
||||
|
@ -18,7 +18,7 @@ final class AskForMore implements SomeAskingInterfaceWithNullable
|
|||
-----
|
||||
<?php
|
||||
|
||||
namespace Rector\Tests\DowngradePhp72\Rector\Class_\DowngradeParameterTypeWideningRector\Fixture;
|
||||
namespace Rector\Tests\DowngradePhp72\Rector\ClassMethod\DowngradeParameterTypeWideningRector\Fixture;
|
||||
|
||||
interface SomeAskingInterfaceWithNullable
|
||||
{
|
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
|
||||
namespace Rector\Tests\DowngradePhp72\Rector\Class_\DowngradeParameterTypeWideningRector\Fixture;
|
||||
namespace Rector\Tests\DowngradePhp72\Rector\ClassMethod\DowngradeParameterTypeWideningRector\Fixture;
|
||||
|
||||
interface ParentWithString
|
||||
{
|
||||
|
@ -18,7 +18,7 @@ class ChildString implements ParentWithString
|
|||
-----
|
||||
<?php
|
||||
|
||||
namespace Rector\Tests\DowngradePhp72\Rector\Class_\DowngradeParameterTypeWideningRector\Fixture;
|
||||
namespace Rector\Tests\DowngradePhp72\Rector\ClassMethod\DowngradeParameterTypeWideningRector\Fixture;
|
||||
|
||||
interface ParentWithString
|
||||
{
|
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
|
||||
namespace Rector\Tests\DowngradePhp72\Rector\Class_\DowngradeParameterTypeWideningRector\Fixture;
|
||||
namespace Rector\Tests\DowngradePhp72\Rector\ClassMethod\DowngradeParameterTypeWideningRector\Fixture;
|
||||
|
||||
interface SecondPositionInterface
|
||||
{
|
||||
|
@ -18,7 +18,7 @@ final class SomeSecondPosition implements SecondPositionInterface
|
|||
-----
|
||||
<?php
|
||||
|
||||
namespace Rector\Tests\DowngradePhp72\Rector\Class_\DowngradeParameterTypeWideningRector\Fixture;
|
||||
namespace Rector\Tests\DowngradePhp72\Rector\ClassMethod\DowngradeParameterTypeWideningRector\Fixture;
|
||||
|
||||
interface SecondPositionInterface
|
||||
{
|
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
|
||||
namespace Rector\Tests\DowngradePhp72\Rector\Class_\DowngradeParameterTypeWideningRector\Fixture;
|
||||
namespace Rector\Tests\DowngradePhp72\Rector\ClassMethod\DowngradeParameterTypeWideningRector\Fixture;
|
||||
|
||||
interface SomeInputInterface
|
||||
{
|
|
@ -1,8 +1,8 @@
|
|||
<?php
|
||||
|
||||
namespace Rector\Tests\DowngradePhp72\Rector\Class_\DowngradeParameterTypeWideningRector\Fixture;
|
||||
namespace Rector\Tests\DowngradePhp72\Rector\ClassMethod\DowngradeParameterTypeWideningRector\Fixture;
|
||||
|
||||
use Rector\Tests\DowngradePhp72\Rector\Class_\DowngradeParameterTypeWideningRector\Source\AnyService;
|
||||
use Rector\Tests\DowngradePhp72\Rector\ClassMethod\DowngradeParameterTypeWideningRector\Source\AnyService;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
|
||||
final class SkipCommand extends Command
|
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
|
||||
namespace Rector\Tests\DowngradePhp72\Rector\Class_\DowngradeParameterTypeWideningRector\Fixture;
|
||||
namespace Rector\Tests\DowngradePhp72\Rector\ClassMethod\DowngradeParameterTypeWideningRector\Fixture;
|
||||
|
||||
use Psr\Container\ContainerInterface;
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
|
||||
namespace Rector\Tests\DowngradePhp72\Rector\Class_\DowngradeParameterTypeWideningRector\Fixture;
|
||||
namespace Rector\Tests\DowngradePhp72\Rector\ClassMethod\DowngradeParameterTypeWideningRector\Fixture;
|
||||
|
||||
interface KeepOriginalIfSharedType
|
||||
{
|
|
@ -0,0 +1,14 @@
|
|||
<?php
|
||||
|
||||
namespace Rector\Tests\DowngradePhp72\Rector\ClassMethod\DowngradeParameterTypeWideningRector\Fixture;
|
||||
|
||||
use Rector\Tests\DowngradePhp72\Rector\ClassMethod\DowngradeParameterTypeWideningRector\Source\ParentNullableString;
|
||||
|
||||
final class SkipNullableStringFromExternal extends ParentNullableString
|
||||
{
|
||||
public function load(string $value = null)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,14 @@
|
|||
<?php
|
||||
|
||||
namespace Rector\Tests\DowngradePhp72\Rector\ClassMethod\DowngradeParameterTypeWideningRector\Fixture;
|
||||
|
||||
use Rector\Tests\DowngradePhp72\Rector\ClassMethod\DowngradeParameterTypeWideningRector\Source\vendor\NullableStringTrait;
|
||||
|
||||
final class SkipNullableStringFromExternalTrait
|
||||
{
|
||||
use NullableStringTrait;
|
||||
|
||||
public function load(string $value = null)
|
||||
{
|
||||
}
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
|
||||
namespace Rector\Tests\DowngradePhp72\Rector\Class_\DowngradeParameterTypeWideningRector\Fixture;
|
||||
namespace Rector\Tests\DowngradePhp72\Rector\ClassMethod\DowngradeParameterTypeWideningRector\Fixture;
|
||||
|
||||
use PhpParser\Node\Param;
|
||||
use PHPStan\Type\Type;
|
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
|
||||
namespace Rector\Tests\DowngradePhp72\Rector\Class_\DowngradeParameterTypeWideningRector\Fixture;
|
||||
namespace Rector\Tests\DowngradePhp72\Rector\ClassMethod\DowngradeParameterTypeWideningRector\Fixture;
|
||||
|
||||
trait StreamDecoratorTrait
|
||||
{
|
||||
|
@ -24,7 +24,7 @@ class MultipartStream
|
|||
----
|
||||
<?php
|
||||
|
||||
namespace Rector\Tests\DowngradePhp72\Rector\Class_\DowngradeParameterTypeWideningRector\Fixture;
|
||||
namespace Rector\Tests\DowngradePhp72\Rector\ClassMethod\DowngradeParameterTypeWideningRector\Fixture;
|
||||
|
||||
trait StreamDecoratorTrait
|
||||
{
|
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
|
||||
namespace Rector\Tests\DowngradePhp72\Rector\Class_\DowngradeParameterTypeWideningRector\Fixture;
|
||||
namespace Rector\Tests\DowngradePhp72\Rector\ClassMethod\DowngradeParameterTypeWideningRector\Fixture;
|
||||
|
||||
class AncestorClass
|
||||
{
|
||||
|
@ -22,7 +22,7 @@ class ChildClass extends AncestorClass
|
|||
-----
|
||||
<?php
|
||||
|
||||
namespace Rector\Tests\DowngradePhp72\Rector\Class_\DowngradeParameterTypeWideningRector\Fixture;
|
||||
namespace Rector\Tests\DowngradePhp72\Rector\ClassMethod\DowngradeParameterTypeWideningRector\Fixture;
|
||||
|
||||
class AncestorClass
|
||||
{
|
|
@ -0,0 +1,10 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Tests\DowngradePhp72\Rector\ClassMethod\DowngradeParameterTypeWideningRector\Source;
|
||||
|
||||
interface AnotherContainerInterface
|
||||
{
|
||||
public function get($name);
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Tests\DowngradePhp72\Rector\ClassMethod\DowngradeParameterTypeWideningRector\Source;
|
||||
|
||||
final class AnyService
|
||||
{
|
||||
|
||||
}
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Tests\DowngradePhp72\Rector\Class_\DowngradeParameterTypeWideningRector\Source;
|
||||
namespace Rector\Tests\DowngradePhp72\Rector\ClassMethod\DowngradeParameterTypeWideningRector\Source;
|
||||
|
||||
class ParentNullableString
|
||||
{
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Tests\DowngradePhp72\Rector\Class_\DowngradeParameterTypeWideningRector\Source;
|
||||
namespace Rector\Tests\DowngradePhp72\Rector\ClassMethod\DowngradeParameterTypeWideningRector\Source;
|
||||
|
||||
interface SomeExternalContainerInterface
|
||||
{
|
|
@ -0,0 +1,9 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Tests\DowngradePhp72\Rector\ClassMethod\DowngradeParameterTypeWideningRector\Source;
|
||||
|
||||
final class UniqueType
|
||||
{
|
||||
}
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Tests\DowngradePhp72\Rector\Class_\DowngradeParameterTypeWideningRector\Source;
|
||||
namespace Rector\Tests\DowngradePhp72\Rector\ClassMethod\DowngradeParameterTypeWideningRector\Source\vendor;
|
||||
|
||||
trait NullableStringTrait
|
||||
{
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Rector\DowngradePhp72\Rector\Class_\DowngradeParameterTypeWideningRector;
|
||||
use Rector\DowngradePhp72\Rector\ClassMethod\DowngradeParameterTypeWideningRector;
|
||||
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
|
||||
|
||||
return static function (ContainerConfigurator $containerConfigurator): void {
|
|
@ -1,12 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Rector\Tests\DowngradePhp72\Rector\Class_\DowngradeParameterTypeWideningRector\Fixture;
|
||||
|
||||
use Rector\Tests\DowngradePhp72\Rector\Class_\DowngradeParameterTypeWideningRector\Source\SomeExternalContainerInterface;
|
||||
|
||||
class KeepInterfaceDonwgraded implements SomeExternalContainerInterface
|
||||
{
|
||||
public function get($id)
|
||||
{
|
||||
}
|
||||
}
|
|
@ -1,14 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Rector\Tests\DowngradePhp72\Rector\Class_\DowngradeParameterTypeWideningRector\Fixture;
|
||||
|
||||
use Rector\Tests\DowngradePhp72\Rector\Class_\DowngradeParameterTypeWideningRector\Source\ParentNullableString;
|
||||
|
||||
final class SkipNullableStringFromExternal extends ParentNullableString
|
||||
{
|
||||
public function load(string $value = null)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -1,16 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Rector\Tests\DowngradePhp72\Rector\Class_\DowngradeParameterTypeWideningRector\Fixture;
|
||||
|
||||
use Rector\Tests\DowngradePhp72\Rector\Class_\DowngradeParameterTypeWideningRector\Source\NullableStringTrait;
|
||||
|
||||
final class SkipNullableStringFromExternalTrait
|
||||
{
|
||||
use NullableStringTrait;
|
||||
|
||||
public function load(string $value = null)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -1,10 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Tests\DowngradePhp72\Rector\Class_\DowngradeParameterTypeWideningRector\Source;
|
||||
|
||||
final class AnyService
|
||||
{
|
||||
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Tests\DowngradePhp72\Rector\Class_\DowngradeParameterTypeWideningRector\Source;
|
||||
|
||||
final class UniqueType
|
||||
{
|
||||
}
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
namespace Rector\Tests\Naming\Rector\ClassMethod\RenameParamToMatchTypeRector\Fixture;
|
||||
|
||||
use Rector\Tests\DowngradePhp72\Rector\Class_\DowngradeParameterTypeWideningRector\Source\UniqueType;
|
||||
use Rector\Tests\DowngradePhp72\Rector\ClassMethod\DowngradeParameterTypeWideningRector\Source\UniqueType;
|
||||
use Rector\Tests\Naming\Rector\ClassMethod\RenameParamToMatchTypeRector\Source\ILoader;
|
||||
use Rector\Tests\Naming\Rector\ClassMethod\RenameParamToMatchTypeRector\Source\SingleSomeClass;
|
||||
use SplFileInfo;
|
||||
|
|
|
@ -14,11 +14,6 @@ final class ClassWithProperty
|
|||
*/
|
||||
private $multiCount;
|
||||
|
||||
/**
|
||||
* @var void
|
||||
*/
|
||||
private $shouldBeSkipped;
|
||||
|
||||
/**
|
||||
* @var callable
|
||||
*/
|
||||
|
@ -45,11 +40,6 @@ final class ClassWithProperty
|
|||
*/
|
||||
private $multiCount;
|
||||
|
||||
/**
|
||||
* @var void
|
||||
*/
|
||||
private $shouldBeSkipped;
|
||||
|
||||
/**
|
||||
* @var callable
|
||||
*/
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
<?php
|
||||
|
||||
namespace Rector\Tests\Php74\Rector\Property\TypedPropertyRector\Fixture;
|
||||
|
||||
final class SkipVoid
|
||||
{
|
||||
/**
|
||||
* @var void
|
||||
*/
|
||||
private $shouldBeSkipped;
|
||||
}
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
namespace Rector\Tests\TypeDeclaration\Rector\ClassMethod\AddVoidReturnTypeWhereNoReturnRector\Fixture;
|
||||
|
||||
use Rector\Tests\TypeDeclaration\Rector\ClassMethod\AddVoidReturnTypeWhereNoReturnRector\Source\Foo;
|
||||
use Rector\Tests\TypeDeclaration\Rector\ClassMethod\AddVoidReturnTypeWhereNoReturnRector\Source\vendor\Foo;
|
||||
|
||||
final class SkipFromExternal2
|
||||
{
|
||||
|
@ -12,5 +12,3 @@ final class SkipFromExternal2
|
|||
{
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
<?php
|
||||
|
||||
namespace Rector\Tests\TypeDeclaration\Rector\ClassMethod\AddVoidReturnTypeWhereNoReturnRector\Source;
|
||||
namespace Rector\Tests\TypeDeclaration\Rector\ClassMethod\AddVoidReturnTypeWhereNoReturnRector\Source\vendor;
|
||||
|
||||
trait Foo
|
||||
{
|
||||
public function load($resource, string $type = null)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,35 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Rector\Tests\TypeDeclaration\Rector\FunctionLike\ReturnTypeDeclarationRector\Fixture;
|
||||
|
||||
class KnownStaticNullableArray
|
||||
{
|
||||
public function getMoreItems()
|
||||
{
|
||||
if ((bool) rand(0, 100)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
-----
|
||||
<?php
|
||||
|
||||
namespace Rector\Tests\TypeDeclaration\Rector\FunctionLike\ReturnTypeDeclarationRector\Fixture;
|
||||
|
||||
class KnownStaticNullableArray
|
||||
{
|
||||
public function getMoreItems(): ?array
|
||||
{
|
||||
if ((bool) rand(0, 100)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -2,11 +2,11 @@
|
|||
|
||||
namespace Rector\Tests\TypeDeclaration\Rector\FunctionLike\ReturnTypeDeclarationRector\Fixture;
|
||||
|
||||
use Rector\Tests\TypeDeclaration\Rector\FunctionLike\ReturnTypeDeclarationRector\Source\ExternalForVoid;
|
||||
use Rector\Tests\TypeDeclaration\Rector\FunctionLike\ReturnTypeDeclarationRector\Source\vendor\ExternalForVoid;
|
||||
|
||||
final class SkipFromExternalVoid extends ExternalForVoid
|
||||
{
|
||||
public function run()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
namespace Rector\Tests\TypeDeclaration\Rector\FunctionLike\ReturnTypeDeclarationRector\Fixture;
|
||||
|
||||
use Rector\Tests\TypeDeclaration\Rector\FunctionLike\ReturnTypeDeclarationRector\Source\ExternalForVoidTrait;
|
||||
use Rector\Tests\TypeDeclaration\Rector\FunctionLike\ReturnTypeDeclarationRector\Source\vendor\ExternalForVoidTrait;
|
||||
|
||||
final class SkipFromExternalVoidTrait
|
||||
{
|
||||
|
@ -11,4 +11,4 @@ final class SkipFromExternalVoidTrait
|
|||
public function run()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Tests\TypeDeclaration\Rector\FunctionLike\ReturnTypeDeclarationRector\Source;
|
||||
namespace Rector\Tests\TypeDeclaration\Rector\FunctionLike\ReturnTypeDeclarationRector\Source\vendor;
|
||||
|
||||
class ExternalForVoid
|
||||
{
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Tests\TypeDeclaration\Rector\FunctionLike\ReturnTypeDeclarationRector\Source;
|
||||
namespace Rector\Tests\TypeDeclaration\Rector\FunctionLike\ReturnTypeDeclarationRector\Source\vendor;
|
||||
|
||||
trait ExternalForVoidTrait
|
||||
{
|
|
@ -138,22 +138,17 @@ final class CurrentAndParentClassMethodComparator
|
|||
$parentMethodReflection = $classReflection->getMethod($methodName, $scope);
|
||||
|
||||
// 3rd party code
|
||||
if ($parentMethodReflection !== null) {
|
||||
if (! $parentMethodReflection->isPrivate() && ! $parentMethodReflection->isPublic() && $classMethod->isPublic()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($parentMethodReflection->isInternal()->yes()) {
|
||||
// we can't know for certain so we assume its a override with purpose
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($this->areParameterDefaultsDifferent($classMethod, $parentMethodReflection)) {
|
||||
return true;
|
||||
}
|
||||
// if ($parentMethodReflection !== null) {
|
||||
if (! $parentMethodReflection->isPrivate() && ! $parentMethodReflection->isPublic() && $classMethod->isPublic()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
if ($parentMethodReflection->isInternal()->yes()) {
|
||||
// we can't know for certain so we assume its a override with purpose
|
||||
return true;
|
||||
}
|
||||
|
||||
return $this->areParameterDefaultsDifferent($classMethod, $parentMethodReflection);
|
||||
}
|
||||
|
||||
private function areParameterDefaultsDifferent(
|
||||
|
|
|
@ -7,13 +7,13 @@ namespace Rector\DeadCode\Comparator\Parameter;
|
|||
use PhpParser\Node\Expr;
|
||||
use PhpParser\Node\Param;
|
||||
use PHPStan\Reflection\ParameterReflection;
|
||||
use Rector\Core\PhpParser\Node\Value\ValueResolver;
|
||||
use Rector\Core\PhpParser\Comparing\NodeComparator;
|
||||
use Rector\DowngradePhp80\Reflection\DefaultParameterValueResolver;
|
||||
|
||||
final class ParameterDefaultsComparator
|
||||
{
|
||||
public function __construct(
|
||||
private ValueResolver $valueResolver,
|
||||
private NodeComparator $nodeComparator,
|
||||
private DefaultParameterValueResolver $defaultParameterValueResolver
|
||||
) {
|
||||
}
|
||||
|
@ -34,29 +34,10 @@ final class ParameterDefaultsComparator
|
|||
$firstParameterValue = $this->defaultParameterValueResolver->resolveFromParameterReflection(
|
||||
$parameterReflection
|
||||
);
|
||||
$secondParameterValue = $this->valueResolver->getValue($paramDefault);
|
||||
|
||||
return $firstParameterValue !== $secondParameterValue;
|
||||
return ! $this->nodeComparator->areNodesEqual($paramDefault, $firstParameterValue);
|
||||
}
|
||||
|
||||
// /**
|
||||
// * @return bool|float|int|string|mixed[]|null
|
||||
// */
|
||||
// public function resolveParameterReflectionDefaultValue(ParameterReflection $parameterReflection)
|
||||
// {
|
||||
// $defaultValue = $parameterReflection->getDefaultValue();
|
||||
// if (! $defaultValue instanceof ConstantType) {
|
||||
// throw new ShouldNotHappenException();
|
||||
// }
|
||||
//
|
||||
// if ($defaultValue instanceof ConstantArrayType) {
|
||||
// return $defaultValue->getAllArrays();
|
||||
// }
|
||||
//
|
||||
// /** @var ConstantStringType|ConstantIntegerType|ConstantFloatType|ConstantBooleanType|NullType $defaultValue */
|
||||
// return $defaultValue->getValue();
|
||||
// }
|
||||
|
||||
private function isMutuallyExclusiveNull(ParameterReflection $parameterReflection, Param $param): bool
|
||||
{
|
||||
if ($parameterReflection->getDefaultValue() === null && $param->default !== null) {
|
||||
|
|
|
@ -5,7 +5,9 @@ declare(strict_types=1);
|
|||
namespace Rector\DeadCode\Rector\ClassMethod;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Expr;
|
||||
use PhpParser\Node\Expr\StaticCall;
|
||||
use PhpParser\Node\Stmt;
|
||||
use PhpParser\Node\Stmt\Class_;
|
||||
use PhpParser\Node\Stmt\ClassLike;
|
||||
use PhpParser\Node\Stmt\ClassMethod;
|
||||
|
@ -69,15 +71,11 @@ CODE_SAMPLE
|
|||
if ($this->shouldSkipClass($classLike)) {
|
||||
return null;
|
||||
}
|
||||
if ($node->stmts === null) {
|
||||
return null;
|
||||
}
|
||||
if (count($node->stmts) !== 1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$stmtsValues = array_values($node->stmts);
|
||||
$onlyStmt = $this->unwrapExpression($stmtsValues[0]);
|
||||
$onlyStmt = $this->matchClassMethodOnlyStmt($node);
|
||||
if ($onlyStmt === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// are both return?
|
||||
if ($this->isMethodReturnType($node, 'void') && ! $onlyStmt instanceof Return_) {
|
||||
|
@ -143,4 +141,20 @@ CODE_SAMPLE
|
|||
$phpDocInfo = $this->phpDocInfoFactory->createFromNodeOrEmpty($classMethod);
|
||||
return $phpDocInfo->hasByName('required');
|
||||
}
|
||||
|
||||
private function matchClassMethodOnlyStmt(ClassMethod $classMethod): null | Stmt | Expr
|
||||
{
|
||||
if ($classMethod->stmts === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (count($classMethod->stmts) !== 1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// recount empty notes
|
||||
$stmtsValues = array_values($classMethod->stmts);
|
||||
|
||||
return $this->unwrapExpression($stmtsValues[0]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,8 +8,11 @@ use PhpParser\Node;
|
|||
use PhpParser\Node\Param;
|
||||
use PHPStan\BetterReflection\Reflection\Adapter\ReflectionParameter;
|
||||
use PHPStan\Reflection\ClassReflection;
|
||||
use PHPStan\Reflection\ParameterReflection;
|
||||
use PHPStan\Type\MixedType;
|
||||
use PHPStan\Type\NullType;
|
||||
use PHPStan\Type\Type;
|
||||
use PHPStan\Type\TypeCombinator;
|
||||
use PHPStan\Type\TypehintHelper;
|
||||
use Rector\StaticTypeMapper\StaticTypeMapper;
|
||||
use Symplify\PackageBuilder\Reflection\PrivatesAccessor;
|
||||
|
@ -29,6 +32,20 @@ final class NativeTypeClassTreeResolver
|
|||
): ?Type {
|
||||
$nativeReflectionClass = $classReflection->getNativeReflection();
|
||||
|
||||
if (! $classReflection->hasNativeMethod($methodName)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$phpstanParameterReflection = null;
|
||||
$methodReflection = $classReflection->getNativeMethod($methodName);
|
||||
foreach ($methodReflection->getVariants() as $parametersAcceptor) {
|
||||
$phpstanParameterReflection = $parametersAcceptor->getParameters()[$position] ?? null;
|
||||
}
|
||||
|
||||
if (! $phpstanParameterReflection instanceof ParameterReflection) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$reflectionMethod = $nativeReflectionClass->getMethod($methodName);
|
||||
$parameterReflection = $reflectionMethod->getParameters()[$position] ?? null;
|
||||
if (! $parameterReflection instanceof \ReflectionParameter) {
|
||||
|
@ -37,7 +54,7 @@ final class NativeTypeClassTreeResolver
|
|||
}
|
||||
|
||||
// "native" reflection from PHPStan removes the type, so we need to check with both reflection and php-paser
|
||||
$nativeType = $this->resolveNativeType($parameterReflection);
|
||||
$nativeType = $this->resolveNativeType($parameterReflection, $phpstanParameterReflection);
|
||||
if (! $nativeType instanceof MixedType) {
|
||||
return $nativeType;
|
||||
}
|
||||
|
@ -50,8 +67,10 @@ final class NativeTypeClassTreeResolver
|
|||
);
|
||||
}
|
||||
|
||||
private function resolveNativeType(\ReflectionParameter $reflectionParameter): Type
|
||||
{
|
||||
private function resolveNativeType(
|
||||
\ReflectionParameter $reflectionParameter,
|
||||
ParameterReflection $parameterReflection
|
||||
): Type {
|
||||
if (! $reflectionParameter instanceof ReflectionParameter) {
|
||||
return new MixedType();
|
||||
}
|
||||
|
@ -70,6 +89,21 @@ final class NativeTypeClassTreeResolver
|
|||
return new MixedType();
|
||||
}
|
||||
|
||||
return $this->staticTypeMapper->mapPhpParserNodePHPStanType($param->type);
|
||||
$paramType = $this->staticTypeMapper->mapPhpParserNodePHPStanType($param->type);
|
||||
return $this->joinWithNullTypeIfNullDefaultValue($parameterReflection, $paramType);
|
||||
}
|
||||
|
||||
private function joinWithNullTypeIfNullDefaultValue(ParameterReflection $parameterReflection, Type $paramType): Type
|
||||
{
|
||||
// nullable type!
|
||||
if (! $parameterReflection->getDefaultValue() instanceof NullType) {
|
||||
return $paramType;
|
||||
}
|
||||
|
||||
if (TypeCombinator::containsNull($paramType)) {
|
||||
return $paramType;
|
||||
}
|
||||
|
||||
return TypeCombinator::addNull($paramType);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,24 +2,23 @@
|
|||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\DowngradePhp72\Rector\Class_;
|
||||
namespace Rector\DowngradePhp72\Rector\ClassMethod;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Param;
|
||||
use PhpParser\Node\Stmt\Class_;
|
||||
use PhpParser\Node\Stmt\ClassLike;
|
||||
use PhpParser\Node\Stmt\ClassMethod;
|
||||
use PhpParser\Node\Stmt\Interface_;
|
||||
use PhpParser\Node\Stmt\Trait_;
|
||||
use PHPStan\Analyser\Scope;
|
||||
use PHPStan\Reflection\ClassReflection;
|
||||
use Rector\Core\Exception\ShouldNotHappenException;
|
||||
use Rector\Core\NodeAnalyzer\ExternalFullyQualifiedAnalyzer;
|
||||
use Rector\Core\Rector\AbstractRector;
|
||||
use Rector\DowngradePhp72\NodeAnalyzer\ClassLikeWithTraitsClassMethodResolver;
|
||||
use Rector\DowngradePhp72\NodeAnalyzer\ParamContravariantDetector;
|
||||
use Rector\DowngradePhp72\NodeAnalyzer\ParentChildClassMethodTypeResolver;
|
||||
use Rector\DowngradePhp72\PhpDoc\NativeParamToPhpDocDecorator;
|
||||
use Rector\NodeTypeResolver\Node\AttributeKey;
|
||||
use Rector\NodeTypeResolver\PHPStan\Collector\TraitNodeScopeCollector;
|
||||
use Rector\NodeTypeResolver\PHPStan\Type\TypeFactory;
|
||||
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
|
||||
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
|
||||
|
@ -28,7 +27,7 @@ use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
|
|||
* @changelog https://www.php.net/manual/en/migration72.new-features.php#migration72.new-features.param-type-widening
|
||||
* @see https://3v4l.org/fOgSE
|
||||
*
|
||||
* @see \Rector\Tests\DowngradePhp72\Rector\Class_\DowngradeParameterTypeWideningRector\DowngradeParameterTypeWideningRectorTest
|
||||
* @see \Rector\Tests\DowngradePhp72\Rector\ClassMethod\DowngradeParameterTypeWideningRector\DowngradeParameterTypeWideningRectorTest
|
||||
*/
|
||||
final class DowngradeParameterTypeWideningRector extends AbstractRector
|
||||
{
|
||||
|
@ -38,7 +37,7 @@ final class DowngradeParameterTypeWideningRector extends AbstractRector
|
|||
private NativeParamToPhpDocDecorator $nativeParamToPhpDocDecorator,
|
||||
private ParamContravariantDetector $paramContravariantDetector,
|
||||
private TypeFactory $typeFactory,
|
||||
private ExternalFullyQualifiedAnalyzer $externalFullyQualifiedAnalyzer
|
||||
private TraitNodeScopeCollector $traitNodeScopeCollector
|
||||
) {
|
||||
}
|
||||
|
||||
|
@ -85,15 +84,15 @@ CODE_SAMPLE
|
|||
*/
|
||||
public function getNodeTypes(): array
|
||||
{
|
||||
return [Class_::class, Interface_::class];
|
||||
return [ClassMethod::class];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Class_|Interface_ $node
|
||||
* @param ClassMethod $node
|
||||
*/
|
||||
public function refactor(Node $node): ?Node
|
||||
{
|
||||
$scope = $node->getAttribute(AttributeKey::SCOPE);
|
||||
$scope = $this->resolveScope($node);
|
||||
if (! $scope instanceof Scope) {
|
||||
return null;
|
||||
}
|
||||
|
@ -107,24 +106,26 @@ CODE_SAMPLE
|
|||
return null;
|
||||
}
|
||||
|
||||
if ($this->externalFullyQualifiedAnalyzer->hasExternalFullyQualifieds($node)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$hasChanged = false;
|
||||
/** @var ClassReflection[] $ancestors */
|
||||
$ancestors = $classReflection->getAncestors();
|
||||
$classMethods = $this->classLikeWithTraitsClassMethodResolver->resolve($ancestors);
|
||||
|
||||
$classLikes = $this->nodeRepository->findClassesAndInterfacesByType($classReflection->getName());
|
||||
$interfaces = $classReflection->getInterfaces();
|
||||
|
||||
$interfaceClassReflections = $classReflection->getInterfaces();
|
||||
foreach ($classMethods as $classMethod) {
|
||||
if ($this->skipClassMethod($classMethod, $classReflection, $ancestors, $classLikes)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// refactor here
|
||||
$changedClassMethod = $this->refactorClassMethod($classMethod, $classReflection, $ancestors, $interfaces);
|
||||
$changedClassMethod = $this->refactorClassMethod(
|
||||
$classMethod,
|
||||
$classReflection,
|
||||
$ancestors,
|
||||
$interfaceClassReflections
|
||||
);
|
||||
if ($changedClassMethod !== null) {
|
||||
$hasChanged = true;
|
||||
}
|
||||
|
@ -235,4 +236,21 @@ CODE_SAMPLE
|
|||
|
||||
return count($classReflection->getAncestors()) === 1;
|
||||
}
|
||||
|
||||
private function resolveScope(ClassMethod $classMethod): ?Scope
|
||||
{
|
||||
$scope = $classMethod->getAttribute(AttributeKey::SCOPE);
|
||||
if ($scope instanceof Scope) {
|
||||
return $scope;
|
||||
}
|
||||
|
||||
// fallback to a trait method
|
||||
$classLike = $classMethod->getAttribute(AttributeKey::CLASS_NODE);
|
||||
if ($classLike instanceof Trait_) {
|
||||
$traitName = $this->getName($classLike);
|
||||
return $this->traitNodeScopeCollector->getScopeForTrait($traitName);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -12,6 +12,7 @@ use PHPStan\Type\UnionType;
|
|||
final class DetailedTypeAnalyzer
|
||||
{
|
||||
/**
|
||||
* Use this constant to avoid overly detailed long-dragging union types across whole universe
|
||||
* @var int
|
||||
*/
|
||||
private const MAX_NUMBER_OF_TYPES = 3;
|
||||
|
|
|
@ -178,10 +178,6 @@ CODE_SAMPLE
|
|||
return true;
|
||||
}
|
||||
|
||||
if ($this->detailedTypeAnalyzer->isTooDetailed($newType)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// not an array type
|
||||
if ($newType instanceof VoidType) {
|
||||
return true;
|
||||
|
|
|
@ -230,14 +230,11 @@ CODE_SAMPLE
|
|||
return false;
|
||||
}
|
||||
|
||||
$hasExternalClassOrInterfaceOrTrait = $this->externalFullyQualifiedAnalyzer->hasExternalFullyQualifieds(
|
||||
$classLike
|
||||
);
|
||||
if (! $this->externalFullyQualifiedAnalyzer->hasVendorLocatedDependency($classLike)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $functionLike->returnType === null && $hasExternalClassOrInterfaceOrTrait && $this->isName(
|
||||
$inferredReturnNode,
|
||||
'void'
|
||||
);
|
||||
return $functionLike->returnType === null && $this->isName($inferredReturnNode, 'void');
|
||||
}
|
||||
|
||||
private function isNullableTypeSubType(Type $currentType, Type $inferedType): bool
|
||||
|
|
|
@ -64,7 +64,11 @@ final class PropertyTypeInferer
|
|||
if ($resolvedTypes !== []) {
|
||||
$resolvedType = $this->typeFactory->createMixedPassedOrUnionType($resolvedTypes);
|
||||
} else {
|
||||
// void type is not allowed in properties
|
||||
$resolvedType = $this->varDocPropertyTypeInferer->inferProperty($property);
|
||||
if ($resolvedType instanceof VoidType) {
|
||||
return new MixedType();
|
||||
}
|
||||
}
|
||||
|
||||
// default value type must be added to each resolved type if set
|
||||
|
|
|
@ -48,7 +48,7 @@ final class SilentVoidResolver
|
|||
return false;
|
||||
}
|
||||
|
||||
if ($classLike instanceof Class_ && $this->externalFullyQualifiedAnalyzer->hasExternalFullyQualifieds(
|
||||
if ($classLike instanceof Class_ && $this->externalFullyQualifiedAnalyzer->hasVendorLocatedDependency(
|
||||
$classLike
|
||||
)) {
|
||||
return false;
|
||||
|
|
|
@ -12,10 +12,13 @@ use PHPStan\Type\NeverType;
|
|||
use PHPStan\Type\ObjectType;
|
||||
use PHPStan\Type\StringType;
|
||||
use PHPStan\Type\Type;
|
||||
use PHPStan\Type\TypeTraverser;
|
||||
use PHPStan\Type\UnionType;
|
||||
use Rector\NodeTypeResolver\PHPStan\Type\TypeFactory;
|
||||
use Rector\StaticTypeMapper\TypeFactory\UnionTypeFactory;
|
||||
use Rector\TypeDeclaration\ValueObject\NestedArrayType;
|
||||
use Symplify\PackageBuilder\Reflection\PrivatesAccessor;
|
||||
use Symplify\SimplePhpDocParser\PhpDocNodeTraverser;
|
||||
|
||||
/**
|
||||
* @see \Rector\Tests\TypeDeclaration\TypeNormalizerTest
|
||||
|
@ -29,7 +32,9 @@ final class TypeNormalizer
|
|||
|
||||
public function __construct(
|
||||
private TypeFactory $typeFactory,
|
||||
private UnionTypeFactory $unionTypeFactory
|
||||
private UnionTypeFactory $unionTypeFactory,
|
||||
// private PhpDocNodeTraverser $phpDocNodeTraverser,
|
||||
private PrivatesAccessor $privatesAccessor
|
||||
) {
|
||||
}
|
||||
|
||||
|
@ -95,24 +100,39 @@ final class TypeNormalizer
|
|||
*/
|
||||
public function normalizeArrayTypeAndArrayNever(Type $type): Type
|
||||
{
|
||||
if (! $type instanceof UnionType) {
|
||||
return $type;
|
||||
}
|
||||
return TypeTraverser::map($type, function (Type $traversedType, callable $traverserCallable): Type {
|
||||
if ($traversedType instanceof ConstantArrayType && $traversedType->getKeyType() instanceof NeverType && $traversedType->getItemType() instanceof NeverType) {
|
||||
// not sure why, but with direct new node everything gets nulled to MixedType
|
||||
$this->privatesAccessor->setPrivateProperty($traversedType, 'keyType', new MixedType());
|
||||
$this->privatesAccessor->setPrivateProperty($traversedType, 'itemType', new MixedType());
|
||||
|
||||
$nonNeverTypes = [];
|
||||
foreach ($type->getTypes() as $unionedType) {
|
||||
if (! $unionedType instanceof ArrayType) {
|
||||
return $type;
|
||||
return $traversedType;
|
||||
}
|
||||
|
||||
if ($unionedType->getItemType() instanceof NeverType) {
|
||||
continue;
|
||||
if ($traversedType instanceof UnionType) {
|
||||
$collectedTypes = [];
|
||||
|
||||
foreach ($traversedType->getTypes() as $unionedType) {
|
||||
// basically an empty array - not useful at all
|
||||
if ($this->isArrayNeverType($unionedType)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$collectedTypes[] = $unionedType;
|
||||
}
|
||||
|
||||
// re-create new union types
|
||||
if (count($traversedType->getTypes()) !== count($collectedTypes)) {
|
||||
return $this->typeFactory->createMixedPassedOrUnionType($collectedTypes);
|
||||
}
|
||||
}
|
||||
|
||||
$nonNeverTypes[] = $unionedType;
|
||||
}
|
||||
if ($traversedType instanceof NeverType) {
|
||||
return new MixedType();
|
||||
}
|
||||
|
||||
return $this->typeFactory->createMixedPassedOrUnionType($nonNeverTypes);
|
||||
return $traverserCallable($traversedType, $traverserCallable);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -164,4 +184,13 @@ final class TypeNormalizer
|
|||
|
||||
return $unionedTypes[0];
|
||||
}
|
||||
|
||||
private function isArrayNeverType(Type $type): bool
|
||||
{
|
||||
if (! $type instanceof ArrayType) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $type->getKeyType() instanceof NeverType && $type->getItemType() instanceof NeverType;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,100 +4,41 @@ declare(strict_types=1);
|
|||
|
||||
namespace Rector\Core\NodeAnalyzer;
|
||||
|
||||
use PhpParser\Node\Name\FullyQualified;
|
||||
use PhpParser\Node\Stmt\Class_;
|
||||
use PhpParser\Node\Stmt\ClassLike;
|
||||
use PhpParser\Node\Stmt\Interface_;
|
||||
use PhpParser\Node\Stmt\TraitUse;
|
||||
use Rector\NodeCollector\NodeCollector\NodeRepository;
|
||||
use Rector\NodeNameResolver\NodeNameResolver;
|
||||
use PhpParser\Node;
|
||||
use PHPStan\Analyser\Scope;
|
||||
use PHPStan\Reflection\ClassReflection;
|
||||
use Rector\NodeTypeResolver\Node\AttributeKey;
|
||||
|
||||
final class ExternalFullyQualifiedAnalyzer
|
||||
{
|
||||
public function __construct(
|
||||
private NodeNameResolver $nodeNameResolver,
|
||||
private NodeRepository $nodeRepository
|
||||
) {
|
||||
}
|
||||
|
||||
public function hasExternalFullyQualifieds(ClassLike $classLike): bool
|
||||
{
|
||||
if ($classLike instanceof Class_ || $classLike instanceof Interface_) {
|
||||
$extends = $classLike->extends ?? [];
|
||||
} else {
|
||||
$extends = [];
|
||||
}
|
||||
|
||||
/** @var FullyQualified[] $extends */
|
||||
$extends = $extends instanceof FullyQualified
|
||||
? [$extends]
|
||||
: $extends;
|
||||
|
||||
/** @var FullyQualified[] $implements */
|
||||
$implements = $classLike instanceof Class_ ? $classLike->implements : [];
|
||||
|
||||
$parentClassesAndInterfaces = array_merge($extends, $implements);
|
||||
$hasExternalClassOrInterface = $this->hasExternalClassOrInterface($parentClassesAndInterfaces);
|
||||
if ($hasExternalClassOrInterface) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/** @var TraitUse[] $traitUses */
|
||||
$traitUses = $classLike->getTraitUses();
|
||||
return $this->hasExternalTrait($traitUses);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param FullyQualified[] $fullyQualifiedClassLikes
|
||||
* Is in a class that depends on a class, interface or trait located in vendor?
|
||||
*/
|
||||
private function hasExternalClassOrInterface(array $fullyQualifiedClassLikes): bool
|
||||
public function hasVendorLocatedDependency(Node $node): bool
|
||||
{
|
||||
if ($fullyQualifiedClassLikes === []) {
|
||||
$scope = $node->getAttribute(AttributeKey::SCOPE);
|
||||
if (! $scope instanceof Scope) {
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach ($fullyQualifiedClassLikes as $fullyQualifiedClassLike) {
|
||||
/** @var string $className */
|
||||
$className = $this->nodeNameResolver->getName($fullyQualifiedClassLike);
|
||||
$isClassFound = (bool) $this->nodeRepository->findClass($className);
|
||||
$isInterfaceFound = (bool) $this->nodeRepository->findInterface($className);
|
||||
if ($isClassFound) {
|
||||
continue;
|
||||
}
|
||||
if ($isInterfaceFound) {
|
||||
continue;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TraitUse[] $traitUses
|
||||
*/
|
||||
private function hasExternalTrait(array $traitUses): bool
|
||||
{
|
||||
if ($traitUses === []) {
|
||||
$classReflection = $scope->getClassReflection();
|
||||
if (! $classReflection instanceof ClassReflection) {
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach ($traitUses as $traitUse) {
|
||||
$traits = $traitUse->traits;
|
||||
foreach ($classReflection->getAncestors() as $ancestorClassReflection) {
|
||||
if ($classReflection === $ancestorClassReflection) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ($traits as $trait) {
|
||||
if (! $trait instanceof FullyQualified) {
|
||||
return false;
|
||||
}
|
||||
$fileName = $ancestorClassReflection->getFileName();
|
||||
if ($fileName === false) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/** @var string $traitName */
|
||||
$traitName = $this->nodeNameResolver->getName($trait);
|
||||
$isTraitFound = (bool) $this->nodeRepository->findTrait($traitName);
|
||||
|
||||
if (! $isTraitFound) {
|
||||
return true;
|
||||
}
|
||||
// file is located in vendor → out of modifiable scope
|
||||
if (str_contains($fileName, '/vendor/')) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user