[PHP 8.0] Add downgrade for str_starts_with() (#126)

This commit is contained in:
Tomas Votruba 2021-05-30 11:02:38 +01:00 committed by GitHub
parent b42fc3dcbd
commit f7e9986835
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
33 changed files with 426 additions and 97 deletions

View File

@ -56,7 +56,7 @@
"phpstan/phpstan-nette": "^0.12.18",
"phpunit/phpunit": "^9.5",
"rector/rector-generator": "^0.1.7",
"rector/phpstan-rules": "^0.2.8",
"rector/phpstan-rules": "^0.3",
"symplify/coding-standard": "^9.3.10",
"symplify/easy-ci": "^9.3.10",
"symplify/easy-coding-standard": "^9.3.10",

View File

@ -42,5 +42,6 @@ return static function (ContainerConfigurator $containerConfigurator): void {
$services->set(DowngradeClassOnObjectToGetClassRector::class);
$services->set(DowngradeNullsafeToTernaryOperatorRector::class);
$services->set(DowngradeTrailingCommasInParamUseRector::class);
$services->set(\Rector\DowngradePhp80\Rector\Class_\DowngradeAttributeToAnnotationRector::class);
$services->set(\Rector\DowngradePhp80\Rector\FuncCall\DowngradeStrStartsWithRector::class);
$services->set(\Rector\DowngradePhp80\Rector\FuncCall\DowngradeStrEndsWithRector::class);
};

View File

@ -47,15 +47,14 @@ final class ClassTypeResolverTest extends AbstractNodeTypeResolverTest
yield [__DIR__ . '/Source/ClassWithParentTrait.php', 0, new ObjectType(ClassWithParentTrait::class)];
}
public function testAnonymousClass(): void
{
$file = __DIR__ . '/Source/AnonymousClass.php';
$nodePosition = 0;
$variableNodes = $this->getNodesForFileOfType($file, Class_::class);
$resolvedType = $this->nodeTypeResolver->resolve($variableNodes[$nodePosition]);
$resolvedType = $this->nodeTypeResolver->resolve($variableNodes[0]);
$this->assertInstanceOf(TypeWithClassName::class, $resolvedType);
/** @var TypeWithClassName $resolvedType */

View File

@ -21,10 +21,9 @@ final class CommentRemover
}
/**
* @param Node[]|Node|null $node
* @return Node[]|null
*/
public function removeFromNode($node): ?array
public function removeFromNode(array | Node | null $node): array | null
{
if ($node === null) {
return null;

View File

@ -39,13 +39,12 @@ final class NodeRemover
$this->rectorChangeCollector->notifyNodeFileInfo($node);
}
/**
* @param Class_|ClassMethod|Function_ $nodeWithStatements
*/
public function removeNodeFromStatements(Node $nodeWithStatements, Node $nodeToRemove): void
{
public function removeNodeFromStatements(
Class_ | ClassMethod | Function_ $nodeWithStatements,
Node $toBeRemovedNode
): void {
foreach ((array) $nodeWithStatements->stmts as $key => $stmt) {
if ($nodeToRemove !== $stmt) {
if ($toBeRemovedNode !== $stmt) {
continue;
}

View File

@ -7,7 +7,6 @@ namespace Rector\NodeTypeResolver\PHPStan\Scope;
use Nette\Utils\Strings;
use PhpParser\Node;
use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\ClassLike;
use PhpParser\Node\Stmt\Interface_;
use PhpParser\Node\Stmt\Trait_;
use PhpParser\NodeTraverser;
@ -121,10 +120,7 @@ final class PHPStanNodeScopeResolver
$nodeTraverser->traverse($nodes);
}
/**
* @param Class_|Interface_ $classLike
*/
private function resolveClassOrInterfaceScope(ClassLike $classLike, Scope $scope): Scope
private function resolveClassOrInterfaceScope(Class_ | Interface_ $classLike, Scope $scope): Scope
{
$className = $this->resolveClassName($classLike);
@ -172,10 +168,7 @@ final class PHPStanNodeScopeResolver
$this->changedFilesDetector->addFileWithDependencies($smartFileInfo, $dependentFiles);
}
/**
* @param Class_|Interface_|Trait_ $classLike
*/
private function resolveClassName(ClassLike $classLike): string
private function resolveClassName(Class_ | Interface_ | Trait_ $classLike): string
{
if (property_exists($classLike, 'namespacedName')) {
return (string) $classLike->namespacedName;

View File

@ -4,10 +4,9 @@ declare(strict_types=1);
namespace Rector\PHPStanStaticTypeMapper;
use PhpParser\Node;
use PhpParser\Node\Name;
use PhpParser\Node\NullableType;
use PhpParser\Node\UnionType as PhpParserUnionType;
use PhpParser\Node\UnionType;
use PHPStan\PhpDocParser\Ast\Type\TypeNode;
use PHPStan\Type\Type;
use Rector\Core\Exception\NotImplementedYetException;
@ -36,11 +35,7 @@ final class PHPStanStaticTypeMapper
throw new NotImplementedYetException(__METHOD__ . ' for ' . get_class($type));
}
/**
* @return Name|NullableType|PhpParserUnionType|null
*/
public function mapToPhpParserNode(Type $type, ?string $kind = null): ?Node
{
public function mapToPhpParserNode(Type $type, ?string $kind = null): Name | NullableType | UnionType | null {
foreach ($this->typeMappers as $typeMapper) {
if (! is_a($type, $typeMapper->getNodeClass(), true)) {
continue;

View File

@ -144,10 +144,7 @@ final class UnionTypeMapper implements TypeMapperInterface
return $unionTypeAnalysis->hasArray();
}
/**
* @return Name|NullableType|null
*/
private function matchArrayTypes(UnionType $unionType): ?Node
private function matchArrayTypes(UnionType $unionType): Name | NullableType | null
{
$unionTypeAnalysis = $this->unionTypeAnalyzer->analyseForNullableAndIterable($unionType);
if (! $unionTypeAnalysis instanceof UnionTypeAnalysis) {

View File

@ -487,3 +487,9 @@ parameters:
-
message: '#Use separate function calls with readable variable names#'
path: 'src/FileSystem/PhpFilesFinder.php'
# union false positive
- '#Method Rector\\Comments\\CommentRemover\:\:removeFromNode\(\) has parameter \$node with no value type specified in iterable type array#'
# should be refactored to collector
- '#Cognitive complexity for "Rector\\CodingStyle\\Naming\\NameRenamer\:\:renameNameNode\(\)" is 10, keep it under 9#'

View File

@ -0,0 +1,31 @@
<?php
namespace Rector\Tests\CodingStyle\Rector\Use_\RemoveUnusedAliasRector\Fixture;
use PhpParser\Node\Scalar\String_;
use PhpParser\Node\UnionType as PhpParserUnionType;
final class UsedUnionType
{
public function param(String_ | PhpParserUnionType $node)
{
}
}
?>
-----
<?php
namespace Rector\Tests\CodingStyle\Rector\Use_\RemoveUnusedAliasRector\Fixture;
use PhpParser\Node\Scalar\String_;
use PhpParser\Node\UnionType;
final class UsedUnionType
{
public function param(String_ | UnionType $node)
{
}
}
?>

View File

@ -4,14 +4,12 @@ declare(strict_types=1);
namespace Rector\Tests\Defluent\Rector\MethodCall\InArgChainFluentMethodCallToStandaloneMethodCallRectorTest\Source;
use Cassandra\Date;
use Nette\Utils\DateTime;
final class SetGetDateTime
{
/**
* @var DateTime|null
*/
private $dateMin = null;
private ?DateTime $dateMin = null;
public function setDateMin(?DateTime $dateTime = null)
{

View File

@ -0,0 +1,33 @@
<?php
declare(strict_types=1);
namespace Rector\Tests\DowngradePhp80\Rector\FuncCall\DowngradeStrEndsWithRector;
use Iterator;
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
use Symplify\SmartFileSystem\SmartFileInfo;
final class DowngradeStrEndsWithRectorTest extends AbstractRectorTestCase
{
/**
* @dataProvider provideData()
*/
public function test(SmartFileInfo $fileInfo): void
{
$this->doTestFileInfo($fileInfo);
}
/**
* @return Iterator<SmartFileInfo>
*/
public function provideData(): Iterator
{
return $this->yieldFilesFromDirectory(__DIR__ . '/Fixture');
}
public function provideConfigFilePath(): string
{
return __DIR__ . '/config/configured_rule.php';
}
}

View File

@ -0,0 +1,15 @@
<?php
namespace Rector\Tests\DowngradePhp80\Rector\FuncCall\DowngradeStrEndsWithRector\Fixture;
! str_ends_with($haystack, $needle);
?>
-----
<?php
namespace Rector\Tests\DowngradePhp80\Rector\FuncCall\DowngradeStrEndsWithRector\Fixture;
substr_compare($haystack, $needle, -strlen($needle)) !== 0;
?>

View File

@ -0,0 +1,15 @@
<?php
namespace Rector\Tests\DowngradePhp80\Rector\FuncCall\DowngradeStrEndsWithRector\Fixture;
str_ends_with($haystack, $needle);
?>
-----
<?php
namespace Rector\Tests\DowngradePhp80\Rector\FuncCall\DowngradeStrEndsWithRector\Fixture;
substr_compare($haystack, $needle, -strlen($needle)) === 0;
?>

View File

@ -0,0 +1,11 @@
<?php
declare(strict_types=1);
use Rector\DowngradePhp80\Rector\FuncCall\DowngradeStrEndsWithRector;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
return static function (ContainerConfigurator $containerConfigurator): void {
$services = $containerConfigurator->services();
$services->set(DowngradeStrEndsWithRector::class);
};

View File

@ -0,0 +1,33 @@
<?php
declare(strict_types=1);
namespace Rector\Tests\DowngradePhp80\Rector\FuncCall\DowngradeStrStartsWithRector;
use Iterator;
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
use Symplify\SmartFileSystem\SmartFileInfo;
final class DowngradeStrStartsWithRectorTest extends AbstractRectorTestCase
{
/**
* @dataProvider provideData()
*/
public function test(SmartFileInfo $fileInfo): void
{
$this->doTestFileInfo($fileInfo);
}
/**
* @return Iterator<SmartFileInfo>
*/
public function provideData(): Iterator
{
return $this->yieldFilesFromDirectory(__DIR__ . '/Fixture');
}
public function provideConfigFilePath(): string
{
return __DIR__ . '/config/configured_rule.php';
}
}

View File

@ -0,0 +1,15 @@
<?php
namespace Rector\Tests\DowngradePhp80\Rector\FuncCall\DowngradeStrStartsWithRector\Fixture;
return ! str_starts_with($haystack, $needle);
?>
-----
<?php
namespace Rector\Tests\DowngradePhp80\Rector\FuncCall\DowngradeStrStartsWithRector\Fixture;
return strncmp($haystack, $needle, strlen($needle)) !== 0;
?>

View File

@ -0,0 +1,15 @@
<?php
namespace Rector\Tests\DowngradePhp80\Rector\FuncCall\DowngradeStrStartsWithRector\Fixture;
str_starts_with($haystack, $needle);
?>
-----
<?php
namespace Rector\Tests\DowngradePhp80\Rector\FuncCall\DowngradeStrStartsWithRector\Fixture;
strncmp($haystack, $needle, strlen($needle)) === 0;
?>

View File

@ -0,0 +1,11 @@
<?php
declare(strict_types=1);
use Rector\DowngradePhp80\Rector\FuncCall\DowngradeStrStartsWithRector;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
return static function (ContainerConfigurator $containerConfigurator): void {
$services = $containerConfigurator->services();
$services->set(DowngradeStrStartsWithRector::class);
};

View File

@ -2,7 +2,7 @@
namespace Rector\Tests\EarlyReturn\Rector\If_\ChangeOrIfContinueToMultiContinueRector\Fixture;
class NotIdentical
final class SomeNotIdentical
{
public function canDrive(Car $newCar)
{
@ -22,7 +22,7 @@ class NotIdentical
namespace Rector\Tests\EarlyReturn\Rector\If_\ChangeOrIfContinueToMultiContinueRector\Fixture;
class NotIdentical
final class SomeNotIdentical
{
public function canDrive(Car $newCar)
{

View File

@ -159,11 +159,10 @@ CODE_SAMPLE
return $this->isObjectType($classLike, $objectType);
}
/**
* @param ClassMethod|MethodCall|StaticCall $node
*/
private function processPositionWithDefaultValues(Node $node, ArgumentAdder $argumentAdder): void
{
private function processPositionWithDefaultValues(
ClassMethod | MethodCall | StaticCall $node,
ArgumentAdder $argumentAdder
): void {
if ($this->shouldSkipParameter($node, $argumentAdder)) {
return;
}

View File

@ -30,10 +30,7 @@ final class ClassNaming
return lcfirst($shortName);
}
/**
* @param string|Name|Identifier|ClassLike $name
*/
public function getShortName($name): string
public function getShortName(string | Name | Identifier | ClassLike $name): string
{
if ($name instanceof ClassLike) {
if ($name->name === null) {

View File

@ -14,6 +14,7 @@ use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Stmt\Interface_;
use PhpParser\Node\Stmt\TraitUse;
use PhpParser\Node\UnionType;
use Rector\CodingStyle\ValueObject\NameAndParent;
use Rector\NodeNameResolver\NodeNameResolver;
@ -60,6 +61,10 @@ final class NameRenamer
if ($parentNode instanceof StaticCall) {
$this->renameStaticCall($lastName, $parentNode);
}
if ($parentNode instanceof UnionType) {
$this->renameUnionType($lastName, $parentNode, $usedName);
}
}
}
@ -105,12 +110,29 @@ final class NameRenamer
if ($param->type === null) {
return;
}
if (! $this->nodeNameResolver->areNamesEqual($param->type, $usedNameNode)) {
return;
}
$param->type = new Name($lastName);
}
private function renameUnionType(string $lastName, UnionType $unionType, Node $usedNameNode): void
{
foreach ($unionType->types as $key => $unionedType) {
if (! $this->nodeNameResolver->areNamesEqual($unionedType, $usedNameNode)) {
continue;
}
if (! $unionedType instanceof Name) {
continue;
}
$unionType->types[$key] = new Name($lastName);
}
}
/**
* @param Name|Identifier $usedNameNode
*/

View File

@ -195,7 +195,6 @@ CODE_SAMPLE
private function refactorAliasName(string $aliasName, string $lastName, UseUse $useUse): void
{
// only alias name is used → use last name directly
$lowerAliasName = strtolower($aliasName);
if (! isset($this->resolvedNodeNames[$lowerAliasName])) {
return;

View File

@ -0,0 +1,79 @@
<?php
declare(strict_types=1);
namespace Rector\DowngradePhp80\Rector\FuncCall;
use PhpParser\Node;
use PhpParser\Node\Arg;
use PhpParser\Node\Expr;
use PhpParser\Node\Expr\BinaryOp\Identical;
use PhpParser\Node\Expr\BinaryOp\NotIdentical;
use PhpParser\Node\Expr\BooleanNot;
use PhpParser\Node\Expr\FuncCall;
use PhpParser\Node\Expr\UnaryMinus;
use PhpParser\Node\Name;
use PhpParser\Node\Scalar\LNumber;
use Rector\Core\Rector\AbstractRector;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
/**
* @changelog https://wiki.php.net/rfc/add_str_starts_with_and_ends_with_functions
*
* @see \Rector\Tests\DowngradePhp80\Rector\FuncCall\DowngradeStrEndsWithRector\DowngradeStrEndsWithRectorTest
*/
final class DowngradeStrEndsWithRector extends AbstractRector
{
public function getRuleDefinition(): RuleDefinition
{
return new RuleDefinition('Downgrade str_ends_with() to strncmp() version', [
new CodeSample(
'str_ends_with($haystack, $needle);',
'"" === $needle || ("" !== $haystack && 0 === substr_compare($haystack, $needle, -\strlen($needle)));'
),
]);
}
/**
* @return array<class-string<Node>>
*/
public function getNodeTypes(): array
{
return [FuncCall::class, BooleanNot::class];
}
/**
* @param FuncCall|BooleanNot $node
*/
public function refactor(Node $node): ?Node
{
if ($node instanceof FuncCall && $this->isName($node->name, 'str_ends_with')) {
return new Identical($this->createSubstrCompareFuncCall($node), new LNumber(0));
}
if ($node instanceof BooleanNot) {
$funcCall = $node->expr;
if ($funcCall instanceof FuncCall && $this->isName($funcCall->name, 'str_ends_with')) {
return new NotIdentical($this->createSubstrCompareFuncCall($funcCall), new LNumber(0));
}
}
return null;
}
private function createSubstrCompareFuncCall(FuncCall $funcCall): FuncCall
{
$args = $funcCall->args;
$strlenFuncCall = $this->createStrlenFuncCall($funcCall->args[1]->value);
$args[] = new Arg(new UnaryMinus($strlenFuncCall));
return new FuncCall(new Name('substr_compare'), $args);
}
private function createStrlenFuncCall(Expr $expr): FuncCall
{
return new FuncCall(new Name('strlen'), [new Arg($expr)]);
}
}

View File

@ -0,0 +1,91 @@
<?php
declare(strict_types=1);
namespace Rector\DowngradePhp80\Rector\FuncCall;
use PhpParser\Node;
use PhpParser\Node\Arg;
use PhpParser\Node\Expr\BinaryOp\Identical;
use PhpParser\Node\Expr\BinaryOp\NotIdentical;
use PhpParser\Node\Expr\BooleanNot;
use PhpParser\Node\Expr\FuncCall;
use PhpParser\Node\Name;
use PhpParser\Node\Scalar\LNumber;
use Rector\Core\Rector\AbstractRector;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
/**
* @changelog https://wiki.php.net/rfc/add_str_starts_with_and_ends_with_functions
*
* @see \Rector\Tests\DowngradePhp80\Rector\FuncCall\DowngradeStrStartsWithRector\DowngradeStrStartsWithRectorTest
*/
final class DowngradeStrStartsWithRector extends AbstractRector
{
public function getRuleDefinition(): RuleDefinition
{
return new RuleDefinition('Downgrade str_starts_with() to strncmp() version', [
new CodeSample(
'str_starts_with($haystack, $needle);',
'strncmp($haystack, $needle, strlen($needle)) === 0;'
),
]);
}
/**
* @return array<class-string<Node>>
*/
public function getNodeTypes(): array
{
return [FuncCall::class, BooleanNot::class];
}
/**
* @param FuncCall|BooleanNot $node
*/
public function refactor(Node $node): ?Node
{
if ($node instanceof FuncCall && $this->isName($node, 'str_starts_with')) {
return $this->createIdentical($node);
}
if ($node instanceof BooleanNot) {
$negatedCall = $node->expr;
if ($negatedCall instanceof FuncCall && $this->isName($negatedCall, 'str_starts_with')) {
return $this->createNotIdenticalStrncmpFuncCall($negatedCall);
}
}
return null;
}
private function createIdentical(FuncCall $funcCall): Identical
{
$strlenFuncCall = $this->createStrlenFuncCall($funcCall);
$strncmpFuncCall = $this->createStrncmpFuncCall($funcCall, $strlenFuncCall);
return new Identical($strncmpFuncCall, new LNumber(0));
}
private function createNotIdenticalStrncmpFuncCall(FuncCall $funcCall): NotIdentical
{
$strlenFuncCall = $this->createStrlenFuncCall($funcCall);
$strncmpFuncCall = $this->createStrncmpFuncCall($funcCall, $strlenFuncCall);
return new NotIdentical($strncmpFuncCall, new LNumber(0));
}
private function createStrlenFuncCall(FuncCall $funcCall): FuncCall
{
return new FuncCall(new Name('strlen'), [$funcCall->args[1]]);
}
private function createStrncmpFuncCall(FuncCall $funcCall, FuncCall $strlenFuncCall): FuncCall
{
$newArgs = $funcCall->args;
$newArgs[] = new Arg($strlenFuncCall);
return new FuncCall(new Name('strncmp'), $newArgs);
}
}

View File

@ -4,7 +4,6 @@ declare(strict_types=1);
namespace Rector\Order;
use PhpParser\Node\Stmt;
use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\ClassConst;
use PhpParser\Node\Stmt\ClassLike;
@ -26,10 +25,9 @@ final class StmtVisibilitySorter
}
/**
* @param Class_|Trait_ $classLike
* @return string[]
*/
public function sortProperties(ClassLike $classLike): array
public function sortProperties(Class_ | Trait_ $classLike): array
{
$propertyRankeables = [];
@ -79,10 +77,9 @@ final class StmtVisibilitySorter
}
/**
* @param Class_|Interface_ $classLike
* @return string[]
*/
public function sortConstants(ClassLike $classLike): array
public function sortConstants(Class_ | Interface_ $classLike): array
{
$classConstsRankeables = [];
foreach ($classLike->stmts as $position => $constantStmt) {
@ -103,10 +100,7 @@ final class StmtVisibilitySorter
return $this->sortByRanksAndGetNames($classConstsRankeables);
}
/**
* @param ClassMethod|Property|ClassConst $stmt
*/
private function getVisibilityLevelOrder(Stmt $stmt): int
private function getVisibilityLevelOrder(ClassMethod | Property | ClassConst $stmt): int
{
if ($stmt->isPrivate()) {
return 2;

View File

@ -5,7 +5,6 @@ declare(strict_types=1);
namespace Rector\Removing\NodeManipulator;
use PhpParser\Node;
use PhpParser\Node\Expr;
use PhpParser\Node\Expr\Assign;
use PhpParser\Node\Expr\PropertyFetch;
use PhpParser\Node\Expr\StaticPropertyFetch;
@ -80,11 +79,12 @@ final class ComplexNodeRemover
}
/**
* @param StaticPropertyFetch|PropertyFetch $expr
* @param string[] $classMethodNamesToSkip
*/
private function shouldSkipPropertyForClassMethod(Expr $expr, array $classMethodNamesToSkip): bool
{
private function shouldSkipPropertyForClassMethod(
StaticPropertyFetch | PropertyFetch $expr,
array $classMethodNamesToSkip
): bool {
$classMethodNode = $expr->getAttribute(AttributeKey::METHOD_NODE);
if (! $classMethodNode instanceof ClassMethod) {
return false;
@ -94,10 +94,7 @@ final class ComplexNodeRemover
return in_array($classMethodName, $classMethodNamesToSkip, true);
}
/**
* @param PropertyFetch|StaticPropertyFetch $expr
*/
private function resolveAssign(Expr $expr): ?Assign
private function resolveAssign(PropertyFetch | StaticPropertyFetch $expr): ?Assign
{
$assign = $expr->getAttribute(AttributeKey::PARENT_NODE);

View File

@ -10,6 +10,7 @@ use PhpParser\Node\Expr\FuncCall;
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Expr\StaticCall;
use PhpParser\Node\FunctionLike;
use PhpParser\Node\Identifier;
use PhpParser\Node\Name;
use PhpParser\Node\Name\FullyQualified;
use PhpParser\Node\NullableType;
@ -131,10 +132,7 @@ CODE_SAMPLE
return $node;
}
/**
* @param ClassMethod|Function_|Closure $node
*/
private function isSkipped(Node $node): bool
private function isSkipped(ClassMethod | Function_ | Closure $node): bool
{
if (! $this->phpVersionProvider->isAtLeastPhpVersion(PhpVersionFeature::SCALAR_TYPES)) {
return true;
@ -149,7 +147,7 @@ CODE_SAMPLE
/**
* @param Return_[] $returns
* @return array<Name|NullableType|UnionType>
* @return array<Identifier|Name|NullableType|PhpParserUnionType>
*/
private function collectStrictReturnTypes(array $returns): array
{
@ -212,10 +210,7 @@ CODE_SAMPLE
return $this->staticTypeMapper->mapPHPStanTypeToPhpParserNode($returnType);
}
/**
* @return Name|NullableType|PhpParserUnionType|null
*/
private function resolveFuncCallReturnNode(FuncCall $funcCall): ?Node
private function resolveFuncCallReturnNode(FuncCall $funcCall): Name | NullableType | PhpParserUnionType | null
{
$returnType = $this->reflectionTypeResolver->resolveFuncCallReturnType($funcCall);
if (! $returnType instanceof Type) {
@ -225,14 +220,10 @@ CODE_SAMPLE
return $this->staticTypeMapper->mapPHPStanTypeToPhpParserNode($returnType);
}
/**
* @param ClassMethod|Function_|Closure $functionLike
* @param Name|NullableType|PhpParserUnionType $returnedStrictTypeNode
*/
private function refactorSingleReturnType(
Return_ $return,
Node $returnedStrictTypeNode,
FunctionLike $functionLike
Identifier | Name | NullableType | PhpParserUnionType $returnedStrictTypeNode,
ClassMethod | Function_ | Closure $functionLike
): FunctionLike {
$resolvedType = $this->nodeTypeResolver->resolve($return);

View File

@ -95,10 +95,7 @@ final class YieldNodesReturnTypeInferer implements ReturnTypeInfererInterface
return $yieldNodes;
}
/**
* @param Yield_|YieldFrom $yieldExpr
*/
private function resolveYieldValue(Expr $yieldExpr): ?Expr
private function resolveYieldValue(Yield_ | YieldFrom $yieldExpr): ?Expr
{
if ($yieldExpr instanceof Yield_) {
return $yieldExpr->value;

View File

@ -22,9 +22,8 @@ final class PhpVersionProvider
public function provide(): int
{
/** @var int|null $phpVersionFeatures */
$phpVersionFeatures = $this->parameterProvider->provideParameter(Option::PHP_VERSION_FEATURES);
if ($phpVersionFeatures !== null) {
$phpVersionFeatures = $this->parameterProvider->provideIntParameter(Option::PHP_VERSION_FEATURES);
if ($phpVersionFeatures > 0) {
return $phpVersionFeatures;
}

View File

@ -474,12 +474,11 @@ abstract class AbstractRector extends NodeVisitorAbstract implements PhpRectorIn
$this->nodeRemover->removeNode($node);
}
/**
* @param Class_|ClassMethod|Function_ $nodeWithStatements
*/
protected function removeNodeFromStatements(Node $nodeWithStatements, Node $nodeToRemove): void
{
$this->nodeRemover->removeNodeFromStatements($nodeWithStatements, $nodeToRemove);
protected function removeNodeFromStatements(
Class_ | ClassMethod | Function_ $nodeWithStatements,
Node $toBeRemovedNode
): void {
$this->nodeRemover->removeNodeFromStatements($nodeWithStatements, $toBeRemovedNode);
}
/**

View File

@ -19,6 +19,5 @@ return static function (ContainerConfigurator $containerConfigurator): void {
'Form' => 'Collective\Html\FormFacade',
'Html' => 'Collective\Html\HtmlFacade',
],
],
]);
]]);
};