mirror of
https://github.com/rectorphp/rector.git
synced 2024-06-01 00:40:52 +00:00
[TriggerExtractor] add ClassMethodDeprecation and ConfigurableChangeMethodNameRector
This commit is contained in:
parent
1d68188503
commit
a532b5306f
|
@ -0,0 +1,8 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Rector\TriggerExtractor\Contract\Deprecation;
|
||||
|
||||
interface DeprecationInterface
|
||||
{
|
||||
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Rector\TriggerExtractor\Deprecation;
|
||||
|
||||
use Rector\TriggerExtractor\Contract\Deprecation\DeprecationInterface;
|
||||
|
||||
final class ClassMethodDeprecation implements DeprecationInterface
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $class;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $oldMethod;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $newMethod;
|
||||
|
||||
public function __construct(string $class, string $oldMethod, string $newMethod)
|
||||
{
|
||||
$this->class = $class;
|
||||
$this->oldMethod = $oldMethod;
|
||||
$this->newMethod = $newMethod;
|
||||
}
|
||||
|
||||
public function getClass(): string
|
||||
{
|
||||
return $this->class;
|
||||
}
|
||||
|
||||
public function getOldMethod(): string
|
||||
{
|
||||
return $this->oldMethod;
|
||||
}
|
||||
|
||||
public function getNewMethod(): string
|
||||
{
|
||||
return $this->newMethod;
|
||||
}
|
||||
}
|
|
@ -2,20 +2,22 @@
|
|||
|
||||
namespace Rector\TriggerExtractor\Deprecation;
|
||||
|
||||
use Rector\TriggerExtractor\Contract\Deprecation\DeprecationInterface;
|
||||
|
||||
final class DeprecationCollector
|
||||
{
|
||||
/**
|
||||
* @var mixed[]
|
||||
* @var DeprecationInterface[]
|
||||
*/
|
||||
private $deprecations = [];
|
||||
|
||||
public function addDeprecation(string $deprecation): void
|
||||
public function addDeprecation(DeprecationInterface $deprecation): void
|
||||
{
|
||||
$this->deprecations[] = $deprecation;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed[]
|
||||
* @return DeprecationInterface[]
|
||||
*/
|
||||
public function getDeprecations(): array
|
||||
{
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Rector\TriggerExtractor;
|
||||
namespace Rector\TriggerExtractor\Deprecation;
|
||||
|
||||
use Nette\Utils\Strings;
|
||||
use PhpParser\Node;
|
||||
|
@ -10,14 +10,31 @@ use PhpParser\Node\Scalar\String_;
|
|||
use PhpParser\Node\Stmt\ClassMethod;
|
||||
use Rector\Exception\NotImplementedException;
|
||||
use Rector\Node\Attribute;
|
||||
use Rector\TriggerExtractor\Contract\Deprecation\DeprecationInterface;
|
||||
|
||||
final class TriggerMessageResolver
|
||||
final class DeprecationFactory
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private const CLASS_REGEX = '([A-Za-z]+(\\\\[A-Za-z]+)+)';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private const CLASS_PATTERN = '#^' . self::CLASS_REGEX . '#s';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
* @see https://regex101.com/r/WdGoyd/1
|
||||
*/
|
||||
private const CLASS_WITH_METHOD_PATTER = '#^' . self::CLASS_REGEX . '::[A-Za-z]+\(\)#s';
|
||||
|
||||
/**
|
||||
* Probably resolve by recursion, similar too
|
||||
* @see \Rector\NodeTypeResolver\NodeVisitor\TypeResolver::__construct()
|
||||
*/
|
||||
public function resolve(Node $node): string
|
||||
public function createFromNode(Node $node): DeprecationInterface
|
||||
{
|
||||
$message = '';
|
||||
if ($node instanceof Concat) {
|
||||
|
@ -25,7 +42,7 @@ final class TriggerMessageResolver
|
|||
$message .= $this->processConcatNode($node->right);
|
||||
}
|
||||
|
||||
return $message;
|
||||
return $this->createFromMesssage($message);
|
||||
}
|
||||
|
||||
private function processConcatNode(Node $node): string
|
||||
|
@ -92,4 +109,46 @@ final class TriggerMessageResolver
|
|||
|
||||
return $word;
|
||||
}
|
||||
|
||||
private function createFromMesssage(string $message): DeprecationInterface
|
||||
{
|
||||
// format: don't use this, use that
|
||||
if (Strings::contains($message, ' use ')) {
|
||||
[$old, $new] = explode(' use ', $message);
|
||||
|
||||
// try to find SomeClass::methodCall()
|
||||
$matches = Strings::matchAll($old, self::CLASS_WITH_METHOD_PATTER);
|
||||
if (isset($matches[0][0])) {
|
||||
$oldClassWithMethod = $matches[0][0];
|
||||
}
|
||||
|
||||
// try to find SomeClass::methodCall()
|
||||
$matches = Strings::matchAll($new, self::CLASS_WITH_METHOD_PATTER);
|
||||
if (isset($matches[0][0])) {
|
||||
$newClassWithMethod = $matches[0][0];
|
||||
}
|
||||
|
||||
if (isset($oldClassWithMethod) && isset($newClassWithMethod)) {
|
||||
[$oldClass, $oldMethod] = explode('::', $oldClassWithMethod);
|
||||
[$newClass, $newMethod] = explode('::', $newClassWithMethod);
|
||||
|
||||
if ($oldClass === $newClass) {
|
||||
// simple method replacement
|
||||
return new ClassMethodDeprecation(
|
||||
$oldClass,
|
||||
rtrim($oldMethod, '()'),
|
||||
rtrim($newMethod, '()')
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
throw new NotImplementedException(sprintf(
|
||||
'%s::%s() did not resolve %s messsage, so %s was not created. Implement it.',
|
||||
self::class,
|
||||
__METHOD__,
|
||||
$message,
|
||||
DeprecationInterface::class
|
||||
));
|
||||
}
|
||||
}
|
|
@ -9,7 +9,7 @@ use PhpParser\Node\Expr\FuncCall;
|
|||
use PhpParser\Node\Name;
|
||||
use PhpParser\NodeVisitorAbstract;
|
||||
use Rector\TriggerExtractor\Deprecation\DeprecationCollector;
|
||||
use Rector\TriggerExtractor\TriggerMessageResolver;
|
||||
use Rector\TriggerExtractor\Deprecation\DeprecationFactory;
|
||||
|
||||
final class DeprecationDetector extends NodeVisitorAbstract
|
||||
{
|
||||
|
@ -19,26 +19,28 @@ final class DeprecationDetector extends NodeVisitorAbstract
|
|||
private $deprecationCollector;
|
||||
|
||||
/**
|
||||
* @var TriggerMessageResolver
|
||||
* @var DeprecationFactory
|
||||
*/
|
||||
private $triggerMessageResolver;
|
||||
private $deprecationFactory;
|
||||
|
||||
public function __construct(
|
||||
DeprecationCollector $deprecationCollector,
|
||||
TriggerMessageResolver $triggerMessageResolver
|
||||
DeprecationFactory $triggerMessageResolver
|
||||
) {
|
||||
$this->deprecationCollector = $deprecationCollector;
|
||||
$this->triggerMessageResolver = $triggerMessageResolver;
|
||||
$this->deprecationFactory = $triggerMessageResolver;
|
||||
}
|
||||
|
||||
public function enterNode(Node $node): void
|
||||
{
|
||||
// @todo: add @deprecate annotations as well,
|
||||
// @see https://github.com/sensiolabs-de/deprecation-detector/blob/master/src/Visitor/Deprecation/FindDeprecatedTagsVisitor.php
|
||||
if (! $this->isTriggerErrorUserDeprecated($node)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/** @var FuncCall $node */
|
||||
$deprecation = $this->triggerMessageResolver->resolve($node->args[0]->value);
|
||||
$deprecation = $this->deprecationFactory->createFromNode($node->args[0]->value);
|
||||
|
||||
$this->deprecationCollector->addDeprecation($deprecation);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Rector\TriggerExtractor\Rector;
|
||||
|
||||
use Rector\Rector\AbstractChangeMethodNameRector;
|
||||
|
||||
final class ConfigurableChangeMethodNameRector extends AbstractChangeMethodNameRector
|
||||
{
|
||||
/**
|
||||
* @var string[][]
|
||||
*/
|
||||
private $perClassOldToNewMethod;
|
||||
|
||||
public function setPerClassOldToNewMethods(array $perClassOldToNewMethod): void
|
||||
{
|
||||
$this->perClassOldToNewMethod = $perClassOldToNewMethod;
|
||||
}
|
||||
|
||||
public function getSetName(): string
|
||||
{
|
||||
return 'dynamic';
|
||||
}
|
||||
|
||||
public function sinceVersion(): float
|
||||
{
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[][] { class => [ oldMethod => newMethod ] }
|
||||
*/
|
||||
protected function getPerClassOldToNewMethods(): array
|
||||
{
|
||||
return $this->perClassOldToNewMethod;
|
||||
}
|
||||
}
|
68
packages/TriggerExtractor/src/Rector/RectorFactory.php
Normal file
68
packages/TriggerExtractor/src/Rector/RectorFactory.php
Normal file
|
@ -0,0 +1,68 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Rector\TriggerExtractor\Rector;
|
||||
|
||||
use Rector\Contract\Rector\RectorInterface;
|
||||
use Rector\Exception\NotImplementedException;
|
||||
use Rector\TriggerExtractor\Contract\Deprecation\DeprecationInterface;
|
||||
use Rector\TriggerExtractor\Deprecation\ClassMethodDeprecation;
|
||||
use Rector\TriggerExtractor\Deprecation\DeprecationCollector;
|
||||
|
||||
/**
|
||||
* Creates rectors with propper setup based on found deprecations.
|
||||
*/
|
||||
final class RectorFactory
|
||||
{
|
||||
/**
|
||||
* @var DeprecationCollector
|
||||
*/
|
||||
private $deprecationCollector;
|
||||
|
||||
/**
|
||||
* @var ConfigurableChangeMethodNameRector
|
||||
*/
|
||||
private $configurableChangeMethodNameRector;
|
||||
|
||||
public function __construct(
|
||||
DeprecationCollector $deprecationCollector,
|
||||
ConfigurableChangeMethodNameRector $configurableChangeMethodNameRector
|
||||
) {
|
||||
$this->deprecationCollector = $deprecationCollector;
|
||||
$this->configurableChangeMethodNameRector = $configurableChangeMethodNameRector;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return RectorInterface[]
|
||||
*/
|
||||
public function createRectors(): array
|
||||
{
|
||||
$rectors = [];
|
||||
|
||||
foreach ($this->deprecationCollector->getDeprecations() as $deprecation) {
|
||||
$rectors[] = $this->createRectorFromDeprecation($deprecation);
|
||||
}
|
||||
|
||||
return $rectors;
|
||||
}
|
||||
|
||||
public function createRectorFromDeprecation(DeprecationInterface $deprecation): RectorInterface
|
||||
{
|
||||
if ($deprecation instanceof ClassMethodDeprecation) {
|
||||
$configurableChangeMethodNameRector = clone $this->configurableChangeMethodNameRector;
|
||||
$configurableChangeMethodNameRector->setPerClassOldToNewMethods([
|
||||
$deprecation->getClass() => [
|
||||
$deprecation->getOldMethod() => $deprecation->getNewMethod()
|
||||
]
|
||||
]);
|
||||
|
||||
return $configurableChangeMethodNameRector;
|
||||
}
|
||||
|
||||
throw new NotImplementedException(sprintf(
|
||||
'%s::%s() was unable to create a Rector based on "%s" Deprecation. Create a new method there.',
|
||||
self::class,
|
||||
__METHOD__,
|
||||
get_class($deprecation)
|
||||
));
|
||||
}
|
||||
}
|
|
@ -5,3 +5,4 @@ services:
|
|||
# PSR-4 autodiscovery
|
||||
Rector\TriggerExtractor\:
|
||||
resource: '../../src'
|
||||
exclude: '../../src/{Deprecation/ClassMethodDeprecation.php}'
|
||||
|
|
29
packages/TriggerExtractor/tests/Rector/RectorFactoryTest.php
Normal file
29
packages/TriggerExtractor/tests/Rector/RectorFactoryTest.php
Normal file
|
@ -0,0 +1,29 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Rector\TriggerExtractor\Tests\Rector;
|
||||
|
||||
use Rector\Tests\AbstractContainerAwareTestCase;
|
||||
use Rector\TriggerExtractor\Rector\RectorFactory;
|
||||
use Rector\TriggerExtractor\TriggerExtractor;
|
||||
|
||||
final class RectorFactoryTest extends AbstractContainerAwareTestCase
|
||||
{
|
||||
/**
|
||||
* @var RectorFactory
|
||||
*/
|
||||
private $rectorFactory;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
$this->rectorFactory = $this->container->get(RectorFactory::class);
|
||||
|
||||
$triggerExtractor = $this->container->get(TriggerExtractor::class);
|
||||
$triggerExtractor->scanDirectories([__DIR__ . '/../TriggerExtractorSource']);
|
||||
}
|
||||
|
||||
public function test(): void
|
||||
{
|
||||
$rectors = $this->rectorFactory->createRectors();
|
||||
$this->assertCount(1, $rectors);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user