From 8e93626e323d3234392e7314236972d06cbd6e3f Mon Sep 17 00:00:00 2001 From: Tomas Votruba Date: Sat, 21 Sep 2019 00:06:46 +0200 Subject: [PATCH 1/4] [Doctrine] Add ChangeSetIdToUuidValueRector --- composer.json | 1 + .../doctrine/doctrine-id-to-uuid-step-3.yaml | 2 + .../src/AbstractRector/DoctrineTrait.php | 5 +- .../PhpDocParser/DoctrineDocBlockResolver.php | 44 +++- .../ChangeSetIdToUuidValueRector.php | 188 ++++++++++++++++++ .../src/ValueObject/DoctrineClass.php | 5 + .../ChangeSetIdToUuidValueRectorTest.php | 32 +++ .../Fixture/fixture.php.inc | 42 ++++ .../Fixture/no_set_uuid.php.inc | 35 ++++ .../Fixture/other_direction.php.inc | 36 ++++ .../Source/Building.php | 12 ++ phpstan.neon | 27 +-- .../PHPUnit/AbstractRectorTestCase.php | 8 +- 13 files changed, 408 insertions(+), 29 deletions(-) create mode 100644 config/set/doctrine/doctrine-id-to-uuid-step-3.yaml create mode 100644 packages/Doctrine/src/Rector/MethodCall/ChangeSetIdToUuidValueRector.php create mode 100644 packages/Doctrine/tests/Rector/MethodCall/ChangeSetIdToUuidValueRector/ChangeSetIdToUuidValueRectorTest.php create mode 100644 packages/Doctrine/tests/Rector/MethodCall/ChangeSetIdToUuidValueRector/Fixture/fixture.php.inc create mode 100644 packages/Doctrine/tests/Rector/MethodCall/ChangeSetIdToUuidValueRector/Fixture/no_set_uuid.php.inc create mode 100644 packages/Doctrine/tests/Rector/MethodCall/ChangeSetIdToUuidValueRector/Fixture/other_direction.php.inc create mode 100644 packages/Doctrine/tests/Rector/MethodCall/ChangeSetIdToUuidValueRector/Source/Building.php diff --git a/composer.json b/composer.json index 926aa932d76..60a6901fda5 100644 --- a/composer.json +++ b/composer.json @@ -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", diff --git a/config/set/doctrine/doctrine-id-to-uuid-step-3.yaml b/config/set/doctrine/doctrine-id-to-uuid-step-3.yaml new file mode 100644 index 00000000000..fcc06c8e8e7 --- /dev/null +++ b/config/set/doctrine/doctrine-id-to-uuid-step-3.yaml @@ -0,0 +1,2 @@ +services: + Rector\Doctrine\Rector\MethodCall\ChangeSetIdToUuidValueRector: ~ diff --git a/packages/Doctrine/src/AbstractRector/DoctrineTrait.php b/packages/Doctrine/src/AbstractRector/DoctrineTrait.php index 96432466597..22abe3da3bc 100644 --- a/packages/Doctrine/src/AbstractRector/DoctrineTrait.php +++ b/packages/Doctrine/src/AbstractRector/DoctrineTrait.php @@ -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); } diff --git a/packages/Doctrine/src/PhpDocParser/DoctrineDocBlockResolver.php b/packages/Doctrine/src/PhpDocParser/DoctrineDocBlockResolver.php index f64ac899b7c..258a6d03403 100644 --- a/packages/Doctrine/src/PhpDocParser/DoctrineDocBlockResolver.php +++ b/packages/Doctrine/src/PhpDocParser/DoctrineDocBlockResolver.php @@ -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(__METHOD__); } public function isDoctrineEntityClassWithIdProperty(Class_ $class): bool diff --git a/packages/Doctrine/src/Rector/MethodCall/ChangeSetIdToUuidValueRector.php b/packages/Doctrine/src/Rector/MethodCall/ChangeSetIdToUuidValueRector.php new file mode 100644 index 00000000000..738995bbd86 --- /dev/null +++ b/packages/Doctrine/src/Rector/MethodCall/ChangeSetIdToUuidValueRector.php @@ -0,0 +1,188 @@ +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; + } + + // already uuid static type + if ($this->isUuidType($node->args[0]->value)) { + return null; + } + + // B. set uuid from string with generated string + $uuidValue = Uuid::uuid4(); + $uuidValueString = $uuidValue->toString(); + + $value = $this->createStaticCall(Uuid::class, 'fromString', [new String_($uuidValueString)]); + $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; + } + + 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; + } +} diff --git a/packages/Doctrine/src/ValueObject/DoctrineClass.php b/packages/Doctrine/src/ValueObject/DoctrineClass.php index 8c10be67568..fd808e06ed4 100644 --- a/packages/Doctrine/src/ValueObject/DoctrineClass.php +++ b/packages/Doctrine/src/ValueObject/DoctrineClass.php @@ -28,4 +28,9 @@ final class DoctrineClass * @var string */ public const OBJECT_MANAGER = 'Doctrine\Common\Persistence\ObjectManager'; + + /** + * @var string + */ + public const RAMSEY_UUID = 'Ramsey\Uuid\Uuid'; } diff --git a/packages/Doctrine/tests/Rector/MethodCall/ChangeSetIdToUuidValueRector/ChangeSetIdToUuidValueRectorTest.php b/packages/Doctrine/tests/Rector/MethodCall/ChangeSetIdToUuidValueRector/ChangeSetIdToUuidValueRectorTest.php new file mode 100644 index 00000000000..8ceda3c466e --- /dev/null +++ b/packages/Doctrine/tests/Rector/MethodCall/ChangeSetIdToUuidValueRector/ChangeSetIdToUuidValueRectorTest.php @@ -0,0 +1,32 @@ +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']; + } + + protected function getRectorClass(): string + { + return ChangeSetIdToUuidValueRector::class; + } +} diff --git a/packages/Doctrine/tests/Rector/MethodCall/ChangeSetIdToUuidValueRector/Fixture/fixture.php.inc b/packages/Doctrine/tests/Rector/MethodCall/ChangeSetIdToUuidValueRector/Fixture/fixture.php.inc new file mode 100644 index 00000000000..6835dbf0313 --- /dev/null +++ b/packages/Doctrine/tests/Rector/MethodCall/ChangeSetIdToUuidValueRector/Fixture/fixture.php.inc @@ -0,0 +1,42 @@ +setId(1); + $buildingFirst->setUuid(Uuid::fromString('a3bfab84-e207-4ddd-b96d-488151de9e96')); + + $buildingFirst2 = new Building(); + $buildingFirst2->setUuid('skip_this'); + } +} + +?> +----- +setId(Uuid::fromString('a3bfab84-e207-4ddd-b96d-488151de9e96')); + + $buildingFirst2 = new Building(); + $buildingFirst2->setUuid('skip_this'); + } +} + +?> diff --git a/packages/Doctrine/tests/Rector/MethodCall/ChangeSetIdToUuidValueRector/Fixture/no_set_uuid.php.inc b/packages/Doctrine/tests/Rector/MethodCall/ChangeSetIdToUuidValueRector/Fixture/no_set_uuid.php.inc new file mode 100644 index 00000000000..9e97786d7ee --- /dev/null +++ b/packages/Doctrine/tests/Rector/MethodCall/ChangeSetIdToUuidValueRector/Fixture/no_set_uuid.php.inc @@ -0,0 +1,35 @@ +setId(1); + } +} + +?> +----- +setId(\Ramsey\Uuid\Uuid::fromString('%s-%s-%s-%s-%s')); + } +} + +?> diff --git a/packages/Doctrine/tests/Rector/MethodCall/ChangeSetIdToUuidValueRector/Fixture/other_direction.php.inc b/packages/Doctrine/tests/Rector/MethodCall/ChangeSetIdToUuidValueRector/Fixture/other_direction.php.inc new file mode 100644 index 00000000000..2e0b19e1237 --- /dev/null +++ b/packages/Doctrine/tests/Rector/MethodCall/ChangeSetIdToUuidValueRector/Fixture/other_direction.php.inc @@ -0,0 +1,36 @@ +setUuid(Uuid::fromString('a3bfab84-e207-4ddd-b96d-488151de9e96')); + $buildingFirst->setId(1); + } +} + +?> +----- +setId(Uuid::fromString('a3bfab84-e207-4ddd-b96d-488151de9e96')); + } +} + +?> diff --git a/packages/Doctrine/tests/Rector/MethodCall/ChangeSetIdToUuidValueRector/Source/Building.php b/packages/Doctrine/tests/Rector/MethodCall/ChangeSetIdToUuidValueRector/Source/Building.php new file mode 100644 index 00000000000..c54d921dc5f --- /dev/null +++ b/packages/Doctrine/tests/Rector/MethodCall/ChangeSetIdToUuidValueRector/Source/Building.php @@ -0,0 +1,12 @@ +\) 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, array 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 but returns array#' - - '#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\|false given#' - - '#Method Rector\\Collector\\CallableCollectorPopulator\:\:populate\(\) should return array but returns array#' - '#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\|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 but returns array#' @@ -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\> but returns array\|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\) does not accept array#' # 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 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#' diff --git a/src/Testing/PHPUnit/AbstractRectorTestCase.php b/src/Testing/PHPUnit/AbstractRectorTestCase.php index 6d2d0a357ba..ceea924dacf 100644 --- a/src/Testing/PHPUnit/AbstractRectorTestCase.php +++ b/src/Testing/PHPUnit/AbstractRectorTestCase.php @@ -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 From d6d48ea44b0d9808dcd63c9420c4df75c08a7ae6 Mon Sep 17 00:00:00 2001 From: Tomas Votruba Date: Sat, 21 Sep 2019 13:03:30 +0200 Subject: [PATCH 2/4] make ShouldNotHappenException smarter --- .../src/Rector/For_/ForToForeachRector.php | 2 +- .../CodingStyle/src/Naming/ClassNaming.php | 2 +- .../ReturnArrayClassMethodToYieldRector.php | 2 +- .../Rector/Use_/RemoveUnusedAliasRector.php | 2 +- .../DeadCode/src/Data/VariableNodeUseInfo.php | 2 +- .../RemoveDelegatingParentCallRector.php | 2 +- .../PhpDocParser/DoctrineDocBlockResolver.php | 2 +- .../src/Uuid/JoinTableNameResolver.php | 2 +- .../AnnotationReader/NodeAnnotationReader.php | 4 ++-- ...erFunctionToConstructorInjectionRector.php | 2 +- .../Assign/MysqlAssignToMysqliRector.php | 2 +- .../src/PHPStan/Scope/NodeScopeResolver.php | 2 +- ...rrayArgumentInTestToDataProviderRector.php | 2 +- .../SpecificMethod/AssertRegExpRector.php | 2 +- .../Assign/MysqlAssignToMysqliRector.php | 2 +- .../ConstFetch/BarewordStringRector.php | 2 +- .../FuncCall/PregReplaceEModifierRector.php | 2 +- .../src/Naming/PhpSpecRenaming.php | 4 ++-- .../src/PhpSpecMockCollector.php | 4 ++-- .../PhpSpecMocksToPHPUnitMocksRector.php | 10 ++++----- .../PhpSpecPromisesToPHPUnitAssertRector.php | 2 +- .../src/Printer/FactoryClassPrinter.php | 4 ++-- .../NewUniqueObjectToEntityFactoryRector.php | 2 +- .../src/UniqueObjectFactoryFactory.php | 2 +- .../Sensio/src/Helper/TemplateGuesser.php | 6 ++--- .../AbstractToConstructorInjectionRector.php | 2 +- .../src/Rector/Yaml/ParseFileRector.php | 2 +- .../ReturnTypeDeclarationRector.php | 4 ++-- src/Exception/ShouldNotHappenException.php | 22 +++++++++++++++++++ src/NodeContainer/ParsedNodesByType.php | 6 ++--- .../Node/Commander/NodeAddingCommander.php | 2 +- .../Node/Manipulator/BinaryOpManipulator.php | 2 +- .../Node/Manipulator/ClassManipulator.php | 2 +- .../Manipulator/ClassMethodManipulator.php | 4 ++-- .../Manipulator/PropertyFetchManipulator.php | 2 +- src/PhpParser/Node/Value/ValueResolver.php | 8 +++---- src/Rector/MethodBody/FluentReplaceRector.php | 2 +- .../MethodBody/ReturnThisRemoveRector.php | 2 +- .../Property/InjectAnnotationClassRector.php | 2 +- .../ParentTypehintedArgumentRector.php | 2 +- src/Reflection/FunctionReflectionResolver.php | 2 +- 41 files changed, 79 insertions(+), 57 deletions(-) diff --git a/packages/CodeQuality/src/Rector/For_/ForToForeachRector.php b/packages/CodeQuality/src/Rector/For_/ForToForeachRector.php index 84d5d12255f..d501cd9f905 100644 --- a/packages/CodeQuality/src/Rector/For_/ForToForeachRector.php +++ b/packages/CodeQuality/src/Rector/For_/ForToForeachRector.php @@ -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 { diff --git a/packages/CodingStyle/src/Naming/ClassNaming.php b/packages/CodingStyle/src/Naming/ClassNaming.php index e85a54b88f3..d662754a1e3 100644 --- a/packages/CodingStyle/src/Naming/ClassNaming.php +++ b/packages/CodingStyle/src/Naming/ClassNaming.php @@ -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(); } } diff --git a/packages/CodingStyle/src/Rector/ClassMethod/ReturnArrayClassMethodToYieldRector.php b/packages/CodingStyle/src/Rector/ClassMethod/ReturnArrayClassMethodToYieldRector.php index b26dfc1bd6d..9087565f5a2 100644 --- a/packages/CodingStyle/src/Rector/ClassMethod/ReturnArrayClassMethodToYieldRector.php +++ b/packages/CodingStyle/src/Rector/ClassMethod/ReturnArrayClassMethodToYieldRector.php @@ -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); diff --git a/packages/CodingStyle/src/Rector/Use_/RemoveUnusedAliasRector.php b/packages/CodingStyle/src/Rector/Use_/RemoveUnusedAliasRector.php index a04a8639ba2..90ca353a2d2 100644 --- a/packages/CodingStyle/src/Rector/Use_/RemoveUnusedAliasRector.php +++ b/packages/CodingStyle/src/Rector/Use_/RemoveUnusedAliasRector.php @@ -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]; diff --git a/packages/DeadCode/src/Data/VariableNodeUseInfo.php b/packages/DeadCode/src/Data/VariableNodeUseInfo.php index 8fd08cb0103..480ca9c7f8c 100644 --- a/packages/DeadCode/src/Data/VariableNodeUseInfo.php +++ b/packages/DeadCode/src/Data/VariableNodeUseInfo.php @@ -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; diff --git a/packages/DeadCode/src/Rector/ClassMethod/RemoveDelegatingParentCallRector.php b/packages/DeadCode/src/Rector/ClassMethod/RemoveDelegatingParentCallRector.php index 032fca0edde..2075f3aa1f6 100644 --- a/packages/DeadCode/src/Rector/ClassMethod/RemoveDelegatingParentCallRector.php +++ b/packages/DeadCode/src/Rector/ClassMethod/RemoveDelegatingParentCallRector.php @@ -180,7 +180,7 @@ PHP $parentClassName = get_parent_class($className); if ($parentClassName === false) { - throw new ShouldNotHappenException(__METHOD__); + throw new ShouldNotHappenException(); } /** @var string $methodName */ diff --git a/packages/Doctrine/src/PhpDocParser/DoctrineDocBlockResolver.php b/packages/Doctrine/src/PhpDocParser/DoctrineDocBlockResolver.php index 258a6d03403..14ca2195c0e 100644 --- a/packages/Doctrine/src/PhpDocParser/DoctrineDocBlockResolver.php +++ b/packages/Doctrine/src/PhpDocParser/DoctrineDocBlockResolver.php @@ -67,7 +67,7 @@ final class DoctrineDocBlockResolver return false; } - throw new ShouldNotHappenException(__METHOD__); + throw new ShouldNotHappenException(); } public function isDoctrineEntityClassWithIdProperty(Class_ $class): bool diff --git a/packages/Doctrine/src/Uuid/JoinTableNameResolver.php b/packages/Doctrine/src/Uuid/JoinTableNameResolver.php index 23de3a6cc82..713c17cd649 100644 --- a/packages/Doctrine/src/Uuid/JoinTableNameResolver.php +++ b/packages/Doctrine/src/Uuid/JoinTableNameResolver.php @@ -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); diff --git a/packages/DoctrinePhpDocParser/src/AnnotationReader/NodeAnnotationReader.php b/packages/DoctrinePhpDocParser/src/AnnotationReader/NodeAnnotationReader.php index 485cf140218..d587bd1122b 100644 --- a/packages/DoctrinePhpDocParser/src/AnnotationReader/NodeAnnotationReader.php +++ b/packages/DoctrinePhpDocParser/src/AnnotationReader/NodeAnnotationReader.php @@ -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; diff --git a/packages/Laravel/src/Rector/FuncCall/HelperFunctionToConstructorInjectionRector.php b/packages/Laravel/src/Rector/FuncCall/HelperFunctionToConstructorInjectionRector.php index a61e34cf180..550b4a3c290 100644 --- a/packages/Laravel/src/Rector/FuncCall/HelperFunctionToConstructorInjectionRector.php +++ b/packages/Laravel/src/Rector/FuncCall/HelperFunctionToConstructorInjectionRector.php @@ -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; diff --git a/packages/MysqlToMysqli/src/Rector/Assign/MysqlAssignToMysqliRector.php b/packages/MysqlToMysqli/src/Rector/Assign/MysqlAssignToMysqliRector.php index 0956b53bf6e..e55892d4827 100644 --- a/packages/MysqlToMysqli/src/Rector/Assign/MysqlAssignToMysqliRector.php +++ b/packages/MysqlToMysqli/src/Rector/Assign/MysqlAssignToMysqliRector.php @@ -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); diff --git a/packages/NodeTypeResolver/src/PHPStan/Scope/NodeScopeResolver.php b/packages/NodeTypeResolver/src/PHPStan/Scope/NodeScopeResolver.php index c26453e3e98..0bcbce38a9d 100644 --- a/packages/NodeTypeResolver/src/PHPStan/Scope/NodeScopeResolver.php +++ b/packages/NodeTypeResolver/src/PHPStan/Scope/NodeScopeResolver.php @@ -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(); diff --git a/packages/PHPUnit/src/Rector/Class_/ArrayArgumentInTestToDataProviderRector.php b/packages/PHPUnit/src/Rector/Class_/ArrayArgumentInTestToDataProviderRector.php index 6762e51cc50..0c5ddc74eca 100644 --- a/packages/PHPUnit/src/Rector/Class_/ArrayArgumentInTestToDataProviderRector.php +++ b/packages/PHPUnit/src/Rector/Class_/ArrayArgumentInTestToDataProviderRector.php @@ -153,7 +153,7 @@ PHP } if (count($node->args) !== 1) { - throw new ShouldNotHappenException(__METHOD__); + throw new ShouldNotHappenException(); } // resolve value types diff --git a/packages/PHPUnit/src/Rector/SpecificMethod/AssertRegExpRector.php b/packages/PHPUnit/src/Rector/SpecificMethod/AssertRegExpRector.php index d4f636b626f..62c2f8548ba 100644 --- a/packages/PHPUnit/src/Rector/SpecificMethod/AssertRegExpRector.php +++ b/packages/PHPUnit/src/Rector/SpecificMethod/AssertRegExpRector.php @@ -84,7 +84,7 @@ final class AssertRegExpRector extends AbstractPHPUnitRector return $this->isTrue($node) ? 1 : 0; } - throw new ShouldNotHappenException(__METHOD__); + throw new ShouldNotHappenException(); } /** diff --git a/packages/Php/src/Rector/Assign/MysqlAssignToMysqliRector.php b/packages/Php/src/Rector/Assign/MysqlAssignToMysqliRector.php index 9a9c9d73302..91e30cb521f 100644 --- a/packages/Php/src/Rector/Assign/MysqlAssignToMysqliRector.php +++ b/packages/Php/src/Rector/Assign/MysqlAssignToMysqliRector.php @@ -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); diff --git a/packages/Php/src/Rector/ConstFetch/BarewordStringRector.php b/packages/Php/src/Rector/ConstFetch/BarewordStringRector.php index de4bd30cd73..7b206c02371 100644 --- a/packages/Php/src/Rector/ConstFetch/BarewordStringRector.php +++ b/packages/Php/src/Rector/ConstFetch/BarewordStringRector.php @@ -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 = []; diff --git a/packages/Php/src/Rector/FuncCall/PregReplaceEModifierRector.php b/packages/Php/src/Rector/FuncCall/PregReplaceEModifierRector.php index 1f62c7d7eb4..8a1e45fef2d 100644 --- a/packages/Php/src/Rector/FuncCall/PregReplaceEModifierRector.php +++ b/packages/Php/src/Rector/FuncCall/PregReplaceEModifierRector.php @@ -111,7 +111,7 @@ PHP { if (! $expr instanceof String_) { // not supported yet - throw new ShouldNotHappenException(__METHOD__ . '() on line ' . __LINE__); + throw new ShouldNotHappenException(); } $phpCode = 'value . ';'; diff --git a/packages/PhpSpecToPHPUnit/src/Naming/PhpSpecRenaming.php b/packages/PhpSpecToPHPUnit/src/Naming/PhpSpecRenaming.php index 2ebbd09952a..0b4283b543a 100644 --- a/packages/PhpSpecToPHPUnit/src/Naming/PhpSpecRenaming.php +++ b/packages/PhpSpecToPHPUnit/src/Naming/PhpSpecRenaming.php @@ -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']); diff --git a/packages/PhpSpecToPHPUnit/src/PhpSpecMockCollector.php b/packages/PhpSpecToPHPUnit/src/PhpSpecMockCollector.php index 2c5c2334b16..a6b39bdffc4 100644 --- a/packages/PhpSpecToPHPUnit/src/PhpSpecMockCollector.php +++ b/packages/PhpSpecToPHPUnit/src/PhpSpecMockCollector.php @@ -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); diff --git a/packages/PhpSpecToPHPUnit/src/Rector/MethodCall/PhpSpecMocksToPHPUnitMocksRector.php b/packages/PhpSpecToPHPUnit/src/Rector/MethodCall/PhpSpecMocksToPHPUnitMocksRector.php index 192134b3967..5df4c7bd7e2 100644 --- a/packages/PhpSpecToPHPUnit/src/Rector/MethodCall/PhpSpecMocksToPHPUnitMocksRector.php +++ b/packages/PhpSpecToPHPUnit/src/Rector/MethodCall/PhpSpecMocksToPHPUnitMocksRector.php @@ -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); diff --git a/packages/PhpSpecToPHPUnit/src/Rector/MethodCall/PhpSpecPromisesToPHPUnitAssertRector.php b/packages/PhpSpecToPHPUnit/src/Rector/MethodCall/PhpSpecPromisesToPHPUnitAssertRector.php index 9945c06bd9c..1b9a4372b44 100644 --- a/packages/PhpSpecToPHPUnit/src/Rector/MethodCall/PhpSpecPromisesToPHPUnitAssertRector.php +++ b/packages/PhpSpecToPHPUnit/src/Rector/MethodCall/PhpSpecPromisesToPHPUnitAssertRector.php @@ -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); diff --git a/packages/RemovingStatic/src/Printer/FactoryClassPrinter.php b/packages/RemovingStatic/src/Printer/FactoryClassPrinter.php index eb56aeead54..2acb23e7b34 100644 --- a/packages/RemovingStatic/src/Printer/FactoryClassPrinter.php +++ b/packages/RemovingStatic/src/Printer/FactoryClassPrinter.php @@ -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'; diff --git a/packages/RemovingStatic/src/Rector/Class_/NewUniqueObjectToEntityFactoryRector.php b/packages/RemovingStatic/src/Rector/Class_/NewUniqueObjectToEntityFactoryRector.php index 9b1876b8d8d..c4bbffaf83e 100644 --- a/packages/RemovingStatic/src/Rector/Class_/NewUniqueObjectToEntityFactoryRector.php +++ b/packages/RemovingStatic/src/Rector/Class_/NewUniqueObjectToEntityFactoryRector.php @@ -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; } diff --git a/packages/RemovingStatic/src/UniqueObjectFactoryFactory.php b/packages/RemovingStatic/src/UniqueObjectFactoryFactory.php index 5cb78103146..4245ffb3e84 100644 --- a/packages/RemovingStatic/src/UniqueObjectFactoryFactory.php +++ b/packages/RemovingStatic/src/UniqueObjectFactoryFactory.php @@ -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'; diff --git a/packages/Sensio/src/Helper/TemplateGuesser.php b/packages/Sensio/src/Helper/TemplateGuesser.php index 92b3f226fbf..4159b04716b 100644 --- a/packages/Sensio/src/Helper/TemplateGuesser.php +++ b/packages/Sensio/src/Helper/TemplateGuesser.php @@ -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) { diff --git a/packages/Symfony/src/Rector/FrameworkBundle/AbstractToConstructorInjectionRector.php b/packages/Symfony/src/Rector/FrameworkBundle/AbstractToConstructorInjectionRector.php index 1c05d333ebc..56ce41d2ca5 100644 --- a/packages/Symfony/src/Rector/FrameworkBundle/AbstractToConstructorInjectionRector.php +++ b/packages/Symfony/src/Rector/FrameworkBundle/AbstractToConstructorInjectionRector.php @@ -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); diff --git a/packages/Symfony/src/Rector/Yaml/ParseFileRector.php b/packages/Symfony/src/Rector/Yaml/ParseFileRector.php index 008ccb4203d..4169b04cbb7 100644 --- a/packages/Symfony/src/Rector/Yaml/ParseFileRector.php +++ b/packages/Symfony/src/Rector/Yaml/ParseFileRector.php @@ -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); diff --git a/packages/TypeDeclaration/src/Rector/FunctionLike/ReturnTypeDeclarationRector.php b/packages/TypeDeclaration/src/Rector/FunctionLike/ReturnTypeDeclarationRector.php index 7f2dadff5a6..310b8d075d7 100644 --- a/packages/TypeDeclaration/src/Rector/FunctionLike/ReturnTypeDeclarationRector.php +++ b/packages/TypeDeclaration/src/Rector/FunctionLike/ReturnTypeDeclarationRector.php @@ -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); diff --git a/src/Exception/ShouldNotHappenException.php b/src/Exception/ShouldNotHappenException.php index 43b64d1e811..0e3fe42131c 100644 --- a/src/Exception/ShouldNotHappenException.php +++ b/src/Exception/ShouldNotHappenException.php @@ -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); + } } diff --git a/src/NodeContainer/ParsedNodesByType.php b/src/NodeContainer/ParsedNodesByType.php index c66444910dd..cc71fe313ef 100644 --- a/src/NodeContainer/ParsedNodesByType.php +++ b/src/NodeContainer/ParsedNodesByType.php @@ -367,7 +367,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); @@ -465,7 +465,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 +475,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); diff --git a/src/PhpParser/Node/Commander/NodeAddingCommander.php b/src/PhpParser/Node/Commander/NodeAddingCommander.php index cb876c06eda..3fd6ec9cae3 100644 --- a/src/PhpParser/Node/Commander/NodeAddingCommander.php +++ b/src/PhpParser/Node/Commander/NodeAddingCommander.php @@ -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(); } } diff --git a/src/PhpParser/Node/Manipulator/BinaryOpManipulator.php b/src/PhpParser/Node/Manipulator/BinaryOpManipulator.php index 8477011555a..9bf3356d725 100644 --- a/src/PhpParser/Node/Manipulator/BinaryOpManipulator.php +++ b/src/PhpParser/Node/Manipulator/BinaryOpManipulator.php @@ -51,7 +51,7 @@ final class BinaryOpManipulator return; } - throw new ShouldNotHappenException(__METHOD__ . '() on line ' . __LINE__); + throw new ShouldNotHappenException(); } /** diff --git a/src/PhpParser/Node/Manipulator/ClassManipulator.php b/src/PhpParser/Node/Manipulator/ClassManipulator.php index 570412d7532..d82ebe36489 100644 --- a/src/PhpParser/Node/Manipulator/ClassManipulator.php +++ b/src/PhpParser/Node/Manipulator/ClassManipulator.php @@ -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)) { diff --git a/src/PhpParser/Node/Manipulator/ClassMethodManipulator.php b/src/PhpParser/Node/Manipulator/ClassMethodManipulator.php index 3e4c28210fe..657dbf42971 100644 --- a/src/PhpParser/Node/Manipulator/ClassMethodManipulator.php +++ b/src/PhpParser/Node/Manipulator/ClassMethodManipulator.php @@ -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(); } /** diff --git a/src/PhpParser/Node/Manipulator/PropertyFetchManipulator.php b/src/PhpParser/Node/Manipulator/PropertyFetchManipulator.php index e10ccc7a3ab..9dd0cd7014e 100644 --- a/src/PhpParser/Node/Manipulator/PropertyFetchManipulator.php +++ b/src/PhpParser/Node/Manipulator/PropertyFetchManipulator.php @@ -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); diff --git a/src/PhpParser/Node/Value/ValueResolver.php b/src/PhpParser/Node/Value/ValueResolver.php index 1adcc24d250..c7d05fcb289 100644 --- a/src/PhpParser/Node/Value/ValueResolver.php +++ b/src/PhpParser/Node/Value/ValueResolver.php @@ -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') { diff --git a/src/Rector/MethodBody/FluentReplaceRector.php b/src/Rector/MethodBody/FluentReplaceRector.php index bd323d86caf..acc7c16a441 100644 --- a/src/Rector/MethodBody/FluentReplaceRector.php +++ b/src/Rector/MethodBody/FluentReplaceRector.php @@ -120,7 +120,7 @@ PHP } } - throw new ShouldNotHappenException(__METHOD__ . '() on line ' . __LINE__); + throw new ShouldNotHappenException(); } private function isLastMethodCallInChainCall(MethodCall $methodCall): bool diff --git a/src/Rector/MethodBody/ReturnThisRemoveRector.php b/src/Rector/MethodBody/ReturnThisRemoveRector.php index e321e8ae145..3d827f779b4 100644 --- a/src/Rector/MethodBody/ReturnThisRemoveRector.php +++ b/src/Rector/MethodBody/ReturnThisRemoveRector.php @@ -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'); diff --git a/src/Rector/Property/InjectAnnotationClassRector.php b/src/Rector/Property/InjectAnnotationClassRector.php index fa7f27b6f1f..b52c71f5272 100644 --- a/src/Rector/Property/InjectAnnotationClassRector.php +++ b/src/Rector/Property/InjectAnnotationClassRector.php @@ -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); diff --git a/src/Rector/Typehint/ParentTypehintedArgumentRector.php b/src/Rector/Typehint/ParentTypehintedArgumentRector.php index d9e0dcbf4c9..53eb0e0a9c3 100644 --- a/src/Rector/Typehint/ParentTypehintedArgumentRector.php +++ b/src/Rector/Typehint/ParentTypehintedArgumentRector.php @@ -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)) { diff --git a/src/Reflection/FunctionReflectionResolver.php b/src/Reflection/FunctionReflectionResolver.php index 44b5cd94c3e..da4255ef652 100644 --- a/src/Reflection/FunctionReflectionResolver.php +++ b/src/Reflection/FunctionReflectionResolver.php @@ -61,6 +61,6 @@ final class FunctionReflectionResolver } } - throw new ShouldNotHappenException(__METHOD__ . '() on line ' . __LINE__); + throw new ShouldNotHappenException(); } } From ca8cfe10baa18b86bfc570aeb0c9a6bc2fbcb9bc Mon Sep 17 00:00:00 2001 From: Tomas Votruba Date: Sat, 21 Sep 2019 13:26:15 +0200 Subject: [PATCH 3/4] add constant reference case --- .../ChangeSetIdToUuidValueRector.php | 53 ++++++++++++++++--- .../ChangeSetIdToUuidValueRectorTest.php | 2 + .../Fixture/with_constant.php.inc | 42 +++++++++++++++ .../Fixture/with_int_constant_only.php.inc | 43 +++++++++++++++ src/NodeContainer/ParsedNodesByType.php | 18 +++++++ 5 files changed, 150 insertions(+), 8 deletions(-) create mode 100644 packages/Doctrine/tests/Rector/MethodCall/ChangeSetIdToUuidValueRector/Fixture/with_constant.php.inc create mode 100644 packages/Doctrine/tests/Rector/MethodCall/ChangeSetIdToUuidValueRector/Fixture/with_int_constant_only.php.inc diff --git a/packages/Doctrine/src/Rector/MethodCall/ChangeSetIdToUuidValueRector.php b/packages/Doctrine/src/Rector/MethodCall/ChangeSetIdToUuidValueRector.php index 738995bbd86..7a53c8248b2 100644 --- a/packages/Doctrine/src/Rector/MethodCall/ChangeSetIdToUuidValueRector.php +++ b/packages/Doctrine/src/Rector/MethodCall/ChangeSetIdToUuidValueRector.php @@ -4,12 +4,15 @@ 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; @@ -22,6 +25,16 @@ use Rector\RectorDefinition\RectorDefinition; */ 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', [ @@ -97,16 +110,31 @@ PHP return $node; } - // already uuid static type - if ($this->isUuidType($node->args[0]->value)) { - return null; + // 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; } - // B. set uuid from string with generated string - $uuidValue = Uuid::uuid4(); - $uuidValueString = $uuidValue->toString(); - - $value = $this->createStaticCall(Uuid::class, 'fromString', [new String_($uuidValueString)]); + // C. set uuid from string with generated string + $value = $this->createStaticCall(Uuid::class, 'fromString', [$this->createUuidStringNode()]); $node->args[0]->value = $value; return $node; @@ -131,6 +159,7 @@ PHP return true; } + // already uuid static type return $this->isUuidType($methodCall->args[0]->value); } @@ -185,4 +214,12 @@ PHP return $argumentStaticType->getClassName() === DoctrineClass::RAMSEY_UUID; } + + private function createUuidStringNode(): String_ + { + $uuidValue = Uuid::uuid4(); + $uuidValueString = $uuidValue->toString(); + + return new String_($uuidValueString); + } } diff --git a/packages/Doctrine/tests/Rector/MethodCall/ChangeSetIdToUuidValueRector/ChangeSetIdToUuidValueRectorTest.php b/packages/Doctrine/tests/Rector/MethodCall/ChangeSetIdToUuidValueRector/ChangeSetIdToUuidValueRectorTest.php index 8ceda3c466e..8a53890508b 100644 --- a/packages/Doctrine/tests/Rector/MethodCall/ChangeSetIdToUuidValueRector/ChangeSetIdToUuidValueRectorTest.php +++ b/packages/Doctrine/tests/Rector/MethodCall/ChangeSetIdToUuidValueRector/ChangeSetIdToUuidValueRectorTest.php @@ -23,6 +23,8 @@ final class ChangeSetIdToUuidValueRectorTest extends AbstractRectorTestCase 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 diff --git a/packages/Doctrine/tests/Rector/MethodCall/ChangeSetIdToUuidValueRector/Fixture/with_constant.php.inc b/packages/Doctrine/tests/Rector/MethodCall/ChangeSetIdToUuidValueRector/Fixture/with_constant.php.inc new file mode 100644 index 00000000000..99d956d3b7f --- /dev/null +++ b/packages/Doctrine/tests/Rector/MethodCall/ChangeSetIdToUuidValueRector/Fixture/with_constant.php.inc @@ -0,0 +1,42 @@ +setUuid(Uuid::fromString(self::UUID_CONSTANT)); + $buildingFirst->setId(self::INTEGER_CONSTANT); + } +} + +?> +----- +setId(Uuid::fromString(self::UUID_CONSTANT)); + } +} + +?> diff --git a/packages/Doctrine/tests/Rector/MethodCall/ChangeSetIdToUuidValueRector/Fixture/with_int_constant_only.php.inc b/packages/Doctrine/tests/Rector/MethodCall/ChangeSetIdToUuidValueRector/Fixture/with_int_constant_only.php.inc new file mode 100644 index 00000000000..226b38a0018 --- /dev/null +++ b/packages/Doctrine/tests/Rector/MethodCall/ChangeSetIdToUuidValueRector/Fixture/with_int_constant_only.php.inc @@ -0,0 +1,43 @@ +setId(self::INTEGER_CONSTANT); + + // this values should be the same + assert($buildingFirst->getId() === self::INTEGER_CONSTANT); + } +} + +?> +----- +setId(\Ramsey\Uuid\Uuid::fromString(self::INTEGER_CONSTANT)); + + // this values should be the same + assert($buildingFirst->getId() === self::INTEGER_CONSTANT); + } +} + +?> diff --git a/src/NodeContainer/ParsedNodesByType.php b/src/NodeContainer/ParsedNodesByType.php index cc71fe313ef..d37bc14e545 100644 --- a/src/NodeContainer/ParsedNodesByType.php +++ b/src/NodeContainer/ParsedNodesByType.php @@ -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; @@ -457,6 +458,23 @@ final class ParsedNodesByType return $newNodesByClass; } + public function findClassConstantByClassConstFetch(ClassConstFetch $classConstFetch): ?ClassConst + { + $class = null; + if ($this->nameResolver->isName($classConstFetch->class, 'self')) { + /** @var string|null $class */ + $class = $classConstFetch->getAttribute(AttributeKey::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)) { From fabbfacd1ae4deec77de8fa4fbdf6f85be9ad0c7 Mon Sep 17 00:00:00 2001 From: Tomas Votruba Date: Sat, 21 Sep 2019 13:32:35 +0200 Subject: [PATCH 4/4] [Doctrine] Add GetUuidMethodCall to GetId --- .../doctrine/doctrine-id-to-uuid-step-3.yaml | 1 + .../ChangeGetUuidMethodCallToGetIdRector.php | 116 ++++++++++++++++++ .../src/ValueObject/DoctrineClass.php | 10 +- ...angeGetUuidMethodCallToGetIdRectorTest.php | 30 +++++ .../Fixture/fixture.php.inc | 35 ++++++ .../Source/Car.php | 19 +++ .../Fixture/const.php.inc | 22 ---- .../Fixture/external_const.php.inc | 41 +++++++ .../RegexDashEscapeRectorTest.php | 1 + src/NodeContainer/ParsedNodesByType.php | 9 +- .../Regex/RegexPatternArgumentManipulator.php | 14 +-- 11 files changed, 256 insertions(+), 42 deletions(-) create mode 100644 packages/Doctrine/src/Rector/MethodCall/ChangeGetUuidMethodCallToGetIdRector.php create mode 100644 packages/Doctrine/tests/Rector/MethodCall/ChangeGetUuidMethodCallToGetIdRector/ChangeGetUuidMethodCallToGetIdRectorTest.php create mode 100644 packages/Doctrine/tests/Rector/MethodCall/ChangeGetUuidMethodCallToGetIdRector/Fixture/fixture.php.inc create mode 100644 packages/Doctrine/tests/Rector/MethodCall/ChangeGetUuidMethodCallToGetIdRector/Source/Car.php create mode 100644 packages/Php/tests/Rector/FuncCall/RegexDashEscapeRector/Fixture/external_const.php.inc diff --git a/config/set/doctrine/doctrine-id-to-uuid-step-3.yaml b/config/set/doctrine/doctrine-id-to-uuid-step-3.yaml index fcc06c8e8e7..5255742e6c4 100644 --- a/config/set/doctrine/doctrine-id-to-uuid-step-3.yaml +++ b/config/set/doctrine/doctrine-id-to-uuid-step-3.yaml @@ -1,2 +1,3 @@ services: Rector\Doctrine\Rector\MethodCall\ChangeSetIdToUuidValueRector: ~ + Rector\Doctrine\Rector\MethodCall\ChangeGetUuidMethodCallToGetIdRector: ~ diff --git a/packages/Doctrine/src/Rector/MethodCall/ChangeGetUuidMethodCallToGetIdRector.php b/packages/Doctrine/src/Rector/MethodCall/ChangeGetUuidMethodCallToGetIdRector.php new file mode 100644 index 00000000000..015c381e5a0 --- /dev/null +++ b/packages/Doctrine/src/Rector/MethodCall/ChangeGetUuidMethodCallToGetIdRector.php @@ -0,0 +1,116 @@ +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()); + } +} diff --git a/packages/Doctrine/src/ValueObject/DoctrineClass.php b/packages/Doctrine/src/ValueObject/DoctrineClass.php index fd808e06ed4..966fa87fcb8 100644 --- a/packages/Doctrine/src/ValueObject/DoctrineClass.php +++ b/packages/Doctrine/src/ValueObject/DoctrineClass.php @@ -4,11 +4,6 @@ namespace Rector\Doctrine\ValueObject; final class DoctrineClass { - /** - * @var string - */ - public const RAMSEY_UUID_INTERFACE = 'Ramsey\Uuid\UuidInterface'; - /** * @var string */ @@ -33,4 +28,9 @@ final class DoctrineClass * @var string */ public const RAMSEY_UUID = 'Ramsey\Uuid\Uuid'; + + /** + * @var string + */ + public const RAMSEY_UUID_INTERFACE = 'Ramsey\Uuid\UuidInterface'; } diff --git a/packages/Doctrine/tests/Rector/MethodCall/ChangeGetUuidMethodCallToGetIdRector/ChangeGetUuidMethodCallToGetIdRectorTest.php b/packages/Doctrine/tests/Rector/MethodCall/ChangeGetUuidMethodCallToGetIdRector/ChangeGetUuidMethodCallToGetIdRectorTest.php new file mode 100644 index 00000000000..c6dc5925e51 --- /dev/null +++ b/packages/Doctrine/tests/Rector/MethodCall/ChangeGetUuidMethodCallToGetIdRector/ChangeGetUuidMethodCallToGetIdRectorTest.php @@ -0,0 +1,30 @@ +doTestFile($file); + } + + /** + * @return string[] + */ + public function provideDataForTest(): iterable + { + yield [__DIR__ . '/Fixture/fixture.php.inc']; + } + + protected function getRectorClass(): string + { + return ChangeGetUuidMethodCallToGetIdRector::class; + } +} diff --git a/packages/Doctrine/tests/Rector/MethodCall/ChangeGetUuidMethodCallToGetIdRector/Fixture/fixture.php.inc b/packages/Doctrine/tests/Rector/MethodCall/ChangeGetUuidMethodCallToGetIdRector/Fixture/fixture.php.inc new file mode 100644 index 00000000000..880d602672d --- /dev/null +++ b/packages/Doctrine/tests/Rector/MethodCall/ChangeGetUuidMethodCallToGetIdRector/Fixture/fixture.php.inc @@ -0,0 +1,35 @@ +getUuid()->toString(); + } +} + +?> +----- +getId()->toString(); + } +} + +?> diff --git a/packages/Doctrine/tests/Rector/MethodCall/ChangeGetUuidMethodCallToGetIdRector/Source/Car.php b/packages/Doctrine/tests/Rector/MethodCall/ChangeGetUuidMethodCallToGetIdRector/Source/Car.php new file mode 100644 index 00000000000..7e78b8e2650 --- /dev/null +++ b/packages/Doctrine/tests/Rector/MethodCall/ChangeGetUuidMethodCallToGetIdRector/Source/Car.php @@ -0,0 +1,19 @@ +uuid; + } +} diff --git a/packages/Php/tests/Rector/FuncCall/RegexDashEscapeRector/Fixture/const.php.inc b/packages/Php/tests/Rector/FuncCall/RegexDashEscapeRector/Fixture/const.php.inc index a416ed81229..2941afeaa4e 100644 --- a/packages/Php/tests/Rector/FuncCall/RegexDashEscapeRector/Fixture/const.php.inc +++ b/packages/Php/tests/Rector/FuncCall/RegexDashEscapeRector/Fixture/const.php.inc @@ -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); - } -} - ?> ----- diff --git a/packages/Php/tests/Rector/FuncCall/RegexDashEscapeRector/Fixture/external_const.php.inc b/packages/Php/tests/Rector/FuncCall/RegexDashEscapeRector/Fixture/external_const.php.inc new file mode 100644 index 00000000000..826e403dae2 --- /dev/null +++ b/packages/Php/tests/Rector/FuncCall/RegexDashEscapeRector/Fixture/external_const.php.inc @@ -0,0 +1,41 @@ + +----- + diff --git a/packages/Php/tests/Rector/FuncCall/RegexDashEscapeRector/RegexDashEscapeRectorTest.php b/packages/Php/tests/Rector/FuncCall/RegexDashEscapeRector/RegexDashEscapeRectorTest.php index e05b4997dcf..81a55afc808 100644 --- a/packages/Php/tests/Rector/FuncCall/RegexDashEscapeRector/RegexDashEscapeRectorTest.php +++ b/packages/Php/tests/Rector/FuncCall/RegexDashEscapeRector/RegexDashEscapeRectorTest.php @@ -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']; } diff --git a/src/NodeContainer/ParsedNodesByType.php b/src/NodeContainer/ParsedNodesByType.php index d37bc14e545..be7a518e62d 100644 --- a/src/NodeContainer/ParsedNodesByType.php +++ b/src/NodeContainer/ParsedNodesByType.php @@ -460,10 +460,14 @@ final class ParsedNodesByType public function findClassConstantByClassConstFetch(ClassConstFetch $classConstFetch): ?ClassConst { - $class = null; - if ($this->nameResolver->isName($classConstFetch->class, 'self')) { + $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) { @@ -472,6 +476,7 @@ final class ParsedNodesByType /** @var string $constantName */ $constantName = $this->nameResolver->getName($classConstFetch->name); + return $this->findClassConstant($class, $constantName); } diff --git a/src/Php/Regex/RegexPatternArgumentManipulator.php b/src/Php/Regex/RegexPatternArgumentManipulator.php index ecd052fbf3b..e16c9227077 100644 --- a/src/Php/Regex/RegexPatternArgumentManipulator.php +++ b/src/Php/Regex/RegexPatternArgumentManipulator.php @@ -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 []; }