[Transform] Remove specific custom Rector without generic usage (#573)

This commit is contained in:
Tomas Votruba 2021-08-02 13:51:51 +02:00 committed by GitHub
parent 4d816080ee
commit e3ce320151
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
27 changed files with 0 additions and 1492 deletions

View File

@ -1,39 +0,0 @@
<?php
namespace Rector\Tests\RemovingStatic\Rector\Class_\PHPUnitStaticToKernelTestCaseGetRector\Fixture;
use Rector\Tests\RemovingStatic\Rector\Class_\PHPUnitStaticToKernelTestCaseGetRector\Source\ClassWithStaticMethods;
use PHPUnit\Framework\TestCase;
final class SomeTest extends TestCase
{
public function test()
{
ClassWithStaticMethods::create('product');
}
}
?>
-----
<?php
namespace Rector\Tests\RemovingStatic\Rector\Class_\PHPUnitStaticToKernelTestCaseGetRector\Fixture;
use Rector\Tests\RemovingStatic\Rector\Class_\PHPUnitStaticToKernelTestCaseGetRector\Source\ClassWithStaticMethods;
use PHPUnit\Framework\TestCase;
final class SomeTest extends \Symfony\Bundle\FrameworkBundle\Test\KernelTestCase
{
private \Rector\Tests\RemovingStatic\Rector\Class_\PHPUnitStaticToKernelTestCaseGetRector\Source\ClassWithStaticMethods $classWithStaticMethods;
protected function setUp()
{
parent::setUp();
$this->classWithStaticMethods = self::$container->get(\Rector\Tests\RemovingStatic\Rector\Class_\PHPUnitStaticToKernelTestCaseGetRector\Source\ClassWithStaticMethods::class);
}
public function test()
{
$this->classWithStaticMethods->create('product');
}
}
?>

View File

@ -1,56 +0,0 @@
<?php
namespace Rector\Tests\RemovingStatic\Rector\Class_\PHPUnitStaticToKernelTestCaseGetRector\Fixture;
use Rector\Tests\RemovingStatic\Rector\Class_\PHPUnitStaticToKernelTestCaseGetRector\Source\ClassWithStaticMethods;
use PHPUnit\Framework\TestCase;
final class SetupAlreadyExistsTest extends TestCase
{
/**
* @var string
*/
private $legitimation;
protected function setUp(): void
{
$this->legitimation = 'GO';
}
public function test()
{
ClassWithStaticMethods::create('product');
}
}
?>
-----
<?php
namespace Rector\Tests\RemovingStatic\Rector\Class_\PHPUnitStaticToKernelTestCaseGetRector\Fixture;
use Rector\Tests\RemovingStatic\Rector\Class_\PHPUnitStaticToKernelTestCaseGetRector\Source\ClassWithStaticMethods;
use PHPUnit\Framework\TestCase;
final class SetupAlreadyExistsTest extends \Symfony\Bundle\FrameworkBundle\Test\KernelTestCase
{
private \Rector\Tests\RemovingStatic\Rector\Class_\PHPUnitStaticToKernelTestCaseGetRector\Source\ClassWithStaticMethods $classWithStaticMethods;
/**
* @var string
*/
private $legitimation;
protected function setUp(): void
{
parent::setUp();
$this->classWithStaticMethods = self::$container->get(\Rector\Tests\RemovingStatic\Rector\Class_\PHPUnitStaticToKernelTestCaseGetRector\Source\ClassWithStaticMethods::class);
$this->legitimation = 'GO';
}
public function test()
{
$this->classWithStaticMethods->create('product');
}
}
?>

View File

@ -1,59 +0,0 @@
<?php
namespace Rector\Tests\RemovingStatic\Rector\Class_\PHPUnitStaticToKernelTestCaseGetRector\Fixture;
use Rector\Tests\RemovingStatic\Rector\Class_\PHPUnitStaticToKernelTestCaseGetRector\Source\ClassWithStaticMethods;
use PHPUnit\Framework\TestCase;
final class SetupAlreadyExistsWithParentSetUpTest extends TestCase
{
/**
* @var string
*/
private $legitimation;
protected function setUp(): void
{
$this->legitimation = 'GO';
parent::setUp();
}
public function test()
{
ClassWithStaticMethods::create('product');
}
}
?>
-----
<?php
namespace Rector\Tests\RemovingStatic\Rector\Class_\PHPUnitStaticToKernelTestCaseGetRector\Fixture;
use Rector\Tests\RemovingStatic\Rector\Class_\PHPUnitStaticToKernelTestCaseGetRector\Source\ClassWithStaticMethods;
use PHPUnit\Framework\TestCase;
final class SetupAlreadyExistsWithParentSetUpTest extends \Symfony\Bundle\FrameworkBundle\Test\KernelTestCase
{
private \Rector\Tests\RemovingStatic\Rector\Class_\PHPUnitStaticToKernelTestCaseGetRector\Source\ClassWithStaticMethods $classWithStaticMethods;
/**
* @var string
*/
private $legitimation;
protected function setUp(): void
{
$this->legitimation = 'GO';
parent::setUp();
$this->classWithStaticMethods = self::$container->get(\Rector\Tests\RemovingStatic\Rector\Class_\PHPUnitStaticToKernelTestCaseGetRector\Source\ClassWithStaticMethods::class);
}
public function test()
{
$this->classWithStaticMethods->create('product');
}
}
?>

View File

@ -1,33 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Tests\RemovingStatic\Rector\Class_\PHPUnitStaticToKernelTestCaseGetRector;
use Iterator;
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
use Symplify\SmartFileSystem\SmartFileInfo;
final class PHPUnitStaticToKernelTestCaseGetRectorTest extends AbstractRectorTestCase
{
/**
* @dataProvider provideData()
*/
public function test(SmartFileInfo $fileInfo): void
{
$this->doTestFileInfo($fileInfo);
}
/**
* @return Iterator<SmartFileInfo>
*/
public function provideData(): Iterator
{
return $this->yieldFilesFromDirectory(__DIR__ . '/Fixture');
}
public function provideConfigFilePath(): string
{
return __DIR__ . '/config/configured_rule.php';
}
}

View File

@ -1,13 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Tests\RemovingStatic\Rector\Class_\PHPUnitStaticToKernelTestCaseGetRector\Source;
final class ClassWithStaticMethods
{
public static function create($value)
{
return $value;
}
}

View File

@ -1,15 +0,0 @@
<?php
declare(strict_types=1);
use Rector\RemovingStatic\Rector\Class_\PHPUnitStaticToKernelTestCaseGetRector;
use Rector\Tests\RemovingStatic\Rector\Class_\PHPUnitStaticToKernelTestCaseGetRector\Source\ClassWithStaticMethods;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
return static function (ContainerConfigurator $containerConfigurator): void {
$services = $containerConfigurator->services();
$services->set(PHPUnitStaticToKernelTestCaseGetRector::class)
->call('configure', [[
PHPUnitStaticToKernelTestCaseGetRector::STATIC_CLASS_TYPES => [ClassWithStaticMethods::class],
]]);
};

View File

@ -1,31 +0,0 @@
<?php
namespace Rector\Tests\Transform\Rector\Expression\MethodCallToReturnRector\Fixture;
use Rector\Tests\Transform\Rector\Expression\MethodCallToReturnRector\Source\ReturnDeny;
class SomeClass
{
public function run(ReturnDeny $returnDeny)
{
$returnDeny->deny();
}
}
?>
-----
<?php
namespace Rector\Tests\Transform\Rector\Expression\MethodCallToReturnRector\Fixture;
use Rector\Tests\Transform\Rector\Expression\MethodCallToReturnRector\Source\ReturnDeny;
class SomeClass
{
public function run(ReturnDeny $returnDeny)
{
return $returnDeny->deny();
}
}
?>

View File

@ -1,20 +0,0 @@
<?php
namespace Rector\Tests\Transform\Rector\Expression\MethodCallToReturnRector\Fixture;
use Rector\Tests\Transform\Rector\Expression\MethodCallToReturnRector\Source\ReturnDeny;
class SkipAlreadyReturn
{
public function run(ReturnDeny $returnDeny)
{
return $returnDeny->deny();
}
public function whatIf(ReturnDeny $returnDeny)
{
if (true) {
return $returnDeny->deny();
}
}
}

View File

@ -1,33 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Tests\Transform\Rector\Expression\MethodCallToReturnRector;
use Iterator;
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
use Symplify\SmartFileSystem\SmartFileInfo;
final class MethodCallToReturnRectorTest extends AbstractRectorTestCase
{
/**
* @dataProvider provideData()
*/
public function test(SmartFileInfo $fileInfo): void
{
$this->doTestFileInfo($fileInfo);
}
/**
* @return Iterator<SmartFileInfo>
*/
public function provideData(): Iterator
{
return $this->yieldFilesFromDirectory(__DIR__ . '/Fixture');
}
public function provideConfigFilePath(): string
{
return __DIR__ . '/config/configured_rule.php';
}
}

View File

@ -1,13 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Tests\Transform\Rector\Expression\MethodCallToReturnRector\Source;
final class ReturnDeny
{
public function deny()
{
return 'error';
}
}

View File

@ -1,19 +0,0 @@
<?php
declare(strict_types=1);
use Rector\Tests\Transform\Rector\Expression\MethodCallToReturnRector\Source\ReturnDeny;
use Rector\Transform\Rector\Expression\MethodCallToReturnRector;
use Rector\Transform\ValueObject\MethodCallToReturn;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
use Symplify\SymfonyPhpConfig\ValueObjectInliner;
return static function (ContainerConfigurator $containerConfigurator): void {
$services = $containerConfigurator->services();
$services->set(MethodCallToReturnRector::class)
->call('configure', [[
MethodCallToReturnRector::METHOD_CALL_WRAPS => ValueObjectInliner::inline([
new MethodCallToReturn(ReturnDeny::class, 'deny'),
]),
]]);
};

View File

@ -1,24 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Tests\Transform\Rector\FileWithoutNamespace\FunctionToStaticMethodRector\Fixture;
function first_static_function()
{
return 5;
}
$value = first_static_function();
?>
-----
<?php
declare(strict_types=1);
namespace Rector\Tests\Transform\Rector\FileWithoutNamespace\FunctionToStaticMethodRector\Fixture;
$value = \StaticFunctions::firstStaticFunction();
?>

View File

@ -1,42 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Tests\Transform\Rector\FileWithoutNamespace\FunctionToStaticMethodRector;
use Iterator;
use Nette\Utils\FileSystem;
use Rector\FileSystemRector\ValueObject\AddedFileWithContent;
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
use Symplify\SmartFileSystem\SmartFileInfo;
final class FunctionToStaticMethodRectorTest extends AbstractRectorTestCase
{
/**
* @dataProvider provideData()
*/
public function test(SmartFileInfo $smartFileInfo): void
{
$this->doTestFileInfo($smartFileInfo);
$addedFileWithContent = new AddedFileWithContent(
$this->originalTempFileInfo->getRealPathDirectory() . '/StaticFunctions.php',
FileSystem::read(__DIR__ . '/Source/ExpectedStaticFunctions.php')
);
$this->assertFileWasAdded($addedFileWithContent);
}
/**
* @return Iterator<SmartFileInfo>
*/
public function provideData(): Iterator
{
return $this->yieldFilesFromDirectory(__DIR__ . '/Fixture');
}
public function provideConfigFilePath(): string
{
return __DIR__ . '/config/configured_rule.php';
}
}

View File

@ -1,11 +0,0 @@
<?php
namespace Rector\Tests\Transform\Rector\FileWithoutNamespace\FunctionToStaticMethodRector\Fixture;
final class StaticFunctions
{
public static function firstStaticFunction()
{
return 5;
}
}

View File

@ -1,11 +0,0 @@
<?php
declare(strict_types=1);
use Rector\Transform\Rector\FileWithoutNamespace\FunctionToStaticMethodRector;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
return static function (ContainerConfigurator $containerConfigurator): void {
$services = $containerConfigurator->services();
$services->set(FunctionToStaticMethodRector::class);
};

View File

@ -1,30 +0,0 @@
<?php
namespace Rector\Tests\Transform\Rector\MethodCall\VariableMethodCallToServiceCallRector\Fixture;
class SomeClass
{
public function run(\PhpParser\Node $node)
{
$phpDocInfo = $node->getAttribute('php_doc_info');
}
}
?>
-----
<?php
namespace Rector\Tests\Transform\Rector\MethodCall\VariableMethodCallToServiceCallRector\Fixture;
class SomeClass
{
public function __construct(private \Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfoFactory $phpDocInfoFactory)
{
}
public function run(\PhpParser\Node $node)
{
$phpDocInfo = $this->phpDocInfoFactory->createFromNodeOrEmpty($node);
}
}
?>

View File

@ -1,33 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Tests\Transform\Rector\MethodCall\VariableMethodCallToServiceCallRector;
use Iterator;
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
use Symplify\SmartFileSystem\SmartFileInfo;
final class VariableMethodCallToServiceCallRectorTest extends AbstractRectorTestCase
{
/**
* @dataProvider provideData()
*/
public function test(SmartFileInfo $fileInfo): void
{
$this->doTestFileInfo($fileInfo);
}
/**
* @return Iterator<SmartFileInfo>
*/
public function provideData(): Iterator
{
return $this->yieldFilesFromDirectory(__DIR__ . '/Fixture');
}
public function provideConfigFilePath(): string
{
return __DIR__ . '/config/configured_rule.php';
}
}

View File

@ -1,30 +0,0 @@
<?php
declare(strict_types=1);
use Rector\Transform\Rector\MethodCall\VariableMethodCallToServiceCallRector;
use Rector\Transform\ValueObject\VariableMethodCallToServiceCall;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
use Symplify\SymfonyPhpConfig\ValueObjectInliner;
return static function (ContainerConfigurator $containerConfigurator): void {
$services = $containerConfigurator->services();
$configuration = ValueObjectInliner::inline([
new VariableMethodCallToServiceCall(
'PhpParser\Node',
'getAttribute',
'php_doc_info',
'Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfoFactory',
'createFromNodeOrEmpty'
),
]);
$services->set(VariableMethodCallToServiceCallRector::class)
->call(
'configure',
[[
VariableMethodCallToServiceCallRector::VARIABLE_METHOD_CALLS_TO_SERVICE_CALLS => $configuration,
]]
);
};

View File

@ -1,63 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\RemovingStatic\NodeAnalyzer;
use PhpParser\Node\Expr\StaticCall;
use PhpParser\Node\Name;
use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Stmt\Expression;
use Rector\Core\ValueObject\MethodName;
use Rector\NodeNameResolver\NodeNameResolver;
final class SetUpClassMethodUpdater
{
public function __construct(
private NodeNameResolver $nodeNameResolver
) {
}
public function updateSetUpMethod(
ClassMethod $setupClassMethod,
Expression $parentSetupStaticCall,
Expression $assign
): void {
$parentSetUpStaticCallPosition = $this->getParentSetUpStaticCallPosition($setupClassMethod);
if ($parentSetUpStaticCallPosition === null) {
$setupClassMethod->stmts = array_merge([$parentSetupStaticCall, $assign], (array) $setupClassMethod->stmts);
} else {
assert($setupClassMethod->stmts !== null);
array_splice($setupClassMethod->stmts, $parentSetUpStaticCallPosition + 1, 0, [$assign]);
}
}
private function getParentSetUpStaticCallPosition(ClassMethod $setupClassMethod): ?int
{
foreach ((array) $setupClassMethod->stmts as $position => $methodStmt) {
if ($methodStmt instanceof Expression) {
$methodStmt = $methodStmt->expr;
}
if (! $methodStmt instanceof StaticCall) {
continue;
}
if (! $methodStmt->class instanceof Name) {
continue;
}
if (! $this->nodeNameResolver->isName($methodStmt->class, 'parent')) {
continue;
}
if (! $this->nodeNameResolver->isName($methodStmt->name, MethodName::SET_UP)) {
continue;
}
return $position;
}
return null;
}
}

View File

@ -1,38 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\RemovingStatic\NodeFactory;
use PhpParser\Node\Arg;
use PhpParser\Node\Expr\ClassConstFetch;
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Expr\StaticPropertyFetch;
use PhpParser\Node\Name;
use PHPStan\Type\ObjectType;
use Rector\Core\Exception\ShouldNotHappenException;
use Rector\PHPStanStaticTypeMapper\ValueObject\TypeKind;
use Rector\StaticTypeMapper\StaticTypeMapper;
final class SelfContainerFactory
{
public function __construct(
private StaticTypeMapper $staticTypeMapper
) {
}
public function createGetTypeMethodCall(ObjectType $objectType): MethodCall
{
$staticPropertyFetch = new StaticPropertyFetch(new Name('self'), 'container');
$getMethodCall = new MethodCall($staticPropertyFetch, 'get');
$className = $this->staticTypeMapper->mapPHPStanTypeToPhpParserNode($objectType, TypeKind::RETURN());
if (! $className instanceof Name) {
throw new ShouldNotHappenException();
}
$getMethodCall->args[] = new Arg(new ClassConstFetch($className, 'class'));
return $getMethodCall;
}
}

View File

@ -1,300 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\RemovingStatic\Rector\Class_;
use PhpParser\Node;
use PhpParser\Node\Expr\Assign;
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Expr\PropertyFetch;
use PhpParser\Node\Expr\StaticCall;
use PhpParser\Node\Expr\Variable;
use PhpParser\Node\Name\FullyQualified;
use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\Expression;
use PhpParser\Node\Stmt\Property;
use PHPStan\Type\ObjectType;
use Rector\Core\Contract\Rector\ConfigurableRectorInterface;
use Rector\Core\NodeManipulator\ClassInsertManipulator;
use Rector\Core\Rector\AbstractRector;
use Rector\Core\ValueObject\MethodName;
use Rector\Naming\Naming\PropertyNaming;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Rector\PHPUnit\NodeFactory\SetUpClassMethodFactory;
use Rector\PostRector\Collector\PropertyToAddCollector;
use Rector\PostRector\ValueObject\PropertyMetadata;
use Rector\RemovingStatic\NodeAnalyzer\SetUpClassMethodUpdater;
use Rector\RemovingStatic\NodeFactory\SelfContainerFactory;
use Rector\RemovingStatic\NodeFactory\SetUpFactory;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\ConfiguredCodeSample;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
/**
* @see \Rector\Tests\RemovingStatic\Rector\Class_\PHPUnitStaticToKernelTestCaseGetRector\PHPUnitStaticToKernelTestCaseGetRectorTest
*/
final class PHPUnitStaticToKernelTestCaseGetRector extends AbstractRector implements ConfigurableRectorInterface
{
/**
* @api
* @var string
*/
public const STATIC_CLASS_TYPES = 'static_class_types';
/**
* @var ObjectType[]
*/
private array $staticObjectTypes = [];
/**
* @var ObjectType[]
*/
private array $newPropertyObjectTypes = [];
public function __construct(
private PropertyNaming $propertyNaming,
private ClassInsertManipulator $classInsertManipulator,
private SetUpClassMethodFactory $setUpClassMethodFactory,
private SetUpFactory $setUpFactory,
private SelfContainerFactory $selfContainerFactory,
private SetUpClassMethodUpdater $setUpClassMethodUpdater,
private PropertyToAddCollector $propertyToAddCollector
) {
}
public function getRuleDefinition(): RuleDefinition
{
return new RuleDefinition('Convert static calls in PHPUnit test cases, to get() from the container of KernelTestCase', [
new ConfiguredCodeSample(
<<<'CODE_SAMPLE'
use PHPUnit\Framework\TestCase;
final class SomeTestCase extends TestCase
{
public function test()
{
$product = EntityFactory::create('product');
}
}
CODE_SAMPLE
,
<<<'CODE_SAMPLE'
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
final class SomeTestCase extends KernelTestCase
{
/**
* @var EntityFactory
*/
private $entityFactory;
protected function setUp(): void
{
parent::setUp();
$this->entityFactory = $this->getService(EntityFactory::class);
}
public function test()
{
$product = $this->entityFactory->create('product');
}
}
CODE_SAMPLE
,
[
self::STATIC_CLASS_TYPES => ['EntityFactory'],
]
),
]);
}
/**
* @return array<class-string<Node>>
*/
public function getNodeTypes(): array
{
return [StaticCall::class, Class_::class];
}
/**
* @param StaticCall|Class_ $node
*/
public function refactor(Node $node): ?Node
{
// skip yourself
$this->newPropertyObjectTypes = [];
if ($node instanceof Class_) {
if ($this->nodeTypeResolver->isObjectTypes($node, $this->staticObjectTypes)) {
return null;
}
return $this->processClass($node);
}
return $this->processStaticCall($node);
}
/**
* @param array<string, mixed> $configuration
*/
public function configure(array $configuration): void
{
$staticClassTypes = $configuration[self::STATIC_CLASS_TYPES] ?? [];
foreach ($staticClassTypes as $staticClassType) {
$this->staticObjectTypes[] = new ObjectType($staticClassType);
}
}
private function processClass(Class_ $class): ?Class_
{
if ($this->isObjectType($class, new ObjectType('PHPUnit\Framework\TestCase'))) {
return $this->processPHPUnitClass($class);
}
// add property with the object
$newPropertyObjectTypes = $this->collectNewPropertyObjectTypes($class);
if ($newPropertyObjectTypes === []) {
return null;
}
// add via constructor
foreach ($newPropertyObjectTypes as $newPropertyObjectType) {
$newPropertyName = $this->propertyNaming->fqnToVariableName($newPropertyObjectType);
$propertyMetadata = new PropertyMetadata(
$newPropertyName,
$newPropertyObjectType,
Class_::MODIFIER_PRIVATE
);
$this->propertyToAddCollector->addPropertyToClass($class, $propertyMetadata);
}
return $class;
}
private function processStaticCall(StaticCall $staticCall): ?MethodCall
{
$classLike = $staticCall->getAttribute(AttributeKey::CLASS_NODE);
if (! $classLike instanceof Class_) {
return null;
}
foreach ($this->staticObjectTypes as $staticObjectType) {
if (! $this->isObjectType($staticCall->class, $staticObjectType)) {
continue;
}
return $this->convertStaticCallToPropertyMethodCall($staticCall, $staticObjectType);
}
return null;
}
private function processPHPUnitClass(Class_ $class): ?Class_
{
// add property with the object
$newPropertyTypes = $this->collectNewPropertyObjectTypes($class);
if ($newPropertyTypes === []) {
return null;
}
// add all properties to class
$class = $this->addNewPropertiesToClass($class, $newPropertyTypes);
$parentSetUpStaticCallExpression = $this->setUpFactory->createParentStaticCall();
foreach ($newPropertyTypes as $newPropertyType) {
// container fetch assign
$assign = $this->createContainerGetTypeToPropertyAssign($newPropertyType);
$setupClassMethod = $class->getMethod(MethodName::SET_UP);
// get setup or create a setup add add it there
if ($setupClassMethod !== null) {
$this->setUpClassMethodUpdater->updateSetUpMethod(
$setupClassMethod,
$parentSetUpStaticCallExpression,
$assign
);
} else {
$setUpMethod = $this->setUpClassMethodFactory->createSetUpMethod([$assign]);
$this->classInsertManipulator->addAsFirstMethod($class, $setUpMethod);
}
}
// update parent clsas if not already
if (! $this->isObjectType($class, new ObjectType('Symfony\Bundle\FrameworkBundle\Test\KernelTestCase'))) {
$class->extends = new FullyQualified('Symfony\Bundle\FrameworkBundle\Test\KernelTestCase');
}
return $class;
}
/**
* @return ObjectType[]
*/
private function collectNewPropertyObjectTypes(Class_ $class): array
{
$this->newPropertyObjectTypes = [];
$this->traverseNodesWithCallable($class->stmts, function (Node $node): void {
if (! $node instanceof StaticCall) {
return;
}
foreach ($this->staticObjectTypes as $staticObjectType) {
if (! $this->isObjectType($node->class, $staticObjectType)) {
continue;
}
$this->newPropertyObjectTypes[] = $staticObjectType;
}
});
$this->newPropertyObjectTypes = array_unique($this->newPropertyObjectTypes);
return $this->newPropertyObjectTypes;
}
private function convertStaticCallToPropertyMethodCall(StaticCall $staticCall, ObjectType $objectType): MethodCall
{
// create "$this->someService" instead
$propertyName = $this->propertyNaming->fqnToVariableName($objectType);
$propertyFetch = new PropertyFetch(new Variable('this'), $propertyName);
// turn static call to method on property call
$methodCall = new MethodCall($propertyFetch, $staticCall->name);
$methodCall->args = $staticCall->args;
return $methodCall;
}
/**
* @param ObjectType[] $propertyTypes
*/
private function addNewPropertiesToClass(Class_ $class, array $propertyTypes): Class_
{
$properties = [];
foreach ($propertyTypes as $propertyType) {
$propertyName = $this->propertyNaming->fqnToVariableName($propertyType);
$properties[] = $this->nodeFactory->createPrivatePropertyFromNameAndType($propertyName, $propertyType);
}
// add property to the start of the class
$class->stmts = array_merge($properties, $class->stmts);
return $class;
}
private function createContainerGetTypeToPropertyAssign(ObjectType $objectType): Expression
{
$getMethodCall = $this->selfContainerFactory->createGetTypeMethodCall($objectType);
$propertyName = $this->propertyNaming->fqnToVariableName($objectType);
$propertyFetch = new PropertyFetch(new Variable('this'), $propertyName);
$assign = new Assign($propertyFetch, $getMethodCall);
return new Expression($assign);
}
}

View File

@ -1,37 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Transform\Naming;
use PhpParser\Node;
use PhpParser\Node\Stmt\Namespace_;
use Rector\Core\PhpParser\Node\BetterNodeFinder;
use Rector\NodeNameResolver\NodeNameResolver;
final class FullyQualifiedNameResolver
{
public function __construct(
private BetterNodeFinder $betterNodeFinder,
private NodeNameResolver $nodeNameResolver
) {
}
/**
* @param Node[] $nodes
*/
public function resolveFullyQualifiedName(array $nodes, string $shortClassName): string
{
$namespace = $this->betterNodeFinder->findFirstInstanceOf($nodes, Namespace_::class);
if (! $namespace instanceof Namespace_) {
return $shortClassName;
}
$namespaceName = $this->nodeNameResolver->getName($namespace);
if ($namespaceName === null) {
return $shortClassName;
}
return $namespaceName . '\\' . $shortClassName;
}
}

View File

@ -1,42 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Transform\NodeFactory;
use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Stmt\Function_;
use Rector\CodingStyle\Naming\ClassNaming;
use Symplify\Astral\ValueObject\NodeBuilder\ClassBuilder;
final class StaticMethodClassFactory
{
public function __construct(
private ClassMethodFactory $classMethodFactory,
private ClassNaming $classNaming
) {
}
/**
* @param Function_[] $functions
*/
public function createStaticMethodClass(string $shortClassName, array $functions): Class_
{
$classBuilder = new ClassBuilder($shortClassName);
$classBuilder->makeFinal();
foreach ($functions as $function) {
$staticClassMethod = $this->createStaticMethod($function);
$classBuilder->addStmt($staticClassMethod);
}
return $classBuilder->getNode();
}
private function createStaticMethod(Function_ $function): ClassMethod
{
$methodName = $this->classNaming->createMethodNameFromFunction($function);
return $this->classMethodFactory->createClassMethodFromFunction($methodName, $function);
}
}

View File

@ -1,131 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Transform\Rector\Expression;
use PhpParser\Node;
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Stmt\Expression;
use PhpParser\Node\Stmt\Return_;
use Rector\Core\Contract\Rector\ConfigurableRectorInterface;
use Rector\Core\Rector\AbstractRector;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Rector\Transform\ValueObject\MethodCallToReturn;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\ConfiguredCodeSample;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
use Webmozart\Assert\Assert;
/**
* @see \Rector\Tests\Transform\Rector\Expression\MethodCallToReturnRector\MethodCallToReturnRectorTest
*/
final class MethodCallToReturnRector extends AbstractRector implements ConfigurableRectorInterface
{
/**
* @var string
*/
public const METHOD_CALL_WRAPS = 'method_call_wraps';
/**
* @var MethodCallToReturn[]
*/
private array $methodCallWraps = [];
public function getRuleDefinition(): RuleDefinition
{
return new RuleDefinition('Wrap method call to return', [
new ConfiguredCodeSample(
<<<'CODE_SAMPLE'
class SomeClass
{
public function run()
{
$this->deny();
}
public function deny()
{
return 1;
}
}
CODE_SAMPLE
,
<<<'CODE_SAMPLE'
class SomeClass
{
public function run()
{
return $this->deny();
}
public function deny()
{
return 1;
}
}
CODE_SAMPLE
,
[
self::METHOD_CALL_WRAPS => [new MethodCallToReturn('SomeClass', 'deny')],
]
),
]);
}
/**
* @return array<class-string<Node>>
*/
public function getNodeTypes(): array
{
return [Expression::class];
}
/**
* @param Expression $node
*/
public function refactor(Node $node): ?Node
{
if (! $node->expr instanceof MethodCall) {
return null;
}
$methodCall = $node->expr;
return $this->refactorMethodCall($methodCall);
}
/**
* @param array<string, MethodCallToReturn[]> $configuration
*/
public function configure(array $configuration): void
{
$methodCallWraps = $configuration[self::METHOD_CALL_WRAPS] ?? [];
Assert::allIsInstanceOf($methodCallWraps, MethodCallToReturn::class);
$this->methodCallWraps = $methodCallWraps;
}
private function refactorMethodCall(MethodCall $methodCall): ?Node
{
$parent = $methodCall->getAttribute(AttributeKey::PARENT_NODE);
foreach ($this->methodCallWraps as $methodCallWrap) {
if (! $this->isObjectType($methodCall->var, $methodCallWrap->getObjectType())) {
continue;
}
if (! $this->isName($methodCall->name, $methodCallWrap->getMethod())) {
continue;
}
// already wrapped
if ($parent instanceof Return_) {
continue;
}
return new Return_($methodCall);
}
return null;
}
}

View File

@ -1,178 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Transform\Rector\FileWithoutNamespace;
use PhpParser\Node;
use PhpParser\Node\Expr\FuncCall;
use PhpParser\Node\Expr\StaticCall;
use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\Function_;
use PhpParser\Node\Stmt\Namespace_;
use Rector\CodingStyle\Naming\ClassNaming;
use Rector\Core\PhpParser\Node\CustomNode\FileWithoutNamespace;
use Rector\Core\Rector\AbstractRector;
use Rector\FileSystemRector\ValueObject\AddedFileWithNodes;
use Rector\Transform\Naming\FullyQualifiedNameResolver;
use Rector\Transform\NodeFactory\StaticMethodClassFactory;
use Rector\Transform\ValueObject\FunctionToStaticCall;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
use Symplify\SmartFileSystem\SmartFileInfo;
/**
* @see \Rector\Tests\Transform\Rector\FileWithoutNamespace\FunctionToStaticMethodRector\FunctionToStaticMethodRectorTest
*/
final class FunctionToStaticMethodRector extends AbstractRector
{
public function __construct(
private ClassNaming $classNaming,
private StaticMethodClassFactory $staticMethodClassFactory,
private FullyQualifiedNameResolver $fullyQualifiedNameResolver
) {
}
public function getRuleDefinition(): RuleDefinition
{
return new RuleDefinition(
'Change functions to static calls, so composer can autoload them',
[
new CodeSample(
<<<'CODE_SAMPLE'
function some_function()
{
}
some_function('lol');
CODE_SAMPLE
,
<<<'CODE_SAMPLE'
class SomeUtilsClass
{
public static function someFunction()
{
}
}
SomeUtilsClass::someFunction('lol');
CODE_SAMPLE
),
]
);
}
/**
* @return array<class-string<Node>>
*/
public function getNodeTypes(): array
{
return [FileWithoutNamespace::class, Namespace_::class];
}
/**
* @param FileWithoutNamespace|Namespace_ $node
*/
public function refactor(Node $node): ?Node
{
/** @var Function_[] $functions */
$functions = $this->betterNodeFinder->findInstanceOf($node, Function_::class);
if ($functions === []) {
return null;
}
$smartFileInfo = $this->file->getSmartFileInfo();
$shortClassName = $this->classNaming->getNameFromFileInfo($smartFileInfo);
$class = $this->staticMethodClassFactory->createStaticMethodClass($shortClassName, $functions);
$stmts = $node->stmts;
$this->removeNodes($functions);
// replace function calls with class static call
$functionsToStaticCalls = $this->resolveFunctionsToStaticCalls($stmts, $shortClassName, $functions);
$node->stmts = $this->replaceFuncCallsWithStaticCalls($stmts, $functionsToStaticCalls);
$this->printStaticMethodClass($smartFileInfo, $shortClassName, $node, $class);
return $node;
}
/**
* @param Node[] $stmts
* @param Function_[] $functions
* @return FunctionToStaticCall[]
*/
private function resolveFunctionsToStaticCalls(array $stmts, string $shortClassName, array $functions): array
{
$functionsToStaticCalls = [];
$className = $this->fullyQualifiedNameResolver->resolveFullyQualifiedName($stmts, $shortClassName);
foreach ($functions as $function) {
$functionName = $this->getName($function);
if ($functionName === null) {
continue;
}
$methodName = $this->classNaming->createMethodNameFromFunction($function);
$functionsToStaticCalls[] = new FunctionToStaticCall($functionName, $className, $methodName);
}
return $functionsToStaticCalls;
}
/**
* @param Node[] $stmts
* @param FunctionToStaticCall[] $functionsToStaticCalls
* @return Node[]
*/
private function replaceFuncCallsWithStaticCalls(array $stmts, array $functionsToStaticCalls): array
{
$this->traverseNodesWithCallable($stmts, function (Node $node) use ($functionsToStaticCalls): ?StaticCall {
if (! $node instanceof FuncCall) {
return null;
}
foreach ($functionsToStaticCalls as $functionToStaticCall) {
if (! $this->isName($node, $functionToStaticCall->getFunction())) {
continue;
}
$staticCall = $this->nodeFactory->createStaticCall(
$functionToStaticCall->getClass(),
$functionToStaticCall->getMethod()
);
$staticCall->args = $node->args;
return $staticCall;
}
return null;
});
return $stmts;
}
private function printStaticMethodClass(
SmartFileInfo $smartFileInfo,
string $shortClassName,
Namespace_ | FileWithoutNamespace $node,
Class_ $class
): void {
$classFileDestination = $smartFileInfo->getPath() . DIRECTORY_SEPARATOR . $shortClassName . '.php';
$nodesToPrint = [$this->resolveNodeToPrint($node, $class)];
$addedFileWithNodes = new AddedFileWithNodes($classFileDestination, $nodesToPrint);
$this->removedAndAddedFilesCollector->addAddedFile($addedFileWithNodes);
}
private function resolveNodeToPrint(Namespace_ | FileWithoutNamespace $node, Class_ $class): Namespace_ | Class_
{
if ($node instanceof Namespace_) {
return new Namespace_($node->name, [$class]);
}
return $class;
}
}

View File

@ -1,165 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Transform\Rector\MethodCall;
use PhpParser\Node;
use PhpParser\Node\Arg;
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Expr\PropertyFetch;
use PhpParser\Node\Expr\Variable;
use PhpParser\Node\Stmt\Class_;
use PHPStan\Type\ObjectType;
use Rector\Core\Contract\Rector\ConfigurableRectorInterface;
use Rector\Core\Rector\AbstractRector;
use Rector\Naming\Naming\PropertyNaming;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Rector\PostRector\Collector\PropertyToAddCollector;
use Rector\PostRector\ValueObject\PropertyMetadata;
use Rector\Transform\ValueObject\VariableMethodCallToServiceCall;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\ConfiguredCodeSample;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
/**
* @see \Rector\Tests\Transform\Rector\MethodCall\VariableMethodCallToServiceCallRector\VariableMethodCallToServiceCallRectorTest
*/
final class VariableMethodCallToServiceCallRector extends AbstractRector implements ConfigurableRectorInterface
{
/**
* @var string
*/
public const VARIABLE_METHOD_CALLS_TO_SERVICE_CALLS = 'variable_method_calls_to_service_calls';
/**
* @var VariableMethodCallToServiceCall[]
*/
private array $variableMethodCallsToServiceCalls = [];
public function __construct(
private PropertyNaming $propertyNaming,
private PropertyToAddCollector $propertyToAddCollector
) {
}
public function getRuleDefinition(): RuleDefinition
{
return new RuleDefinition('Replace variable method call to a service one', [
new ConfiguredCodeSample(
<<<'CODE_SAMPLE'
use PhpParser\Node;
class SomeClass
{
public function run(Node $node)
{
$phpDocInfo = $node->getAttribute('php_doc_info');
}
}
CODE_SAMPLE
,
<<<'CODE_SAMPLE'
use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfoFactory;
use PhpParser\Node;
class SomeClass
{
public function __construct(PhpDocInfoFactory $phpDocInfoFactory)
{
$this->phpDocInfoFactory = $phpDocInfoFactory;
}
public function run(Node $node)
{
$phpDocInfo = $this->phpDocInfoFactory->createFromNodeOrEmpty($node);
}
}
CODE_SAMPLE
,
[
self::VARIABLE_METHOD_CALLS_TO_SERVICE_CALLS => [
new VariableMethodCallToServiceCall(
'PhpParser\Node',
'getAttribute',
'php_doc_info',
'Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfoFactory',
'createFromNodeOrEmpty'
),
],
]
),
]);
}
/**
* @return array<class-string<Node>>
*/
public function getNodeTypes(): array
{
return [MethodCall::class];
}
/**
* @param MethodCall $node
*/
public function refactor(Node $node): ?Node
{
foreach ($this->variableMethodCallsToServiceCalls as $variableMethodCallToServiceCall) {
if (! $node->var instanceof Variable) {
continue;
}
if (! $this->isObjectType($node->var, $variableMethodCallToServiceCall->getVariableObjectType())) {
continue;
}
if (! $this->isName($node->name, $variableMethodCallToServiceCall->getMethodName())) {
continue;
}
$firstArgValue = $node->args[0]->value;
if (! $this->valueResolver->isValue(
$firstArgValue,
$variableMethodCallToServiceCall->getArgumentValue()
)) {
continue;
}
$classLike = $node->getAttribute(AttributeKey::CLASS_NODE);
if (! $classLike instanceof Class_) {
continue;
}
$serviceObjectType = new ObjectType($variableMethodCallToServiceCall->getServiceType());
$propertyName = $this->propertyNaming->fqnToVariableName($serviceObjectType);
$propertyMetadata = new PropertyMetadata($propertyName, $serviceObjectType, Class_::MODIFIER_PRIVATE);
$this->propertyToAddCollector->addPropertyToClass($classLike, $propertyMetadata);
return $this->createServiceMethodCall(
$serviceObjectType,
$variableMethodCallToServiceCall->getServiceMethodName(),
$node
);
}
return null;
}
/**
* @param mixed[] $configuration
*/
public function configure(array $configuration): void
{
$this->variableMethodCallsToServiceCalls = $configuration[self::VARIABLE_METHOD_CALLS_TO_SERVICE_CALLS] ?? [];
}
private function createServiceMethodCall(ObjectType $objectType, string $methodName, MethodCall $node): MethodCall
{
$propertyName = $this->propertyNaming->fqnToVariableName($objectType);
$propertyFetch = new PropertyFetch(new Variable('this'), $propertyName);
$methodCall = new MethodCall($propertyFetch, $methodName);
$methodCall->args[] = new Arg($node->var);
return $methodCall;
}
}

View File

@ -1,26 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Transform\ValueObject;
use PHPStan\Type\ObjectType;
final class MethodCallToReturn
{
public function __construct(
private string $class,
private string $method
) {
}
public function getObjectType(): ObjectType
{
return new ObjectType($this->class);
}
public function getMethod(): string
{
return $this->method;
}
}