mirror of
https://github.com/rectorphp/rector.git
synced 2025-01-17 21:38:22 +01:00
[DoctrineAnnotationSyncer] Remove to move to static reflection (#6006)
This commit is contained in:
parent
ca8cfa103b
commit
5fa858b072
4
.github/workflows/code_analysis.yaml
vendored
4
.github/workflows/code_analysis.yaml
vendored
@ -29,10 +29,6 @@ jobs:
|
||||
name: 'PHPStan for config'
|
||||
run: composer phpstan-config
|
||||
|
||||
-
|
||||
name: "Check doctrine/annotation"
|
||||
run: "bin/rector sync-annotation-parser --dry-run --ansi"
|
||||
|
||||
# see https://github.com/rectorphp/rector-generator
|
||||
-
|
||||
name: 'Rector Generate From Recipe'
|
||||
|
@ -99,8 +99,7 @@
|
||||
"Rector\\Core\\Tests\\": "tests",
|
||||
"Rector\\RuleDocGenerator\\": "utils/rule-doc-generator/src",
|
||||
"Rector\\PHPStanExtensions\\": "utils/phpstan-extensions/src",
|
||||
"Rector\\PHPStanExtensions\\Tests\\": "utils/phpstan-extensions/tests",
|
||||
"Rector\\Utils\\DoctrineAnnotationParserSyncer\\": "utils/doctrine-annotation-parser-syncer/src"
|
||||
"Rector\\PHPStanExtensions\\Tests\\": "utils/phpstan-extensions/tests"
|
||||
},
|
||||
"classmap": [
|
||||
"stubs/Annotations",
|
||||
|
@ -31,6 +31,12 @@ final class PhpDocInfoPrinter
|
||||
*/
|
||||
public const CLOSING_DOCBLOCK_REGEX = '#\*\/(\s+)?$#';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
* @see https://regex101.com/r/Jzqzpw/1
|
||||
*/
|
||||
private const MISSING_NEWLINE_REGEX = '#([^\s])\*/$#';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
@ -125,6 +131,10 @@ final class PhpDocInfoPrinter
|
||||
public function printNew(PhpDocInfo $phpDocInfo): string
|
||||
{
|
||||
$docContent = (string) $phpDocInfo->getPhpDocNode();
|
||||
|
||||
// fix missing newline in the end of docblock - keep BC compatible for both cases until phpstan with phpdoc-parser 0.5.2 is released
|
||||
$docContent = Strings::replace($docContent, self::MISSING_NEWLINE_REGEX, "$1\n */");
|
||||
|
||||
if ($phpDocInfo->isSingleLine()) {
|
||||
return $this->docBlockInliner->inline($docContent);
|
||||
}
|
||||
|
@ -213,12 +213,6 @@ parameters:
|
||||
- rules/Php80/Rector/Switch_/ChangeSwitchToMatchRector.php
|
||||
- packages/NodeNestingScope/NodeFinder/ScopeAwareNodeFinder.php
|
||||
|
||||
# internal generating Rector
|
||||
-
|
||||
message: '#Class "Rector\\Utils\\DoctrineAnnotationParserSyncer\\Rector\\(.*?)" is missing @see annotation with test case class reference#'
|
||||
paths:
|
||||
- utils/doctrine-annotation-parser-syncer/src/Rector/*
|
||||
|
||||
-
|
||||
message: '#Do not use setter on a service#'
|
||||
paths:
|
||||
|
@ -273,7 +273,8 @@ CODE_SAMPLE
|
||||
$throwableType = new ObjectType('Throwable');
|
||||
$type = new ObjectType($class->toString());
|
||||
|
||||
return $throwableType->isSuperTypeOf($type)->yes();
|
||||
return $throwableType->isSuperTypeOf($type)
|
||||
->yes();
|
||||
}
|
||||
|
||||
private function hasCall(Node $node): bool
|
||||
|
@ -110,7 +110,7 @@ CODE_SAMPLE
|
||||
return true;
|
||||
}
|
||||
|
||||
/** @var FuncCall|MethodCall|New_|NullsafeMethodCall|StaticCall $expr */
|
||||
/** @var FuncCall|MethodCall|New_|NullsafeMethodCall|StaticCall $expr */
|
||||
$expr = $assign->expr;
|
||||
if (! $this->isCall($expr)) {
|
||||
return false;
|
||||
@ -136,7 +136,7 @@ CODE_SAMPLE
|
||||
return false;
|
||||
}
|
||||
|
||||
private function isCall(Expr $expr) : bool
|
||||
private function isCall(Expr $expr): bool
|
||||
{
|
||||
return $expr instanceof FuncCall || $expr instanceof MethodCall || $expr instanceof New_ || $expr instanceof NullsafeMethodCall || $expr instanceof StaticCall;
|
||||
}
|
||||
|
@ -7,12 +7,12 @@ namespace Rector\TypeDeclaration\Rector\Property;
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Stmt\Property;
|
||||
use PHPStan\Type\MixedType;
|
||||
use PHPStan\Type\NullType;
|
||||
use Rector\BetterPhpDocParser\PhpDocManipulator\PhpDocTypeChanger;
|
||||
use Rector\Core\Rector\AbstractRector;
|
||||
use Rector\TypeDeclaration\TypeInferer\PropertyTypeInferer;
|
||||
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
|
||||
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
|
||||
use PHPStan\Type\NullType;
|
||||
|
||||
/**
|
||||
* @see \Rector\Tests\TypeDeclaration\Rector\Property\PropertyTypeDeclarationRector\PropertyTypeDeclarationRectorTest
|
||||
|
@ -77,13 +77,6 @@ final class RectorConfigsResolver
|
||||
}
|
||||
}
|
||||
|
||||
// load config only if "sync" command is used to avoid useless rules traversing
|
||||
if ($argvInput->getFirstArgument() === 'sync-annotation-parser') {
|
||||
$configFileInfos[] = new SmartFileInfo(
|
||||
__DIR__ . '/../../utils/doctrine-annotation-parser-syncer/config/config.php'
|
||||
);
|
||||
}
|
||||
|
||||
return new BootstrapConfigs($mainConfigFileInfo, $configFileInfos);
|
||||
}
|
||||
}
|
||||
|
@ -1,16 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
|
||||
|
||||
return static function (ContainerConfigurator $containerConfigurator): void {
|
||||
$services = $containerConfigurator->services();
|
||||
|
||||
$services->defaults()
|
||||
->public()
|
||||
->autowire()
|
||||
->autoconfigure();
|
||||
|
||||
$services->load('Rector\Utils\DoctrineAnnotationParserSyncer\\', __DIR__ . '/../src');
|
||||
};
|
@ -1,42 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Utils\DoctrineAnnotationParserSyncer;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\NodeTraverser;
|
||||
use PhpParser\NodeVisitor;
|
||||
use Rector\PostRector\Application\PostFileProcessor;
|
||||
use Rector\Utils\DoctrineAnnotationParserSyncer\Contract\Rector\ClassSyncerRectorInterface;
|
||||
|
||||
final class ClassSyncerNodeTraverser extends NodeTraverser
|
||||
{
|
||||
/**
|
||||
* @var PostFileProcessor
|
||||
*/
|
||||
private $postFileProcessor;
|
||||
|
||||
/**
|
||||
* @param ClassSyncerRectorInterface[] $classSyncerRectors
|
||||
*/
|
||||
public function __construct(array $classSyncerRectors, PostFileProcessor $postFileProcessor)
|
||||
{
|
||||
foreach ($classSyncerRectors as $classSyncerRector) {
|
||||
/** @var ClassSyncerRectorInterface&NodeVisitor $classSyncerRector */
|
||||
$this->addVisitor($classSyncerRector);
|
||||
}
|
||||
|
||||
$this->postFileProcessor = $postFileProcessor;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Node[] $nodes
|
||||
* @return Node[]
|
||||
*/
|
||||
public function traverse(array $nodes): array
|
||||
{
|
||||
$traversedNodes = parent::traverse($nodes);
|
||||
return $this->postFileProcessor->traverse($traversedNodes);
|
||||
}
|
||||
}
|
@ -1,77 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Utils\DoctrineAnnotationParserSyncer\Command;
|
||||
|
||||
use Rector\Core\Configuration\Option;
|
||||
use Rector\Utils\DoctrineAnnotationParserSyncer\FileSyncer\AnnotationReaderClassSyncer;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
use Symplify\PackageBuilder\Console\ShellCode;
|
||||
use Symplify\PackageBuilder\Parameter\ParameterProvider;
|
||||
|
||||
final class SyncAnnotationParserCommand extends Command
|
||||
{
|
||||
/**
|
||||
* @var SymfonyStyle
|
||||
*/
|
||||
private $symfonyStyle;
|
||||
|
||||
/**
|
||||
* @var ParameterProvider
|
||||
*/
|
||||
private $parameterProvider;
|
||||
|
||||
/**
|
||||
* @var AnnotationReaderClassSyncer
|
||||
*/
|
||||
private $annotationReaderClassSyncer;
|
||||
|
||||
public function __construct(
|
||||
AnnotationReaderClassSyncer $annotationReaderClassSyncer,
|
||||
SymfonyStyle $symfonyStyle,
|
||||
ParameterProvider $parameterProvider
|
||||
) {
|
||||
$this->symfonyStyle = $symfonyStyle;
|
||||
$this->parameterProvider = $parameterProvider;
|
||||
$this->annotationReaderClassSyncer = $annotationReaderClassSyncer;
|
||||
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
protected function configure(): void
|
||||
{
|
||||
$this->setDescription('[DEV] Generate value-preserving DocParser from doctrine/annotation');
|
||||
|
||||
$this->addOption(
|
||||
Option::OPTION_DRY_RUN,
|
||||
'n',
|
||||
InputOption::VALUE_NONE,
|
||||
'See diff of changes, do not save them to files.'
|
||||
);
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
// disable imports
|
||||
$this->parameterProvider->changeParameter(Option::AUTO_IMPORT_NAMES, false);
|
||||
|
||||
$dryRun = (bool) $input->getOption(Option::OPTION_DRY_RUN);
|
||||
|
||||
$isSuccess = $this->annotationReaderClassSyncer->sync($dryRun);
|
||||
if (! $isSuccess) {
|
||||
$message = 'Doctrine Annotation files have changed, sync them: bin/rector sync-annotation-parser';
|
||||
$this->symfonyStyle->error($message);
|
||||
|
||||
return ShellCode::ERROR;
|
||||
}
|
||||
|
||||
$this->symfonyStyle->success('Constant preserving doctrine/annotation parser was updated');
|
||||
|
||||
return ShellCode::SUCCESS;
|
||||
}
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Utils\DoctrineAnnotationParserSyncer\Contract\Rector;
|
||||
|
||||
interface ClassSyncerRectorInterface
|
||||
{
|
||||
}
|
@ -1,92 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Utils\DoctrineAnnotationParserSyncer\FileSyncer;
|
||||
|
||||
use PhpParser\Node;
|
||||
use Rector\Core\PhpParser\Printer\BetterStandardPrinter;
|
||||
use Rector\FileSystemRector\Parser\FileInfoParser;
|
||||
use Rector\Utils\DoctrineAnnotationParserSyncer\ClassSyncerNodeTraverser;
|
||||
use Symplify\SmartFileSystem\SmartFileInfo;
|
||||
use Symplify\SmartFileSystem\SmartFileSystem;
|
||||
|
||||
final class AnnotationReaderClassSyncer
|
||||
{
|
||||
/**
|
||||
* @var array<string, string>
|
||||
*/
|
||||
private const VENDOR_FILES_TO_LOCAL_FILES = [
|
||||
__DIR__ . '/../../../../vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/AnnotationReader.php' => __DIR__ . '/../../../../packages/DoctrineAnnotationGenerated/ConstantPreservingAnnotationReader.php',
|
||||
__DIR__ . '/../../../../vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/DocParser.php' => __DIR__ . '/../../../../packages/DoctrineAnnotationGenerated/ConstantPreservingDocParser.php',
|
||||
];
|
||||
|
||||
/**
|
||||
* @var SmartFileSystem
|
||||
*/
|
||||
private $smartFileSystem;
|
||||
|
||||
/**
|
||||
* @var FileInfoParser
|
||||
*/
|
||||
private $fileInfoParser;
|
||||
|
||||
/**
|
||||
* @var ClassSyncerNodeTraverser
|
||||
*/
|
||||
private $classSyncerNodeTraverser;
|
||||
|
||||
/**
|
||||
* @var BetterStandardPrinter
|
||||
*/
|
||||
private $betterStandardPrinter;
|
||||
|
||||
public function __construct(
|
||||
BetterStandardPrinter $betterStandardPrinter,
|
||||
FileInfoParser $fileInfoParser,
|
||||
SmartFileSystem $smartFileSystem,
|
||||
ClassSyncerNodeTraverser $classSyncerNodeTraverser
|
||||
) {
|
||||
$this->betterStandardPrinter = $betterStandardPrinter;
|
||||
$this->fileInfoParser = $fileInfoParser;
|
||||
$this->smartFileSystem = $smartFileSystem;
|
||||
$this->classSyncerNodeTraverser = $classSyncerNodeTraverser;
|
||||
}
|
||||
|
||||
public function sync(bool $isDryRun): bool
|
||||
{
|
||||
foreach (self::VENDOR_FILES_TO_LOCAL_FILES as $vendorFile => $localFile) {
|
||||
$docParserFileInfo = new SmartFileInfo($vendorFile);
|
||||
$fileNodes = $this->fileInfoParser->parseFileInfoToNodesAndDecorate($docParserFileInfo);
|
||||
$changedNodes = $this->classSyncerNodeTraverser->traverse($fileNodes);
|
||||
|
||||
if ($isDryRun) {
|
||||
return ! $this->hasContentChanged($fileNodes, $localFile);
|
||||
}
|
||||
|
||||
// print file
|
||||
$printedContent = $this->betterStandardPrinter->prettyPrintFile($changedNodes);
|
||||
$this->smartFileSystem->dumpFile($localFile, $printedContent);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Node[] $nodes
|
||||
*/
|
||||
private function hasContentChanged(array $nodes, string $targetFilePath): bool
|
||||
{
|
||||
$finalContent = $this->betterStandardPrinter->prettyPrintFile($nodes);
|
||||
|
||||
// nothing to validate against
|
||||
if (! file_exists($targetFilePath)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$currentContent = $this->smartFileSystem->readFile($targetFilePath);
|
||||
|
||||
// has content changed
|
||||
return $finalContent !== $currentContent;
|
||||
}
|
||||
}
|
@ -1,85 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Utils\DoctrineAnnotationParserSyncer\Rector\Assign;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Expr\Assign;
|
||||
use PhpParser\Node\Expr\New_;
|
||||
use PhpParser\Node\Name\FullyQualified;
|
||||
use PHPStan\Analyser\Scope;
|
||||
use PHPStan\Reflection\ClassReflection;
|
||||
use Rector\Core\Rector\AbstractRector;
|
||||
use Rector\NodeTypeResolver\Node\AttributeKey;
|
||||
use Rector\Utils\DoctrineAnnotationParserSyncer\Contract\Rector\ClassSyncerRectorInterface;
|
||||
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
|
||||
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
|
||||
|
||||
final class AssignNewDocParserRector extends AbstractRector implements ClassSyncerRectorInterface
|
||||
{
|
||||
/**
|
||||
* @return array<class-string<Node>>
|
||||
*/
|
||||
public function getNodeTypes(): array
|
||||
{
|
||||
return [Assign::class];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Assign $node
|
||||
*/
|
||||
public function refactor(Node $node): ?Node
|
||||
{
|
||||
/** @var Scope $scope */
|
||||
$scope = $node->getAttribute(AttributeKey::SCOPE);
|
||||
|
||||
$classReflection = $scope->getClassReflection();
|
||||
if (! $classReflection instanceof ClassReflection) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if ($classReflection->getName() !== 'Doctrine\Common\Annotations\AnnotationReader') {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (! $this->isName($node->var, 'preParser')) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$node->expr = new New_(new FullyQualified('Rector\DoctrineAnnotationGenerated\ConstantPreservingDocParser'));
|
||||
|
||||
return $node;
|
||||
}
|
||||
|
||||
public function getRuleDefinition(): RuleDefinition
|
||||
{
|
||||
return new RuleDefinition('Change $this->preParser assign to new doc parser', [
|
||||
new CodeSample(
|
||||
<<<'CODE_SAMPLE'
|
||||
namespace Doctrine\Common\Annotations;
|
||||
|
||||
class AnnotationReader
|
||||
{
|
||||
public function run()
|
||||
{
|
||||
$this->preParser = ...
|
||||
}
|
||||
}
|
||||
CODE_SAMPLE
|
||||
,
|
||||
<<<'CODE_SAMPLE'
|
||||
namespace Doctrine\Common\Annotations;
|
||||
|
||||
class AnnotationReader
|
||||
{
|
||||
public function run()
|
||||
{
|
||||
$this->preParser = new \Rector\DoctrineAnnotationGenerated\ConstantPreservingDocParser();
|
||||
}
|
||||
}
|
||||
CODE_SAMPLE
|
||||
),
|
||||
]);
|
||||
}
|
||||
}
|
@ -1,84 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Utils\DoctrineAnnotationParserSyncer\Rector\ClassMethod;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Name\FullyQualified;
|
||||
use PhpParser\Node\Stmt\ClassMethod;
|
||||
use PHPStan\Analyser\Scope;
|
||||
use PHPStan\Reflection\ClassReflection;
|
||||
use Rector\Core\Rector\AbstractRector;
|
||||
use Rector\Core\ValueObject\MethodName;
|
||||
use Rector\NodeTypeResolver\Node\AttributeKey;
|
||||
use Rector\Utils\DoctrineAnnotationParserSyncer\Contract\Rector\ClassSyncerRectorInterface;
|
||||
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
|
||||
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
|
||||
|
||||
final class ChangeOriginalTypeToCustomRector extends AbstractRector implements ClassSyncerRectorInterface
|
||||
{
|
||||
/**
|
||||
* @return array<class-string<\PhpParser\Node>>
|
||||
*/
|
||||
public function getNodeTypes(): array
|
||||
{
|
||||
return [ClassMethod::class];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ClassMethod $node
|
||||
*/
|
||||
public function refactor(Node $node): ?Node
|
||||
{
|
||||
/** @var Scope $scope */
|
||||
$scope = $node->getAttribute(AttributeKey::SCOPE);
|
||||
|
||||
$classReflection = $scope->getClassReflection();
|
||||
if (! $classReflection instanceof ClassReflection) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if ($classReflection->getName() !== 'Doctrine\Common\Annotations\AnnotationReader') {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (! $this->isName($node, MethodName::CONSTRUCT)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$firstParam = $node->params[0];
|
||||
$firstParam->type = new FullyQualified('Rector\DoctrineAnnotationGenerated\ConstantPreservingDocParser');
|
||||
|
||||
return $node;
|
||||
}
|
||||
|
||||
public function getRuleDefinition(): RuleDefinition
|
||||
{
|
||||
return new RuleDefinition('Change DocParser type to custom one', [
|
||||
new CodeSample(
|
||||
<<<'CODE_SAMPLE'
|
||||
namespace Doctrine\Common\Annotations;
|
||||
|
||||
class AnnotationReader
|
||||
{
|
||||
public function __construct(... $parser)
|
||||
{
|
||||
}
|
||||
}
|
||||
CODE_SAMPLE
|
||||
,
|
||||
<<<'CODE_SAMPLE'
|
||||
namespace Doctrine\Common\Annotations;
|
||||
|
||||
class AnnotationReader
|
||||
{
|
||||
public function __construct(\Rector\DoctrineAnnotationGenerated\ConstantPreservingDocParser $parser)
|
||||
{
|
||||
}
|
||||
}
|
||||
CODE_SAMPLE
|
||||
),
|
||||
]);
|
||||
}
|
||||
}
|
@ -1,150 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Utils\DoctrineAnnotationParserSyncer\Rector\ClassMethod;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Expr\Assign;
|
||||
use PhpParser\Node\Expr\Variable;
|
||||
use PhpParser\Node\Stmt\ClassMethod;
|
||||
use PhpParser\Node\Stmt\Expression;
|
||||
use PhpParser\Node\Stmt\Return_;
|
||||
use PHPStan\Analyser\Scope;
|
||||
use PHPStan\Reflection\ClassReflection;
|
||||
use Rector\Core\Rector\AbstractRector;
|
||||
use Rector\DoctrineAnnotationGenerated\DataCollector\ResolvedConstantStaticCollector;
|
||||
use Rector\NodeTypeResolver\Node\AttributeKey;
|
||||
use Rector\Utils\DoctrineAnnotationParserSyncer\Contract\Rector\ClassSyncerRectorInterface;
|
||||
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
|
||||
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
|
||||
|
||||
/**
|
||||
* @see \Rector\DoctrineAnnotationGenerated\ConstantPreservingDocParser::Constant()
|
||||
*/
|
||||
final class LogIdentifierAndResolverValueInConstantClassMethodRector extends AbstractRector implements ClassSyncerRectorInterface
|
||||
{
|
||||
/**
|
||||
* @return array<class-string<\PhpParser\Node>>
|
||||
*/
|
||||
public function getNodeTypes(): array
|
||||
{
|
||||
return [ClassMethod::class];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ClassMethod $node
|
||||
*/
|
||||
public function refactor(Node $node): ?Node
|
||||
{
|
||||
/** @var Scope $scope */
|
||||
$scope = $node->getAttribute(AttributeKey::SCOPE);
|
||||
|
||||
$classReflection = $scope->getClassReflection();
|
||||
if (! $classReflection instanceof ClassReflection) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if ($classReflection->getName() !== 'Doctrine\Common\Annotations\DocParser') {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (! $this->isName($node->name, 'Constant')) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// 1. store original value right in the start
|
||||
if (! isset($node->stmts[0])) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$firstStmt = $node->stmts[0];
|
||||
|
||||
unset($node->stmts[0]);
|
||||
$assignExpression = $this->createAssignOriginalIdentifierExpression();
|
||||
$node->stmts = array_merge([$firstStmt], [$assignExpression], (array) $node->stmts);
|
||||
|
||||
// 2. record value in each return
|
||||
$this->traverseNodesWithCallable($node->stmts, function (Node $node): ?Return_ {
|
||||
if (! $node instanceof Return_) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if ($node->expr === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// assign resolved value to temporary variable
|
||||
$resolvedValueVariable = new Variable('resolvedValue');
|
||||
$assign = new Assign($resolvedValueVariable, $node->expr);
|
||||
$assignExpression = new Expression($assign);
|
||||
|
||||
$this->addNodeBeforeNode($assignExpression, $node);
|
||||
|
||||
// log the value in static call
|
||||
$originalIdentifier = new Variable('originalIdentifier');
|
||||
$staticCallExpression = $this->createStaticCallExpression($originalIdentifier, $resolvedValueVariable);
|
||||
$this->addNodeBeforeNode($staticCallExpression, $node);
|
||||
|
||||
$node->expr = $resolvedValueVariable;
|
||||
return $node;
|
||||
});
|
||||
|
||||
return $node;
|
||||
}
|
||||
|
||||
public function getRuleDefinition(): RuleDefinition
|
||||
{
|
||||
return new RuleDefinition('Log original and changed constant value', [
|
||||
new CodeSample(
|
||||
<<<'CODE_SAMPLE'
|
||||
namespace Doctrine\Common\Annotations;
|
||||
|
||||
class AnnotationReader
|
||||
{
|
||||
public function Constant()
|
||||
{
|
||||
// ...
|
||||
}
|
||||
}
|
||||
CODE_SAMPLE
|
||||
,
|
||||
<<<'CODE_SAMPLE'
|
||||
namespace Doctrine\Common\Annotations;
|
||||
|
||||
class AnnotationReader
|
||||
{
|
||||
public function Constant()
|
||||
{
|
||||
$identifier = $this->Identifier();
|
||||
$originalIdentifier = $identifier;
|
||||
// ...
|
||||
}
|
||||
}
|
||||
CODE_SAMPLE
|
||||
),
|
||||
]);
|
||||
}
|
||||
|
||||
private function createAssignOriginalIdentifierExpression(): Expression
|
||||
{
|
||||
$originalIdentifier = new Variable('originalIdentifier');
|
||||
$identifier = new Variable('identifier');
|
||||
|
||||
$assign = new Assign($originalIdentifier, $identifier);
|
||||
|
||||
return new Expression($assign);
|
||||
}
|
||||
|
||||
private function createStaticCallExpression(Variable $identifierVariable, Variable $resolvedVariable): Expression
|
||||
{
|
||||
$arguments = [$identifierVariable, $resolvedVariable];
|
||||
$staticCall = $this->nodeFactory->createStaticCall(
|
||||
ResolvedConstantStaticCollector::class,
|
||||
'collect',
|
||||
$arguments
|
||||
);
|
||||
|
||||
return new Expression($staticCall);
|
||||
}
|
||||
}
|
@ -1,69 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Utils\DoctrineAnnotationParserSyncer\Rector\Namespace_;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Identifier;
|
||||
use PhpParser\Node\Name;
|
||||
use PhpParser\Node\Stmt\Class_;
|
||||
use PhpParser\Node\Stmt\Namespace_;
|
||||
use Rector\Core\Rector\AbstractRector;
|
||||
use Rector\Utils\DoctrineAnnotationParserSyncer\Contract\Rector\ClassSyncerRectorInterface;
|
||||
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
|
||||
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
|
||||
|
||||
final class RenameAnnotationReaderClassRector extends AbstractRector implements ClassSyncerRectorInterface
|
||||
{
|
||||
/**
|
||||
* @return array<class-string<\PhpParser\Node>>
|
||||
*/
|
||||
public function getNodeTypes(): array
|
||||
{
|
||||
return [Namespace_::class];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Namespace_ $node
|
||||
*/
|
||||
public function refactor(Node $node): ?Node
|
||||
{
|
||||
$firstClass = $this->betterNodeFinder->findFirstInstanceOf($node, Class_::class);
|
||||
if (! $firstClass instanceof Class_) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (! $this->isName($firstClass, 'Doctrine\Common\Annotations\AnnotationReader')) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$firstClass->name = new Identifier('ConstantPreservingAnnotationReader');
|
||||
$node->name = new Name('Rector\DoctrineAnnotationGenerated');
|
||||
|
||||
return $node;
|
||||
}
|
||||
|
||||
public function getRuleDefinition(): RuleDefinition
|
||||
{
|
||||
return new RuleDefinition('Rename AnnotationReader to own constant preserving format', [
|
||||
new CodeSample(
|
||||
<<<'CODE_SAMPLE'
|
||||
namespace Doctrine\Common\Annotations;
|
||||
|
||||
class AnnotationReader
|
||||
{
|
||||
}
|
||||
CODE_SAMPLE
|
||||
,
|
||||
<<<'CODE_SAMPLE'
|
||||
namespace Rector\DoctrineAnnotationGenerated;
|
||||
|
||||
class ConstantPreservingAnnotationReader
|
||||
{
|
||||
}
|
||||
CODE_SAMPLE
|
||||
),
|
||||
]);
|
||||
}
|
||||
}
|
@ -1,69 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Utils\DoctrineAnnotationParserSyncer\Rector\Namespace_;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Identifier;
|
||||
use PhpParser\Node\Name;
|
||||
use PhpParser\Node\Stmt\Class_;
|
||||
use PhpParser\Node\Stmt\Namespace_;
|
||||
use Rector\Core\Rector\AbstractRector;
|
||||
use Rector\Utils\DoctrineAnnotationParserSyncer\Contract\Rector\ClassSyncerRectorInterface;
|
||||
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
|
||||
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
|
||||
|
||||
final class RenameDocParserClassRector extends AbstractRector implements ClassSyncerRectorInterface
|
||||
{
|
||||
/**
|
||||
* @return array<class-string<\PhpParser\Node>>
|
||||
*/
|
||||
public function getNodeTypes(): array
|
||||
{
|
||||
return [Namespace_::class];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Namespace_ $node
|
||||
*/
|
||||
public function refactor(Node $node): ?Node
|
||||
{
|
||||
$firstClass = $this->betterNodeFinder->findFirstInstanceOf($node, Class_::class);
|
||||
if (! $firstClass instanceof Class_) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (! $this->isName($firstClass, 'Doctrine\Common\Annotations\DocParser')) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$firstClass->name = new Identifier('ConstantPreservingDocParser');
|
||||
$node->name = new Name('Rector\DoctrineAnnotationGenerated');
|
||||
|
||||
return $node;
|
||||
}
|
||||
|
||||
public function getRuleDefinition(): RuleDefinition
|
||||
{
|
||||
return new RuleDefinition('Rename DocParser to own constant preserving format', [
|
||||
new CodeSample(
|
||||
<<<'CODE_SAMPLE'
|
||||
namespace Doctrine\Common\Annotations;
|
||||
|
||||
class DocParser
|
||||
{
|
||||
}
|
||||
CODE_SAMPLE
|
||||
,
|
||||
<<<'CODE_SAMPLE'
|
||||
namespace Rector\DoctrineAnnotationGenerated;
|
||||
|
||||
class ConstantPreservingDocParser
|
||||
{
|
||||
}
|
||||
CODE_SAMPLE
|
||||
),
|
||||
]);
|
||||
}
|
||||
}
|
@ -1,88 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Utils\DoctrineAnnotationParserSyncer\Rector\StaticCall;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Expr\StaticCall;
|
||||
use PHPStan\Analyser\Scope;
|
||||
use PHPStan\Reflection\ClassReflection;
|
||||
use PHPStan\Type\ObjectType;
|
||||
use Rector\Core\Rector\AbstractRector;
|
||||
use Rector\NodeTypeResolver\Node\AttributeKey;
|
||||
use Rector\Utils\DoctrineAnnotationParserSyncer\Contract\Rector\ClassSyncerRectorInterface;
|
||||
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
|
||||
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
|
||||
|
||||
final class RemoveAnnotationRegistryRegisterFileRector extends AbstractRector implements ClassSyncerRectorInterface
|
||||
{
|
||||
public function getRuleDefinition(): RuleDefinition
|
||||
{
|
||||
return new RuleDefinition('Remove registerFile() static calls from AnnotationParser', [
|
||||
new CodeSample(
|
||||
<<<'CODE_SAMPLE'
|
||||
class AnnotationParser
|
||||
{
|
||||
public function run()
|
||||
{
|
||||
Doctrine\Common\Annotations\AnnotationRegistry::registerFile('...');
|
||||
}
|
||||
}
|
||||
CODE_SAMPLE
|
||||
,
|
||||
<<<'CODE_SAMPLE'
|
||||
class AnnotationParser
|
||||
{
|
||||
public function run()
|
||||
{
|
||||
}
|
||||
}
|
||||
CODE_SAMPLE
|
||||
),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<class-string<\PhpParser\Node>>
|
||||
*/
|
||||
public function getNodeTypes(): array
|
||||
{
|
||||
return [StaticCall::class];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param StaticCall $node
|
||||
*/
|
||||
public function refactor(Node $node): ?Node
|
||||
{
|
||||
$scope = $node->getAttribute(AttributeKey::SCOPE);
|
||||
if (! $scope instanceof Scope) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$classReflection = $scope->getClassReflection();
|
||||
if (! $classReflection instanceof ClassReflection) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (! $classReflection->isSubclassOf(
|
||||
'Doctrine\Common\Annotations\DocParser'
|
||||
) && ! $classReflection->isSubclassOf('Doctrine\Common\Annotations\AnnotationReader')) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$callerType = $this->nodeTypeResolver->resolve($node->class);
|
||||
if (! $callerType->isSuperTypeOf(new ObjectType('Doctrine\Common\Annotations\AnnotationRegistry'))->yes()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (! $this->isName($node->name, 'registerFile')) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$this->removeNode($node);
|
||||
|
||||
return $node;
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user