mirror of
https://github.com/rectorphp/rector.git
synced 2024-05-28 23:10:51 +00:00
[Strict] Add rules to resolve PHPStan Strict rule set (#955)
Co-authored-by: GitHub Action <action@github.com>
This commit is contained in:
parent
687f9e9de9
commit
c4de350289
|
@ -1,4 +1,4 @@
|
|||
# 477 Rules Overview
|
||||
# 482 Rules Overview
|
||||
|
||||
<br>
|
||||
|
||||
|
@ -92,6 +92,8 @@
|
|||
|
||||
- [Restoration](#restoration) (6)
|
||||
|
||||
- [Strict](#strict) (5)
|
||||
|
||||
- [Transform](#transform) (34)
|
||||
|
||||
- [TypeDeclaration](#typedeclaration) (20)
|
||||
|
@ -9774,6 +9776,111 @@ Rename file to respect class name
|
|||
|
||||
<br>
|
||||
|
||||
## Strict
|
||||
|
||||
### BooleanInBooleanNotRuleFixerRector
|
||||
|
||||
Fixer for PHPStan reports by strict type rule - "PHPStan\Rules\BooleansInConditions\BooleanInBooleanNotRule"
|
||||
|
||||
- class: [`Rector\Strict\Rector\BooleanNot\BooleanInBooleanNotRuleFixerRector`](../rules/Strict/Rector/BooleanNot/BooleanInBooleanNotRuleFixerRector.php)
|
||||
|
||||
```diff
|
||||
class SomeClass
|
||||
{
|
||||
public function run(string $name)
|
||||
{
|
||||
- if (! $name) {
|
||||
+ if ($name !== '') {
|
||||
return 'name';
|
||||
}
|
||||
|
||||
return 'no name';
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
<br>
|
||||
|
||||
### BooleanInIfConditionRuleFixerRector
|
||||
|
||||
Fixer for PHPStan reports by strict type rule - "PHPStan\Rules\BooleansInConditions\BooleanInIfConditionRule"
|
||||
|
||||
- class: [`Rector\Strict\Rector\If_\BooleanInIfConditionRuleFixerRector`](../rules/Strict/Rector/If_/BooleanInIfConditionRuleFixerRector.php)
|
||||
|
||||
```diff
|
||||
final class NegatedString
|
||||
{
|
||||
public function run(string $name)
|
||||
{
|
||||
- if ($name) {
|
||||
+ if ($name !== '') {
|
||||
return 'name';
|
||||
}
|
||||
|
||||
return 'no name';
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
<br>
|
||||
|
||||
### BooleanInTernaryOperatorRuleFixerRector
|
||||
|
||||
Fixer for PHPStan reports by strict type rule - "PHPStan\Rules\BooleansInConditions\BooleanInTernaryOperatorRule"
|
||||
|
||||
- class: [`Rector\Strict\Rector\Ternary\BooleanInTernaryOperatorRuleFixerRector`](../rules/Strict/Rector/Ternary/BooleanInTernaryOperatorRuleFixerRector.php)
|
||||
|
||||
```diff
|
||||
final class ArrayCompare
|
||||
{
|
||||
public function run(array $data)
|
||||
{
|
||||
- return $data ? 1 : 2;
|
||||
+ return $data !== [] ? 1 : 2;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
<br>
|
||||
|
||||
### DisallowedEmptyRuleFixerRector
|
||||
|
||||
Fixer for PHPStan reports by strict type rule - "PHPStan\Rules\DisallowedConstructs\DisallowedEmptyRule"
|
||||
|
||||
- class: [`Rector\Strict\Rector\Empty_\DisallowedEmptyRuleFixerRector`](../rules/Strict/Rector/Empty_/DisallowedEmptyRuleFixerRector.php)
|
||||
|
||||
```diff
|
||||
final class SomeEmptyArray
|
||||
{
|
||||
public function run(array $items)
|
||||
{
|
||||
- return empty($items);
|
||||
+ return $items === [];
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
<br>
|
||||
|
||||
### DisallowedShortTernaryRuleFixerRector
|
||||
|
||||
Fixer for PHPStan reports by strict type rule - "PHPStan\Rules\DisallowedConstructs\DisallowedShortTernaryRule"
|
||||
|
||||
- class: [`Rector\Strict\Rector\Ternary\DisallowedShortTernaryRuleFixerRector`](../rules/Strict/Rector/Ternary/DisallowedShortTernaryRuleFixerRector.php)
|
||||
|
||||
```diff
|
||||
final class ShortTernaryArray
|
||||
{
|
||||
public function run(array $array)
|
||||
{
|
||||
- return $array ?: 2;
|
||||
+ return $array !== [] ? $array : 2;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
<br>
|
||||
|
||||
## Transform
|
||||
|
||||
### AddInterfaceByParentRector
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Tests\Strict\Rector\BooleanNot\BooleanInBooleanNotRuleFixerRector;
|
||||
|
||||
use Iterator;
|
||||
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
|
||||
use Symplify\SmartFileSystem\SmartFileInfo;
|
||||
|
||||
final class BooleanInBooleanNotRuleFixerRectorTest 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';
|
||||
}
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Tests\Strict\Rector\BooleanNot\BooleanInBooleanNotRuleFixerRector\Fixture;
|
||||
|
||||
final class NegatedInteger
|
||||
{
|
||||
private int $age;
|
||||
|
||||
public function run()
|
||||
{
|
||||
if (! $this->age) {
|
||||
return 'age';
|
||||
}
|
||||
|
||||
return 'no age';
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
-----
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Tests\Strict\Rector\BooleanNot\BooleanInBooleanNotRuleFixerRector\Fixture;
|
||||
|
||||
final class NegatedInteger
|
||||
{
|
||||
private int $age;
|
||||
|
||||
public function run()
|
||||
{
|
||||
if ($this->age === 0) {
|
||||
return 'age';
|
||||
}
|
||||
|
||||
return 'no age';
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,43 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Tests\Strict\Rector\BooleanNot\BooleanInBooleanNotRuleFixerRector\Fixture;
|
||||
|
||||
final class NegatedString
|
||||
{
|
||||
private string $name = '';
|
||||
|
||||
public function run()
|
||||
{
|
||||
if (!$this->name) {
|
||||
return 'name';
|
||||
}
|
||||
|
||||
return 'no name';
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
-----
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Tests\Strict\Rector\BooleanNot\BooleanInBooleanNotRuleFixerRector\Fixture;
|
||||
|
||||
final class NegatedString
|
||||
{
|
||||
private string $name = '';
|
||||
|
||||
public function run()
|
||||
{
|
||||
if ($this->name === '') {
|
||||
return 'name';
|
||||
}
|
||||
|
||||
return 'no name';
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,39 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Tests\Strict\Rector\BooleanNot\BooleanInBooleanNotRuleFixerRector\Fixture;
|
||||
|
||||
final class UnionNullBoolean
|
||||
{
|
||||
public function run(bool|null $maye)
|
||||
{
|
||||
if (! $maye) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
-----
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Tests\Strict\Rector\BooleanNot\BooleanInBooleanNotRuleFixerRector\Fixture;
|
||||
|
||||
final class UnionNullBoolean
|
||||
{
|
||||
public function run(bool|null $maye)
|
||||
{
|
||||
if ($maye === true) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,49 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Tests\Strict\Rector\BooleanNot\BooleanInBooleanNotRuleFixerRector\Fixture;
|
||||
|
||||
final class UnionWithNull
|
||||
{
|
||||
/**
|
||||
* @var string|null
|
||||
*/
|
||||
private $value;
|
||||
|
||||
public function run()
|
||||
{
|
||||
if (! $this->value) {
|
||||
return 'empty';
|
||||
}
|
||||
|
||||
return 'set';
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
-----
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Tests\Strict\Rector\BooleanNot\BooleanInBooleanNotRuleFixerRector\Fixture;
|
||||
|
||||
final class UnionWithNull
|
||||
{
|
||||
/**
|
||||
* @var string|null
|
||||
*/
|
||||
private $value;
|
||||
|
||||
public function run()
|
||||
{
|
||||
if ($this->value === null) {
|
||||
return 'empty';
|
||||
}
|
||||
|
||||
return 'set';
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,11 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Rector\Strict\Rector\BooleanNot\BooleanInBooleanNotRuleFixerRector;
|
||||
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
|
||||
|
||||
return static function (ContainerConfigurator $containerConfigurator): void {
|
||||
$services = $containerConfigurator->services();
|
||||
$services->set(BooleanInBooleanNotRuleFixerRector::class);
|
||||
};
|
|
@ -0,0 +1,33 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Tests\Strict\Rector\Empty_\DisallowedEmptyRuleFixerRector;
|
||||
|
||||
use Iterator;
|
||||
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
|
||||
use Symplify\SmartFileSystem\SmartFileInfo;
|
||||
|
||||
final class DisallowedEmptyRuleFixerRectorTest 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';
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
<?php
|
||||
|
||||
namespace Rector\Tests\Strict\Rector\Empty_\DisallowedEmptyRuleFixerRector\Fixture;
|
||||
|
||||
final class NegatedEmptyArray
|
||||
{
|
||||
public function run(array $items)
|
||||
{
|
||||
return ! empty($items);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
-----
|
||||
<?php
|
||||
|
||||
namespace Rector\Tests\Strict\Rector\Empty_\DisallowedEmptyRuleFixerRector\Fixture;
|
||||
|
||||
final class NegatedEmptyArray
|
||||
{
|
||||
public function run(array $items)
|
||||
{
|
||||
return $items !== [];
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,14 @@
|
|||
<?php
|
||||
|
||||
namespace Rector\Tests\Strict\Rector\Empty_\DisallowedEmptyRuleFixerRector\Fixture;
|
||||
|
||||
final class SkipMultiUnionTypes
|
||||
{
|
||||
/**
|
||||
* @param int|int[]|null|string $id
|
||||
*/
|
||||
public function get($id)
|
||||
{
|
||||
return empty($id);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
<?php
|
||||
|
||||
namespace Rector\Tests\Strict\Rector\Empty_\DisallowedEmptyRuleFixerRector\Fixture;
|
||||
|
||||
final class SomeEmptyArray
|
||||
{
|
||||
public function run(array $items)
|
||||
{
|
||||
return empty($items);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
-----
|
||||
<?php
|
||||
|
||||
namespace Rector\Tests\Strict\Rector\Empty_\DisallowedEmptyRuleFixerRector\Fixture;
|
||||
|
||||
final class SomeEmptyArray
|
||||
{
|
||||
public function run(array $items)
|
||||
{
|
||||
return $items === [];
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,27 @@
|
|||
<?php
|
||||
|
||||
namespace Rector\Tests\Strict\Rector\Empty_\DisallowedEmptyRuleFixerRector\Fixture;
|
||||
|
||||
final class UnionObjectNullable
|
||||
{
|
||||
public function run(null|\DateTime $dateTime)
|
||||
{
|
||||
return empty($dateTime);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
-----
|
||||
<?php
|
||||
|
||||
namespace Rector\Tests\Strict\Rector\Empty_\DisallowedEmptyRuleFixerRector\Fixture;
|
||||
|
||||
final class UnionObjectNullable
|
||||
{
|
||||
public function run(null|\DateTime $dateTime)
|
||||
{
|
||||
return $dateTime === null;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,11 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Rector\Strict\Rector\Empty_\DisallowedEmptyRuleFixerRector;
|
||||
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
|
||||
|
||||
return static function (ContainerConfigurator $containerConfigurator): void {
|
||||
$services = $containerConfigurator->services();
|
||||
$services->set(DisallowedEmptyRuleFixerRector::class);
|
||||
};
|
|
@ -0,0 +1,33 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Tests\Strict\Rector\If_\BooleanInIfConditionRuleFixerRector;
|
||||
|
||||
use Iterator;
|
||||
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
|
||||
use Symplify\SmartFileSystem\SmartFileInfo;
|
||||
|
||||
final class BooleanInIfConditionRuleFixerRectorTest 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';
|
||||
}
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Tests\Strict\Rector\If_\BooleanInIfConditionRuleFixerRector\Fixture;
|
||||
|
||||
final class ArrayFromFilter
|
||||
{
|
||||
public function run(array $items)
|
||||
{
|
||||
if ($items) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
-----
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Tests\Strict\Rector\If_\BooleanInIfConditionRuleFixerRector\Fixture;
|
||||
|
||||
final class ArrayFromFilter
|
||||
{
|
||||
public function run(array $items)
|
||||
{
|
||||
if ($items !== []) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,47 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Tests\Strict\Rector\If_\BooleanInIfConditionRuleFixerRector\Fixture;
|
||||
|
||||
final class ElseIfNegatedString
|
||||
{
|
||||
private string $name = '';
|
||||
|
||||
public function run(bool $boolValue)
|
||||
{
|
||||
if ($boolValue) {
|
||||
return 'bool';
|
||||
} elseif ($this->name) {
|
||||
return 'name';
|
||||
}
|
||||
|
||||
return 'no name';
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
-----
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Tests\Strict\Rector\If_\BooleanInIfConditionRuleFixerRector\Fixture;
|
||||
|
||||
final class ElseIfNegatedString
|
||||
{
|
||||
private string $name = '';
|
||||
|
||||
public function run(bool $boolValue)
|
||||
{
|
||||
if ($boolValue) {
|
||||
return 'bool';
|
||||
} elseif ($this->name !== '') {
|
||||
return 'name';
|
||||
}
|
||||
|
||||
return 'no name';
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,43 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Tests\Strict\Rector\If_\BooleanInIfConditionRuleFixerRector\Fixture;
|
||||
|
||||
final class NegatedString
|
||||
{
|
||||
private string $name = '';
|
||||
|
||||
public function run()
|
||||
{
|
||||
if ($this->name) {
|
||||
return 'name';
|
||||
}
|
||||
|
||||
return 'no name';
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
-----
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Tests\Strict\Rector\If_\BooleanInIfConditionRuleFixerRector\Fixture;
|
||||
|
||||
final class NegatedString
|
||||
{
|
||||
private string $name = '';
|
||||
|
||||
public function run()
|
||||
{
|
||||
if ($this->name !== '') {
|
||||
return 'name';
|
||||
}
|
||||
|
||||
return 'no name';
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,39 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Tests\Strict\Rector\If_\BooleanInIfConditionRuleFixerRector\Fixture;
|
||||
|
||||
final class NullableBool
|
||||
{
|
||||
public function run(bool|null $value)
|
||||
{
|
||||
if ($value) {
|
||||
return 'yes';
|
||||
}
|
||||
|
||||
return 'no';
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
-----
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Tests\Strict\Rector\If_\BooleanInIfConditionRuleFixerRector\Fixture;
|
||||
|
||||
final class NullableBool
|
||||
{
|
||||
public function run(bool|null $value)
|
||||
{
|
||||
if ($value === true) {
|
||||
return 'yes';
|
||||
}
|
||||
|
||||
return 'no';
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,39 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Tests\Strict\Rector\If_\BooleanInIfConditionRuleFixerRector\Fixture;
|
||||
|
||||
final class NullableObject
|
||||
{
|
||||
public function run(\stdClass|null $value)
|
||||
{
|
||||
if ($value) {
|
||||
return 'yes';
|
||||
}
|
||||
|
||||
return 'no';
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
-----
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Tests\Strict\Rector\If_\BooleanInIfConditionRuleFixerRector\Fixture;
|
||||
|
||||
final class NullableObject
|
||||
{
|
||||
public function run(\stdClass|null $value)
|
||||
{
|
||||
if ($value instanceof \stdClass) {
|
||||
return 'yes';
|
||||
}
|
||||
|
||||
return 'no';
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,11 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Rector\Strict\Rector\If_\BooleanInIfConditionRuleFixerRector;
|
||||
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
|
||||
|
||||
return static function (ContainerConfigurator $containerConfigurator): void {
|
||||
$services = $containerConfigurator->services();
|
||||
$services->set(BooleanInIfConditionRuleFixerRector::class);
|
||||
};
|
|
@ -0,0 +1,33 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Tests\Strict\Rector\Ternary\BooleanInTernaryOperatorRuleFixerRector;
|
||||
|
||||
use Iterator;
|
||||
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
|
||||
use Symplify\SmartFileSystem\SmartFileInfo;
|
||||
|
||||
final class BooleanInTernaryOperatorRuleFixerRectorTest 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';
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Tests\Strict\Rector\Ternary\BooleanInTernaryOperatorRuleFixerRector\Fixture;
|
||||
|
||||
final class ArrayCompare
|
||||
{
|
||||
public function run(array $data)
|
||||
{
|
||||
return $data ? 1 : 2;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
-----
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Tests\Strict\Rector\Ternary\BooleanInTernaryOperatorRuleFixerRector\Fixture;
|
||||
|
||||
final class ArrayCompare
|
||||
{
|
||||
public function run(array $data)
|
||||
{
|
||||
return $data !== [] ? 1 : 2;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,31 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Tests\Strict\Rector\Ternary\BooleanInTernaryOperatorRuleFixerRector\Fixture;
|
||||
|
||||
final class StringSilentCompare
|
||||
{
|
||||
public function run(string $string)
|
||||
{
|
||||
return $string ? 1 : 2;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
-----
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Tests\Strict\Rector\Ternary\BooleanInTernaryOperatorRuleFixerRector\Fixture;
|
||||
|
||||
final class StringSilentCompare
|
||||
{
|
||||
public function run(string $string)
|
||||
{
|
||||
return $string !== '' ? 1 : 2;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,31 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Tests\Strict\Rector\Ternary\BooleanInTernaryOperatorRuleFixerRector\Fixture;
|
||||
|
||||
final class StrlenNumber
|
||||
{
|
||||
public function run(string $string)
|
||||
{
|
||||
return strlen($string) ? 1 : 2;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
-----
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Tests\Strict\Rector\Ternary\BooleanInTernaryOperatorRuleFixerRector\Fixture;
|
||||
|
||||
final class StrlenNumber
|
||||
{
|
||||
public function run(string $string)
|
||||
{
|
||||
return strlen($string) !== 0 ? 1 : 2;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,11 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Rector\Strict\Rector\Ternary\BooleanInTernaryOperatorRuleFixerRector;
|
||||
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
|
||||
|
||||
return static function (ContainerConfigurator $containerConfigurator): void {
|
||||
$services = $containerConfigurator->services();
|
||||
$services->set(BooleanInTernaryOperatorRuleFixerRector::class);
|
||||
};
|
|
@ -0,0 +1,33 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Tests\Strict\Rector\Ternary\DisallowedShortTernaryRuleFixerRector;
|
||||
|
||||
use Iterator;
|
||||
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
|
||||
use Symplify\SmartFileSystem\SmartFileInfo;
|
||||
|
||||
final class DisallowedShortTernaryRuleFixerRectorTest 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';
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Tests\Strict\Rector\Ternary\DisallowedShortTernaryRuleFixerRector\Fixture;
|
||||
|
||||
trait ResetTrait
|
||||
{
|
||||
public function run(array $albums)
|
||||
{
|
||||
return \reset($albums) ?: null;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
-----
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Tests\Strict\Rector\Ternary\DisallowedShortTernaryRuleFixerRector\Fixture;
|
||||
|
||||
trait ResetTrait
|
||||
{
|
||||
public function run(array $albums)
|
||||
{
|
||||
return $albums !== [] ? \reset($albums) : null;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,31 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Tests\Strict\Rector\Ternary\DisallowedShortTernaryRuleFixerRector\Fixture;
|
||||
|
||||
final class ShortTernaryArray
|
||||
{
|
||||
public function run(array $array)
|
||||
{
|
||||
return $array ?: 2;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
-----
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Tests\Strict\Rector\Ternary\DisallowedShortTernaryRuleFixerRector\Fixture;
|
||||
|
||||
final class ShortTernaryArray
|
||||
{
|
||||
public function run(array $array)
|
||||
{
|
||||
return $array !== [] ? $array : 2;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,31 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Tests\Strict\Rector\Ternary\DisallowedShortTernaryRuleFixerRector\Fixture;
|
||||
|
||||
final class ShortTernaryString
|
||||
{
|
||||
public function run(string $string)
|
||||
{
|
||||
return $string ?: 2;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
-----
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Tests\Strict\Rector\Ternary\DisallowedShortTernaryRuleFixerRector\Fixture;
|
||||
|
||||
final class ShortTernaryString
|
||||
{
|
||||
public function run(string $string)
|
||||
{
|
||||
return $string !== '' ? $string : 2;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,11 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Rector\Strict\Rector\Ternary\DisallowedShortTernaryRuleFixerRector;
|
||||
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
|
||||
|
||||
return static function (ContainerConfigurator $containerConfigurator): void {
|
||||
$services = $containerConfigurator->services();
|
||||
$services->set(DisallowedShortTernaryRuleFixerRector::class);
|
||||
};
|
|
@ -1,41 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\CodeQualityStrict\NodeFactory;
|
||||
|
||||
use PhpParser\Node\Expr\ClassConstFetch;
|
||||
use PhpParser\Node\Name\FullyQualified;
|
||||
use PHPStan\Type\ObjectType;
|
||||
use PHPStan\Type\TypeWithClassName;
|
||||
use PHPStan\Type\UnionType;
|
||||
use Rector\Core\Exception\ShouldNotHappenException;
|
||||
use Rector\StaticTypeMapper\ValueObject\Type\ShortenedObjectType;
|
||||
|
||||
final class ClassConstFetchFactory
|
||||
{
|
||||
/**
|
||||
* @return ClassConstFetch[]
|
||||
*/
|
||||
public function createFromType(ObjectType | UnionType $type): array
|
||||
{
|
||||
$classConstTypes = [];
|
||||
if ($type instanceof ShortenedObjectType) {
|
||||
$classConstTypes[] = new ClassConstFetch(new FullyQualified($type->getFullyQualifiedName()), 'class');
|
||||
} elseif ($type instanceof ObjectType) {
|
||||
$classConstTypes[] = new ClassConstFetch(new FullyQualified($type->getClassName()), 'class');
|
||||
}
|
||||
|
||||
if ($type instanceof UnionType) {
|
||||
foreach ($type->getTypes() as $unionedType) {
|
||||
if (! $unionedType instanceof TypeWithClassName) {
|
||||
throw new ShouldNotHappenException();
|
||||
}
|
||||
|
||||
$classConstTypes[] = new ClassConstFetch(new FullyQualified($unionedType->getClassName()), 'class');
|
||||
}
|
||||
}
|
||||
|
||||
return $classConstTypes;
|
||||
}
|
||||
}
|
|
@ -1,30 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\CodeQualityStrict\TypeAnalyzer;
|
||||
|
||||
use PHPStan\Type\Type;
|
||||
use PHPStan\Type\TypeWithClassName;
|
||||
|
||||
final class SubTypeAnalyzer
|
||||
{
|
||||
public function isObjectSubType(Type $checkedType, Type $mainType): bool
|
||||
{
|
||||
if (! $checkedType instanceof TypeWithClassName) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (! $mainType instanceof TypeWithClassName) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// parent type to all objects
|
||||
if ($mainType->getClassName() === 'stdClass') {
|
||||
return true;
|
||||
}
|
||||
|
||||
return $mainType->isSuperTypeOf($checkedType)
|
||||
->yes();
|
||||
}
|
||||
}
|
142
rules/Strict/NodeFactory/ExactCompareFactory.php
Normal file
142
rules/Strict/NodeFactory/ExactCompareFactory.php
Normal file
|
@ -0,0 +1,142 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Strict\NodeFactory;
|
||||
|
||||
use PhpParser\Node\Expr;
|
||||
use PhpParser\Node\Expr\Array_;
|
||||
use PhpParser\Node\Expr\BinaryOp\Identical;
|
||||
use PhpParser\Node\Expr\BinaryOp\NotIdentical;
|
||||
use PhpParser\Node\Expr\ConstFetch;
|
||||
use PhpParser\Node\Expr\Instanceof_;
|
||||
use PhpParser\Node\Name;
|
||||
use PhpParser\Node\Name\FullyQualified;
|
||||
use PhpParser\Node\Scalar\LNumber;
|
||||
use PhpParser\Node\Scalar\String_;
|
||||
use PHPStan\Type\ArrayType;
|
||||
use PHPStan\Type\BooleanType;
|
||||
use PHPStan\Type\FloatType;
|
||||
use PHPStan\Type\IntegerType;
|
||||
use PHPStan\Type\StringType;
|
||||
use PHPStan\Type\Type;
|
||||
use PHPStan\Type\TypeCombinator;
|
||||
use PHPStan\Type\TypeWithClassName;
|
||||
use PHPStan\Type\UnionType;
|
||||
|
||||
final class ExactCompareFactory
|
||||
{
|
||||
public function createIdenticalFalsyCompare(Type $exprType, Expr $expr): ?Identical
|
||||
{
|
||||
if ($exprType instanceof StringType) {
|
||||
return new Identical($expr, new String_(''));
|
||||
}
|
||||
|
||||
if ($exprType instanceof IntegerType) {
|
||||
return new Identical($expr, new LNumber(0));
|
||||
}
|
||||
|
||||
if ($exprType instanceof ArrayType) {
|
||||
return new Identical($expr, new Array_([]));
|
||||
}
|
||||
|
||||
if (! $exprType instanceof UnionType) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (! TypeCombinator::containsNull($exprType)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $this->createTruthyFromUnionType($exprType, $expr);
|
||||
}
|
||||
|
||||
public function createNotIdenticalFalsyCompare(Type $exprType, Expr $expr): NotIdentical|Identical|Instanceof_|null
|
||||
{
|
||||
if ($exprType instanceof StringType) {
|
||||
return new NotIdentical($expr, new String_(''));
|
||||
}
|
||||
|
||||
if ($exprType instanceof IntegerType) {
|
||||
return new NotIdentical($expr, new LNumber(0));
|
||||
}
|
||||
|
||||
if ($exprType instanceof ArrayType) {
|
||||
return new NotIdentical($expr, new Array_([]));
|
||||
}
|
||||
|
||||
if (! $exprType instanceof UnionType) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (! TypeCombinator::containsNull($exprType)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $this->createFromUnionType($exprType, $expr);
|
||||
}
|
||||
|
||||
private function createFromUnionType(Type|UnionType $exprType, Expr $expr): Identical|Instanceof_|NotIdentical
|
||||
{
|
||||
$exprType = TypeCombinator::removeNull($exprType);
|
||||
|
||||
if ($exprType instanceof BooleanType) {
|
||||
$trueConstFetch = new ConstFetch(new Name('true'));
|
||||
return new Identical($expr, $trueConstFetch);
|
||||
}
|
||||
|
||||
if ($exprType instanceof TypeWithClassName) {
|
||||
return new Instanceof_($expr, new FullyQualified($exprType->getClassName()));
|
||||
}
|
||||
|
||||
$nullConstFetch = new ConstFetch(new Name('null'));
|
||||
return new NotIdentical($expr, $nullConstFetch);
|
||||
}
|
||||
|
||||
private function resolveFalsyTypesCount(UnionType $unionType): int
|
||||
{
|
||||
$falsyTypesCount = 0;
|
||||
|
||||
foreach ($unionType->getTypes() as $unionedType) {
|
||||
if ($unionedType instanceof StringType) {
|
||||
++$falsyTypesCount;
|
||||
}
|
||||
|
||||
if ($unionedType instanceof IntegerType) {
|
||||
++$falsyTypesCount;
|
||||
}
|
||||
|
||||
if ($unionedType instanceof FloatType) {
|
||||
++$falsyTypesCount;
|
||||
}
|
||||
|
||||
if ($unionedType instanceof ArrayType) {
|
||||
++$falsyTypesCount;
|
||||
}
|
||||
}
|
||||
|
||||
return $falsyTypesCount;
|
||||
}
|
||||
|
||||
private function createTruthyFromUnionType(UnionType $unionType, Expr $expr): ?Identical
|
||||
{
|
||||
$unionType = TypeCombinator::removeNull($unionType);
|
||||
|
||||
if ($unionType instanceof BooleanType) {
|
||||
$trueConstFetch = new ConstFetch(new Name('true'));
|
||||
return new Identical($expr, $trueConstFetch);
|
||||
}
|
||||
|
||||
if ($unionType instanceof UnionType) {
|
||||
$falsyTypesCount = $this->resolveFalsyTypesCount($unionType);
|
||||
|
||||
// impossible to refactor to string value compare, as many falsy values can be provided
|
||||
if ($falsyTypesCount > 1) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
$nullConstFetch = new ConstFetch(new Name('null'));
|
||||
return new Identical($expr, $nullConstFetch);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,91 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Strict\Rector\BooleanNot;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Expr\BinaryOp\Identical;
|
||||
use PhpParser\Node\Expr\BooleanNot;
|
||||
use PHPStan\Analyser\Scope;
|
||||
use Rector\Core\Rector\AbstractRector;
|
||||
use Rector\NodeTypeResolver\Node\AttributeKey;
|
||||
use Rector\Strict\NodeFactory\ExactCompareFactory;
|
||||
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
|
||||
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
|
||||
|
||||
/**
|
||||
* Fixer Rector for PHPStan rule:
|
||||
* https://github.com/phpstan/phpstan-strict-rules/blob/0705fefc7c9168529fd130e341428f5f10f4f01d/src/Rules/BooleansInConditions/BooleanInBooleanNotRule.php
|
||||
*
|
||||
* @see \Rector\Tests\Strict\Rector\BooleanNot\BooleanInBooleanNotRuleFixerRector\BooleanInBooleanNotRuleFixerRectorTest
|
||||
*/
|
||||
final class BooleanInBooleanNotRuleFixerRector extends AbstractRector
|
||||
{
|
||||
public function __construct(
|
||||
private ExactCompareFactory $exactCompareFactory
|
||||
) {
|
||||
}
|
||||
|
||||
public function getRuleDefinition(): RuleDefinition
|
||||
{
|
||||
$errorMessage = \sprintf(
|
||||
'Fixer for PHPStan reports by strict type rule - "%s"',
|
||||
'PHPStan\Rules\BooleansInConditions\BooleanInBooleanNotRule'
|
||||
);
|
||||
return new RuleDefinition($errorMessage, [
|
||||
new CodeSample(
|
||||
<<<'CODE_SAMPLE'
|
||||
class SomeClass
|
||||
{
|
||||
public function run(string $name)
|
||||
{
|
||||
if (! $name) {
|
||||
return 'name';
|
||||
}
|
||||
|
||||
return 'no name';
|
||||
}
|
||||
}
|
||||
CODE_SAMPLE
|
||||
,
|
||||
<<<'CODE_SAMPLE'
|
||||
class SomeClass
|
||||
{
|
||||
public function run(string $name)
|
||||
{
|
||||
if ($name !== '') {
|
||||
return 'name';
|
||||
}
|
||||
|
||||
return 'no name';
|
||||
}
|
||||
}
|
||||
CODE_SAMPLE
|
||||
),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<class-string<Node>>
|
||||
*/
|
||||
public function getNodeTypes(): array
|
||||
{
|
||||
return [BooleanNot::class];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param BooleanNot $node
|
||||
*/
|
||||
public function refactor(Node $node): ?Identical
|
||||
{
|
||||
$scope = $node->getAttribute(AttributeKey::SCOPE);
|
||||
if (! $scope instanceof Scope) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$exprType = $scope->getType($node->expr);
|
||||
|
||||
return $this->exactCompareFactory->createIdenticalFalsyCompare($exprType, $node->expr);
|
||||
}
|
||||
}
|
103
rules/Strict/Rector/Empty_/DisallowedEmptyRuleFixerRector.php
Normal file
103
rules/Strict/Rector/Empty_/DisallowedEmptyRuleFixerRector.php
Normal file
|
@ -0,0 +1,103 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Strict\Rector\Empty_;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Expr\BinaryOp\Identical;
|
||||
use PhpParser\Node\Expr\BinaryOp\NotIdentical;
|
||||
use PhpParser\Node\Expr\BooleanNot;
|
||||
use PhpParser\Node\Expr\Empty_;
|
||||
use PhpParser\Node\Expr\Instanceof_;
|
||||
use PHPStan\Analyser\Scope;
|
||||
use Rector\Core\Rector\AbstractRector;
|
||||
use Rector\NodeTypeResolver\Node\AttributeKey;
|
||||
use Rector\Strict\NodeFactory\ExactCompareFactory;
|
||||
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
|
||||
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
|
||||
|
||||
/**
|
||||
* @see \Rector\Tests\Strict\Rector\Empty_\DisallowedEmptyRuleFixerRector\DisallowedEmptyRuleFixerRectorTest
|
||||
*/
|
||||
final class DisallowedEmptyRuleFixerRector extends AbstractRector
|
||||
{
|
||||
public function __construct(
|
||||
private ExactCompareFactory $exactCompareFactory,
|
||||
) {
|
||||
}
|
||||
|
||||
public function getRuleDefinition(): RuleDefinition
|
||||
{
|
||||
$errorMessage = \sprintf(
|
||||
'Fixer for PHPStan reports by strict type rule - "%s"',
|
||||
'PHPStan\Rules\DisallowedConstructs\DisallowedEmptyRule'
|
||||
);
|
||||
return new RuleDefinition($errorMessage, [
|
||||
new CodeSample(
|
||||
<<<'CODE_SAMPLE'
|
||||
final class SomeEmptyArray
|
||||
{
|
||||
public function run(array $items)
|
||||
{
|
||||
return empty($items);
|
||||
}
|
||||
}
|
||||
CODE_SAMPLE
|
||||
,
|
||||
<<<'CODE_SAMPLE'
|
||||
final class SomeEmptyArray
|
||||
{
|
||||
public function run(array $items)
|
||||
{
|
||||
return $items === [];
|
||||
}
|
||||
}
|
||||
CODE_SAMPLE
|
||||
),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<class-string<Node>>
|
||||
*/
|
||||
public function getNodeTypes(): array
|
||||
{
|
||||
return [Empty_::class, BooleanNot::class];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Empty_|BooleanNot $node
|
||||
*/
|
||||
public function refactor(Node $node)
|
||||
{
|
||||
$scope = $node->getAttribute(AttributeKey::SCOPE);
|
||||
if (! $scope instanceof Scope) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if ($node instanceof BooleanNot) {
|
||||
return $this->refactorBooleanNot($node, $scope);
|
||||
}
|
||||
|
||||
return $this->refactorEmpty($node, $scope);
|
||||
}
|
||||
|
||||
private function refactorBooleanNot(BooleanNot $booleanNot, Scope $scope): NotIdentical|Identical|Instanceof_|null
|
||||
{
|
||||
if (! $booleanNot->expr instanceof Empty_) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$empty = $booleanNot->expr;
|
||||
$emptyExprType = $scope->getType($empty->expr);
|
||||
|
||||
return $this->exactCompareFactory->createNotIdenticalFalsyCompare($emptyExprType, $empty->expr);
|
||||
}
|
||||
|
||||
private function refactorEmpty(Empty_ $empty, Scope $scope): ?Identical
|
||||
{
|
||||
$exprType = $scope->getType($empty->expr);
|
||||
return $this->exactCompareFactory->createIdenticalFalsyCompare($exprType, $empty->expr);
|
||||
}
|
||||
}
|
110
rules/Strict/Rector/If_/BooleanInIfConditionRuleFixerRector.php
Normal file
110
rules/Strict/Rector/If_/BooleanInIfConditionRuleFixerRector.php
Normal file
|
@ -0,0 +1,110 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Strict\Rector\If_;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Stmt\If_;
|
||||
use PHPStan\Analyser\Scope;
|
||||
use Rector\Core\Rector\AbstractRector;
|
||||
use Rector\NodeTypeResolver\Node\AttributeKey;
|
||||
use Rector\Strict\NodeFactory\ExactCompareFactory;
|
||||
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
|
||||
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
|
||||
|
||||
/**
|
||||
* Fixer Rector for PHPStan rules:
|
||||
* https://github.com/phpstan/phpstan-strict-rules/blob/master/src/Rules/BooleansInConditions/BooleanInIfConditionRule.php
|
||||
* https://github.com/phpstan/phpstan-strict-rules/blob/master/src/Rules/BooleansInConditions/BooleanInElseIfConditionRule.php
|
||||
*
|
||||
* @see \Rector\Tests\Strict\Rector\If_\BooleanInIfConditionRuleFixerRector\BooleanInIfConditionRuleFixerRectorTest
|
||||
*/
|
||||
final class BooleanInIfConditionRuleFixerRector extends AbstractRector
|
||||
{
|
||||
public function __construct(
|
||||
private ExactCompareFactory $exactCompareFactory
|
||||
) {
|
||||
}
|
||||
|
||||
public function getRuleDefinition(): RuleDefinition
|
||||
{
|
||||
$errorMessage = \sprintf(
|
||||
'Fixer for PHPStan reports by strict type rule - "%s"',
|
||||
'PHPStan\Rules\BooleansInConditions\BooleanInIfConditionRule'
|
||||
);
|
||||
return new RuleDefinition($errorMessage, [
|
||||
new CodeSample(
|
||||
<<<'CODE_SAMPLE'
|
||||
final class NegatedString
|
||||
{
|
||||
public function run(string $name)
|
||||
{
|
||||
if ($name) {
|
||||
return 'name';
|
||||
}
|
||||
|
||||
return 'no name';
|
||||
}
|
||||
}
|
||||
CODE_SAMPLE
|
||||
,
|
||||
<<<'CODE_SAMPLE'
|
||||
final class NegatedString
|
||||
{
|
||||
public function run(string $name)
|
||||
{
|
||||
if ($name !== '') {
|
||||
return 'name';
|
||||
}
|
||||
|
||||
return 'no name';
|
||||
}
|
||||
}
|
||||
CODE_SAMPLE
|
||||
),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<class-string<Node>>
|
||||
*/
|
||||
public function getNodeTypes(): array
|
||||
{
|
||||
return [If_::class];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param If_ $node
|
||||
*/
|
||||
public function refactor(Node $node): ?If_
|
||||
{
|
||||
$scope = $node->getAttribute(AttributeKey::SCOPE);
|
||||
if (! $scope instanceof Scope) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// 1. if
|
||||
$ifCondExprType = $scope->getType($node->cond);
|
||||
$notIdentical = $this->exactCompareFactory->createNotIdenticalFalsyCompare($ifCondExprType, $node->cond);
|
||||
if ($notIdentical !== null) {
|
||||
$node->cond = $notIdentical;
|
||||
}
|
||||
|
||||
// 2. elseifs
|
||||
foreach ($node->elseifs as $elseif) {
|
||||
$elseifCondExprType = $scope->getType($elseif->cond);
|
||||
$notIdentical = $this->exactCompareFactory->createNotIdenticalFalsyCompare(
|
||||
$elseifCondExprType,
|
||||
$elseif->cond
|
||||
);
|
||||
if ($notIdentical === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$elseif->cond = $notIdentical;
|
||||
}
|
||||
|
||||
return $node;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,95 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Strict\Rector\Ternary;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Expr;
|
||||
use PhpParser\Node\Expr\Ternary;
|
||||
use PHPStan\Analyser\Scope;
|
||||
use Rector\Core\Rector\AbstractRector;
|
||||
use Rector\NodeTypeResolver\Node\AttributeKey;
|
||||
use Rector\Strict\NodeFactory\ExactCompareFactory;
|
||||
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
|
||||
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
|
||||
|
||||
/**
|
||||
* Fixer Rector for PHPStan rule:
|
||||
* https://github.com/phpstan/phpstan-strict-rules/blob/master/src/Rules/BooleansInConditions/BooleanInTernaryOperatorRule.php
|
||||
*
|
||||
* @see \Rector\Tests\Strict\Rector\Ternary\BooleanInTernaryOperatorRuleFixerRector\BooleanInTernaryOperatorRuleFixerRectorTest
|
||||
*/
|
||||
final class BooleanInTernaryOperatorRuleFixerRector extends AbstractRector
|
||||
{
|
||||
public function __construct(
|
||||
private ExactCompareFactory $exactCompareFactory
|
||||
) {
|
||||
}
|
||||
|
||||
public function getRuleDefinition(): RuleDefinition
|
||||
{
|
||||
$errorMessage = \sprintf(
|
||||
'Fixer for PHPStan reports by strict type rule - "%s"',
|
||||
'PHPStan\Rules\BooleansInConditions\BooleanInTernaryOperatorRule'
|
||||
);
|
||||
return new RuleDefinition($errorMessage, [
|
||||
new CodeSample(
|
||||
<<<'CODE_SAMPLE'
|
||||
final class ArrayCompare
|
||||
{
|
||||
public function run(array $data)
|
||||
{
|
||||
return $data ? 1 : 2;
|
||||
}
|
||||
}
|
||||
CODE_SAMPLE
|
||||
,
|
||||
<<<'CODE_SAMPLE'
|
||||
final class ArrayCompare
|
||||
{
|
||||
public function run(array $data)
|
||||
{
|
||||
return $data !== [] ? 1 : 2;
|
||||
}
|
||||
}
|
||||
CODE_SAMPLE
|
||||
),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<class-string<Node>>
|
||||
*/
|
||||
public function getNodeTypes(): array
|
||||
{
|
||||
return [Ternary::class];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Ternary $node
|
||||
*/
|
||||
public function refactor(Node $node): ?Ternary
|
||||
{
|
||||
$scope = $node->getAttribute(AttributeKey::SCOPE);
|
||||
if (! $scope instanceof Scope) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// skip short ternary
|
||||
if ($node->if === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$exprType = $scope->getType($node->cond);
|
||||
|
||||
$falsyIdentical = $this->exactCompareFactory->createNotIdenticalFalsyCompare($exprType, $node->cond);
|
||||
if (! $falsyIdentical instanceof Expr) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$node->cond = $falsyIdentical;
|
||||
|
||||
return $node;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,120 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Strict\Rector\Ternary;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Expr\FuncCall;
|
||||
use PhpParser\Node\Expr\Ternary;
|
||||
use PHPStan\Analyser\Scope;
|
||||
use Rector\Core\Rector\AbstractRector;
|
||||
use Rector\NodeTypeResolver\Node\AttributeKey;
|
||||
use Rector\Strict\NodeFactory\ExactCompareFactory;
|
||||
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
|
||||
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
|
||||
|
||||
/**
|
||||
* Fixer Rector for PHPStan rule:
|
||||
* https://github.com/phpstan/phpstan-strict-rules/blob/master/src/Rules/DisallowedConstructs/DisallowedShortTernaryRule.php
|
||||
*
|
||||
* @see \Rector\Tests\Strict\Rector\Ternary\DisallowedShortTernaryRuleFixerRector\DisallowedShortTernaryRuleFixerRectorTest
|
||||
*/
|
||||
final class DisallowedShortTernaryRuleFixerRector extends AbstractRector
|
||||
{
|
||||
public function __construct(
|
||||
private ExactCompareFactory $exactCompareFactory,
|
||||
) {
|
||||
}
|
||||
|
||||
public function getRuleDefinition(): RuleDefinition
|
||||
{
|
||||
$errorMessage = sprintf(
|
||||
'Fixer for PHPStan reports by strict type rule - "%s"',
|
||||
'PHPStan\Rules\DisallowedConstructs\DisallowedShortTernaryRule'
|
||||
);
|
||||
return new RuleDefinition($errorMessage, [
|
||||
new CodeSample(
|
||||
<<<'CODE_SAMPLE'
|
||||
final class ShortTernaryArray
|
||||
{
|
||||
public function run(array $array)
|
||||
{
|
||||
return $array ?: 2;
|
||||
}
|
||||
}
|
||||
CODE_SAMPLE
|
||||
,
|
||||
<<<'CODE_SAMPLE'
|
||||
final class ShortTernaryArray
|
||||
{
|
||||
public function run(array $array)
|
||||
{
|
||||
return $array !== [] ? $array : 2;
|
||||
}
|
||||
}
|
||||
CODE_SAMPLE
|
||||
),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<class-string<Node>>
|
||||
*/
|
||||
public function getNodeTypes(): array
|
||||
{
|
||||
return [Ternary::class];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Ternary $node
|
||||
*/
|
||||
public function refactor(Node $node): ?Ternary
|
||||
{
|
||||
$scope = $node->getAttribute(AttributeKey::SCOPE);
|
||||
if (! $scope instanceof Scope) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// skip non-short ternary
|
||||
if ($node->if !== null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// special case for reset() function
|
||||
if ($node->cond instanceof FuncCall && $this->isName($node->cond, 'reset')) {
|
||||
$this->refactorResetFuncCall($node, $node->cond, $scope);
|
||||
return $node;
|
||||
}
|
||||
|
||||
$exprType = $scope->getType($node->cond);
|
||||
$falsyIdentical = $this->exactCompareFactory->createNotIdenticalFalsyCompare($exprType, $node->cond);
|
||||
if ($falsyIdentical === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$node->if = $node->cond;
|
||||
$node->cond = $falsyIdentical;
|
||||
|
||||
return $node;
|
||||
}
|
||||
|
||||
private function refactorResetFuncCall(Ternary $ternary, FuncCall $resetFuncCall, Scope $scope): void
|
||||
{
|
||||
$ternary->if = $ternary->cond;
|
||||
|
||||
$firstArgValue = $resetFuncCall->args[0]->value;
|
||||
$firstArgType = $scope->getType($firstArgValue);
|
||||
|
||||
$falsyCompareExpr = $this->exactCompareFactory->createNotIdenticalFalsyCompare(
|
||||
$firstArgType,
|
||||
$firstArgValue
|
||||
);
|
||||
|
||||
if ($falsyCompareExpr === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
$ternary->cond = $falsyCompareExpr;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user