[DowngradePhp80] Add return property downgrade case (#1415)

This commit is contained in:
Tomas Votruba 2021-12-07 21:48:15 +03:00 committed by GitHub
parent a78fc17015
commit 327144efdf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 196 additions and 168 deletions

View File

@ -124,11 +124,9 @@ return static function (ContainerConfigurator $containerConfigurator): void {
$services = $containerConfigurator->services();
$services->set(ArgumentAdderRector::class)
->configure([
ArgumentAdderRector::ADDED_ARGUMENTS => [
new ArgumentAdder('SomeExampleClass', 'someMethod', 0, 'someArgument', true, new ObjectType('SomeType')),
],
]);
->configure(
[new ArgumentAdder('SomeExampleClass', 'someMethod', 0, 'someArgument', true, new ObjectType('SomeType'))]
);
};
```
@ -2600,11 +2598,7 @@ return static function (ContainerConfigurator $containerConfigurator): void {
$services = $containerConfigurator->services();
$services->set(AddPackageToRequireComposerRector::class)
->configure([
AddPackageToRequireComposerRector::PACKAGES_AND_VERSIONS => [
new PackageAndVersion('symfony/console', '^3.4'),
],
]);
->configure([new PackageAndVersion('symfony/console', '^3.4')]);
};
```
@ -2637,11 +2631,7 @@ return static function (ContainerConfigurator $containerConfigurator): void {
$services = $containerConfigurator->services();
$services->set(AddPackageToRequireDevComposerRector::class)
->configure([
AddPackageToRequireDevComposerRector::PACKAGES_AND_VERSIONS => [
new PackageAndVersion('symfony/console', '^3.4'),
],
]);
->configure([new PackageAndVersion('symfony/console', '^3.4')]);
};
```
@ -2674,11 +2664,7 @@ return static function (ContainerConfigurator $containerConfigurator): void {
$services = $containerConfigurator->services();
$services->set(ChangePackageVersionComposerRector::class)
->configure([
ChangePackageVersionComposerRector::PACKAGES_AND_VERSIONS => [
new PackageAndVersion('symfony/console', '^4.4'),
],
]);
->configure([new PackageAndVersion('symfony/console', '^4.4')]);
};
```
@ -2712,9 +2698,7 @@ return static function (ContainerConfigurator $containerConfigurator): void {
$services = $containerConfigurator->services();
$services->set(RemovePackageComposerRector::class)
->configure([
RemovePackageComposerRector::PACKAGE_NAMES => ['symfony/console'],
]);
->configure(['symfony/console']);
};
```
@ -2747,9 +2731,7 @@ return static function (ContainerConfigurator $containerConfigurator): void {
$services = $containerConfigurator->services();
$services->set(RenamePackageComposerRector::class)
->configure([
RenamePackageComposerRector::RENAME_PACKAGES => [new RenamePackage('rector/rector', 'rector/rector-src')],
]);
->configure([new RenamePackage('rector/rector', 'rector/rector-src')]);
};
```
@ -2783,11 +2765,7 @@ return static function (ContainerConfigurator $containerConfigurator): void {
$services = $containerConfigurator->services();
$services->set(ReplacePackageAndVersionComposerRector::class)
->configure([
ReplacePackageAndVersionComposerRector::REPLACE_PACKAGES_AND_VERSIONS => [
new ReplacePackageAndVersion('symfony/console', 'symfony/http-kernel', '^4.4'),
],
]);
->configure([new ReplacePackageAndVersion('symfony/console', 'symfony/http-kernel', '^4.4')]);
};
```
@ -5498,22 +5476,17 @@ Downgrade `str_starts_with()` to `strncmp()` version
### DowngradeThrowExprRector
Downgrade throw as expr
Downgrade throw expression
- class: [`Rector\DowngradePhp80\Rector\Expression\DowngradeThrowExprRector`](../rules/DowngradePhp80/Rector/Expression/DowngradeThrowExprRector.php)
```diff
class SomeClass
{
public function run()
{
- $id = $somethingNonexistent ?? throw new RuntimeException();
+ if (!isset($somethingNonexistent)) {
+ throw new RuntimeException();
+ }
+ $id = $somethingNonexistent;
}
}
-echo $variable ?? throw new RuntimeException();
+if (! isset($variable)) {
+ throw new RuntimeException();
+}
+
+echo $variable;
```
<br>
@ -9129,9 +9102,7 @@ return static function (ContainerConfigurator $containerConfigurator): void {
$services = $containerConfigurator->services();
$services->set(RemoveFuncCallRector::class)
->configure([
RemoveFuncCallRector::REMOVE_FUNC_CALLS => [new RemoveFuncCall('ini_get', [['y2k_compliance']])],
]);
->configure([new RemoveFuncCall('ini_get', [['y2k_compliance']])]);
};
```
@ -9451,16 +9422,16 @@ Replaces defined class constants in their calls.
```php
use Rector\Renaming\Rector\ClassConstFetch\RenameClassConstFetchRector;
use Rector\Renaming\ValueObject\RenameClassAndConstFetch;
use Rector\Renaming\ValueObject\RenameClassConstFetch;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
return static function (ContainerConfigurator $containerConfigurator): void {
$services = $containerConfigurator->services();
$services->set(RenameClassConstFetchRector::class)
->configure([new RenameClassConstFetch('SomeClass', 'OLD_CONSTANT', 'NEW_CONSTANT')])
->configure([
RenameClassConstFetchRector::CLASS_CONSTANT_RENAME => [
new RenameClassAndConstFetch('SomeClass', 'OTHER_OLD_CONSTANT', 'DifferentClass', 'NEW_CONSTANT'),
],
1 => new RenameClassAndConstFetch('SomeClass', 'OTHER_OLD_CONSTANT', 'DifferentClass', 'NEW_CONSTANT'),
]);
};
```
@ -9699,11 +9670,7 @@ return static function (ContainerConfigurator $containerConfigurator): void {
$services = $containerConfigurator->services();
$services->set(RenameStaticMethodRector::class)
->configure([
RenameStaticMethodRector::OLD_TO_NEW_METHODS_BY_CLASSES => [
new RenameStaticMethod('SomeClass', 'oldMethod', 'AnotherExampleClass', 'newStaticMethod'),
],
]);
->configure([new RenameStaticMethod('SomeClass', 'oldMethod', 'AnotherExampleClass', 'newStaticMethod')]);
};
```
@ -9716,32 +9683,6 @@ return static function (ContainerConfigurator $containerConfigurator): void {
<br>
```php
use Rector\Renaming\Rector\StaticCall\RenameStaticMethodRector;
use Rector\Renaming\ValueObject\RenameStaticMethod;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
return static function (ContainerConfigurator $containerConfigurator): void {
$services = $containerConfigurator->services();
$services->set(RenameStaticMethodRector::class)
->configure([
RenameStaticMethodRector::OLD_TO_NEW_METHODS_BY_CLASSES => [
new RenameStaticMethod('SomeClass', 'oldMethod', 'SomeClass', 'newStaticMethod'),
],
]);
};
```
```diff
-SomeClass::oldStaticMethod();
+SomeClass::newStaticMethod();
```
<br>
### RenameStringRector
Change string value
@ -10992,10 +10933,9 @@ return static function (ContainerConfigurator $containerConfigurator): void {
$services = $containerConfigurator->services();
$services->set(PropertyFetchToMethodCallRector::class)
->configure([new PropertyFetchToMethodCall('SomeObject', 'property', 'getProperty', 'setProperty', [])])
->configure([
PropertyFetchToMethodCallRector::PROPERTIES_TO_METHOD_CALLS => [
new PropertyFetchToMethodCall('SomeObject', 'property', 'getProperty', 'setProperty', []),
],
1 => new PropertyFetchToMethodCall('SomeObject', 'bareProperty', 'getConfig', ['someArg']),
]);
};
```
@ -11007,32 +10947,9 @@ return static function (ContainerConfigurator $containerConfigurator): void {
-$object->property = $value;
+$result = $object->getProperty();
+$object->setProperty($value);
```
<br>
```php
use Rector\Transform\Rector\Assign\PropertyFetchToMethodCallRector;
use Rector\Transform\ValueObject\PropertyFetchToMethodCall;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
return static function (ContainerConfigurator $containerConfigurator): void {
$services = $containerConfigurator->services();
$services->set(PropertyFetchToMethodCallRector::class)
->configure([
PropertyFetchToMethodCallRector::PROPERTIES_TO_METHOD_CALLS => [
new PropertyFetchToMethodCall('SomeObject', 'property', 'getConfig', ['someArg']),
],
]);
};
```
```diff
-$result = $object->property;
+$result = $object->getProperty('someArg');
-$bare = $object->bareProperty;
+$bare = $object->getConfig('someArg');
```
<br>
@ -11559,11 +11476,7 @@ return static function (ContainerConfigurator $containerConfigurator): void {
$services = $containerConfigurator->services();
$services->set(AddParamTypeDeclarationRector::class)
->configure([
AddParamTypeDeclarationRector::PARAMETER_TYPEHINTS => [
new AddParamTypeDeclaration('SomeClass', 'process', 0, new StringType()),
],
]);
->configure([new AddParamTypeDeclaration('SomeClass', 'process', 0, new StringType())]);
};
```
@ -11634,13 +11547,11 @@ return static function (ContainerConfigurator $containerConfigurator): void {
$services = $containerConfigurator->services();
$services->set(AddReturnTypeDeclarationRector::class)
->configure([
AddReturnTypeDeclarationRector::METHOD_RETURN_TYPES => [
new AddReturnTypeDeclaration('SomeClass', 'getData', new ArrayType(new MixedType(false), new MixedType(
false
))),
],
]);
->configure(
[new AddReturnTypeDeclaration('SomeClass', 'getData', new ArrayType(new MixedType(false), new MixedType(
false
)))]
);
};
```

View File

@ -0,0 +1,34 @@
<?php
namespace Rector\Tests\DowngradePhp80\Rector\Expression\DowngradeThrowExprRector\Fixture;
use Symfony\Component\Console\Helper\ProgressBar;
final class ReturnThrowVariable
{
public function run()
{
return $variable ?? throw new \InvalidArgumentException();
}
}
?>
-----
<?php
namespace Rector\Tests\DowngradePhp80\Rector\Expression\DowngradeThrowExprRector\Fixture;
use Symfony\Component\Console\Helper\ProgressBar;
final class ReturnThrowVariable
{
public function run()
{
if (!isset($variable)) {
throw new \InvalidArgumentException();
}
return $variable;
}
}
?>

View File

@ -0,0 +1,44 @@
<?php
namespace Rector\Tests\DowngradePhp80\Rector\Expression\DowngradeThrowExprRector\Fixture;
use Symfony\Component\Console\Helper\ProgressBar;
final class ThrowPropertyFetch
{
public function __construct(
private ProgressBar|null $progressBar
) {
}
public function run()
{
return $this->progressBar ?? throw new \InvalidArgumentException();
}
}
?>
-----
<?php
namespace Rector\Tests\DowngradePhp80\Rector\Expression\DowngradeThrowExprRector\Fixture;
use Symfony\Component\Console\Helper\ProgressBar;
final class ThrowPropertyFetch
{
public function __construct(
private ProgressBar|null $progressBar
) {
}
public function run()
{
if ($this->progressBar === null) {
throw new \InvalidArgumentException();
}
return $this->progressBar;
}
}
?>

View File

@ -7,12 +7,16 @@ namespace Rector\DowngradePhp80\Rector\Expression;
use PhpParser\Node;
use PhpParser\Node\Expr\Assign;
use PhpParser\Node\Expr\BinaryOp\Coalesce;
use PhpParser\Node\Expr\BinaryOp\Identical;
use PhpParser\Node\Expr\BooleanNot;
use PhpParser\Node\Expr\Isset_;
use PhpParser\Node\Expr\Ternary;
use PhpParser\Node\Expr\Throw_;
use PhpParser\Node\Expr\Variable;
use PhpParser\Node\Stmt;
use PhpParser\Node\Stmt\Expression;
use PhpParser\Node\Stmt\If_;
use PhpParser\Node\Stmt\Return_;
use Rector\Core\NodeAnalyzer\CoalesceAnalyzer;
use Rector\Core\NodeManipulator\BinaryOpManipulator;
use Rector\Core\NodeManipulator\IfManipulator;
@ -36,30 +40,19 @@ final class DowngradeThrowExprRector extends AbstractRector
public function getRuleDefinition(): RuleDefinition
{
return new RuleDefinition('Downgrade throw as expr', [
return new RuleDefinition('Downgrade throw expression', [
new CodeSample(
<<<'CODE_SAMPLE'
class SomeClass
{
public function run()
{
$id = $somethingNonexistent ?? throw new RuntimeException();
}
}
echo $variable ?? throw new RuntimeException();
CODE_SAMPLE
,
<<<'CODE_SAMPLE'
class SomeClass
{
public function run()
{
if (!isset($somethingNonexistent)) {
throw new RuntimeException();
}
$id = $somethingNonexistent;
}
if (! isset($variable)) {
throw new RuntimeException();
}
echo $variable;
CODE_SAMPLE
),
]);
@ -70,41 +63,49 @@ CODE_SAMPLE
*/
public function getNodeTypes(): array
{
return [Expression::class];
return [Expression::class, Return_::class];
}
/**
* @param Expression $node
* @param Expression|Return_ $node
* @return Node|Node[]|null
*/
public function refactor(Node $node): ?Node
public function refactor(Node $node)
{
if ($node instanceof Return_) {
return $this->refactorReturn($node);
}
if ($node->expr instanceof Throw_) {
return null;
}
if ($node->expr instanceof Assign) {
return $this->processAssign($node, $node->expr);
return $this->refactorAssign($node, $node->expr);
}
if ($node->expr instanceof Coalesce) {
return $this->processCoalesce($node->expr, null);
return $this->refactorCoalesce($node->expr, null);
}
if ($node->expr instanceof Ternary) {
return $this->processTernary($node->expr, null);
return $this->refactorTernary($node->expr, null);
}
return $node;
return null;
}
private function processAssign(Expression $expression, Assign $assign): If_ | Expression | null
/**
* @return If_|Expression|Stmt[]|null
*/
private function refactorAssign(Expression $expression, Assign $assign): If_ | Expression | null | array
{
if (! $this->hasThrowInAssignExpr($assign)) {
return null;
}
if ($assign->expr instanceof Coalesce) {
return $this->processCoalesce($assign->expr, $assign);
return $this->refactorCoalesce($assign->expr, $assign);
}
if ($assign->expr instanceof Throw_) {
@ -112,13 +113,16 @@ CODE_SAMPLE
}
if ($assign->expr instanceof Ternary) {
return $this->processTernary($assign->expr, $assign);
return $this->refactorTernary($assign->expr, $assign);
}
return $expression;
}
private function processTernary(Ternary $ternary, ?Assign $assign): ?If_
/**
* @return If_|Stmt[]|null
*/
private function refactorTernary(Ternary $ternary, ?Assign $assign): If_|null|array
{
if (! $ternary->else instanceof Throw_) {
return null;
@ -133,11 +137,13 @@ CODE_SAMPLE
$assign->expr = $ternary->if ?? $ternary->cond;
$this->nodesToAddCollector->addNodeAfterNode(new Expression($assign), $if);
return $if;
return [$if, new Expression($assign)];
}
private function processCoalesce(Coalesce $coalesce, ?Assign $assign): ?If_
/**
* @return If_|Stmt[]|null
*/
private function refactorCoalesce(Coalesce $coalesce, ?Assign $assign): If_|null|array
{
if (! $coalesce->right instanceof Throw_) {
return null;
@ -147,15 +153,16 @@ CODE_SAMPLE
return null;
}
$booleanNot = new BooleanNot(new Isset_([$coalesce->left]));
$if = $this->ifManipulator->createIfExpr($booleanNot, new Expression($coalesce->right));
$condExpr = $this->createCondExpr($coalesce);
$if = $this->ifManipulator->createIfExpr($condExpr, new Expression($coalesce->right));
if (! $assign instanceof Assign) {
return $if;
}
$assign->expr = $coalesce->left;
$this->nodesToAddCollector->addNodeAfterNode(new Expression($assign), $if);
return $if;
return [$if, new Expression($assign)];
}
private function hasThrowInAssignExpr(Assign $assign): bool
@ -165,4 +172,45 @@ CODE_SAMPLE
fn (Node $node): bool => $node instanceof Throw_
);
}
/**
* @return Node[]|null
*/
private function refactorReturn(Return_ $return): ?array
{
$throwExpr = $this->betterNodeFinder->findFirstInstanceOf($return, Throw_::class);
if (! $throwExpr instanceof Throw_) {
return null;
}
if ($return->expr instanceof Coalesce) {
$coalesce = $return->expr;
if (! $coalesce->right instanceof Throw_) {
return null;
}
$if = $this->createIf($coalesce, $coalesce->right);
return [$if, new Return_($coalesce->left)];
}
return null;
}
private function createIf(Coalesce $coalesce, Throw_ $throw): If_
{
$condExpr = $this->createCondExpr($coalesce);
return new If_($condExpr, [
'stmts' => [new Expression($throw)],
]);
}
private function createCondExpr(Coalesce $coalesce): BooleanNot|Identical
{
if ($coalesce->left instanceof Variable) {
return new BooleanNot(new Isset_([$coalesce->left]));
}
return new Identical($coalesce->left, $this->nodeFactory->createNull());
}
}

View File

@ -258,23 +258,14 @@ final class IfManipulator
public function createIfNegation(Expr $expr, Stmt $stmt): If_
{
$expr = $this->conditionInverter->createInvertedCondition($expr);
return new If_(
$expr,
[
'stmts' => [$stmt],
]
);
return $this->createIfExpr($expr, $stmt);
}
public function createIfExpr(Expr $expr, Stmt $stmt): If_
{
return new If_(
$expr,
[
'stmts' => [$stmt],
]
);
return new If_($expr, [
'stmts' => [$stmt],
]);
}
private function matchComparedAndReturnedNode(NotIdentical $notIdentical, Return_ $return): ?Expr