Updated Rector to commit c4de350289

c4de350289 [Strict] Add rules to resolve PHPStan Strict rule set (#955)
This commit is contained in:
Tomas Votruba 2021-10-05 08:51:30 +00:00
parent f6dfd556b7
commit 0b0fa02f46
15 changed files with 709 additions and 85 deletions

View File

@ -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

View File

@ -1,37 +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[]
* @param \PHPStan\Type\ObjectType|\PHPStan\Type\UnionType $type
*/
public function createFromType($type) : array
{
$classConstTypes = [];
if ($type instanceof \Rector\StaticTypeMapper\ValueObject\Type\ShortenedObjectType) {
$classConstTypes[] = new \PhpParser\Node\Expr\ClassConstFetch(new \PhpParser\Node\Name\FullyQualified($type->getFullyQualifiedName()), 'class');
} elseif ($type instanceof \PHPStan\Type\ObjectType) {
$classConstTypes[] = new \PhpParser\Node\Expr\ClassConstFetch(new \PhpParser\Node\Name\FullyQualified($type->getClassName()), 'class');
}
if ($type instanceof \PHPStan\Type\UnionType) {
foreach ($type->getTypes() as $unionedType) {
if (!$unionedType instanceof \PHPStan\Type\TypeWithClassName) {
throw new \Rector\Core\Exception\ShouldNotHappenException();
}
$classConstTypes[] = new \PhpParser\Node\Expr\ClassConstFetch(new \PhpParser\Node\Name\FullyQualified($unionedType->getClassName()), 'class');
}
}
return $classConstTypes;
}
}

View File

@ -1,24 +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(\PHPStan\Type\Type $checkedType, \PHPStan\Type\Type $mainType) : bool
{
if (!$checkedType instanceof \PHPStan\Type\TypeWithClassName) {
return \false;
}
if (!$mainType instanceof \PHPStan\Type\TypeWithClassName) {
return \false;
}
// parent type to all objects
if ($mainType->getClassName() === 'stdClass') {
return \true;
}
return $mainType->isSuperTypeOf($checkedType)->yes();
}
}

View File

@ -0,0 +1,121 @@
<?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(\PHPStan\Type\Type $exprType, \PhpParser\Node\Expr $expr) : ?\PhpParser\Node\Expr\BinaryOp\Identical
{
if ($exprType instanceof \PHPStan\Type\StringType) {
return new \PhpParser\Node\Expr\BinaryOp\Identical($expr, new \PhpParser\Node\Scalar\String_(''));
}
if ($exprType instanceof \PHPStan\Type\IntegerType) {
return new \PhpParser\Node\Expr\BinaryOp\Identical($expr, new \PhpParser\Node\Scalar\LNumber(0));
}
if ($exprType instanceof \PHPStan\Type\ArrayType) {
return new \PhpParser\Node\Expr\BinaryOp\Identical($expr, new \PhpParser\Node\Expr\Array_([]));
}
if (!$exprType instanceof \PHPStan\Type\UnionType) {
return null;
}
if (!\PHPStan\Type\TypeCombinator::containsNull($exprType)) {
return null;
}
return $this->createTruthyFromUnionType($exprType, $expr);
}
/**
* @return \PhpParser\Node\Expr\BinaryOp\NotIdentical|\PhpParser\Node\Expr\BinaryOp\Identical|\PhpParser\Node\Expr\Instanceof_|null
*/
public function createNotIdenticalFalsyCompare(\PHPStan\Type\Type $exprType, \PhpParser\Node\Expr $expr)
{
if ($exprType instanceof \PHPStan\Type\StringType) {
return new \PhpParser\Node\Expr\BinaryOp\NotIdentical($expr, new \PhpParser\Node\Scalar\String_(''));
}
if ($exprType instanceof \PHPStan\Type\IntegerType) {
return new \PhpParser\Node\Expr\BinaryOp\NotIdentical($expr, new \PhpParser\Node\Scalar\LNumber(0));
}
if ($exprType instanceof \PHPStan\Type\ArrayType) {
return new \PhpParser\Node\Expr\BinaryOp\NotIdentical($expr, new \PhpParser\Node\Expr\Array_([]));
}
if (!$exprType instanceof \PHPStan\Type\UnionType) {
return null;
}
if (!\PHPStan\Type\TypeCombinator::containsNull($exprType)) {
return null;
}
return $this->createFromUnionType($exprType, $expr);
}
/**
* @param \PHPStan\Type\Type|\PHPStan\Type\UnionType $exprType
* @return \PhpParser\Node\Expr\BinaryOp\Identical|\PhpParser\Node\Expr\Instanceof_|\PhpParser\Node\Expr\BinaryOp\NotIdentical
*/
private function createFromUnionType($exprType, \PhpParser\Node\Expr $expr)
{
$exprType = \PHPStan\Type\TypeCombinator::removeNull($exprType);
if ($exprType instanceof \PHPStan\Type\BooleanType) {
$trueConstFetch = new \PhpParser\Node\Expr\ConstFetch(new \PhpParser\Node\Name('true'));
return new \PhpParser\Node\Expr\BinaryOp\Identical($expr, $trueConstFetch);
}
if ($exprType instanceof \PHPStan\Type\TypeWithClassName) {
return new \PhpParser\Node\Expr\Instanceof_($expr, new \PhpParser\Node\Name\FullyQualified($exprType->getClassName()));
}
$nullConstFetch = new \PhpParser\Node\Expr\ConstFetch(new \PhpParser\Node\Name('null'));
return new \PhpParser\Node\Expr\BinaryOp\NotIdentical($expr, $nullConstFetch);
}
private function resolveFalsyTypesCount(\PHPStan\Type\UnionType $unionType) : int
{
$falsyTypesCount = 0;
foreach ($unionType->getTypes() as $unionedType) {
if ($unionedType instanceof \PHPStan\Type\StringType) {
++$falsyTypesCount;
}
if ($unionedType instanceof \PHPStan\Type\IntegerType) {
++$falsyTypesCount;
}
if ($unionedType instanceof \PHPStan\Type\FloatType) {
++$falsyTypesCount;
}
if ($unionedType instanceof \PHPStan\Type\ArrayType) {
++$falsyTypesCount;
}
}
return $falsyTypesCount;
}
private function createTruthyFromUnionType(\PHPStan\Type\UnionType $unionType, \PhpParser\Node\Expr $expr) : ?\PhpParser\Node\Expr\BinaryOp\Identical
{
$unionType = \PHPStan\Type\TypeCombinator::removeNull($unionType);
if ($unionType instanceof \PHPStan\Type\BooleanType) {
$trueConstFetch = new \PhpParser\Node\Expr\ConstFetch(new \PhpParser\Node\Name('true'));
return new \PhpParser\Node\Expr\BinaryOp\Identical($expr, $trueConstFetch);
}
if ($unionType instanceof \PHPStan\Type\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 \PhpParser\Node\Expr\ConstFetch(new \PhpParser\Node\Name('null'));
return new \PhpParser\Node\Expr\BinaryOp\Identical($expr, $nullConstFetch);
}
}

View File

@ -0,0 +1,81 @@
<?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 \Rector\Core\Rector\AbstractRector
{
/**
* @var \Rector\Strict\NodeFactory\ExactCompareFactory
*/
private $exactCompareFactory;
public function __construct(\Rector\Strict\NodeFactory\ExactCompareFactory $exactCompareFactory)
{
$this->exactCompareFactory = $exactCompareFactory;
}
public function getRuleDefinition() : \Symplify\RuleDocGenerator\ValueObject\RuleDefinition
{
$errorMessage = \sprintf('Fixer for PHPStan reports by strict type rule - "%s"', 'PHPStan\\Rules\\BooleansInConditions\\BooleanInBooleanNotRule');
return new \Symplify\RuleDocGenerator\ValueObject\RuleDefinition($errorMessage, [new \Symplify\RuleDocGenerator\ValueObject\CodeSample\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 [\PhpParser\Node\Expr\BooleanNot::class];
}
/**
* @param BooleanNot $node
*/
public function refactor(\PhpParser\Node $node) : ?\PhpParser\Node\Expr\BinaryOp\Identical
{
$scope = $node->getAttribute(\Rector\NodeTypeResolver\Node\AttributeKey::SCOPE);
if (!$scope instanceof \PHPStan\Analyser\Scope) {
return null;
}
$exprType = $scope->getType($node->expr);
return $this->exactCompareFactory->createIdenticalFalsyCompare($exprType, $node->expr);
}
}

View File

@ -0,0 +1,92 @@
<?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 \Rector\Core\Rector\AbstractRector
{
/**
* @var \Rector\Strict\NodeFactory\ExactCompareFactory
*/
private $exactCompareFactory;
public function __construct(\Rector\Strict\NodeFactory\ExactCompareFactory $exactCompareFactory)
{
$this->exactCompareFactory = $exactCompareFactory;
}
public function getRuleDefinition() : \Symplify\RuleDocGenerator\ValueObject\RuleDefinition
{
$errorMessage = \sprintf('Fixer for PHPStan reports by strict type rule - "%s"', 'PHPStan\\Rules\\DisallowedConstructs\\DisallowedEmptyRule');
return new \Symplify\RuleDocGenerator\ValueObject\RuleDefinition($errorMessage, [new \Symplify\RuleDocGenerator\ValueObject\CodeSample\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 [\PhpParser\Node\Expr\Empty_::class, \PhpParser\Node\Expr\BooleanNot::class];
}
/**
* @param Empty_|BooleanNot $node
*/
public function refactor(\PhpParser\Node $node)
{
$scope = $node->getAttribute(\Rector\NodeTypeResolver\Node\AttributeKey::SCOPE);
if (!$scope instanceof \PHPStan\Analyser\Scope) {
return null;
}
if ($node instanceof \PhpParser\Node\Expr\BooleanNot) {
return $this->refactorBooleanNot($node, $scope);
}
return $this->refactorEmpty($node, $scope);
}
/**
* @return \PhpParser\Node\Expr\BinaryOp\NotIdentical|\PhpParser\Node\Expr\BinaryOp\Identical|\PhpParser\Node\Expr\Instanceof_|null
*/
private function refactorBooleanNot(\PhpParser\Node\Expr\BooleanNot $booleanNot, \PHPStan\Analyser\Scope $scope)
{
if (!$booleanNot->expr instanceof \PhpParser\Node\Expr\Empty_) {
return null;
}
$empty = $booleanNot->expr;
$emptyExprType = $scope->getType($empty->expr);
return $this->exactCompareFactory->createNotIdenticalFalsyCompare($emptyExprType, $empty->expr);
}
private function refactorEmpty(\PhpParser\Node\Expr\Empty_ $empty, \PHPStan\Analyser\Scope $scope) : ?\PhpParser\Node\Expr\BinaryOp\Identical
{
$exprType = $scope->getType($empty->expr);
return $this->exactCompareFactory->createIdenticalFalsyCompare($exprType, $empty->expr);
}
}

View File

@ -0,0 +1,95 @@
<?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 \Rector\Core\Rector\AbstractRector
{
/**
* @var \Rector\Strict\NodeFactory\ExactCompareFactory
*/
private $exactCompareFactory;
public function __construct(\Rector\Strict\NodeFactory\ExactCompareFactory $exactCompareFactory)
{
$this->exactCompareFactory = $exactCompareFactory;
}
public function getRuleDefinition() : \Symplify\RuleDocGenerator\ValueObject\RuleDefinition
{
$errorMessage = \sprintf('Fixer for PHPStan reports by strict type rule - "%s"', 'PHPStan\\Rules\\BooleansInConditions\\BooleanInIfConditionRule');
return new \Symplify\RuleDocGenerator\ValueObject\RuleDefinition($errorMessage, [new \Symplify\RuleDocGenerator\ValueObject\CodeSample\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 [\PhpParser\Node\Stmt\If_::class];
}
/**
* @param If_ $node
*/
public function refactor(\PhpParser\Node $node) : ?\PhpParser\Node\Stmt\If_
{
$scope = $node->getAttribute(\Rector\NodeTypeResolver\Node\AttributeKey::SCOPE);
if (!$scope instanceof \PHPStan\Analyser\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;
}
}

View File

@ -0,0 +1,82 @@
<?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 \Rector\Core\Rector\AbstractRector
{
/**
* @var \Rector\Strict\NodeFactory\ExactCompareFactory
*/
private $exactCompareFactory;
public function __construct(\Rector\Strict\NodeFactory\ExactCompareFactory $exactCompareFactory)
{
$this->exactCompareFactory = $exactCompareFactory;
}
public function getRuleDefinition() : \Symplify\RuleDocGenerator\ValueObject\RuleDefinition
{
$errorMessage = \sprintf('Fixer for PHPStan reports by strict type rule - "%s"', 'PHPStan\\Rules\\BooleansInConditions\\BooleanInTernaryOperatorRule');
return new \Symplify\RuleDocGenerator\ValueObject\RuleDefinition($errorMessage, [new \Symplify\RuleDocGenerator\ValueObject\CodeSample\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 [\PhpParser\Node\Expr\Ternary::class];
}
/**
* @param Ternary $node
*/
public function refactor(\PhpParser\Node $node) : ?\PhpParser\Node\Expr\Ternary
{
$scope = $node->getAttribute(\Rector\NodeTypeResolver\Node\AttributeKey::SCOPE);
if (!$scope instanceof \PHPStan\Analyser\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 \PhpParser\Node\Expr) {
return null;
}
$node->cond = $falsyIdentical;
return $node;
}
}

View File

@ -0,0 +1,99 @@
<?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 \Rector\Core\Rector\AbstractRector
{
/**
* @var \Rector\Strict\NodeFactory\ExactCompareFactory
*/
private $exactCompareFactory;
public function __construct(\Rector\Strict\NodeFactory\ExactCompareFactory $exactCompareFactory)
{
$this->exactCompareFactory = $exactCompareFactory;
}
public function getRuleDefinition() : \Symplify\RuleDocGenerator\ValueObject\RuleDefinition
{
$errorMessage = \sprintf('Fixer for PHPStan reports by strict type rule - "%s"', 'PHPStan\\Rules\\DisallowedConstructs\\DisallowedShortTernaryRule');
return new \Symplify\RuleDocGenerator\ValueObject\RuleDefinition($errorMessage, [new \Symplify\RuleDocGenerator\ValueObject\CodeSample\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 [\PhpParser\Node\Expr\Ternary::class];
}
/**
* @param Ternary $node
*/
public function refactor(\PhpParser\Node $node) : ?\PhpParser\Node\Expr\Ternary
{
$scope = $node->getAttribute(\Rector\NodeTypeResolver\Node\AttributeKey::SCOPE);
if (!$scope instanceof \PHPStan\Analyser\Scope) {
return null;
}
// skip non-short ternary
if ($node->if !== null) {
return null;
}
// special case for reset() function
if ($node->cond instanceof \PhpParser\Node\Expr\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(\PhpParser\Node\Expr\Ternary $ternary, \PhpParser\Node\Expr\FuncCall $resetFuncCall, \PHPStan\Analyser\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;
}
}

View File

@ -16,11 +16,11 @@ final class VersionResolver
/**
* @var string
*/
public const PACKAGE_VERSION = '687f9e9de9d5b25cdef988b8572d30f21ad42ea9';
public const PACKAGE_VERSION = 'c4de350289baf6f7cf4b64f1708f1e02fc1827dd';
/**
* @var string
*/
public const RELEASE_DATE = '2021-10-05 11:55:21';
public const RELEASE_DATE = '2021-10-05 10:39:10';
public static function resolvePackageVersion() : string
{
$process = new \RectorPrefix20211005\Symfony\Component\Process\Process(['git', 'log', '--pretty="%H"', '-n1', 'HEAD'], __DIR__);

2
vendor/autoload.php vendored
View File

@ -4,4 +4,4 @@
require_once __DIR__ . '/composer/autoload_real.php';
return ComposerAutoloaderInit4b6cbad13c5a382a52d8b5f3d0364da8::getLoader();
return ComposerAutoloaderInit05da1cb31897006fe595ba09380e4767::getLoader();

View File

@ -1613,8 +1613,6 @@ return array(
'Rector\\ChangesReporting\\ValueObjectFactory\\ErrorFactory' => $baseDir . '/packages/ChangesReporting/ValueObjectFactory/ErrorFactory.php',
'Rector\\ChangesReporting\\ValueObjectFactory\\FileDiffFactory' => $baseDir . '/packages/ChangesReporting/ValueObjectFactory/FileDiffFactory.php',
'Rector\\ChangesReporting\\ValueObject\\RectorWithLineChange' => $baseDir . '/packages/ChangesReporting/ValueObject/RectorWithLineChange.php',
'Rector\\CodeQualityStrict\\NodeFactory\\ClassConstFetchFactory' => $baseDir . '/rules/CodeQualityStrict/NodeFactory/ClassConstFetchFactory.php',
'Rector\\CodeQualityStrict\\TypeAnalyzer\\SubTypeAnalyzer' => $baseDir . '/rules/CodeQualityStrict/TypeAnalyzer/SubTypeAnalyzer.php',
'Rector\\CodeQuality\\CompactConverter' => $baseDir . '/rules/CodeQuality/CompactConverter.php',
'Rector\\CodeQuality\\NodeAnalyzer\\ArrayCompacter' => $baseDir . '/rules/CodeQuality/NodeAnalyzer/ArrayCompacter.php',
'Rector\\CodeQuality\\NodeAnalyzer\\ArrayItemsAnalyzer' => $baseDir . '/rules/CodeQuality/NodeAnalyzer/ArrayItemsAnalyzer.php',
@ -2962,6 +2960,12 @@ return array(
'Rector\\StaticTypeMapper\\ValueObject\\Type\\ParentStaticType' => $baseDir . '/packages/StaticTypeMapper/ValueObject/Type/ParentStaticType.php',
'Rector\\StaticTypeMapper\\ValueObject\\Type\\SelfObjectType' => $baseDir . '/packages/StaticTypeMapper/ValueObject/Type/SelfObjectType.php',
'Rector\\StaticTypeMapper\\ValueObject\\Type\\ShortenedObjectType' => $baseDir . '/packages/StaticTypeMapper/ValueObject/Type/ShortenedObjectType.php',
'Rector\\Strict\\NodeFactory\\ExactCompareFactory' => $baseDir . '/rules/Strict/NodeFactory/ExactCompareFactory.php',
'Rector\\Strict\\Rector\\BooleanNot\\BooleanInBooleanNotRuleFixerRector' => $baseDir . '/rules/Strict/Rector/BooleanNot/BooleanInBooleanNotRuleFixerRector.php',
'Rector\\Strict\\Rector\\Empty_\\DisallowedEmptyRuleFixerRector' => $baseDir . '/rules/Strict/Rector/Empty_/DisallowedEmptyRuleFixerRector.php',
'Rector\\Strict\\Rector\\If_\\BooleanInIfConditionRuleFixerRector' => $baseDir . '/rules/Strict/Rector/If_/BooleanInIfConditionRuleFixerRector.php',
'Rector\\Strict\\Rector\\Ternary\\BooleanInTernaryOperatorRuleFixerRector' => $baseDir . '/rules/Strict/Rector/Ternary/BooleanInTernaryOperatorRuleFixerRector.php',
'Rector\\Strict\\Rector\\Ternary\\DisallowedShortTernaryRuleFixerRector' => $baseDir . '/rules/Strict/Rector/Ternary/DisallowedShortTernaryRuleFixerRector.php',
'Rector\\Symfony\\ApplicationMetadata\\ListenerServiceDefinitionProvider' => $vendorDir . '/rector/rector-symfony/src/ApplicationMetadata/ListenerServiceDefinitionProvider.php',
'Rector\\Symfony\\Bridge\\NodeAnalyzer\\ControllerMethodAnalyzer' => $vendorDir . '/rector/rector-symfony/src/Bridge/NodeAnalyzer/ControllerMethodAnalyzer.php',
'Rector\\Symfony\\BundleClassResolver' => $vendorDir . '/rector/rector-symfony/src/BundleClassResolver.php',

View File

@ -2,7 +2,7 @@
// autoload_real.php @generated by Composer
class ComposerAutoloaderInit4b6cbad13c5a382a52d8b5f3d0364da8
class ComposerAutoloaderInit05da1cb31897006fe595ba09380e4767
{
private static $loader;
@ -22,15 +22,15 @@ class ComposerAutoloaderInit4b6cbad13c5a382a52d8b5f3d0364da8
return self::$loader;
}
spl_autoload_register(array('ComposerAutoloaderInit4b6cbad13c5a382a52d8b5f3d0364da8', 'loadClassLoader'), true, true);
spl_autoload_register(array('ComposerAutoloaderInit05da1cb31897006fe595ba09380e4767', 'loadClassLoader'), true, true);
self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(\dirname(__FILE__)));
spl_autoload_unregister(array('ComposerAutoloaderInit4b6cbad13c5a382a52d8b5f3d0364da8', 'loadClassLoader'));
spl_autoload_unregister(array('ComposerAutoloaderInit05da1cb31897006fe595ba09380e4767', 'loadClassLoader'));
$useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
if ($useStaticLoader) {
require __DIR__ . '/autoload_static.php';
call_user_func(\Composer\Autoload\ComposerStaticInit4b6cbad13c5a382a52d8b5f3d0364da8::getInitializer($loader));
call_user_func(\Composer\Autoload\ComposerStaticInit05da1cb31897006fe595ba09380e4767::getInitializer($loader));
} else {
$classMap = require __DIR__ . '/autoload_classmap.php';
if ($classMap) {
@ -42,19 +42,19 @@ class ComposerAutoloaderInit4b6cbad13c5a382a52d8b5f3d0364da8
$loader->register(true);
if ($useStaticLoader) {
$includeFiles = Composer\Autoload\ComposerStaticInit4b6cbad13c5a382a52d8b5f3d0364da8::$files;
$includeFiles = Composer\Autoload\ComposerStaticInit05da1cb31897006fe595ba09380e4767::$files;
} else {
$includeFiles = require __DIR__ . '/autoload_files.php';
}
foreach ($includeFiles as $fileIdentifier => $file) {
composerRequire4b6cbad13c5a382a52d8b5f3d0364da8($fileIdentifier, $file);
composerRequire05da1cb31897006fe595ba09380e4767($fileIdentifier, $file);
}
return $loader;
}
}
function composerRequire4b6cbad13c5a382a52d8b5f3d0364da8($fileIdentifier, $file)
function composerRequire05da1cb31897006fe595ba09380e4767($fileIdentifier, $file)
{
if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
require $file;

View File

@ -4,7 +4,7 @@
namespace Composer\Autoload;
class ComposerStaticInit4b6cbad13c5a382a52d8b5f3d0364da8
class ComposerStaticInit05da1cb31897006fe595ba09380e4767
{
public static $files = array (
'a4a119a56e50fbb293281d9a48007e0e' => __DIR__ . '/..' . '/symfony/polyfill-php80/bootstrap.php',
@ -1973,8 +1973,6 @@ class ComposerStaticInit4b6cbad13c5a382a52d8b5f3d0364da8
'Rector\\ChangesReporting\\ValueObjectFactory\\ErrorFactory' => __DIR__ . '/../..' . '/packages/ChangesReporting/ValueObjectFactory/ErrorFactory.php',
'Rector\\ChangesReporting\\ValueObjectFactory\\FileDiffFactory' => __DIR__ . '/../..' . '/packages/ChangesReporting/ValueObjectFactory/FileDiffFactory.php',
'Rector\\ChangesReporting\\ValueObject\\RectorWithLineChange' => __DIR__ . '/../..' . '/packages/ChangesReporting/ValueObject/RectorWithLineChange.php',
'Rector\\CodeQualityStrict\\NodeFactory\\ClassConstFetchFactory' => __DIR__ . '/../..' . '/rules/CodeQualityStrict/NodeFactory/ClassConstFetchFactory.php',
'Rector\\CodeQualityStrict\\TypeAnalyzer\\SubTypeAnalyzer' => __DIR__ . '/../..' . '/rules/CodeQualityStrict/TypeAnalyzer/SubTypeAnalyzer.php',
'Rector\\CodeQuality\\CompactConverter' => __DIR__ . '/../..' . '/rules/CodeQuality/CompactConverter.php',
'Rector\\CodeQuality\\NodeAnalyzer\\ArrayCompacter' => __DIR__ . '/../..' . '/rules/CodeQuality/NodeAnalyzer/ArrayCompacter.php',
'Rector\\CodeQuality\\NodeAnalyzer\\ArrayItemsAnalyzer' => __DIR__ . '/../..' . '/rules/CodeQuality/NodeAnalyzer/ArrayItemsAnalyzer.php',
@ -3322,6 +3320,12 @@ class ComposerStaticInit4b6cbad13c5a382a52d8b5f3d0364da8
'Rector\\StaticTypeMapper\\ValueObject\\Type\\ParentStaticType' => __DIR__ . '/../..' . '/packages/StaticTypeMapper/ValueObject/Type/ParentStaticType.php',
'Rector\\StaticTypeMapper\\ValueObject\\Type\\SelfObjectType' => __DIR__ . '/../..' . '/packages/StaticTypeMapper/ValueObject/Type/SelfObjectType.php',
'Rector\\StaticTypeMapper\\ValueObject\\Type\\ShortenedObjectType' => __DIR__ . '/../..' . '/packages/StaticTypeMapper/ValueObject/Type/ShortenedObjectType.php',
'Rector\\Strict\\NodeFactory\\ExactCompareFactory' => __DIR__ . '/../..' . '/rules/Strict/NodeFactory/ExactCompareFactory.php',
'Rector\\Strict\\Rector\\BooleanNot\\BooleanInBooleanNotRuleFixerRector' => __DIR__ . '/../..' . '/rules/Strict/Rector/BooleanNot/BooleanInBooleanNotRuleFixerRector.php',
'Rector\\Strict\\Rector\\Empty_\\DisallowedEmptyRuleFixerRector' => __DIR__ . '/../..' . '/rules/Strict/Rector/Empty_/DisallowedEmptyRuleFixerRector.php',
'Rector\\Strict\\Rector\\If_\\BooleanInIfConditionRuleFixerRector' => __DIR__ . '/../..' . '/rules/Strict/Rector/If_/BooleanInIfConditionRuleFixerRector.php',
'Rector\\Strict\\Rector\\Ternary\\BooleanInTernaryOperatorRuleFixerRector' => __DIR__ . '/../..' . '/rules/Strict/Rector/Ternary/BooleanInTernaryOperatorRuleFixerRector.php',
'Rector\\Strict\\Rector\\Ternary\\DisallowedShortTernaryRuleFixerRector' => __DIR__ . '/../..' . '/rules/Strict/Rector/Ternary/DisallowedShortTernaryRuleFixerRector.php',
'Rector\\Symfony\\ApplicationMetadata\\ListenerServiceDefinitionProvider' => __DIR__ . '/..' . '/rector/rector-symfony/src/ApplicationMetadata/ListenerServiceDefinitionProvider.php',
'Rector\\Symfony\\Bridge\\NodeAnalyzer\\ControllerMethodAnalyzer' => __DIR__ . '/..' . '/rector/rector-symfony/src/Bridge/NodeAnalyzer/ControllerMethodAnalyzer.php',
'Rector\\Symfony\\BundleClassResolver' => __DIR__ . '/..' . '/rector/rector-symfony/src/BundleClassResolver.php',
@ -3888,9 +3892,9 @@ class ComposerStaticInit4b6cbad13c5a382a52d8b5f3d0364da8
public static function getInitializer(ClassLoader $loader)
{
return \Closure::bind(function () use ($loader) {
$loader->prefixLengthsPsr4 = ComposerStaticInit4b6cbad13c5a382a52d8b5f3d0364da8::$prefixLengthsPsr4;
$loader->prefixDirsPsr4 = ComposerStaticInit4b6cbad13c5a382a52d8b5f3d0364da8::$prefixDirsPsr4;
$loader->classMap = ComposerStaticInit4b6cbad13c5a382a52d8b5f3d0364da8::$classMap;
$loader->prefixLengthsPsr4 = ComposerStaticInit05da1cb31897006fe595ba09380e4767::$prefixLengthsPsr4;
$loader->prefixDirsPsr4 = ComposerStaticInit05da1cb31897006fe595ba09380e4767::$prefixDirsPsr4;
$loader->classMap = ComposerStaticInit05da1cb31897006fe595ba09380e4767::$classMap;
}, null, ClassLoader::class);
}

View File

@ -9,8 +9,8 @@ $loader = require_once __DIR__.'/autoload.php';
if (!class_exists('AutoloadIncluder', false) && !interface_exists('AutoloadIncluder', false) && !trait_exists('AutoloadIncluder', false)) {
spl_autoload_call('RectorPrefix20211005\AutoloadIncluder');
}
if (!class_exists('ComposerAutoloaderInit4b6cbad13c5a382a52d8b5f3d0364da8', false) && !interface_exists('ComposerAutoloaderInit4b6cbad13c5a382a52d8b5f3d0364da8', false) && !trait_exists('ComposerAutoloaderInit4b6cbad13c5a382a52d8b5f3d0364da8', false)) {
spl_autoload_call('RectorPrefix20211005\ComposerAutoloaderInit4b6cbad13c5a382a52d8b5f3d0364da8');
if (!class_exists('ComposerAutoloaderInit05da1cb31897006fe595ba09380e4767', false) && !interface_exists('ComposerAutoloaderInit05da1cb31897006fe595ba09380e4767', false) && !trait_exists('ComposerAutoloaderInit05da1cb31897006fe595ba09380e4767', false)) {
spl_autoload_call('RectorPrefix20211005\ComposerAutoloaderInit05da1cb31897006fe595ba09380e4767');
}
if (!class_exists('Helmich\TypoScriptParser\Parser\AST\Statement', false) && !interface_exists('Helmich\TypoScriptParser\Parser\AST\Statement', false) && !trait_exists('Helmich\TypoScriptParser\Parser\AST\Statement', false)) {
spl_autoload_call('RectorPrefix20211005\Helmich\TypoScriptParser\Parser\AST\Statement');
@ -3306,9 +3306,9 @@ if (!function_exists('print_node')) {
return \RectorPrefix20211005\print_node(...func_get_args());
}
}
if (!function_exists('composerRequire4b6cbad13c5a382a52d8b5f3d0364da8')) {
function composerRequire4b6cbad13c5a382a52d8b5f3d0364da8() {
return \RectorPrefix20211005\composerRequire4b6cbad13c5a382a52d8b5f3d0364da8(...func_get_args());
if (!function_exists('composerRequire05da1cb31897006fe595ba09380e4767')) {
function composerRequire05da1cb31897006fe595ba09380e4767() {
return \RectorPrefix20211005\composerRequire05da1cb31897006fe595ba09380e4767(...func_get_args());
}
}
if (!function_exists('parseArgs')) {