[Doctrine] Step #3 - getUuid/setUuid method calls to id values (#2011)

[Doctrine] Step #3 - getUuid/setUuid method calls to id values
This commit is contained in:
Tomáš Votruba 2019-09-21 16:35:35 +02:00 committed by GitHub
commit 87c5dcb9b0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
63 changed files with 882 additions and 125 deletions

View File

@ -21,6 +21,7 @@
"phpstan/phpdoc-parser": "^0.3.5",
"phpstan/phpstan": "^0.11.13",
"phpstan/phpstan-phpunit": "^0.11.2",
"ramsey/uuid": "^3.8",
"sebastian/diff": "^3.0",
"symfony/console": "^3.4|^4.2",
"symfony/dependency-injection": "^3.4|^4.2",

View File

@ -0,0 +1,3 @@
services:
Rector\Doctrine\Rector\MethodCall\ChangeSetIdToUuidValueRector: ~
Rector\Doctrine\Rector\MethodCall\ChangeGetUuidMethodCallToGetIdRector: ~

View File

@ -246,7 +246,7 @@ PHP
private function useForeachVariableInStmts(Expr $expr, array $stmts): void
{
if ($this->keyValueName === null) {
throw new ShouldNotHappenException(__METHOD__ . '() on line ' . __LINE__);
throw new ShouldNotHappenException();
}
$this->traverseNodesWithCallable($stmts, function (Node $node) use ($expr): ?Expr {

View File

@ -28,7 +28,7 @@ final class ClassNaming
if ($name instanceof Name) {
$name = $this->nameResolver->getName($name);
if ($name === null) {
throw new ShouldNotHappenException(__METHOD__ . '() on line ' . __LINE__);
throw new ShouldNotHappenException();
}
}

View File

@ -131,7 +131,7 @@ PHP
// remove whole return node
$parentNode = $arrayNode->getAttribute(AttributeKey::PARENT_NODE);
if ($parentNode === null) {
throw new ShouldNotHappenException(__METHOD__ . '() on line ' . __LINE__);
throw new ShouldNotHappenException();
}
$this->removeNode($parentNode);

View File

@ -266,7 +266,7 @@ PHP
$parentNode = $nameNode->getAttribute(AttributeKey::PARENT_NODE);
if ($parentNode === null) {
throw new ShouldNotHappenException(__METHOD__ . '() on line ' . __LINE__);
throw new ShouldNotHappenException();
}
$this->resolvedNodeNames[$originalName->toString()][] = [$nameNode, $parentNode];

View File

@ -82,7 +82,7 @@ final class VariableNodeUseInfo
{
$parentNode = $this->variable->getAttribute(AttributeKey::PARENT_NODE);
if ($parentNode === null) {
throw new ShouldNotHappenException(__METHOD__ . '() on line ' . __LINE__);
throw new ShouldNotHappenException();
}
return $parentNode;

View File

@ -180,7 +180,7 @@ PHP
$parentClassName = get_parent_class($className);
if ($parentClassName === false) {
throw new ShouldNotHappenException(__METHOD__);
throw new ShouldNotHappenException();
}
/** @var string $methodName */

View File

@ -28,7 +28,10 @@ trait DoctrineTrait
return $this->doctrineDocBlockResolver->isDoctrineProperty($property);
}
protected function isDoctrineEntityClass(Class_ $class): bool
/**
* @param Class_|string $class
*/
protected function isDoctrineEntityClass($class): bool
{
return $this->doctrineDocBlockResolver->isDoctrineEntityClass($class);
}

View File

@ -2,6 +2,7 @@
namespace Rector\Doctrine\PhpDocParser;
use Nette\Utils\Strings;
use PhpParser\Node;
use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\ClassLike;
@ -11,8 +12,12 @@ use Rector\DoctrinePhpDocParser\Ast\PhpDoc\Class_\EntityTagValueNode;
use Rector\DoctrinePhpDocParser\Ast\PhpDoc\Property_\ColumnTagValueNode;
use Rector\DoctrinePhpDocParser\Ast\PhpDoc\Property_\IdTagValueNode;
use Rector\DoctrinePhpDocParser\Contract\Ast\PhpDoc\DoctrineRelationTagValueNodeInterface;
use Rector\Exception\ShouldNotHappenException;
use Rector\NodeContainer\ParsedNodesByType;
use Rector\NodeTypeResolver\ClassExistenceStaticHelper;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Rector\NodeTypeResolver\PhpDoc\NodeAnalyzer\DocBlockManipulator;
use ReflectionClass;
final class DoctrineDocBlockResolver
{
@ -21,19 +26,48 @@ final class DoctrineDocBlockResolver
*/
private $docBlockManipulator;
public function __construct(DocBlockManipulator $docBlockManipulator)
/**
* @var ParsedNodesByType
*/
private $parsedNodesByType;
public function __construct(DocBlockManipulator $docBlockManipulator, ParsedNodesByType $parsedNodesByType)
{
$this->docBlockManipulator = $docBlockManipulator;
$this->parsedNodesByType = $parsedNodesByType;
}
public function isDoctrineEntityClass(Class_ $class): bool
/**
* @param Class_|string $class
*/
public function isDoctrineEntityClass($class): bool
{
$classPhpDocInfo = $this->getPhpDocInfo($class);
if ($classPhpDocInfo === null) {
if ($class instanceof Class_) {
$classPhpDocInfo = $this->getPhpDocInfo($class);
if ($classPhpDocInfo === null) {
return false;
}
return (bool) $classPhpDocInfo->getByType(EntityTagValueNode::class);
}
if (is_string($class)) {
if (ClassExistenceStaticHelper::doesClassLikeExist($class)) {
$classNode = $this->parsedNodesByType->findClass($class);
if ($classNode) {
return $this->isDoctrineEntityClass($classNode);
}
$reflectionClass = new ReflectionClass($class);
// dummy check of 3rd party code without running it
return Strings::contains((string) $reflectionClass->getDocComment(), '@ORM\Entity');
}
return false;
}
return (bool) $classPhpDocInfo->getByType(EntityTagValueNode::class);
throw new ShouldNotHappenException();
}
public function isDoctrineEntityClassWithIdProperty(Class_ $class): bool

View File

@ -0,0 +1,116 @@
<?php declare(strict_types=1);
namespace Rector\Doctrine\Rector\MethodCall;
use PhpParser\Node;
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Identifier;
use PHPStan\Type\ObjectType;
use Rector\Rector\AbstractRector;
use Rector\RectorDefinition\CodeSample;
use Rector\RectorDefinition\RectorDefinition;
/**
* @see \Rector\Doctrine\Tests\Rector\MethodCall\ChangeGetUuidMethodCallToGetIdRector\ChangeGetUuidMethodCallToGetIdRectorTest
*/
final class ChangeGetUuidMethodCallToGetIdRector extends AbstractRector
{
public function getDefinition(): RectorDefinition
{
return new RectorDefinition('Change getUuid() method call to getId()', [
new CodeSample(
<<<'PHP'
use Doctrine\ORM\Mapping as ORM;
use Ramsey\Uuid\Uuid;
use Ramsey\Uuid\UuidInterface;
class SomeClass
{
public function run()
{
$buildingFirst = new Building();
return $buildingFirst->getUuid()->toString();
}
}
/**
* @ORM\Entity
*/
class UuidEntity
{
private $uuid;
public function getUuid(): UuidInterface
{
return $this->uuid;
}
}
PHP
,
<<<'PHP'
use Doctrine\ORM\Mapping as ORM;
use Ramsey\Uuid\Uuid;
use Ramsey\Uuid\UuidInterface;
class SomeClass
{
public function run()
{
$buildingFirst = new Building();
return $buildingFirst->getId()->toString();
}
}
/**
* @ORM\Entity
*/
class UuidEntity
{
private $uuid;
public function getUuid(): UuidInterface
{
return $this->uuid;
}
}
PHP
),
]);
}
/**
* @return string[]
*/
public function getNodeTypes(): array
{
return [MethodCall::class];
}
/**
* @param MethodCall $node
*/
public function refactor(Node $node): ?Node
{
if ($this->shouldSkip($node)) {
return null;
}
$node->name = new Identifier('getId');
return $node;
}
private function shouldSkip(Node\Expr\MethodCall $methodCall): bool
{
if (! $this->isName($methodCall->name, 'getUuid')) {
return true;
}
$methodVarObjectType = $this->getObjectType($methodCall->var);
if (! $methodVarObjectType instanceof ObjectType) {
return true;
}
return ! $this->isDoctrineEntityClass($methodVarObjectType->getClassName());
}
}

View File

@ -0,0 +1,225 @@
<?php declare(strict_types=1);
namespace Rector\Doctrine\Rector\MethodCall;
use PhpParser\Node;
use PhpParser\Node\Expr;
use PhpParser\Node\Expr\ClassConstFetch;
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Scalar\String_;
use PhpParser\Node\Stmt\Expression;
use PHPStan\Type\ObjectType;
use PHPStan\Type\StringType;
use Ramsey\Uuid\Uuid;
use Rector\Doctrine\ValueObject\DoctrineClass;
use Rector\NodeContainer\ParsedNodesByType;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Rector\Rector\AbstractRector;
use Rector\RectorDefinition\CodeSample;
use Rector\RectorDefinition\RectorDefinition;
/**
* @sponsor Thanks https://spaceflow.io/ for sponsoring this rule - visit them on https://github.com/SpaceFlow-app
*
* @see \Rector\Doctrine\Tests\Rector\MethodCall\ChangeSetIdToUuidValueRector\ChangeSetIdToUuidValueRectorTest
*/
final class ChangeSetIdToUuidValueRector extends AbstractRector
{
/**
* @var ParsedNodesByType
*/
private $parsedNodesByType;
public function __construct(ParsedNodesByType $parsedNodesByType)
{
$this->parsedNodesByType = $parsedNodesByType;
}
public function getDefinition(): RectorDefinition
{
return new RectorDefinition('Change set id to uuid values', [
new CodeSample(
<<<'PHP'
use Doctrine\ORM\Mapping as ORM;
use Ramsey\Uuid\Uuid;
class SomeClass
{
public function run()
{
$buildingFirst = new Building();
$buildingFirst->setId(1);
$buildingFirst->setUuid(Uuid::fromString('a3bfab84-e207-4ddd-b96d-488151de9e96'));
}
}
/**
* @ORM\Entity
*/
class Building
{
}
PHP
,
<<<'PHP'
use Doctrine\ORM\Mapping as ORM;
use Ramsey\Uuid\Uuid;
class SomeClass
{
public function run()
{
$buildingFirst = new Building();
$buildingFirst->setId(Uuid::fromString('a3bfab84-e207-4ddd-b96d-488151de9e96'));
}
}
/**
* @ORM\Entity
*/
class Building
{
}
PHP
),
]);
}
/**
* @return string[]
*/
public function getNodeTypes(): array
{
return [MethodCall::class];
}
/**
* @param MethodCall $node
*/
public function refactor(Node $node): ?Node
{
if ($this->shouldSkip($node)) {
return null;
}
// A. try find "setUuid()" call on the same object later
$setUuidCallOnSameVariable = $this->getSetUuidMethodCallOnSameVariable($node);
if ($setUuidCallOnSameVariable) {
$node->args = $setUuidCallOnSameVariable->args;
$this->removeNode($setUuidCallOnSameVariable);
return $node;
}
// B. is the value constant reference?
$argumentValue = $node->args[0]->value;
if ($argumentValue instanceof ClassConstFetch) {
$classConst = $this->parsedNodesByType->findClassConstantByClassConstFetch($argumentValue);
if ($classConst === null) {
return null;
}
$constantValueStaticType = $this->getStaticType($classConst->consts[0]->value);
// probably already uuid
if ($constantValueStaticType instanceof StringType) {
return null;
}
// update constant value
$classConst->consts[0]->value = $this->createUuidStringNode();
$node->args[0]->value = $this->createStaticCall(Uuid::class, 'fromString', [$argumentValue]);
return $node;
}
// C. set uuid from string with generated string
$value = $this->createStaticCall(Uuid::class, 'fromString', [$this->createUuidStringNode()]);
$node->args[0]->value = $value;
return $node;
}
private function shouldSkip(MethodCall $methodCall): bool
{
if (! $this->isName($methodCall->name, 'setId')) {
return true;
}
$objectType = $this->getObjectType($methodCall);
if (! $objectType instanceof ObjectType) {
return true;
}
if (! $this->isDoctrineEntityClass($objectType->getClassName())) {
return true;
}
if (! isset($methodCall->args[0])) {
return true;
}
// already uuid static type
return $this->isUuidType($methodCall->args[0]->value);
}
private function getSetUuidMethodCallOnSameVariable(MethodCall $methodCall): ?MethodCall
{
$parentNode = $methodCall->getAttribute(AttributeKey::PARENT_NODE);
if ($parentNode instanceof Expression) {
$parentNode = $parentNode->getAttribute(AttributeKey::PARENT_NODE);
}
if ($parentNode === null) {
return null;
}
$variableName = $this->getName($methodCall->var);
/** @var ObjectType $variableType */
$variableType = $this->getStaticType($methodCall->var);
return $this->betterNodeFinder->findFirst($parentNode, function (Node $node) use (
$variableName,
$variableType
): bool {
if (! $node instanceof MethodCall) {
return false;
}
if (! $this->isName($node->var, $variableName)) {
return false;
}
if (! $this->isObjectType($node->var, $variableType)) {
return false;
}
if (! $this->isName($node, 'setUuid')) {
return false;
}
return true;
});
}
private function isUuidType(Expr $expr): bool
{
$argumentStaticType = $this->getStaticType($expr);
// UUID is already set
if (! $argumentStaticType instanceof ObjectType) {
return false;
}
return $argumentStaticType->getClassName() === DoctrineClass::RAMSEY_UUID;
}
private function createUuidStringNode(): String_
{
$uuidValue = Uuid::uuid4();
$uuidValueString = $uuidValue->toString();
return new String_($uuidValueString);
}
}

View File

@ -31,7 +31,7 @@ final class JoinTableNameResolver
$targetEntity = $this->doctrineDocBlockResolver->getTargetEntity($property);
if ($targetEntity === null) {
throw new ShouldNotHappenException(__METHOD__);
throw new ShouldNotHappenException();
}
$targetTableName = $this->resolveShortClassName($targetEntity);

View File

@ -4,11 +4,6 @@ namespace Rector\Doctrine\ValueObject;
final class DoctrineClass
{
/**
* @var string
*/
public const RAMSEY_UUID_INTERFACE = 'Ramsey\Uuid\UuidInterface';
/**
* @var string
*/
@ -28,4 +23,14 @@ final class DoctrineClass
* @var string
*/
public const OBJECT_MANAGER = 'Doctrine\Common\Persistence\ObjectManager';
/**
* @var string
*/
public const RAMSEY_UUID = 'Ramsey\Uuid\Uuid';
/**
* @var string
*/
public const RAMSEY_UUID_INTERFACE = 'Ramsey\Uuid\UuidInterface';
}

View File

@ -0,0 +1,30 @@
<?php declare(strict_types=1);
namespace Rector\Doctrine\Tests\Rector\MethodCall\ChangeGetUuidMethodCallToGetIdRector;
use Rector\Doctrine\Rector\MethodCall\ChangeGetUuidMethodCallToGetIdRector;
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
final class ChangeGetUuidMethodCallToGetIdRectorTest extends AbstractRectorTestCase
{
/**
* @dataProvider provideDataForTest()
*/
public function test(string $file): void
{
$this->doTestFile($file);
}
/**
* @return string[]
*/
public function provideDataForTest(): iterable
{
yield [__DIR__ . '/Fixture/fixture.php.inc'];
}
protected function getRectorClass(): string
{
return ChangeGetUuidMethodCallToGetIdRector::class;
}
}

View File

@ -0,0 +1,35 @@
<?php
namespace Rector\Doctrine\Tests\Rector\MethodCall\ChangeGetUuidMethodCallToGetIdRector\Fixture;
use Rector\Doctrine\Tests\Rector\MethodCall\ChangeGetUuidMethodCallToGetIdRector\Source\Car;
class SomeClass
{
public function run()
{
$car = new Car();
return $car->getUuid()->toString();
}
}
?>
-----
<?php
namespace Rector\Doctrine\Tests\Rector\MethodCall\ChangeGetUuidMethodCallToGetIdRector\Fixture;
use Rector\Doctrine\Tests\Rector\MethodCall\ChangeGetUuidMethodCallToGetIdRector\Source\Car;
class SomeClass
{
public function run()
{
$car = new Car();
return $car->getId()->toString();
}
}
?>

View File

@ -0,0 +1,19 @@
<?php declare(strict_types=1);
namespace Rector\Doctrine\Tests\Rector\MethodCall\ChangeGetUuidMethodCallToGetIdRector\Source;
use Doctrine\ORM\Mapping as ORM;
use Ramsey\Uuid\UuidInterface;
/**
* @ORM\Entity
*/
class Car
{
private $uuid;
public function getUuid(): UuidInterface
{
return $this->uuid;
}
}

View File

@ -0,0 +1,34 @@
<?php declare(strict_types=1);
namespace Rector\Doctrine\Tests\Rector\MethodCall\ChangeSetIdToUuidValueRector;
use Rector\Doctrine\Rector\MethodCall\ChangeSetIdToUuidValueRector;
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
final class ChangeSetIdToUuidValueRectorTest extends AbstractRectorTestCase
{
/**
* @dataProvider provideDataForTest()
*/
public function test(string $file): void
{
$this->doTestFile($file);
}
/**
* @return string[]
*/
public function provideDataForTest(): iterable
{
yield [__DIR__ . '/Fixture/fixture.php.inc'];
yield [__DIR__ . '/Fixture/no_set_uuid.php.inc'];
yield [__DIR__ . '/Fixture/other_direction.php.inc'];
yield [__DIR__ . '/Fixture/with_constant.php.inc'];
yield [__DIR__ . '/Fixture/with_int_constant_only.php.inc'];
}
protected function getRectorClass(): string
{
return ChangeSetIdToUuidValueRector::class;
}
}

View File

@ -0,0 +1,42 @@
<?php
namespace Rector\Doctrine\Tests\Rector\MethodCall\ChangeSetIdToUuidValueRector\Fixture;
use Ramsey\Uuid\Uuid;
use Rector\Doctrine\Tests\Rector\MethodCall\ChangeSetIdToUuidValueRector\Source\Building;
class SomeClass
{
public function run()
{
$buildingFirst = new Building();
$buildingFirst->setId(1);
$buildingFirst->setUuid(Uuid::fromString('a3bfab84-e207-4ddd-b96d-488151de9e96'));
$buildingFirst2 = new Building();
$buildingFirst2->setUuid('skip_this');
}
}
?>
-----
<?php
namespace Rector\Doctrine\Tests\Rector\MethodCall\ChangeSetIdToUuidValueRector\Fixture;
use Ramsey\Uuid\Uuid;
use Rector\Doctrine\Tests\Rector\MethodCall\ChangeSetIdToUuidValueRector\Source\Building;
class SomeClass
{
public function run()
{
$buildingFirst = new Building();
$buildingFirst->setId(Uuid::fromString('a3bfab84-e207-4ddd-b96d-488151de9e96'));
$buildingFirst2 = new Building();
$buildingFirst2->setUuid('skip_this');
}
}
?>

View File

@ -0,0 +1,35 @@
<?php
namespace Rector\Doctrine\Tests\Rector\MethodCall\ChangeSetIdToUuidValueRector\Fixture;
use Doctrine\ORM\Mapping as ORM;
use Rector\Doctrine\Tests\Rector\MethodCall\ChangeSetIdToUuidValueRector\Source\Building;
class NoSetUuid
{
public function run()
{
$car = new Building();
$car->setId(1);
}
}
?>
-----
<?php
namespace Rector\Doctrine\Tests\Rector\MethodCall\ChangeSetIdToUuidValueRector\Fixture;
use Doctrine\ORM\Mapping as ORM;
use Rector\Doctrine\Tests\Rector\MethodCall\ChangeSetIdToUuidValueRector\Source\Building;
class NoSetUuid
{
public function run()
{
$car = new Building();
$car->setId(\Ramsey\Uuid\Uuid::fromString('%s-%s-%s-%s-%s'));
}
}
?>

View File

@ -0,0 +1,36 @@
<?php
namespace Rector\Doctrine\Tests\Rector\MethodCall\ChangeSetIdToUuidValueRector\Fixture;
use Ramsey\Uuid\Uuid;
use Rector\Doctrine\Tests\Rector\MethodCall\ChangeSetIdToUuidValueRector\Source\Building;
class OtherDirection
{
public function run()
{
$buildingFirst = new Building();
$buildingFirst->setUuid(Uuid::fromString('a3bfab84-e207-4ddd-b96d-488151de9e96'));
$buildingFirst->setId(1);
}
}
?>
-----
<?php
namespace Rector\Doctrine\Tests\Rector\MethodCall\ChangeSetIdToUuidValueRector\Fixture;
use Ramsey\Uuid\Uuid;
use Rector\Doctrine\Tests\Rector\MethodCall\ChangeSetIdToUuidValueRector\Source\Building;
class OtherDirection
{
public function run()
{
$buildingFirst = new Building();
$buildingFirst->setId(Uuid::fromString('a3bfab84-e207-4ddd-b96d-488151de9e96'));
}
}
?>

View File

@ -0,0 +1,42 @@
<?php
namespace Rector\Doctrine\Tests\Rector\MethodCall\ChangeSetIdToUuidValueRector\Fixture;
use Ramsey\Uuid\Uuid;
use Rector\Doctrine\Tests\Rector\MethodCall\ChangeSetIdToUuidValueRector\Source\Building;
class WithConstant
{
const INTEGER_CONSTANT = 1;
const UUID_CONSTANT = 'a3bfab84-e207-4ddd-b96d-488151de9e96';
public function run()
{
$buildingFirst = new Building();
$buildingFirst->setUuid(Uuid::fromString(self::UUID_CONSTANT));
$buildingFirst->setId(self::INTEGER_CONSTANT);
}
}
?>
-----
<?php
namespace Rector\Doctrine\Tests\Rector\MethodCall\ChangeSetIdToUuidValueRector\Fixture;
use Ramsey\Uuid\Uuid;
use Rector\Doctrine\Tests\Rector\MethodCall\ChangeSetIdToUuidValueRector\Source\Building;
class WithConstant
{
const INTEGER_CONSTANT = 1;
const UUID_CONSTANT = 'a3bfab84-e207-4ddd-b96d-488151de9e96';
public function run()
{
$buildingFirst = new Building();
$buildingFirst->setId(Uuid::fromString(self::UUID_CONSTANT));
}
}
?>

View File

@ -0,0 +1,43 @@
<?php
namespace Rector\Doctrine\Tests\Rector\MethodCall\ChangeSetIdToUuidValueRector\Fixture;
use Rector\Doctrine\Tests\Rector\MethodCall\ChangeSetIdToUuidValueRector\Source\Building;
class WithIntConstantOnly
{
const INTEGER_CONSTANT = 1;
public function run()
{
$buildingFirst = new Building();
$buildingFirst->setId(self::INTEGER_CONSTANT);
// this values should be the same
assert($buildingFirst->getId() === self::INTEGER_CONSTANT);
}
}
?>
-----
<?php
namespace Rector\Doctrine\Tests\Rector\MethodCall\ChangeSetIdToUuidValueRector\Fixture;
use Rector\Doctrine\Tests\Rector\MethodCall\ChangeSetIdToUuidValueRector\Source\Building;
class WithIntConstantOnly
{
const INTEGER_CONSTANT = '%s-%s-%s-%s-%s';
public function run()
{
$buildingFirst = new Building();
$buildingFirst->setId(\Ramsey\Uuid\Uuid::fromString(self::INTEGER_CONSTANT));
// this values should be the same
assert($buildingFirst->getId() === self::INTEGER_CONSTANT);
}
}
?>

View File

@ -0,0 +1,12 @@
<?php declare(strict_types=1);
namespace Rector\Doctrine\Tests\Rector\MethodCall\ChangeSetIdToUuidValueRector\Source;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity
*/
class Building
{
}

View File

@ -61,7 +61,7 @@ final class NodeAnnotationReader
/** @var Annotation|null $classAnnotation */
$classAnnotation = $this->annotationReader->getClassAnnotation($classReflection, $annotationClassName);
if ($classAnnotation === null) {
throw new ShouldNotHappenException(__METHOD__ . '() on line ' . __LINE__);
throw new ShouldNotHappenException();
}
return $classAnnotation;
@ -80,7 +80,7 @@ final class NodeAnnotationReader
/** @var Annotation|null $propertyAnnotation */
$propertyAnnotation = $this->annotationReader->getPropertyAnnotation($propertyReflection, $annotationClassName);
if ($propertyAnnotation === null) {
throw new ShouldNotHappenException(__METHOD__ . '() on line ' . __LINE__);
throw new ShouldNotHappenException();
}
return $propertyAnnotation;

View File

@ -255,7 +255,7 @@ PHP
return new MethodCall($propertyFetchNode, $service['non_array_method'], $node->args);
}
throw new ShouldNotHappenException(__METHOD__ . '() on line ' . __LINE__);
throw new ShouldNotHappenException();
}
return null;

View File

@ -155,7 +155,7 @@ PHP
$previousExpression = $assign->getAttribute(AttributeKey::PREVIOUS_EXPRESSION);
if ($previousExpression === null) {
throw new ShouldNotHappenException(__METHOD__ . '() on line ' . __LINE__);
throw new ShouldNotHappenException();
}
$this->addNodeAfterNode($forNode, $previousExpression);

View File

@ -126,7 +126,7 @@ final class NodeScopeResolver
}
if ($classOrInterfaceNode->name === null) {
throw new ShouldNotHappenException(__METHOD__ . '() on line ' . __LINE__);
throw new ShouldNotHappenException();
}
return $classOrInterfaceNode->name->toString();

View File

@ -153,7 +153,7 @@ PHP
}
if (count($node->args) !== 1) {
throw new ShouldNotHappenException(__METHOD__);
throw new ShouldNotHappenException();
}
// resolve value types

View File

@ -84,7 +84,7 @@ final class AssertRegExpRector extends AbstractPHPUnitRector
return $this->isTrue($node) ? 1 : 0;
}
throw new ShouldNotHappenException(__METHOD__);
throw new ShouldNotHappenException();
}
/**

View File

@ -154,7 +154,7 @@ PHP
$previousExpression = $assign->getAttribute(AttributeKey::PREVIOUS_EXPRESSION);
if ($previousExpression === null) {
throw new ShouldNotHappenException(__METHOD__ . '() on line ' . __LINE__);
throw new ShouldNotHappenException();
}
$this->addNodeAfterNode($forNode, $previousExpression);

View File

@ -52,7 +52,7 @@ final class BarewordStringRector extends AbstractRector
// load the file!
$fileInfo = $node->getAttribute(AttributeKey::FILE_INFO);
if ($fileInfo === null) {
throw new ShouldNotHappenException(__METHOD__ . '() on line ' . __LINE__);
throw new ShouldNotHappenException();
}
$this->undefinedConstants = [];

View File

@ -111,7 +111,7 @@ PHP
{
if (! $expr instanceof String_) {
// not supported yet
throw new ShouldNotHappenException(__METHOD__ . '() on line ' . __LINE__);
throw new ShouldNotHappenException();
}
$phpCode = '<?php ' . $expr->value . ';';

View File

@ -2,13 +2,10 @@
namespace Rector\Php\Tests\Rector\FuncCall\RegexDashEscapeRector\Fixture;
use Nette\Utils\Strings;
class ConstPattern
{
const COMPAT_PATTERN = '#[-\w()]#';
const NON_COMPAT_PATTERN = '#[\w-()]#';
const EXTERNAL_NON_COMPAT_PATTERN = '#[\w-()]#';
public function run()
{
@ -17,27 +14,16 @@ class ConstPattern
}
}
class AnotherClass
{
public function run()
{
Strings::match('...', ConstPattern::EXTERNAL_NON_COMPAT_PATTERN);
}
}
?>
-----
<?php
namespace Rector\Php\Tests\Rector\FuncCall\RegexDashEscapeRector\Fixture;
use Nette\Utils\Strings;
class ConstPattern
{
const COMPAT_PATTERN = '#[-\w()]#';
const NON_COMPAT_PATTERN = '#[\w\-()]#';
const EXTERNAL_NON_COMPAT_PATTERN = '#[\w-()]#';
public function run()
{
@ -46,12 +32,4 @@ class ConstPattern
}
}
class AnotherClass
{
public function run()
{
Strings::match('...', ConstPattern::EXTERNAL_NON_COMPAT_PATTERN);
}
}
?>

View File

@ -0,0 +1,41 @@
<?php
namespace Rector\Php\Tests\Rector\FuncCall\RegexDashEscapeRector\Fixture;
use Nette\Utils\Strings;
class ExternalConstPattern
{
const EXTERNAL_NON_COMPAT_PATTERN = '#[\w-()]#';
}
class AnotherExternalClass
{
public function run()
{
Strings::match('...', ExternalConstPattern::EXTERNAL_NON_COMPAT_PATTERN);
}
}
?>
-----
<?php
namespace Rector\Php\Tests\Rector\FuncCall\RegexDashEscapeRector\Fixture;
use Nette\Utils\Strings;
class ExternalConstPattern
{
const EXTERNAL_NON_COMPAT_PATTERN = '#[\w\-()]#';
}
class AnotherExternalClass
{
public function run()
{
Strings::match('...', ExternalConstPattern::EXTERNAL_NON_COMPAT_PATTERN);
}
}
?>

View File

@ -23,6 +23,7 @@ final class RegexDashEscapeRectorTest extends AbstractRectorTestCase
yield [__DIR__ . '/Fixture/fixture.php.inc'];
yield [__DIR__ . '/Fixture/method_call.php.inc'];
yield [__DIR__ . '/Fixture/const.php.inc'];
yield [__DIR__ . '/Fixture/external_const.php.inc'];
yield [__DIR__ . '/Fixture/variable.php.inc'];
yield [__DIR__ . '/Fixture/multiple_variables.php.inc'];
}

View File

@ -80,7 +80,7 @@ final class PhpSpecRenaming
{
// anonymous class?
if ($class->name === null) {
throw new ShouldNotHappenException(__METHOD__ . '() on line ' . __LINE__);
throw new ShouldNotHappenException();
}
// 2. change class name
@ -94,7 +94,7 @@ final class PhpSpecRenaming
{
// anonymous class?
if ($class->name === null) {
throw new ShouldNotHappenException(__METHOD__ . '() on line ' . __LINE__);
throw new ShouldNotHappenException();
}
$bareClassName = RectorStrings::removeSuffixes($class->name->toString(), ['Spec', 'Test']);

View File

@ -91,7 +91,7 @@ final class PhpSpecMockCollector
$className = $this->nameResolver->getName($node);
if (! isset($this->mocksWithsTypes[$className][$variable])) {
throw new ShouldNotHappenException(__METHOD__ . '() on line ' . __LINE__);
throw new ShouldNotHappenException();
}
return $this->mocksWithsTypes[$className][$variable];
@ -112,7 +112,7 @@ final class PhpSpecMockCollector
$this->mocks[$class][$variable][] = $param->getAttribute(AttributeKey::METHOD_NAME);
if ($param->type === null) {
throw new ShouldNotHappenException(__METHOD__ . '() on line ' . __LINE__);
throw new ShouldNotHappenException();
}
$paramType = (string) ($param->type->getAttribute('originalName') ?: $param->type);

View File

@ -113,7 +113,7 @@ final class PhpSpecMocksToPHPUnitMocksRector extends AbstractPhpSpecToPHPUnitRec
$variableName = $this->getName($param->var);
if ($variableName === null) {
throw new ShouldNotHappenException(__METHOD__ . '() on line ' . __LINE__);
throw new ShouldNotHappenException();
}
return sprintf(
@ -130,7 +130,7 @@ final class PhpSpecMocksToPHPUnitMocksRector extends AbstractPhpSpecToPHPUnitRec
$assigns = [];
foreach ((array) $classMethod->params as $param) {
if (! $param->type instanceof Name) {
throw new ShouldNotHappenException(__METHOD__ . '() on line ' . __LINE__);
throw new ShouldNotHappenException();
}
$createMockCall = $this->createCreateMockCall($param, $param->type);
@ -149,12 +149,12 @@ final class PhpSpecMocksToPHPUnitMocksRector extends AbstractPhpSpecToPHPUnitRec
{
if ($this->isName($methodCall, 'shouldBeCalled')) {
if (! $methodCall->var instanceof MethodCall) {
throw new ShouldNotHappenException(__METHOD__ . '() on line ' . __LINE__);
throw new ShouldNotHappenException();
}
$mockMethodName = $this->getName($methodCall->var);
if ($mockMethodName === null) {
throw new ShouldNotHappenException(__METHOD__ . '() on line ' . __LINE__);
throw new ShouldNotHappenException();
}
$expectedArg = $methodCall->var->args[0]->value ?? null;
@ -221,7 +221,7 @@ final class PhpSpecMocksToPHPUnitMocksRector extends AbstractPhpSpecToPHPUnitRec
{
$variable = $this->getName($param->var);
if ($variable === null) {
throw new ShouldNotHappenException(__METHOD__ . '() on line ' . __LINE__);
throw new ShouldNotHappenException();
}
$propertyFetch = new PropertyFetch(new Variable('this'), $variable);

View File

@ -357,7 +357,7 @@ final class PhpSpecPromisesToPHPUnitAssertRector extends AbstractPhpSpecToPHPUni
private function processDuring(MethodCall $methodCall): MethodCall
{
if (! isset($methodCall->args[0])) {
throw new ShouldNotHappenException(__METHOD__ . '() on line ' . __LINE__);
throw new ShouldNotHappenException();
}
$name = $this->getValue($methodCall->args[0]->value);

View File

@ -73,13 +73,13 @@ final class FactoryClassPrinter
/** @var SmartFileInfo|null $classFileInfo */
$classFileInfo = $oldClass->getAttribute(AttributeKey::FILE_INFO);
if ($classFileInfo === null) {
throw new ShouldNotHappenException(__METHOD__ . '() on line ' . __LINE__);
throw new ShouldNotHappenException();
}
$directoryPath = Strings::before($classFileInfo->getRealPath(), DIRECTORY_SEPARATOR, -1);
$resolvedOldClass = $this->nameResolver->getName($oldClass);
if ($resolvedOldClass === null) {
throw new ShouldNotHappenException(__METHOD__ . '() on line ' . __LINE__);
throw new ShouldNotHappenException();
}
$bareClassName = Strings::after($resolvedOldClass, '\\', -1) . 'Factory.php';

View File

@ -201,7 +201,7 @@ PHP
if ($hasTypes) {
$name = $this->getName($class);
if ($name === null) {
throw new ShouldNotHappenException(__METHOD__ . '() on line ' . __LINE__);
throw new ShouldNotHappenException();
}
$this->classesUsingTypes[] = $name;
}

View File

@ -69,7 +69,7 @@ final class UniqueObjectFactoryFactory
{
$className = $this->nameResolver->getName($class);
if ($className === null) {
throw new ShouldNotHappenException(__METHOD__ . '() on line ' . __LINE__);
throw new ShouldNotHappenException();
}
$name = $className . 'Factory';

View File

@ -24,17 +24,17 @@ final class TemplateGuesser
{
$namespace = $classMethod->getAttribute(AttributeKey::NAMESPACE_NAME);
if (! is_string($namespace)) {
throw new ShouldNotHappenException(__METHOD__ . '() on line ' . __LINE__);
throw new ShouldNotHappenException();
}
$class = $classMethod->getAttribute(AttributeKey::CLASS_NAME);
if (! is_string($class)) {
throw new ShouldNotHappenException(__METHOD__ . '() on line ' . __LINE__);
throw new ShouldNotHappenException();
}
$method = $this->nameResolver->getName($classMethod);
if ($method === null) {
throw new ShouldNotHappenException(__METHOD__ . '() on line ' . __LINE__);
throw new ShouldNotHappenException();
}
if ($version === 3) {

View File

@ -50,7 +50,7 @@ abstract class AbstractToConstructorInjectionRector extends AbstractRector
$propertyName = $this->propertyNaming->fqnToVariableName($serviceType);
$classNode = $methodCall->getAttribute(AttributeKey::CLASS_NODE);
if (! $classNode instanceof Class_) {
throw new ShouldNotHappenException(__METHOD__ . '() on line ' . __LINE__);
throw new ShouldNotHappenException();
}
$this->addPropertyToClass($classNode, $serviceType, $propertyName);

View File

@ -78,7 +78,7 @@ final class ParseFileRector extends AbstractRector
// try to detect current value
$nodeScope = $possibleFileNode->getAttribute(AttributeKey::SCOPE);
if ($nodeScope === null) {
throw new ShouldNotHappenException(__METHOD__ . '() on line ' . __LINE__);
throw new ShouldNotHappenException();
}
$nodeType = $nodeScope->getType($possibleFileNode);

View File

@ -152,12 +152,12 @@ PHP
{
$methodName = $this->getName($classMethod);
if ($methodName === null) {
throw new ShouldNotHappenException(__METHOD__ . '() on line ' . __LINE__);
throw new ShouldNotHappenException();
}
$className = $classMethod->getAttribute(AttributeKey::CLASS_NAME);
if (! is_string($className)) {
throw new ShouldNotHappenException(__METHOD__ . '() on line ' . __LINE__);
throw new ShouldNotHappenException();
}
$childrenClassLikes = $this->parsedNodesByType->findChildrenOfClass($className);

View File

@ -67,7 +67,6 @@ parameters:
- '#Access to an undefined property PhpParser\\Node\\Expr::\$left#'
- '#Access to an undefined property PhpParser\\Node\\Expr::\$right#'
- '#Array \(array<PhpParser\\Node\\Expr\\MethodCall>\) does not accept PhpParser\\Node\\Expr#'
- '#Cannot access property \$expr on PhpParser\\Node\\Stmt\|null#'
- '#Access to an undefined property PhpParser\\Node\\Expr\\MethodCall\|PhpParser\\Node\\Stmt\\ClassMethod::\$params#'
- '#Cannot call method getName\(\) on PHPStan\\Reflection\\ClassReflection\|null#'
@ -118,25 +117,15 @@ parameters:
- '#Cannot call method getParentNode\(\) on Rector\\DeadCode\\Data\\VariableNodeUseInfo\|null#'
# part of test
- '#Class Manual\\Twig\\TwigFilter not found#'
- '#Class Manual_Twig_Filter not found#'
- '#Rector\\NetteToSymfony\\Annotation\\SymfonyRoutePhpDocTagNode\:\:__construct\(\) does not call parent constructor from PHPStan\\PhpDocParser\\Ast\\PhpDoc\\PhpDocTagNode#'
- '#Access to an undefined property Rector\\BetterPhpDocParser\\Attributes\\Contract\\Ast\\AttributeAwareNodeInterface\:\:\$type#'
- '#(.*?)(AttributeAwareNodeInterface|AttributeAware(.*?)TagValueNode)(.*?)#'
- '#Call to an undefined method PHPStan\\PhpDocParser\\Ast\\PhpDoc\\(.*?)\:\:getAttribute\(\)#'
- '#Access to an undefined property PHPStan\\PhpDocParser\\Ast\\PhpDoc\\PhpDocTagValueNode\:\:\$type#'
- '#Parameter \#1 \$children of class PHPStan\\PhpDocParser\\Ast\\PhpDoc\\PhpDocNode constructor expects array<PHPStan\\PhpDocParser\\Ast\\PhpDoc\\PhpDocChildNode\>, array<int, PHPStan\\PhpDocParser\\Ast\\Node\> given#'
# false positive
- '#If condition is always false#'
- '#Call to an undefined method PHPStan\\Type\\Type\:\:getValue\(\)#'
- '#Method Rector\\PHPUnit\\Rector\\MethodCall\\ReplaceAssertArraySubsetRector\:\:matchArray\(\) should return PhpParser\\Node\\Expr\\Array_\|null but returns PhpParser\\Node\\Expr#'
- '#Parameter \#2 \$classMethod of method Rector\\NetteToSymfony\\Rector\\ClassMethod\\RouterListToControllerAnnotationsRector\:\:resolvePathFromClassAndMethodNodes\(\) expects PhpParser\\Node\\Stmt\\ClassMethod, PhpParser\\Node\\Stmt given#'
- '#(.*?)PhpParser\\Node\\Expr\\Error\|PhpParser\\Node\\Expr\\Variable given#'
# false positive 0.11.5
@ -148,12 +137,10 @@ parameters:
# known types
- '#Method Rector\\NodeContainer\\ParsedNodesByType\:\:(.*?)\(\) should return PhpParser\\Node\\Stmt\\(.*?)\|null but returns PhpParser\\Node\|null#'
- '#Method Rector\\NodeContainer\\ParsedNodesByType\:\:findImplementersOfInterface\(\) should return array<PhpParser\\Node\\Stmt\\Interface_\> but returns array<int, PhpParser\\Node\>#'
- '#PHPDoc tag @param for parameter \$classLike with type PhpParser\\Builder\\Trait_\|PhpParser\\Node\\Stmt\\Interface_ is not subtype of native type PhpParser\\Node\\Stmt\\ClassLike#'
- '#Access to an undefined property PhpParser\\Node\\Expr\\Error\|PhpParser\\Node\\Expr\\Variable\:\:\$name#'
- '#Empty array passed to foreach#'
- '#Strict comparison using \=\=\= between PhpParser\\Node\\Expr\\ArrayItem and null will always evaluate to false#'
- '#Parameter \#2 \.\.\.\$args of function array_merge expects array, array<int, string\>\|false given#'
- '#Method Rector\\Collector\\CallableCollectorPopulator\:\:populate\(\) should return array<Closure\> but returns array<int\|string, callable\>#'
- '#Access to an undefined property PhpParser\\Node\\Expr\:\:\$args#'
- '#Parameter \#2 \$name of method Rector\\Rector\\AbstractRector\:\:isName\(\) expects string, string\|null given#'
@ -169,7 +156,6 @@ parameters:
- '#Call to function method_exists\(\) with (.*?) will always evaluate to false#'
- '#Parameter \#1 \$rule of method Rector\\Configuration\\Configuration\:\:setRule\(\) expects string\|null, array<string\>\|bool\|string\|null given#'
- '#In method "Rector\\Rector\\Property\\InjectAnnotationClassRector\:\:resolveType", caught "Throwable" must be rethrown\. Either catch a more specific exception or add a "throw" clause in the "catch" block to propagate the exception\. More info\: http\://bit\.ly/failloud#'
- '#Empty catch block\. If you are sure this is meant to be empty, please add a "// @ignoreException" comment in the catch block#'
- '#Method Rector\\Rector\\AbstractRector\:\:wrapToArg\(\) should return array<PhpParser\\Node\\Arg\> but returns array<PhpParser\\Node\\Arg\|PhpParser\\Node\\Expr\>#'
@ -187,25 +173,17 @@ parameters:
- '#Rector\\EventDispatcher\\AutowiredEventDispatcher\:\:__construct\(\) calls parent constructor but parent does not have one#'
- '#Ternary operator condition is always true#'
- '#Access to an undefined property PhpParser\\Node\\Expr\\Assign\|PhpParser\\Node\\Stmt\\ClassMethod\|PhpParser\\Node\\Stmt\\Property\:\:\$var#'
- '#Parameter \#1 \$node of method Rector\\NodeTypeResolver\\NodeTypeResolver\:\:resolveSingleTypeToStrings\(\) expects PhpParser\\Node, PhpParser\\Node\\Expr\|null given#'
- '#Parameter \#1 \$name of class ReflectionFunction constructor expects Closure\|string, callable\(\)\: mixed given#'
- '#Method Rector\\DoctrinePhpDocParser\\Tests\\PhpDocParser\\OrmTagParser\\AbstractOrmTagParserTest\:\:parseFileAndGetFirstNodeOfType\(\) should return PhpParser\\Node but returns PhpParser\\Node\|null#'
- '#Method Rector\\Symfony\\Bridge\\DefaultAnalyzedSymfonyApplicationContainer\:\:getService\(\) should return object but returns object\|null#'
- '#Method Rector\\BetterPhpDocParser\\PhpDocInfo\\PhpDocInfo\:\:(.*?)\(\) should return Rector\\DoctrinePhpDocParser\\Ast\\PhpDoc\\(.*?)\|null but returns PHPStan\\PhpDocParser\\Ast\\PhpDoc\\PhpDocTagValueNode\|null#'
- '#Call to function property_exists\(\) with string and (.*?) will always evaluate to false#'
- '#Method Rector\\Console\\Option\\SetOptionResolver\:\:separateVersionedAndUnversionedSets\(\) should return array<array<string\>\> but returns array<int, array<int\|string, array<int, string\>\|string\>\>#'
- '#Method Rector\\DoctrinePhpDocParser\\AnnotationReader\\NodeAnnotationReader\:\:readMethodAnnotation\(\) should return Sensio\\Bundle\\FrameworkExtraBundle\\Configuration\\Template but returns object\|null#'
- '#PHPDoc tag @param for parameter \$nodeWithStatements with type PhpParser\\Builder\\FunctionLike\|PhpParser\\Node\\Stmt\\ClassLike is not subtype of native type PhpParser\\Node#'
- '#Access to an undefined property PhpParser\\Node\\FunctionLike\|PhpParser\\Node\\Stmt\\ClassLike\:\:\$stmts#'
- '#Property Rector\\TypeDeclaration\\TypeInferer\\(.*?)\:\:\$(.*?)TypeInferers \(array<Rector\\TypeDeclaration\\Contract\\TypeInferer\\(.*?)TypeInfererInterface\>\) does not accept array<Rector\\TypeDeclaration\\Contract\\TypeInferer\\PriorityAwareTypeInfererInterface\>#'
# sense-less errors
- '#Parameter \#1 \$functionLike of method Rector\\NodeTypeResolver\\PhpDoc\\NodeAnalyzer\\DocBlockManipulator\:\:getParamTypeInfos\(\) expects PhpParser\\Node\\Expr\\Closure\|PhpParser\\Node\\Stmt\\ClassMethod\|PhpParser\\Node\\Stmt\\Function_, PhpParser\\Node\\FunctionLike given#'
- '#Parameter \#1 \$classLike of method Rector\\PhpParser\\Node\\Resolver\\NameResolver\:\:resolveNamespacedNameAwareNode\(\) expects PhpParser\\Node\\Stmt\\ClassLike, \(PhpParser\\Builder\\Trait_&PhpParser\\Node\)\|PhpParser\\Node\\Stmt\\Interface_ given#'
- '#In method "Rector\\(.*?)\:\:isType", parameter \$type has no type\-hint and no @param annotation\. More info\: http\://bit\.ly/usetypehint#'
- '#In method "Rector\\(.*?)\:\:isTypes", parameter \$requiredTypes type is "array"\. (.*?)#'
- '#Parameter \#1 \$type of method PhpParser\\Builder\\Param\:\:setType\(\) expects PhpParser\\Node\\Name\|PhpParser\\Node\\NullableType\|string, PhpParser\\Node\\Identifier\|PhpParser\\Node\\Name\|PhpParser\\Node\\NullableType given#'
- '#Generator expects value type string, array<int, string\> given#'
- '#In method "Rector\\Rector\\Property\\InjectAnnotationClassRector\:\:resolveJMSDIInjectType", caught "Throwable" must be rethrown\. Either catch a more specific exception or add a "throw" clause in the "catch" block to propagate the exception\. More info\: http\://bit\.ly/failloud#'
@ -224,3 +202,8 @@ parameters:
- '#Parameter \#1 \$obj of function spl_object_hash expects object, PhpParser\\Comment\\Doc\|null given#'
- '#Method Rector\\DoctrinePhpDocParser\\AnnotationReader\\NodeAnnotationReader\:\:readMethodAnnotation\(\) should return Sensio\\Bundle\\FrameworkExtraBundle\\Configuration\\Template\|Symfony\\Component\\Routing\\Annotation\\Route\|null but returns object\|null#'
- '#Method Rector\\Doctrine\\Rector\\MethodCall\\ChangeSetIdToUuidValueRector\:\:getSetUuidMethodCallOnSameVariable\(\) should return PhpParser\\Node\\Expr\\MethodCall\|null but returns PhpParser\\Node\|null#'
# bugs
- '#In method "Rector\\FileSystemRector\\Rector\\AbstractFileSystemRector\:\:isDoctrineEntityClass", parameter \$class has no type\-hint and no @param annotation\. More info\: http\://bit\.ly/usetypehint#'
- '#In method "Rector\\Rector\\AbstractRector\:\:isDoctrineEntityClass", parameter \$class has no type\-hint and no @param annotation\. More info\: http\://bit\.ly/usetypehint#'

View File

@ -3,7 +3,29 @@
namespace Rector\Exception;
use Exception;
use Throwable;
final class ShouldNotHappenException extends Exception
{
public function __construct($message = '', $code = 0, ?Throwable $throwable = null)
{
if ($message === '') {
$message = $this->createDefaultMessageWithLocation();
}
parent::__construct($message, $code, $throwable);
}
private function createDefaultMessageWithLocation(): string
{
$debugBacktrace = debug_backtrace();
$class = $debugBacktrace[1]['class'] ?? null;
$function = $debugBacktrace[1]['function'];
$line = $debugBacktrace[1]['line'];
$method = $class ? ($class . '::' . $function) : $function;
return sprintf('Look at "%s()" on line %d', $method, $line);
}
}

View File

@ -22,6 +22,7 @@ use PHPStan\Type\MixedType;
use PHPStan\Type\ObjectType;
use PHPStan\Type\Type;
use PHPStan\Type\UnionType;
use Rector\Exception\NotImplementedException;
use Rector\Exception\ShouldNotHappenException;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Rector\NodeTypeResolver\NodeTypeResolver;
@ -367,7 +368,7 @@ final class ParsedNodesByType
if ($node instanceof Interface_ || $node instanceof Trait_ || $node instanceof Function_) {
$name = $this->nameResolver->getName($node);
if ($name === null) {
throw new ShouldNotHappenException(__METHOD__ . '() on line ' . __LINE__);
throw new ShouldNotHappenException();
}
$nodeClass = get_class($node);
@ -457,6 +458,28 @@ final class ParsedNodesByType
return $newNodesByClass;
}
public function findClassConstantByClassConstFetch(ClassConstFetch $classConstFetch): ?ClassConst
{
$class = $this->nameResolver->getName($classConstFetch->class);
if ($class === 'self') {
/** @var string|null $class */
$class = $classConstFetch->getAttribute(AttributeKey::CLASS_NAME);
} elseif ($class === 'parent') {
/** @var string|null $class */
$class = $classConstFetch->getAttribute(AttributeKey::PARENT_CLASS_NAME);
}
if ($class === null) {
throw new NotImplementedException();
}
/** @var string $constantName */
$constantName = $this->nameResolver->getName($classConstFetch->name);
return $this->findClassConstant($class, $constantName);
}
private function addClass(Class_ $classNode): void
{
if ($this->isClassAnonymous($classNode)) {
@ -465,7 +488,7 @@ final class ParsedNodesByType
$name = $classNode->getAttribute(AttributeKey::CLASS_NAME);
if ($name === null) {
throw new ShouldNotHappenException(__METHOD__ . '() on line ' . __LINE__);
throw new ShouldNotHappenException();
}
$this->classes[$name] = $classNode;
@ -475,7 +498,7 @@ final class ParsedNodesByType
{
$className = $classConst->getAttribute(AttributeKey::CLASS_NAME);
if ($className === null) {
throw new ShouldNotHappenException(__METHOD__ . '() on line ' . __LINE__);
throw new ShouldNotHappenException();
}
$constantName = $this->nameResolver->getName($classConst);

View File

@ -202,19 +202,7 @@ final class RegexPatternArgumentManipulator
*/
private function resolveClassConstFetchValue(ClassConstFetch $classConstFetch): array
{
$className = $classConstFetch->getAttribute(AttributeKey::CLASS_NAME);
if (! is_string($className)) {
return [];
}
$constantName = $this->nameResolver->getName($classConstFetch->name);
if ($constantName === null) {
return [];
}
$classConstNode = $this->parsedNodesByType->findClassConstant($className, $constantName);
$classConstNode = $this->parsedNodesByType->findClassConstantByClassConstFetch($classConstFetch);
if ($classConstNode === null) {
return [];
}

View File

@ -95,7 +95,7 @@ final class NodeAddingCommander implements CommanderInterface
if ($parentNode instanceof ClassLike) {
$foundNode = $node;
} else {
throw new ShouldNotHappenException(__METHOD__ . '() on line ' . __LINE__);
throw new ShouldNotHappenException();
}
}

View File

@ -51,7 +51,7 @@ final class BinaryOpManipulator
return;
}
throw new ShouldNotHappenException(__METHOD__ . '() on line ' . __LINE__);
throw new ShouldNotHappenException();
}
/**

View File

@ -199,7 +199,7 @@ final class ClassManipulator
foreach ($class->getProperties() as $property) {
if (count($property->props) > 1) {
// usually full property is needed to have all the docs values
throw new ShouldNotHappenException(__METHOD__ . '() on line ' . __LINE__);
throw new ShouldNotHappenException();
}
if ($this->nameResolver->isName($property, $name)) {

View File

@ -136,7 +136,7 @@ final class ClassMethodManipulator
$classMethodNode = $node->getAttribute(AttributeKey::METHOD_NODE);
if (! $classMethodNode instanceof ClassMethod) {
// or null?
throw new ShouldNotHappenException(__METHOD__ . '() on line ' . __LINE__);
throw new ShouldNotHappenException();
}
foreach ($classMethodNode->params as $paramNode) {
@ -177,7 +177,7 @@ final class ClassMethodManipulator
return $possibleName;
}
throw new ShouldNotHappenException(__METHOD__ . '() on line ' . __LINE__);
throw new ShouldNotHappenException();
}
/**

View File

@ -300,7 +300,7 @@ final class PropertyFetchManipulator
{
$nodeScope = $propertyFetch->getAttribute(AttributeKey::SCOPE);
if ($nodeScope === null) {
throw new ShouldNotHappenException(__METHOD__ . '() on line ' . __LINE__);
throw new ShouldNotHappenException();
}
$propertyFetchType = $nodeScope->getType($propertyFetch->var);

View File

@ -117,7 +117,7 @@ final class ValueResolver
{
$fileInfo = $dir->getAttribute(AttributeKey::FILE_INFO);
if (! $fileInfo instanceof SmartFileInfo) {
throw new ShouldNotHappenException(__METHOD__ . '() on line ' . __LINE__);
throw new ShouldNotHappenException();
}
return $fileInfo->getPath();
@ -127,7 +127,7 @@ final class ValueResolver
{
$fileInfo = $file->getAttribute(AttributeKey::FILE_INFO);
if (! $fileInfo instanceof SmartFileInfo) {
throw new ShouldNotHappenException(__METHOD__ . '() on line ' . __LINE__);
throw new ShouldNotHappenException();
}
return $fileInfo->getPathname();
@ -142,11 +142,11 @@ final class ValueResolver
$constant = $this->nameResolver->getName($classConstFetch->name);
if ($class === null) {
throw new ShouldNotHappenException(__METHOD__ . '() on line ' . __LINE__);
throw new ShouldNotHappenException();
}
if ($constant === null) {
throw new ShouldNotHappenException(__METHOD__ . '() on line ' . __LINE__);
throw new ShouldNotHappenException();
}
if ($class === 'self') {

View File

@ -120,7 +120,7 @@ PHP
}
}
throw new ShouldNotHappenException(__METHOD__ . '() on line ' . __LINE__);
throw new ShouldNotHappenException();
}
private function isLastMethodCallInChainCall(MethodCall $methodCall): bool

View File

@ -95,7 +95,7 @@ PHP
$methodNode = $node->getAttribute(AttributeKey::METHOD_NODE);
if ($methodNode === null) {
throw new ShouldNotHappenException(__METHOD__ . '() on line ' . __LINE__);
throw new ShouldNotHappenException();
}
$this->docBlockManipulator->removeTagFromNode($methodNode, 'return');

View File

@ -163,7 +163,7 @@ PHP
$classNode = $property->getAttribute(AttributeKey::CLASS_NODE);
if (! $classNode instanceof Class_) {
throw new ShouldNotHappenException(__METHOD__ . '() on line ' . __LINE__);
throw new ShouldNotHappenException();
}
$this->addPropertyToClass($classNode, $type, $name);

View File

@ -92,7 +92,7 @@ PHP
foreach ($this->typehintForArgumentByMethodAndClass as $type => $methodToArgumentToTypes) {
$classNode = $node->getAttribute(AttributeKey::CLASS_NODE);
if ($classNode === null) {
throw new ShouldNotHappenException(__METHOD__ . '() on line ' . __LINE__);
throw new ShouldNotHappenException();
}
if (! $this->isObjectType($classNode, $type)) {

View File

@ -61,6 +61,6 @@ final class FunctionReflectionResolver
}
}
throw new ShouldNotHappenException(__METHOD__ . '() on line ' . __LINE__);
throw new ShouldNotHappenException();
}
}

View File

@ -4,6 +4,7 @@ namespace Rector\Testing\PHPUnit;
use Nette\Utils\FileSystem;
use PHPStan\Analyser\NodeScopeResolver;
use PHPUnit\Framework\ExpectationFailedException;
use Psr\Container\ContainerInterface;
use Rector\Application\FileProcessor;
use Rector\Configuration\Option;
@ -161,7 +162,12 @@ abstract class AbstractRectorTestCase extends AbstractGenericRectorTestCase
$this->fileProcessor->refactor($smartFileInfo);
$changedContent = $this->fileProcessor->printToString($smartFileInfo);
$this->assertStringEqualsFile($expectedFile, $changedContent, 'Caused by ' . $fixtureFile);
try {
$this->assertStringEqualsFile($expectedFile, $changedContent, 'Caused by ' . $fixtureFile);
} catch (ExpectationFailedException $expectationFailedException) {
$expectedFileContent = FileSystem::read($expectedFile);
$this->assertStringMatchesFormat($expectedFileContent, $changedContent, 'Caused by ' . $fixtureFile);
}
}
private function ensureConfigFileExists(): void