mirror of
https://github.com/rectorphp/rector.git
synced 2025-01-19 14:27:14 +01:00
[PHP 8.0] Add OptionalParametersAfterRequiredRector (#5277)
This commit is contained in:
parent
f7fc1ea144
commit
e90a430bcf
@ -11,6 +11,7 @@ use Rector\Php80\Rector\Class_\AnnotationToAttributeRector;
|
||||
use Rector\Php80\Rector\Class_\ClassPropertyAssignToConstructorPromotionRector;
|
||||
use Rector\Php80\Rector\Class_\StringableForToStringRector;
|
||||
use Rector\Php80\Rector\ClassMethod\FinalPrivateToPrivateVisibilityRector;
|
||||
use Rector\Php80\Rector\ClassMethod\OptionalParametersAfterRequiredRector;
|
||||
use Rector\Php80\Rector\ClassMethod\SetStateToStaticRector;
|
||||
use Rector\Php80\Rector\FuncCall\ClassOnObjectRector;
|
||||
use Rector\Php80\Rector\FuncCall\TokenGetAllToObjectRector;
|
||||
@ -38,6 +39,7 @@ return static function (ContainerConfigurator $containerConfigurator): void {
|
||||
$services->set(RemoveUnusedVariableInCatchRector::class);
|
||||
$services->set(ClassPropertyAssignToConstructorPromotionRector::class);
|
||||
$services->set(ChangeSwitchToMatchRector::class);
|
||||
|
||||
// nette\utils and Strings::replace()
|
||||
$services->set(ArgumentAdderRector::class)->call('configure', [[
|
||||
ArgumentAddingScope::ADDED_ARGUMENTS => ValueObjectInliner::inline([
|
||||
@ -76,4 +78,5 @@ return static function (ContainerConfigurator $containerConfigurator): void {
|
||||
'pg_setclientencoding' => 'pg_set_client_encoding',
|
||||
],
|
||||
]]);
|
||||
$services->set(OptionalParametersAfterRequiredRector::class);
|
||||
};
|
||||
|
@ -9,6 +9,7 @@ use PhpParser\Node\Name;
|
||||
use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode;
|
||||
use PHPStan\PhpDocParser\Ast\Type\TypeNode;
|
||||
use PHPStan\Type\CallableType;
|
||||
use PHPStan\Type\ClosureType;
|
||||
use PHPStan\Type\Type;
|
||||
use PHPStan\Type\VerbosityLevel;
|
||||
use Rector\AttributeAwarePhpDoc\Ast\Type\AttributeAwareCallableTypeNode;
|
||||
@ -46,7 +47,7 @@ final class CallableTypeMapper implements TypeMapperInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* @param CallableType $type
|
||||
* @param CallableType|ClosureType $type
|
||||
*/
|
||||
public function mapToPhpParserNode(Type $type, ?string $kind = null): ?Node
|
||||
{
|
||||
|
@ -6,7 +6,6 @@ namespace Rector\PHPStanStaticTypeMapper\TypeMapper;
|
||||
|
||||
use Closure;
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Name;
|
||||
use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode;
|
||||
use PHPStan\PhpDocParser\Ast\Type\TypeNode;
|
||||
use PHPStan\Type\ClosureType;
|
||||
@ -23,6 +22,16 @@ final class ClosureTypeMapper implements TypeMapperInterface, PHPStanStaticTypeM
|
||||
*/
|
||||
private $phpStanStaticTypeMapper;
|
||||
|
||||
/**
|
||||
* @var CallableTypeMapper
|
||||
*/
|
||||
private $callableTypeMapper;
|
||||
|
||||
public function __construct(CallableTypeMapper $callableTypeMapper)
|
||||
{
|
||||
$this->callableTypeMapper = $callableTypeMapper;
|
||||
}
|
||||
|
||||
public function getNodeClass(): string
|
||||
{
|
||||
return ClosureType::class;
|
||||
@ -45,11 +54,7 @@ final class ClosureTypeMapper implements TypeMapperInterface, PHPStanStaticTypeM
|
||||
*/
|
||||
public function mapToPhpParserNode(Type $type, ?string $kind = null): ?Node
|
||||
{
|
||||
if ($kind === 'property') {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new Name('callable');
|
||||
return $this->callableTypeMapper->mapToPhpParserNode($type, $kind);
|
||||
}
|
||||
|
||||
public function mapToDocString(Type $type, ?Type $parentType = null): string
|
||||
|
@ -43,9 +43,7 @@ final class TemplateFinder
|
||||
$filePaths[] = __DIR__ . '/../../templates/rules/__package__/tests/Rector/__Category__/__Name__/Source/extra_file.php.inc';
|
||||
}
|
||||
|
||||
/** @var string[] $filePaths */
|
||||
$filePaths = $this->addRuleAndTestCase($rectorRecipe, $filePaths);
|
||||
|
||||
$filePaths[] = $this->resolveFixtureFilePath();
|
||||
|
||||
$this->ensureFilePathsExists($filePaths);
|
||||
@ -87,7 +85,7 @@ final class TemplateFinder
|
||||
|
||||
private function resolveFixtureFilePath(): string
|
||||
{
|
||||
return __DIR__ . '/../../templates/rules/__package__/tests/Rector/__Category__/__Name__/Fixture/fixture.php.inc';
|
||||
return __DIR__ . '/../../templates/rules/__package__/tests/Rector/__Category__/__Name__/Fixture/some_class.php.inc';
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -19,7 +19,7 @@ final class __Name__Test extends AbstractRectorTestCase
|
||||
|
||||
public function provideData(): \Iterator
|
||||
{
|
||||
yield [new \Symplify\SmartFileSystem\SmartFileInfo(__DIR__ . '/Fixture/fixture.php.inc'), '__ExtraFileName__', __DIR__ . '/Source/extra_file.php'];
|
||||
yield [new \Symplify\SmartFileSystem\SmartFileInfo(__DIR__ . '/Fixture/some_class.php.inc'), '__ExtraFileName__', __DIR__ . '/Source/extra_file.php'];
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -19,7 +19,7 @@ final class __Name__Test extends AbstractRectorTestCase
|
||||
|
||||
public function provideData(): \Iterator
|
||||
{
|
||||
yield [new \Symplify\SmartFileSystem\SmartFileInfo(__DIR__ . '/Fixture/fixture.php.inc'), '__ExtraFileName__', __DIR__ . '/Source/extra_file.php'];
|
||||
yield [new \Symplify\SmartFileSystem\SmartFileInfo(__DIR__ . '/Fixture/some_class.php.inc'), '__ExtraFileName__', __DIR__ . '/Source/extra_file.php'];
|
||||
}
|
||||
|
||||
protected function getRectorClass(): string
|
||||
|
@ -0,0 +1,111 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Php80\Rector\ClassMethod;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Param;
|
||||
use PhpParser\Node\Stmt\ClassMethod;
|
||||
use Rector\Core\Rector\AbstractRector;
|
||||
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
|
||||
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
|
||||
|
||||
/**
|
||||
* @see https://php.watch/versions/8.0#deprecate-required-param-after-optional
|
||||
*
|
||||
* @see \Rector\Php80\Tests\Rector\ClassMethod\OptionalParametersAfterRequiredRector\OptionalParametersAfterRequiredRectorTest
|
||||
*/
|
||||
final class OptionalParametersAfterRequiredRector extends AbstractRector
|
||||
{
|
||||
public function getRuleDefinition(): RuleDefinition
|
||||
{
|
||||
return new RuleDefinition('Move required parameters after optional ones', [
|
||||
new CodeSample(
|
||||
<<<'CODE_SAMPLE'
|
||||
class SomeObject
|
||||
{
|
||||
public function run($optional = 1, $required)
|
||||
{
|
||||
}
|
||||
}
|
||||
CODE_SAMPLE
|
||||
|
||||
,
|
||||
<<<'CODE_SAMPLE'
|
||||
class SomeObject
|
||||
{
|
||||
public function run($required, $optional = 1)
|
||||
{
|
||||
}
|
||||
}
|
||||
CODE_SAMPLE
|
||||
|
||||
),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
public function getNodeTypes(): array
|
||||
{
|
||||
return [ClassMethod::class];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ClassMethod $node
|
||||
*/
|
||||
public function refactor(Node $node): ?Node
|
||||
{
|
||||
if ($node->params === []) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$requireParams = $this->resolveRequiredParams($node);
|
||||
$optionalParams = $this->resolveOptionalParams($node);
|
||||
|
||||
$expectedOrderParams = array_merge($requireParams, $optionalParams);
|
||||
if ($node->params === $expectedOrderParams) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$node->params = $expectedOrderParams;
|
||||
|
||||
return $node;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<int, Param>
|
||||
*/
|
||||
private function resolveOptionalParams(ClassMethod $classMethod): array
|
||||
{
|
||||
$paramsByPosition = [];
|
||||
foreach ($classMethod->params as $position => $param) {
|
||||
if ($param->default === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$paramsByPosition[$position] = $param;
|
||||
}
|
||||
|
||||
return $paramsByPosition;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Param[]
|
||||
*/
|
||||
private function resolveRequiredParams(ClassMethod $classMethod): array
|
||||
{
|
||||
$paramsByPosition = [];
|
||||
foreach ($classMethod->params as $param) {
|
||||
if ($param->default !== null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$paramsByPosition[] = $param;
|
||||
}
|
||||
|
||||
return $paramsByPosition;
|
||||
}
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace Rector\Php80\Tests\Rector\ClassMethod\OptionalParametersAfterRequiredRector\Fixture;
|
||||
|
||||
class Mashup
|
||||
{
|
||||
public function run($optional = 1, $required, $anotherOptional = false, $yetRequired)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
-----
|
||||
<?php
|
||||
|
||||
namespace Rector\Php80\Tests\Rector\ClassMethod\OptionalParametersAfterRequiredRector\Fixture;
|
||||
|
||||
class Mashup
|
||||
{
|
||||
public function run($required, $yetRequired, $optional = 1, $anotherOptional = false)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Php80\Tests\Rector\ClassMethod\OptionalParametersAfterRequiredRector\Fixture;
|
||||
|
||||
final class SkipCorrectOrder
|
||||
{
|
||||
public function run($required, $optional = 1)
|
||||
{
|
||||
}
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace Rector\Php80\Tests\Rector\ClassMethod\OptionalParametersAfterRequiredRector\Fixture;
|
||||
|
||||
final class SkipNoParams
|
||||
{
|
||||
public function run()
|
||||
{
|
||||
}
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace Rector\Php80\Tests\Rector\ClassMethod\OptionalParametersAfterRequiredRector\Fixture;
|
||||
|
||||
class SomeObject
|
||||
{
|
||||
public function run($optional = 1, $required)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
-----
|
||||
<?php
|
||||
|
||||
namespace Rector\Php80\Tests\Rector\ClassMethod\OptionalParametersAfterRequiredRector\Fixture;
|
||||
|
||||
class SomeObject
|
||||
{
|
||||
public function run($required, $optional = 1)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Php80\Tests\Rector\ClassMethod\OptionalParametersAfterRequiredRector;
|
||||
|
||||
use Iterator;
|
||||
use Rector\Php80\Rector\ClassMethod\OptionalParametersAfterRequiredRector;
|
||||
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
|
||||
use Symplify\SmartFileSystem\SmartFileInfo;
|
||||
|
||||
final class OptionalParametersAfterRequiredRectorTest extends AbstractRectorTestCase
|
||||
{
|
||||
/**
|
||||
* @dataProvider provideData()
|
||||
*/
|
||||
public function test(SmartFileInfo $fileInfo): void
|
||||
{
|
||||
$this->doTestFileInfo($fileInfo);
|
||||
}
|
||||
|
||||
public function provideData(): Iterator
|
||||
{
|
||||
return $this->yieldFilesFromDirectory(__DIR__ . '/Fixture');
|
||||
}
|
||||
|
||||
protected function getRectorClass(): string
|
||||
{
|
||||
return OptionalParametersAfterRequiredRector::class;
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user