mirror of
https://github.com/rectorphp/rector.git
synced 2024-06-01 08:50:50 +00:00
Add meta node FileWithoutNamespace (#4355)
* [CakePHP] Promote AppUsesStaticCallToUseStatementRector to File * [CakePHP] Change ImplicitShortClassNameUseStatementRector to FileWithoutNamespace approach * [Renaming] Update PseudoNamespaceToNamespaceRector to use FileWithnoutNamespace * [rector] [Renaming] Update PseudoNamespaceToNamespaceRector to use FileWithnoutNamespace * [cs] [Renaming] Update PseudoNamespaceToNamespaceRector to use FileWithnoutNamespace Co-authored-by: rector-bot <tomas@getrector.org>
This commit is contained in:
parent
7e124dffc0
commit
1c8fac5242
|
@ -245,14 +245,14 @@
|
|||
"Rector\\PHPStanStaticTypeMapper\\Tests\\": "packages/phpstan-static-type-mapper/tests"
|
||||
},
|
||||
"classmap": [
|
||||
"rules/cakephp/tests/Rector/Name/ImplicitShortClassNameUseStatementRector/Source",
|
||||
"rules/cakephp/tests/Rector/FileWithoutNamespace/ImplicitShortClassNameUseStatementRector/Source",
|
||||
"rules/symfony/tests/Rector/MethodCall/ContainerGetToConstructorInjectionRector/Source",
|
||||
"rules/autodiscovery/tests/Rector/FileSystem/MoveInterfacesToContractNamespaceDirectoryRector/Expected",
|
||||
"rules/autodiscovery/tests/Rector/FileSystem/MoveServicesBySuffixToDirectoryRector/Expected",
|
||||
"rules/cakephp/tests/Rector/Expression/AppUsesStaticCallToUseStatementRector/Source",
|
||||
"rules/cakephp/tests/Rector/Namespace_/AppUsesStaticCallToUseStatementRector/Source",
|
||||
"tests/Source",
|
||||
"rules/psr4/tests/Rector/MultipleClassFileToPsr4ClassesRector/Source",
|
||||
"rules/generic/tests/Rector/Name/PseudoNamespaceToNamespaceRector/Source"
|
||||
"rules/renaming/tests/Rector/FileWithoutNamespace/PseudoNamespaceToNamespaceRector/Source"
|
||||
],
|
||||
"files": [
|
||||
"rules/naming/tests/ValueObjectFactory/PropertyRenameFactory/Fixture/SomeClass.php.inc",
|
||||
|
@ -266,7 +266,7 @@
|
|||
"rules/renaming/tests/Rector/Name/RenameClassRector/Source/Twig_Extension_Sandbox.php",
|
||||
"rules/renaming/tests/Rector/Name/RenameClassRector/Source/TwigFilter.php",
|
||||
"rules/renaming/tests/Rector/Name/RenameClassRector/Source/Manual_Twig_Filter.php",
|
||||
"rules/generic/tests/Rector/Name/PseudoNamespaceToNamespaceRector/Source/ChangeMeAnotherNamespace.php",
|
||||
"rules/renaming/tests/Rector/FileWithoutNamespace/PseudoNamespaceToNamespaceRector/Source/ChangeMeAnotherNamespace.php",
|
||||
"rules/coding-style/tests/Rector/Namespace_/ImportFullyQualifiedNamesRector/Source/Foo.php",
|
||||
"rules/coding-style/tests/Rector/Namespace_/ImportFullyQualifiedNamesRector/Source/Function_/count.php",
|
||||
"rules/coding-style/tests/Rector/Namespace_/ImportFullyQualifiedNamesRector/Source/AnotherClass.php",
|
||||
|
|
|
@ -53,6 +53,7 @@ return static function (ContainerConfigurator $containerConfigurator): void {
|
|||
__DIR__ . '/../src/ValueObject',
|
||||
__DIR__ . '/../src/Configuration/MinimalVersionChecker',
|
||||
__DIR__ . '/../src/Bootstrap',
|
||||
__DIR__ . '/../src/PhpParser/Node/CustomNode',
|
||||
// loaded for PHPStan factory
|
||||
__DIR__ . '/../src/PHPStan/Type',
|
||||
]);
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Rector\CakePHP\Rector\Expression\AppUsesStaticCallToUseStatementRector;
|
||||
use Rector\CakePHP\Rector\Name\ImplicitShortClassNameUseStatementRector;
|
||||
use Rector\CakePHP\Rector\FileWithoutNamespace\ImplicitShortClassNameUseStatementRector;
|
||||
use Rector\CakePHP\Rector\Namespace_\AppUsesStaticCallToUseStatementRector;
|
||||
use Rector\Renaming\Rector\Name\RenameClassRector;
|
||||
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
|
||||
|
||||
|
|
|
@ -2,11 +2,10 @@
|
|||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Rector\Generic\Rector\Name\PseudoNamespaceToNamespaceRector;
|
||||
|
||||
use Rector\Generic\ValueObject\PseudoNamespaceToNamespace;
|
||||
use Rector\PHPUnit\Rector\ClassMethod\AddDoesNotPerformAssertionToNonAssertingTestRector;
|
||||
use Rector\PHPUnit\Rector\MethodCall\GetMockBuilderGetMockToCreateMockRector;
|
||||
use Rector\Renaming\Rector\FileWithoutNamespace\PseudoNamespaceToNamespaceRector;
|
||||
use Rector\Renaming\Rector\MethodCall\RenameMethodRector;
|
||||
use Rector\Renaming\Rector\Name\RenameClassRector;
|
||||
use Rector\Renaming\ValueObject\MethodCallRename;
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Rector\Generic\Rector\Name\PseudoNamespaceToNamespaceRector;
|
||||
use Rector\Generic\ValueObject\PseudoNamespaceToNamespace;
|
||||
use Rector\Renaming\Rector\FileWithoutNamespace\PseudoNamespaceToNamespaceRector;
|
||||
use Rector\Renaming\Rector\Name\RenameClassRector;
|
||||
use function Rector\SymfonyPhpConfig\inline_value_objects;
|
||||
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# All 583 Rectors Overview
|
||||
# All 584 Rectors Overview
|
||||
|
||||
- [Projects](#projects)
|
||||
---
|
||||
|
@ -9,7 +9,7 @@
|
|||
- [Autodiscovery](#autodiscovery) (4)
|
||||
- [CakePHP](#cakephp) (6)
|
||||
- [CodeQuality](#codequality) (59)
|
||||
- [CodingStyle](#codingstyle) (34)
|
||||
- [CodingStyle](#codingstyle) (33)
|
||||
- [DeadCode](#deadcode) (40)
|
||||
- [Decouple](#decouple) (1)
|
||||
- [Doctrine](#doctrine) (17)
|
||||
|
@ -29,7 +29,7 @@
|
|||
- [MockeryToProphecy](#mockerytoprophecy) (2)
|
||||
- [MockistaToMockery](#mockistatomockery) (2)
|
||||
- [MysqlToMysqli](#mysqltomysqli) (4)
|
||||
- [Naming](#naming) (10)
|
||||
- [Naming](#naming) (11)
|
||||
- [Nette](#nette) (16)
|
||||
- [NetteCodeQuality](#nettecodequality) (6)
|
||||
- [NetteKdyby](#nettekdyby) (4)
|
||||
|
@ -66,7 +66,7 @@
|
|||
- [SOLID](#solid) (12)
|
||||
- [Sensio](#sensio) (3)
|
||||
- [StrictCodeQuality](#strictcodequality) (1)
|
||||
- [Symfony](#symfony) (33)
|
||||
- [Symfony](#symfony) (34)
|
||||
- [SymfonyCodeQuality](#symfonycodequality) (1)
|
||||
- [SymfonyPHPUnit](#symfonyphpunit) (1)
|
||||
- [SymfonyPhpConfig](#symfonyphpconfig) (2)
|
||||
|
@ -269,8 +269,8 @@ return static function (ContainerConfigurator $containerConfigurator): void {
|
|||
|
||||
### `AppUsesStaticCallToUseStatementRector`
|
||||
|
||||
- class: [`Rector\CakePHP\Rector\Expression\AppUsesStaticCallToUseStatementRector`](/rules/cakephp/src/Rector/Expression/AppUsesStaticCallToUseStatementRector.php)
|
||||
- [test fixtures](/rules/cakephp/tests/Rector/Expression/AppUsesStaticCallToUseStatementRector/Fixture)
|
||||
- class: [`Rector\CakePHP\Rector\Namespace_\AppUsesStaticCallToUseStatementRector`](/rules/cakephp/src/Rector/Namespace_/AppUsesStaticCallToUseStatementRector.php)
|
||||
- [test fixtures](/rules/cakephp/tests/Rector/Namespace_/AppUsesStaticCallToUseStatementRector/Fixture)
|
||||
|
||||
Change `App::uses()` to use imports
|
||||
|
||||
|
@ -363,8 +363,8 @@ Changes `$fixtues` style from snake_case to PascalCase.
|
|||
|
||||
### `ImplicitShortClassNameUseStatementRector`
|
||||
|
||||
- class: [`Rector\CakePHP\Rector\Name\ImplicitShortClassNameUseStatementRector`](/rules/cakephp/src/Rector/Name/ImplicitShortClassNameUseStatementRector.php)
|
||||
- [test fixtures](/rules/cakephp/tests/Rector/Name/ImplicitShortClassNameUseStatementRector/Fixture)
|
||||
- class: [`Rector\CakePHP\Rector\FileWithoutNamespace\ImplicitShortClassNameUseStatementRector`](/rules/cakephp/src/Rector/FileWithoutNamespace/ImplicitShortClassNameUseStatementRector.php)
|
||||
- [test fixtures](/rules/cakephp/tests/Rector/FileWithoutNamespace/ImplicitShortClassNameUseStatementRector/Fixture)
|
||||
|
||||
Collect implicit class names and add imports
|
||||
|
||||
|
@ -2403,26 +2403,6 @@ Assign outcome of ternary condition to variable, where applicable
|
|||
|
||||
<br><br>
|
||||
|
||||
### `UnderscoreToCamelCaseLocalVariableNameRector`
|
||||
|
||||
- class: [`Rector\CodingStyle\Rector\Variable\UnderscoreToCamelCaseLocalVariableNameRector`](/rules/coding-style/src/Rector/Variable/UnderscoreToCamelCaseLocalVariableNameRector.php)
|
||||
- [test fixtures](/rules/coding-style/tests/Rector/Variable/UnderscoreToCamelCaseLocalVariableNameRector/Fixture)
|
||||
|
||||
Change under_score local variable names to camelCase
|
||||
|
||||
```diff
|
||||
final class SomeClass
|
||||
{
|
||||
public function run($a_b)
|
||||
{
|
||||
- $some_value = $a_b;
|
||||
+ $someValue = $a_b;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
<br><br>
|
||||
|
||||
### `UseClassKeywordForClassNameResolutionRector`
|
||||
|
||||
- class: [`Rector\CodingStyle\Rector\String_\UseClassKeywordForClassNameResolutionRector`](/rules/coding-style/src/Rector/String_/UseClassKeywordForClassNameResolutionRector.php)
|
||||
|
@ -6361,7 +6341,7 @@ return static function (ContainerConfigurator $containerConfigurator): void {
|
|||
|
||||
### `PseudoNamespaceToNamespaceRector`
|
||||
|
||||
- class: [`Rector\Generic\Rector\Name\PseudoNamespaceToNamespaceRector`](/rules/generic/src/Rector/Name/PseudoNamespaceToNamespaceRector.php)
|
||||
- class: [`Rector\Renaming\Rector\FileWithoutNamespace\PseudoNamespaceToNamespaceRector`](/rules/generic/src/Rector/Name/PseudoNamespaceToNamespaceRector.php)
|
||||
- [test fixtures](/rules/generic/tests/Rector/Name/PseudoNamespaceToNamespaceRector/Fixture)
|
||||
|
||||
Replaces defined Pseudo_Namespaces by Namespace\Ones.
|
||||
|
@ -6371,8 +6351,8 @@ Replaces defined Pseudo_Namespaces by Namespace\Ones.
|
|||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Rector\Generic\Rector\Name\PseudoNamespaceToNamespaceRector;
|
||||
use Rector\Generic\ValueObject\PseudoNamespaceToNamespace;
|
||||
use Rector\Renaming\Rector\FileWithoutNamespace\PseudoNamespaceToNamespaceRector;
|
||||
use function Rector\SymfonyPhpConfig\inline_value_objects;
|
||||
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
|
||||
|
||||
|
@ -7805,6 +7785,26 @@ Rename variable to match new ClassType
|
|||
|
||||
<br><br>
|
||||
|
||||
### `UnderscoreToCamelCaseLocalVariableNameRector`
|
||||
|
||||
- class: [`Rector\Naming\Rector\Variable\UnderscoreToCamelCaseLocalVariableNameRector`](/rules/naming/src/Rector/Variable/UnderscoreToCamelCaseLocalVariableNameRector.php)
|
||||
- [test fixtures](/rules/naming/tests/Rector/Variable/UnderscoreToCamelCaseLocalVariableNameRector/Fixture)
|
||||
|
||||
Change under_score local variable names to camelCase
|
||||
|
||||
```diff
|
||||
final class SomeClass
|
||||
{
|
||||
public function run($a_b)
|
||||
{
|
||||
- $some_value = $a_b;
|
||||
+ $someValue = $a_b;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
<br><br>
|
||||
|
||||
### `UnderscoreToCamelCasePropertyNameRector`
|
||||
|
||||
- class: [`Rector\Naming\Rector\Property\UnderscoreToCamelCasePropertyNameRector`](/rules/naming/src/Rector/Property/UnderscoreToCamelCasePropertyNameRector.php)
|
||||
|
@ -14428,6 +14428,26 @@ Turns long flash adding to short helper method in Controller in Symfony
|
|||
|
||||
<br><br>
|
||||
|
||||
### `AutoWireWithClassNameSuffixForMethodWithRequiredAnnotationRector`
|
||||
|
||||
- class: [`Rector\Symfony\Rector\ClassMethod\AutoWireWithClassNameSuffixForMethodWithRequiredAnnotationRector`](/rules/symfony/src/Rector/ClassMethod/AutoWireWithClassNameSuffixForMethodWithRequiredAnnotationRector.php)
|
||||
- [test fixtures](/rules/symfony/tests/Rector/ClassMethod/AutoWireWithClassNameSuffixForMethodWithRequiredAnnotationRector/Fixture)
|
||||
|
||||
Use autowire + class name suffix for method with @required annotation
|
||||
|
||||
```diff
|
||||
class SomeClass
|
||||
{
|
||||
/** @required */
|
||||
- public function foo()
|
||||
+ public function autowireSomeClass()
|
||||
{
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
<br><br>
|
||||
|
||||
### `CascadeValidationFormBuilderRector`
|
||||
|
||||
- class: [`Rector\Symfony\Rector\MethodCall\CascadeValidationFormBuilderRector`](/rules/symfony/src/Rector/MethodCall/CascadeValidationFormBuilderRector.php)
|
||||
|
|
|
@ -87,6 +87,15 @@ services:
|
|||
'Hoa\Protocol\Node\Node': 'PhpParser\Node'
|
||||
'Nette\Utils\FileSystem': 'Symplify\SmartFileSystem\SmartFileSystem'
|
||||
'Symfony\Component\Filesystem\Filesystem': 'Symplify\SmartFileSystem\SmartFileSystem'
|
||||
# builder typo nodes
|
||||
PhpParser\Builder\Use_: Rector\Core\PhpParser\Builder\UseBuilder
|
||||
PhpParser\Builder\Class_: Rector\Core\PhpParser\Builder\ClassBuilder
|
||||
PhpParser\Builder\Method: Rector\Core\PhpParser\Builder\MethodBuilder
|
||||
PhpParser\Builder\Namespace_: Rector\Core\PhpParser\Builder\NamespaceBuilder
|
||||
PhpParser\Builder\Param: Rector\Core\PhpParser\Builder\ParamBuilder
|
||||
PhpParser\Builder\Property: Rector\Core\PhpParser\Builder\PropertyBuilder
|
||||
PhpParser\Builder\TraitUse: Rector\Core\PhpParser\Builder\TraitUseBuilder
|
||||
|
||||
|
||||
parameters:
|
||||
level: max
|
||||
|
|
|
@ -44,7 +44,9 @@ return static function (ContainerConfigurator $containerConfigurator): void {
|
|||
$parameters->set(Option::AUTOLOAD_PATHS, [__DIR__ . '/compiler/src']);
|
||||
|
||||
$parameters->set(Option::EXCLUDE_PATHS, [
|
||||
'/Fixture/', '/Source/', '/Expected/',
|
||||
'/Fixture/',
|
||||
'/Source/',
|
||||
'/Expected/',
|
||||
__DIR__ . '/packages/doctrine-annotation-generated/src/*',
|
||||
// tempalte files
|
||||
__DIR__ . '/packages/rector-generator/templates/*',
|
||||
|
|
|
@ -1,120 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\CakePHP\Rector\Expression;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Expr\StaticCall;
|
||||
use PhpParser\Node\Name;
|
||||
use PhpParser\Node\Stmt\Expression;
|
||||
use PhpParser\Node\Stmt\Namespace_;
|
||||
use PhpParser\Node\Stmt\Use_;
|
||||
use PhpParser\Node\Stmt\UseUse;
|
||||
use Rector\CakePHP\Naming\CakePHPFullyQualifiedClassNameResolver;
|
||||
use Rector\Core\Rector\AbstractRector;
|
||||
use Rector\Core\RectorDefinition\CodeSample;
|
||||
use Rector\Core\RectorDefinition\RectorDefinition;
|
||||
use Rector\NodeTypeResolver\Node\AttributeKey;
|
||||
use Rector\PHPStan\Type\FullyQualifiedObjectType;
|
||||
|
||||
/**
|
||||
* @see https://github.com/cakephp/upgrade/blob/756410c8b7d5aff9daec3fa1fe750a3858d422ac/src/Shell/Task/AppUsesTask.php
|
||||
* @see https://github.com/cakephp/upgrade/search?q=uses&unscoped_q=uses
|
||||
*
|
||||
* @see \Rector\CakePHP\Tests\Rector\Expression\AppUsesStaticCallToUseStatementRector\AppUsesStaticCallToUseStatementRectorTest
|
||||
*/
|
||||
final class AppUsesStaticCallToUseStatementRector extends AbstractRector
|
||||
{
|
||||
/**
|
||||
* @var CakePHPFullyQualifiedClassNameResolver
|
||||
*/
|
||||
private $cakePHPFullyQualifiedClassNameResolver;
|
||||
|
||||
public function __construct(CakePHPFullyQualifiedClassNameResolver $cakePHPFullyQualifiedClassNameResolver)
|
||||
{
|
||||
$this->cakePHPFullyQualifiedClassNameResolver = $cakePHPFullyQualifiedClassNameResolver;
|
||||
}
|
||||
|
||||
public function getDefinition(): RectorDefinition
|
||||
{
|
||||
return new RectorDefinition('Change App::uses() to use imports', [
|
||||
new CodeSample(
|
||||
<<<'CODE_SAMPLE'
|
||||
App::uses('NotificationListener', 'Event');
|
||||
|
||||
CakeEventManager::instance()->attach(new NotificationListener());
|
||||
CODE_SAMPLE
|
||||
,
|
||||
<<<'CODE_SAMPLE'
|
||||
use Event\NotificationListener;
|
||||
|
||||
CakeEventManager::instance()->attach(new NotificationListener());
|
||||
CODE_SAMPLE
|
||||
),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
public function getNodeTypes(): array
|
||||
{
|
||||
return [Expression::class];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Expression $node
|
||||
*/
|
||||
public function refactor(Node $node): ?Node
|
||||
{
|
||||
if (! $node->expr instanceof StaticCall) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$staticCall = $node->expr;
|
||||
if (! $this->isAppUses($staticCall)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$fullyQualifiedName = $this->createFullyQualifiedNameFromAppUsesStaticCall($staticCall);
|
||||
|
||||
// A. is above the class or under the namespace
|
||||
$parentNode = $node->getAttribute(AttributeKey::PARENT_NODE);
|
||||
if ($parentNode instanceof Namespace_ || $parentNode === null) {
|
||||
return $this->createUseFromFullyQualifiedName($fullyQualifiedName);
|
||||
}
|
||||
|
||||
// B. is inside the code → add use import
|
||||
$this->addUseType(new FullyQualifiedObjectType($fullyQualifiedName), $node);
|
||||
$this->removeNode($node);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private function isAppUses(StaticCall $staticCall): bool
|
||||
{
|
||||
return $this->isStaticCallNamed($staticCall, 'App', 'uses');
|
||||
}
|
||||
|
||||
private function createFullyQualifiedNameFromAppUsesStaticCall(StaticCall $staticCall): string
|
||||
{
|
||||
/** @var string $shortClassName */
|
||||
$shortClassName = $this->getValue($staticCall->args[0]->value);
|
||||
|
||||
/** @var string $namespaceName */
|
||||
$namespaceName = $this->getValue($staticCall->args[1]->value);
|
||||
|
||||
return $this->cakePHPFullyQualifiedClassNameResolver->resolveFromPseudoNamespaceAndShortClassName(
|
||||
$namespaceName,
|
||||
$shortClassName
|
||||
);
|
||||
}
|
||||
|
||||
private function createUseFromFullyQualifiedName(string $fullyQualifiedName): Use_
|
||||
{
|
||||
$useUse = new UseUse(new Name($fullyQualifiedName));
|
||||
|
||||
return new Use_([$useUse]);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,123 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\CakePHP\Rector\FileWithoutNamespace;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Expr\New_;
|
||||
use PhpParser\Node\Name;
|
||||
use Rector\CakePHP\ImplicitNameResolver;
|
||||
use Rector\Core\PhpParser\Node\CustomNode\FileWithoutNamespace;
|
||||
use Rector\Core\Rector\AbstractRector;
|
||||
use Rector\Core\RectorDefinition\CodeSample;
|
||||
use Rector\Core\RectorDefinition\RectorDefinition;
|
||||
use Rector\NodeTypeResolver\Node\AttributeKey;
|
||||
|
||||
/**
|
||||
* @see https://github.com/cakephp/upgrade/blob/05d85c147bb1302b576b818cabb66a40462aaed0/src/Shell/Task/AppUsesTask.php#L183
|
||||
*
|
||||
* @see \Rector\CakePHP\Tests\Rector\FileWithoutNamespace\ImplicitShortClassNameUseStatementRector\ImplicitShortClassNameUseStatementRectorTest
|
||||
*/
|
||||
final class ImplicitShortClassNameUseStatementRector extends AbstractRector
|
||||
{
|
||||
/**
|
||||
* @var ImplicitNameResolver
|
||||
*/
|
||||
private $implicitNameResolver;
|
||||
|
||||
public function __construct(ImplicitNameResolver $implicitNameResolver)
|
||||
{
|
||||
$this->implicitNameResolver = $implicitNameResolver;
|
||||
}
|
||||
|
||||
public function getDefinition(): RectorDefinition
|
||||
{
|
||||
return new RectorDefinition('Collect implicit class names and add imports', [
|
||||
new CodeSample(
|
||||
<<<'CODE_SAMPLE'
|
||||
use App\Foo\Plugin;
|
||||
|
||||
class LocationsFixture extends TestFixture implements Plugin
|
||||
{
|
||||
}
|
||||
CODE_SAMPLE
|
||||
,
|
||||
<<<'CODE_SAMPLE'
|
||||
use App\Foo\Plugin;
|
||||
use Cake\TestSuite\Fixture\TestFixture;
|
||||
|
||||
class LocationsFixture extends TestFixture implements Plugin
|
||||
{
|
||||
}
|
||||
CODE_SAMPLE
|
||||
),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
public function getNodeTypes(): array
|
||||
{
|
||||
return [FileWithoutNamespace::class];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param FileWithoutNamespace $node
|
||||
*/
|
||||
public function refactor(Node $node): ?Node
|
||||
{
|
||||
$names = $this->findNames($node);
|
||||
|
||||
/** @var Name[] $names */
|
||||
if ($names === []) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$resolvedNames = $this->resolveNames($names);
|
||||
if ($resolvedNames === []) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$uses = $this->nodeFactory->createUsesFromNames($resolvedNames);
|
||||
$node->stmts = array_merge($uses, $node->stmts);
|
||||
|
||||
return $node;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Name[]
|
||||
*/
|
||||
private function findNames(FileWithoutNamespace $fileWithoutNamespace): array
|
||||
{
|
||||
return $this->betterNodeFinder->find($fileWithoutNamespace->stmts, function (Node $node): bool {
|
||||
if (! $node instanceof Name) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$parent = $node->getAttribute(AttributeKey::PARENT_NODE);
|
||||
return ! $parent instanceof New_;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Name[] $names
|
||||
* @return string[]
|
||||
*/
|
||||
private function resolveNames(array $names): array
|
||||
{
|
||||
$resolvedNames = [];
|
||||
foreach ($names as $name) {
|
||||
$classShortName = $this->getName($name);
|
||||
$resolvedName = $this->implicitNameResolver->resolve($classShortName);
|
||||
if ($resolvedName === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$resolvedNames[] = $resolvedName;
|
||||
}
|
||||
|
||||
return $resolvedNames;
|
||||
}
|
||||
}
|
|
@ -1,87 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\CakePHP\Rector\Name;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Expr\New_;
|
||||
use PhpParser\Node\Name;
|
||||
use PhpParser\Node\Stmt\ClassLike;
|
||||
use Rector\CakePHP\ImplicitNameResolver;
|
||||
use Rector\Core\Rector\AbstractRector;
|
||||
use Rector\Core\RectorDefinition\CodeSample;
|
||||
use Rector\Core\RectorDefinition\RectorDefinition;
|
||||
use Rector\NodeTypeResolver\Node\AttributeKey;
|
||||
use Rector\PHPStan\Type\FullyQualifiedObjectType;
|
||||
|
||||
/**
|
||||
* @see https://github.com/cakephp/upgrade/blob/05d85c147bb1302b576b818cabb66a40462aaed0/src/Shell/Task/AppUsesTask.php#L183
|
||||
*
|
||||
* @see \Rector\CakePHP\Tests\Rector\Name\ImplicitShortClassNameUseStatementRector\ImplicitShortClassNameUseStatementRectorTest
|
||||
*/
|
||||
final class ImplicitShortClassNameUseStatementRector extends AbstractRector
|
||||
{
|
||||
/**
|
||||
* @var ImplicitNameResolver
|
||||
*/
|
||||
private $implicitNameResolver;
|
||||
|
||||
public function __construct(ImplicitNameResolver $implicitNameResolver)
|
||||
{
|
||||
$this->implicitNameResolver = $implicitNameResolver;
|
||||
}
|
||||
|
||||
public function getDefinition(): RectorDefinition
|
||||
{
|
||||
return new RectorDefinition('Collect implicit class names and add imports', [
|
||||
new CodeSample(
|
||||
<<<'CODE_SAMPLE'
|
||||
use App\Foo\Plugin;
|
||||
|
||||
class LocationsFixture extends TestFixture implements Plugin
|
||||
{
|
||||
}
|
||||
CODE_SAMPLE
|
||||
,
|
||||
<<<'CODE_SAMPLE'
|
||||
use App\Foo\Plugin;
|
||||
use Cake\TestSuite\Fixture\TestFixture;
|
||||
|
||||
class LocationsFixture extends TestFixture implements Plugin
|
||||
{
|
||||
}
|
||||
CODE_SAMPLE
|
||||
),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
public function getNodeTypes(): array
|
||||
{
|
||||
return [Name::class];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Name $node
|
||||
*/
|
||||
public function refactor(Node $node): ?Node
|
||||
{
|
||||
$parentNode = $node->getAttribute(AttributeKey::PARENT_NODE);
|
||||
if (! $parentNode instanceof ClassLike && $parentNode instanceof New_) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$classShortName = $this->getName($node);
|
||||
$resvoledName = $this->implicitNameResolver->resolve($classShortName);
|
||||
if ($resvoledName === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$this->addUseType(new FullyQualifiedObjectType($resvoledName), $node);
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,173 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\CakePHP\Rector\Namespace_;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Expr\StaticCall;
|
||||
use PhpParser\Node\Stmt\Declare_;
|
||||
use PhpParser\Node\Stmt\Namespace_;
|
||||
use PhpParser\Node\Stmt\Use_;
|
||||
use Rector\CakePHP\Naming\CakePHPFullyQualifiedClassNameResolver;
|
||||
use Rector\Core\PhpParser\Node\CustomNode\FileWithoutNamespace;
|
||||
use Rector\Core\Rector\AbstractRector;
|
||||
use Rector\Core\RectorDefinition\CodeSample;
|
||||
use Rector\Core\RectorDefinition\RectorDefinition;
|
||||
|
||||
/**
|
||||
* @see https://github.com/cakephp/upgrade/blob/756410c8b7d5aff9daec3fa1fe750a3858d422ac/src/Shell/Task/AppUsesTask.php
|
||||
* @see https://github.com/cakephp/upgrade/search?q=uses&unscoped_q=uses
|
||||
*
|
||||
* @see \Rector\CakePHP\Tests\Rector\Namespace_\AppUsesStaticCallToUseStatementRector\AppUsesStaticCallToUseStatementRectorTest
|
||||
*/
|
||||
final class AppUsesStaticCallToUseStatementRector extends AbstractRector
|
||||
{
|
||||
/**
|
||||
* @var CakePHPFullyQualifiedClassNameResolver
|
||||
*/
|
||||
private $cakePHPFullyQualifiedClassNameResolver;
|
||||
|
||||
public function __construct(CakePHPFullyQualifiedClassNameResolver $cakePHPFullyQualifiedClassNameResolver)
|
||||
{
|
||||
$this->cakePHPFullyQualifiedClassNameResolver = $cakePHPFullyQualifiedClassNameResolver;
|
||||
}
|
||||
|
||||
public function getDefinition(): RectorDefinition
|
||||
{
|
||||
return new RectorDefinition('Change App::uses() to use imports', [
|
||||
new CodeSample(
|
||||
<<<'CODE_SAMPLE'
|
||||
App::uses('NotificationListener', 'Event');
|
||||
|
||||
CakeEventManager::instance()->attach(new NotificationListener());
|
||||
CODE_SAMPLE
|
||||
,
|
||||
<<<'CODE_SAMPLE'
|
||||
use Event\NotificationListener;
|
||||
|
||||
CakeEventManager::instance()->attach(new NotificationListener());
|
||||
CODE_SAMPLE
|
||||
),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
public function getNodeTypes(): array
|
||||
{
|
||||
return [FileWithoutNamespace::class, Namespace_::class];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param FileWithoutNamespace|Namespace_ $node
|
||||
*/
|
||||
public function refactor(Node $node): ?Node
|
||||
{
|
||||
$appUsesStaticCalls = $this->collectAppUseStaticCalls($node);
|
||||
if ($appUsesStaticCalls === []) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$this->removeNodes($appUsesStaticCalls);
|
||||
|
||||
$names = $this->resolveNamesFromStaticCalls($appUsesStaticCalls);
|
||||
$uses = $this->nodeFactory->createUsesFromNames($names);
|
||||
|
||||
if ($node instanceof Namespace_) {
|
||||
$node->stmts = array_merge($uses, (array) $node->stmts);
|
||||
return $node;
|
||||
}
|
||||
|
||||
return $this->refactorFile($node, $uses);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return StaticCall[]
|
||||
*/
|
||||
private function collectAppUseStaticCalls(Node $node): array
|
||||
{
|
||||
/** @var StaticCall[] $appUsesStaticCalls */
|
||||
$appUsesStaticCalls = $this->betterNodeFinder->find($node, function (Node $node): bool {
|
||||
if (! $node instanceof StaticCall) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->isStaticCallNamed($node, 'App', 'uses');
|
||||
});
|
||||
|
||||
return $appUsesStaticCalls;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param StaticCall[] $staticCalls
|
||||
* @return string[]
|
||||
*/
|
||||
private function resolveNamesFromStaticCalls(array $staticCalls): array
|
||||
{
|
||||
$names = [];
|
||||
foreach ($staticCalls as $staticCall) {
|
||||
$names[] = $this->createFullyQualifiedNameFromAppUsesStaticCall($staticCall);
|
||||
}
|
||||
|
||||
return $names;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Use_[] $uses
|
||||
*/
|
||||
private function refactorFile(FileWithoutNamespace $fileWithoutNamespace, array $uses): ?FileWithoutNamespace
|
||||
{
|
||||
$hasNamespace = $this->betterNodeFinder->findFirstInstanceOf($fileWithoutNamespace, Namespace_::class);
|
||||
// already handled above
|
||||
if ($hasNamespace !== null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$hasDeclare = $this->betterNodeFinder->findFirstInstanceOf($fileWithoutNamespace, Declare_::class);
|
||||
if ($hasDeclare !== null) {
|
||||
return $this->refactorFileWithDeclare($fileWithoutNamespace, $uses);
|
||||
}
|
||||
|
||||
$fileWithoutNamespace->stmts = array_merge($uses, (array) $fileWithoutNamespace->stmts);
|
||||
return $fileWithoutNamespace;
|
||||
}
|
||||
|
||||
private function createFullyQualifiedNameFromAppUsesStaticCall(StaticCall $staticCall): string
|
||||
{
|
||||
/** @var string $shortClassName */
|
||||
$shortClassName = $this->getValue($staticCall->args[0]->value);
|
||||
|
||||
/** @var string $namespaceName */
|
||||
$namespaceName = $this->getValue($staticCall->args[1]->value);
|
||||
|
||||
return $this->cakePHPFullyQualifiedClassNameResolver->resolveFromPseudoNamespaceAndShortClassName(
|
||||
$namespaceName,
|
||||
$shortClassName
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Use_[] $uses
|
||||
*/
|
||||
private function refactorFileWithDeclare(
|
||||
FileWithoutNamespace $fileWithoutNamespace,
|
||||
array $uses
|
||||
): FileWithoutNamespace {
|
||||
$newStmts = [];
|
||||
foreach ($fileWithoutNamespace->stmts as $stmt) {
|
||||
$newStmts[] = $stmt;
|
||||
|
||||
if ($stmt instanceof Declare_) {
|
||||
foreach ($uses as $use) {
|
||||
$newStmts[] = $use;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
return new FileWithoutNamespace($newStmts);
|
||||
}
|
||||
}
|
|
@ -2,10 +2,10 @@
|
|||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\CakePHP\Tests\Rector\Name\ImplicitShortClassNameUseStatementRector;
|
||||
namespace Rector\CakePHP\Tests\Rector\FileWithoutNamespace\ImplicitShortClassNameUseStatementRector;
|
||||
|
||||
use Iterator;
|
||||
use Rector\CakePHP\Rector\Name\ImplicitShortClassNameUseStatementRector;
|
||||
use Rector\CakePHP\Rector\FileWithoutNamespace\ImplicitShortClassNameUseStatementRector;
|
||||
use Rector\Core\Testing\PHPUnit\AbstractRectorTestCase;
|
||||
use Symplify\SmartFileSystem\SmartFileInfo;
|
||||
|
|
@ -2,10 +2,10 @@
|
|||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\CakePHP\Tests\Rector\Expression\AppUsesStaticCallToUseStatementRector;
|
||||
namespace Rector\CakePHP\Tests\Rector\Namespace_\AppUsesStaticCallToUseStatementRector;
|
||||
|
||||
use Iterator;
|
||||
use Rector\CakePHP\Rector\Expression\AppUsesStaticCallToUseStatementRector;
|
||||
use Rector\CakePHP\Rector\Namespace_\AppUsesStaticCallToUseStatementRector;
|
||||
use Rector\Core\Testing\PHPUnit\AbstractRectorTestCase;
|
||||
use Symplify\SmartFileSystem\SmartFileInfo;
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
|
||||
namespace Rector\CakePHP\Tests\Rector\Expression\AppUsesStaticCallToUseStatementRector\Fixture;
|
||||
namespace Rector\CakePHP\Tests\Rector\Namespace_\AppUsesStaticCallToUseStatementRector\Fixture;
|
||||
|
||||
\App::uses('Component', 'Controller');
|
||||
|
||||
|
@ -12,7 +12,7 @@ class CakeController
|
|||
-----
|
||||
<?php
|
||||
|
||||
namespace Rector\CakePHP\Tests\Rector\Expression\AppUsesStaticCallToUseStatementRector\Fixture;
|
||||
namespace Rector\CakePHP\Tests\Rector\Namespace_\AppUsesStaticCallToUseStatementRector\Fixture;
|
||||
|
||||
use Cake\Controller\Component;
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\CakePHP\Tests\Rector\Namespace_\AppUsesStaticCallToUseStatementRector\Fixture;
|
||||
|
||||
\App::uses('Component', 'Controller');
|
||||
|
||||
class CakeControllerWithStrictTypes
|
||||
{
|
||||
}
|
||||
|
||||
?>
|
||||
-----
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\CakePHP\Tests\Rector\Namespace_\AppUsesStaticCallToUseStatementRector\Fixture;
|
||||
|
||||
use Cake\Controller\Component;
|
||||
|
||||
class CakeControllerWithStrictTypes
|
||||
{
|
||||
}
|
||||
|
||||
?>
|
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
|
||||
namespace Rector\CakePHP\Tests\Rector\Expression\AppUsesStaticCallToUseStatementRector\Fixture;
|
||||
namespace Rector\CakePHP\Tests\Rector\Namespace_\AppUsesStaticCallToUseStatementRector\Fixture;
|
||||
|
||||
\App::uses('HttpSocket', 'Network/Http');
|
||||
\App::uses('Xml', 'Utility');
|
||||
|
@ -18,7 +18,7 @@ class CakePhpFixture
|
|||
-----
|
||||
<?php
|
||||
|
||||
namespace Rector\CakePHP\Tests\Rector\Expression\AppUsesStaticCallToUseStatementRector\Fixture;
|
||||
namespace Rector\CakePHP\Tests\Rector\Namespace_\AppUsesStaticCallToUseStatementRector\Fixture;
|
||||
|
||||
use App\Network\Http\HttpSocket;
|
||||
use Cake\Utility\Xml;
|
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
|
||||
namespace Rector\CakePHP\Tests\Rector\Expression\AppUsesStaticCallToUseStatementRector\Fixture;
|
||||
namespace Rector\CakePHP\Tests\Rector\Namespace_\AppUsesStaticCallToUseStatementRector\Fixture;
|
||||
|
||||
class ImportNamespacesUp
|
||||
{
|
||||
|
@ -17,7 +17,7 @@ class ImportNamespacesUp
|
|||
-----
|
||||
<?php
|
||||
|
||||
namespace Rector\CakePHP\Tests\Rector\Expression\AppUsesStaticCallToUseStatementRector\Fixture;
|
||||
namespace Rector\CakePHP\Tests\Rector\Namespace_\AppUsesStaticCallToUseStatementRector\Fixture;
|
||||
|
||||
use Foo\Lib\HtmlDomLib;
|
||||
use Foo\Lib\HtmlDomLibExt;
|
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
|
||||
namespace Rector\CakePHP\Tests\Rector\Expression\AppUsesStaticCallToUseStatementRector\Fixture;
|
||||
namespace Rector\CakePHP\Tests\Rector\Namespace_\AppUsesStaticCallToUseStatementRector\Fixture;
|
||||
|
||||
\App::uses('NotificationListener', 'Event');
|
||||
|
||||
|
@ -16,7 +16,7 @@ class SomeClass
|
|||
-----
|
||||
<?php
|
||||
|
||||
namespace Rector\CakePHP\Tests\Rector\Expression\AppUsesStaticCallToUseStatementRector\Fixture;
|
||||
namespace Rector\CakePHP\Tests\Rector\Namespace_\AppUsesStaticCallToUseStatementRector\Fixture;
|
||||
|
||||
use Event\NotificationListener;
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
<?php
|
||||
|
||||
\App::uses('NotificationListener', 'Event');
|
||||
|
||||
class WithoutNamespace
|
||||
{
|
||||
public function run()
|
||||
{
|
||||
$values = new NotificationListener();
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
-----
|
||||
<?php
|
||||
|
||||
use Event\NotificationListener;
|
||||
|
||||
class WithoutNamespace
|
||||
{
|
||||
public function run()
|
||||
{
|
||||
$values = new NotificationListener();
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,31 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
\App::uses('NotificationListener', 'Event');
|
||||
|
||||
class WithoutNamespaceWithStrictTypes
|
||||
{
|
||||
public function run()
|
||||
{
|
||||
$values = new NotificationListener();
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
-----
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Event\NotificationListener;
|
||||
|
||||
class WithoutNamespaceWithStrictTypes
|
||||
{
|
||||
public function run()
|
||||
{
|
||||
$values = new NotificationListener();
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -1,18 +1,26 @@
|
|||
<?php
|
||||
|
||||
$newValue = null;
|
||||
$values = [];
|
||||
$input = '123';
|
||||
namespace Rector\CodeQuality\Tests\Rector\Foreach_\SimplifyForeachToCoalescingRector\Fixture;
|
||||
|
||||
foreach ($values as $key => $value) {
|
||||
if ($key === $input) {
|
||||
$newValue = $value;
|
||||
}
|
||||
}
|
||||
class SimpleIdenticalForeach
|
||||
{
|
||||
public function run()
|
||||
{
|
||||
$newValue = null;
|
||||
$values = [];
|
||||
$input = '123';
|
||||
|
||||
foreach ($values as $key => $value) {
|
||||
if ($input === $key) {
|
||||
$newValue = $value;
|
||||
foreach ($values as $key => $value) {
|
||||
if ($key === $input) {
|
||||
$newValue = $value;
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($values as $key => $value) {
|
||||
if ($input === $key) {
|
||||
$newValue = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -20,12 +28,20 @@ foreach ($values as $key => $value) {
|
|||
-----
|
||||
<?php
|
||||
|
||||
$newValue = null;
|
||||
$values = [];
|
||||
$input = '123';
|
||||
namespace Rector\CodeQuality\Tests\Rector\Foreach_\SimplifyForeachToCoalescingRector\Fixture;
|
||||
|
||||
$newValue = $values[$input] ?? $newValue;
|
||||
class SimpleIdenticalForeach
|
||||
{
|
||||
public function run()
|
||||
{
|
||||
$newValue = null;
|
||||
$values = [];
|
||||
$input = '123';
|
||||
|
||||
$newValue = $values[$input] ?? $newValue;
|
||||
$newValue = $values[$input] ?? $newValue;
|
||||
|
||||
$newValue = $values[$input] ?? $newValue;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
|
|
|
@ -1,13 +0,0 @@
|
|||
<?php
|
||||
|
||||
$array = [];
|
||||
in_array('key', array_values($array), true);
|
||||
|
||||
?>
|
||||
-----
|
||||
<?php
|
||||
|
||||
$array = [];
|
||||
in_array('key', $array, true);
|
||||
|
||||
?>
|
|
@ -0,0 +1,35 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\CodeQuality\Tests\Rector\FuncCall\SimplifyInArrayValuesRector\Fixture;
|
||||
|
||||
final class InArray
|
||||
{
|
||||
public function run()
|
||||
{
|
||||
$array = ['key', 'value'];
|
||||
return in_array('key', array_values($array), true);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
||||
-----
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\CodeQuality\Tests\Rector\FuncCall\SimplifyInArrayValuesRector\Fixture;
|
||||
|
||||
final class InArray
|
||||
{
|
||||
public function run()
|
||||
{
|
||||
$array = ['key', 'value'];
|
||||
return in_array('key', $array, true);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
|
@ -1,19 +0,0 @@
|
|||
<?php
|
||||
|
||||
$string = 'hey';
|
||||
strpos(strtolower($string), 'find-me');
|
||||
|
||||
$funcName = 'strpos';
|
||||
$funcName(strtolower($string), 'find-me');
|
||||
|
||||
?>
|
||||
-----
|
||||
<?php
|
||||
|
||||
$string = 'hey';
|
||||
stripos($string, 'find-me');
|
||||
|
||||
$funcName = 'strpos';
|
||||
$funcName(strtolower($string), 'find-me');
|
||||
|
||||
?>
|
|
@ -0,0 +1,39 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\CodeQuality\Tests\Rector\FuncCall\SimplifyStrposLowerRector\Fixture;
|
||||
|
||||
final class StrposCalls
|
||||
{
|
||||
public function run()
|
||||
{
|
||||
$string = 'hey';
|
||||
strpos(strtolower($string), 'find-me');
|
||||
|
||||
$funcName = 'strpos';
|
||||
$funcName(strtolower($string), 'find-me');
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
-----
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\CodeQuality\Tests\Rector\FuncCall\SimplifyStrposLowerRector\Fixture;
|
||||
|
||||
final class StrposCalls
|
||||
{
|
||||
public function run()
|
||||
{
|
||||
$string = 'hey';
|
||||
stripos($string, 'find-me');
|
||||
|
||||
$funcName = 'strpos';
|
||||
$funcName(strtolower($string), 'find-me');
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -1,10 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Generic\Tests\Rector\Name\PseudoNamespaceToNamespaceRector\Source;
|
||||
|
||||
final class Keep_This
|
||||
{
|
||||
|
||||
}
|
|
@ -90,11 +90,11 @@ final class ClassRenamer
|
|||
}
|
||||
|
||||
if ($node instanceof Namespace_) {
|
||||
return $this->refactorNamespaceNode($node, $oldToNewClasses);
|
||||
return $this->refactorNamespace($node, $oldToNewClasses);
|
||||
}
|
||||
|
||||
if ($node instanceof ClassLike) {
|
||||
return $this->refactorClassLikeNode($node, $oldToNewClasses);
|
||||
return $this->refactorClassLike($node, $oldToNewClasses);
|
||||
}
|
||||
|
||||
return null;
|
||||
|
@ -149,7 +149,7 @@ final class ClassRenamer
|
|||
return $name;
|
||||
}
|
||||
|
||||
private function refactorNamespaceNode(Namespace_ $namespace, array $oldToNewClasses): ?Node
|
||||
private function refactorNamespace(Namespace_ $namespace, array $oldToNewClasses): ?Node
|
||||
{
|
||||
$name = $this->nodeNameResolver->getName($namespace);
|
||||
if ($name === null) {
|
||||
|
@ -178,7 +178,7 @@ final class ClassRenamer
|
|||
return $namespace;
|
||||
}
|
||||
|
||||
private function refactorClassLikeNode(ClassLike $classLike, array $oldToNewClasses): ?Node
|
||||
private function refactorClassLike(ClassLike $classLike, array $oldToNewClasses): ?Node
|
||||
{
|
||||
// rename interfaces
|
||||
$this->renameClassImplements($classLike, $oldToNewClasses);
|
||||
|
|
|
@ -2,22 +2,19 @@
|
|||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Generic\Rector\Name;
|
||||
namespace Rector\Renaming\Rector\FileWithoutNamespace;
|
||||
|
||||
use Nette\Utils\Strings;
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\FunctionLike;
|
||||
use PhpParser\Node\Identifier;
|
||||
use PhpParser\Node\Name;
|
||||
use PhpParser\Node\Stmt;
|
||||
use PhpParser\Node\Stmt\Class_;
|
||||
use PhpParser\Node\Stmt\Expression;
|
||||
use PhpParser\Node\Stmt\Namespace_;
|
||||
use PhpParser\Node\Stmt\Property;
|
||||
use PhpParser\Node\Stmt\Use_;
|
||||
use Rector\Core\Contract\Rector\ConfigurableRectorInterface;
|
||||
use Rector\Core\Exception\ShouldNotHappenException;
|
||||
use Rector\Core\PhpParser\Node\Manipulator\ClassInsertManipulator;
|
||||
use Rector\Core\PhpParser\Node\CustomNode\FileWithoutNamespace;
|
||||
use Rector\Core\Rector\AbstractRector;
|
||||
use Rector\Core\RectorDefinition\ConfiguredCodeSample;
|
||||
use Rector\Core\RectorDefinition\RectorDefinition;
|
||||
|
@ -27,7 +24,7 @@ use Rector\NodeTypeResolver\PhpDoc\PhpDocTypeRenamer;
|
|||
use Webmozart\Assert\Assert;
|
||||
|
||||
/**
|
||||
* @see \Rector\Generic\Tests\Rector\Name\PseudoNamespaceToNamespaceRector\PseudoNamespaceToNamespaceRectorTest
|
||||
* @see \Rector\Renaming\Tests\Rector\FileWithoutNamespace\PseudoNamespaceToNamespaceRector\PseudoNamespaceToNamespaceRectorTest
|
||||
*/
|
||||
final class PseudoNamespaceToNamespaceRector extends AbstractRector implements ConfigurableRectorInterface
|
||||
{
|
||||
|
@ -45,29 +42,21 @@ final class PseudoNamespaceToNamespaceRector extends AbstractRector implements C
|
|||
/**
|
||||
* @var PseudoNamespaceToNamespace[]
|
||||
*/
|
||||
private $namespacePrefixesWithExcludedClasses = [];
|
||||
private $pseudoNamespacesToNamespaces = [];
|
||||
|
||||
/**
|
||||
* @var PhpDocTypeRenamer
|
||||
*/
|
||||
private $phpDocTypeRenamer;
|
||||
|
||||
/**
|
||||
* @var ClassInsertManipulator
|
||||
*/
|
||||
private $classInsertManipulator;
|
||||
|
||||
/**
|
||||
* @var string|null
|
||||
*/
|
||||
private $newNamespace;
|
||||
|
||||
public function __construct(
|
||||
ClassInsertManipulator $classInsertManipulator,
|
||||
PhpDocTypeRenamer $phpDocTypeRenamer
|
||||
) {
|
||||
public function __construct(PhpDocTypeRenamer $phpDocTypeRenamer)
|
||||
{
|
||||
$this->phpDocTypeRenamer = $phpDocTypeRenamer;
|
||||
$this->classInsertManipulator = $classInsertManipulator;
|
||||
}
|
||||
|
||||
public function getDefinition(): RectorDefinition
|
||||
|
@ -101,55 +90,83 @@ CODE_SAMPLE
|
|||
public function getNodeTypes(): array
|
||||
{
|
||||
// property, method
|
||||
return [Name::class, Identifier::class, Property::class, FunctionLike::class, Expression::class];
|
||||
return [FileWithoutNamespace::class, Namespace_::class];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Name|Identifier|Property|FunctionLike $node
|
||||
* @param Name|Identifier|Property|FunctionLike|FileWithoutNamespace|Namespace_ $node
|
||||
*/
|
||||
public function refactor(Node $node): ?Node
|
||||
{
|
||||
// replace on @var/@param/@return/@throws
|
||||
foreach ($this->namespacePrefixesWithExcludedClasses as $namespacePrefixWithExcludedClasses) {
|
||||
$this->phpDocTypeRenamer->changeUnderscoreType($node, $namespacePrefixWithExcludedClasses);
|
||||
}
|
||||
$this->newNamespace = null;
|
||||
|
||||
if ($node instanceof Name || $node instanceof Identifier) {
|
||||
return $this->processNameOrIdentifier($node);
|
||||
}
|
||||
if ($node instanceof FileWithoutNamespace) {
|
||||
$stmts = $this->refactorStmts((array) $node->stmts);
|
||||
$node->stmts = $stmts;
|
||||
|
||||
return null;
|
||||
}
|
||||
// add a new namespace?
|
||||
if ($this->newNamespace) {
|
||||
$namespace = new Namespace_(new Name($this->newNamespace));
|
||||
$namespace->stmts = $stmts;
|
||||
|
||||
/**
|
||||
* @param Stmt[] $nodes
|
||||
* @return Node[]
|
||||
*/
|
||||
public function afterTraverse(array $nodes): array
|
||||
{
|
||||
if ($this->newNamespace === null) {
|
||||
return $nodes;
|
||||
}
|
||||
|
||||
$namespace = new Namespace_(new Name($this->newNamespace));
|
||||
foreach ($nodes as $key => $node) {
|
||||
if ($node instanceof Use_ || $node instanceof Class_) {
|
||||
$nodes = $this->classInsertManipulator->insertBefore($nodes, $namespace, $key);
|
||||
|
||||
break;
|
||||
return $namespace;
|
||||
}
|
||||
}
|
||||
|
||||
$this->newNamespace = null;
|
||||
if ($node instanceof Namespace_) {
|
||||
$this->refactorStmts([$node]);
|
||||
return $node;
|
||||
}
|
||||
|
||||
return $nodes;
|
||||
return null;
|
||||
}
|
||||
|
||||
public function configure(array $configuration): void
|
||||
{
|
||||
$namespacePrefixesWithExcludedClasses = $configuration[self::NAMESPACE_PREFIXES_WITH_EXCLUDED_CLASSES] ?? [];
|
||||
Assert::allIsInstanceOf($namespacePrefixesWithExcludedClasses, PseudoNamespaceToNamespace::class);
|
||||
$this->namespacePrefixesWithExcludedClasses = $namespacePrefixesWithExcludedClasses;
|
||||
|
||||
$this->pseudoNamespacesToNamespaces = $namespacePrefixesWithExcludedClasses;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Node[] $nodes
|
||||
* @return Node[]
|
||||
*/
|
||||
private function refactorStmts(array $nodes): array
|
||||
{
|
||||
$this->traverseNodesWithCallable($nodes, function (Node $node): ?Node {
|
||||
if (! $this->isInstancesOf($node, [Name::class, Identifier::class, Property::class, FunctionLike::class])) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// replace on @var/@param/@return/@throws
|
||||
foreach ($this->pseudoNamespacesToNamespaces as $namespacePrefixWithExcludedClasses) {
|
||||
$this->phpDocTypeRenamer->changeUnderscoreType($node, $namespacePrefixWithExcludedClasses);
|
||||
}
|
||||
|
||||
if ($node instanceof Name || $node instanceof Identifier) {
|
||||
return $this->processNameOrIdentifier($node);
|
||||
}
|
||||
|
||||
return null;
|
||||
});
|
||||
|
||||
return $nodes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param class-string[] $types
|
||||
*/
|
||||
private function isInstancesOf(Node $node, array $types): bool
|
||||
{
|
||||
foreach ($types as $type) {
|
||||
if (is_a($node, $type, true)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -163,12 +180,12 @@ CODE_SAMPLE
|
|||
return null;
|
||||
}
|
||||
|
||||
foreach ($this->namespacePrefixesWithExcludedClasses as $namespacePrefixWithExcludedClasses) {
|
||||
if (! $this->isName($node, $namespacePrefixWithExcludedClasses->getNamespacePrefix() . '*')) {
|
||||
foreach ($this->pseudoNamespacesToNamespaces as $pseudoNamespacesToNamespace) {
|
||||
if (! $this->isName($node, $pseudoNamespacesToNamespace->getNamespacePrefix() . '*')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$excludedClasses = $namespacePrefixWithExcludedClasses->getExcludedClasses();
|
||||
$excludedClasses = $pseudoNamespacesToNamespace->getExcludedClasses();
|
||||
if (is_array($excludedClasses) && $this->isNames($node, $excludedClasses)) {
|
||||
return null;
|
||||
}
|
|
@ -13,6 +13,7 @@ use PhpParser\Node\Stmt\Namespace_;
|
|||
use PhpParser\Node\Stmt\Property;
|
||||
use Rector\Core\Configuration\ChangeConfiguration;
|
||||
use Rector\Core\Contract\Rector\ConfigurableRectorInterface;
|
||||
use Rector\Core\PhpParser\Node\CustomNode\FileWithoutNamespace;
|
||||
use Rector\Core\Rector\AbstractRector;
|
||||
use Rector\Core\RectorDefinition\ConfiguredCodeSample;
|
||||
use Rector\Core\RectorDefinition\RectorDefinition;
|
||||
|
@ -100,6 +101,7 @@ CODE_SAMPLE
|
|||
Expression::class,
|
||||
ClassLike::class,
|
||||
Namespace_::class,
|
||||
FileWithoutNamespace::class,
|
||||
];
|
||||
}
|
||||
|
||||
|
|
|
@ -21,3 +21,5 @@ class Abc
|
|||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -17,7 +17,6 @@ class Rector_Generic_Tests_Rector_Name_PseudoNamespaceToNamespaceRector_Fixture_
|
|||
namespace Rector\Generic\Tests\Rector\Name\PseudoNamespaceToNamespaceRector\Fixture;
|
||||
|
||||
use Rector\Generic\Tests\Rector\Name\PseudoNamespaceToNamespaceRector\Source\Keep_This;
|
||||
|
||||
class UseStatement
|
||||
{
|
||||
public function run()
|
||||
|
@ -25,5 +24,3 @@ class UseStatement
|
|||
return new Keep_This;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -2,12 +2,12 @@
|
|||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Generic\Tests\Rector\Name\PseudoNamespaceToNamespaceRector;
|
||||
namespace Rector\Renaming\Tests\Rector\FileWithoutNamespace\PseudoNamespaceToNamespaceRector;
|
||||
|
||||
use Iterator;
|
||||
use Rector\Core\Testing\PHPUnit\AbstractRectorTestCase;
|
||||
use Rector\Generic\Rector\Name\PseudoNamespaceToNamespaceRector;
|
||||
use Rector\Generic\ValueObject\PseudoNamespaceToNamespace;
|
||||
use Rector\Renaming\Rector\FileWithoutNamespace\PseudoNamespaceToNamespaceRector;
|
||||
use Symplify\SmartFileSystem\SmartFileInfo;
|
||||
|
||||
final class PseudoNamespaceToNamespaceRectorTest extends AbstractRectorTestCase
|
|
@ -0,0 +1,10 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Renaming\Tests\Rector\FileWithoutNamespace\PseudoNamespaceToNamespaceRector\Source;
|
||||
|
||||
final class Keep_This
|
||||
{
|
||||
|
||||
}
|
|
@ -1,7 +1,5 @@
|
|||
<?php
|
||||
|
||||
namespace Rector\TypeDeclaration\Tests\Rector\ClassMethod\ParamTypeDeclarationRector\Fixture\PhpCsFixerParam\TypehintAlreadyDefinedWithWrongPhpdocTypehint;
|
||||
|
||||
namespace Rector\TypeDeclaration\Tests\Rector\ClassMethod\ParamTypeDeclarationRector\Fixture\PhpCsFixerParam\Php72;
|
||||
|
||||
/** @param object $foo */ function my_foo($foo) {}
|
||||
|
@ -11,8 +9,6 @@ namespace Rector\TypeDeclaration\Tests\Rector\ClassMethod\ParamTypeDeclarationRe
|
|||
-----
|
||||
<?php
|
||||
|
||||
namespace Rector\TypeDeclaration\Tests\Rector\ClassMethod\ParamTypeDeclarationRector\Fixture\PhpCsFixerParam\TypehintAlreadyDefinedWithWrongPhpdocTypehint;
|
||||
|
||||
namespace Rector\TypeDeclaration\Tests\Rector\ClassMethod\ParamTypeDeclarationRector\Fixture\PhpCsFixerParam\Php72;
|
||||
|
||||
/** @param object $foo */ function my_foo(object $foo) {}
|
||||
|
|
|
@ -1,11 +1,19 @@
|
|||
<?php
|
||||
|
||||
/** @return mixed */
|
||||
function test222($value) {
|
||||
return $value;
|
||||
}
|
||||
namespace Rector\TypeDeclaration\Tests\Rector\FunctionLike\ReturnTypeDeclarationRector\Fixture\nikic;
|
||||
|
||||
/** @return static */
|
||||
function test333($value) {
|
||||
return $value;
|
||||
class SkipMixedAndStaticOverFunction
|
||||
{
|
||||
public function run(): void
|
||||
{
|
||||
/** @return mixed */
|
||||
function test222($value) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
/** @return static */
|
||||
function test333($value) {
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
50
src/PhpParser/Node/CustomNode/FileWithoutNamespace.php
Normal file
50
src/PhpParser/Node/CustomNode/FileWithoutNamespace.php
Normal file
|
@ -0,0 +1,50 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Core\PhpParser\Node\CustomNode;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\NodeAbstract;
|
||||
|
||||
/**
|
||||
* Inspired by https://github.com/phpstan/phpstan-src/commit/ed81c3ad0b9877e6122c79b4afda9d10f3994092
|
||||
*/
|
||||
final class FileWithoutNamespace extends NodeAbstract
|
||||
{
|
||||
/**
|
||||
* @var Node[]
|
||||
*/
|
||||
public $stmts = [];
|
||||
|
||||
/**
|
||||
* @param Node[] $stmts
|
||||
*/
|
||||
public function __construct(array $stmts)
|
||||
{
|
||||
$this->stmts = $stmts;
|
||||
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
public function getType(): string
|
||||
{
|
||||
return 'FileWithoutNamespace';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
public function getSubNodeNames(): array
|
||||
{
|
||||
return ['stmts'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Node[]
|
||||
*/
|
||||
public function getStmts(): array
|
||||
{
|
||||
return $this->stmts;
|
||||
}
|
||||
}
|
|
@ -35,6 +35,8 @@ use PhpParser\Node\Stmt\ClassConst;
|
|||
use PhpParser\Node\Stmt\ClassMethod;
|
||||
use PhpParser\Node\Stmt\Property;
|
||||
use PhpParser\Node\Stmt\Return_;
|
||||
use PhpParser\Node\Stmt\Use_;
|
||||
use PhpParser\Node\Stmt\UseUse;
|
||||
use PhpParser\Node\UnionType;
|
||||
use PHPStan\Type\Generic\GenericObjectType;
|
||||
use PHPStan\Type\MixedType;
|
||||
|
@ -407,6 +409,21 @@ final class NodeFactory
|
|||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string[] $names
|
||||
* @return Use_[]
|
||||
*/
|
||||
public function createUsesFromNames(array $names): array
|
||||
{
|
||||
$uses = [];
|
||||
foreach ($names as $resolvedName) {
|
||||
$useUse = new UseUse(new Name($resolvedName));
|
||||
$uses[] = new Use_([$useUse]);
|
||||
}
|
||||
|
||||
return $uses;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $item
|
||||
* @param string|int|null $key
|
||||
|
|
|
@ -5,6 +5,8 @@ declare(strict_types=1);
|
|||
namespace Rector\Core\PhpParser\NodeTraverser;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Stmt\Namespace_;
|
||||
use PhpParser\NodeFinder;
|
||||
use PhpParser\NodeTraverser;
|
||||
use Rector\Caching\Contract\Rector\ZeroCacheRectorInterface;
|
||||
use Rector\Core\Application\ActiveRectorsProvider;
|
||||
|
@ -12,8 +14,11 @@ use Rector\Core\Configuration\Configuration;
|
|||
use Rector\Core\Contract\Rector\ConfigurableRectorInterface;
|
||||
use Rector\Core\Contract\Rector\PhpRectorInterface;
|
||||
use Rector\Core\Exception\ShouldNotHappenException;
|
||||
use Rector\Core\PhpParser\Node\CustomNode\FileWithoutNamespace;
|
||||
use Rector\Core\Testing\Application\EnabledRectorsProvider;
|
||||
use Rector\Core\Testing\PHPUnit\StaticPHPUnitEnvironment;
|
||||
use Rector\NodeTypeResolver\FileSystem\CurrentFileInfoProvider;
|
||||
use Rector\NodeTypeResolver\Node\AttributeKey;
|
||||
|
||||
final class RectorNodeTraverser extends NodeTraverser
|
||||
{
|
||||
|
@ -27,10 +32,22 @@ final class RectorNodeTraverser extends NodeTraverser
|
|||
*/
|
||||
private $enabledRectorsProvider;
|
||||
|
||||
/**
|
||||
* @var NodeFinder
|
||||
*/
|
||||
private $nodeFinder;
|
||||
|
||||
/**
|
||||
* @var CurrentFileInfoProvider
|
||||
*/
|
||||
private $currentFileInfoProvider;
|
||||
|
||||
public function __construct(
|
||||
EnabledRectorsProvider $enabledRectorsProvider,
|
||||
Configuration $configuration,
|
||||
ActiveRectorsProvider $activeRectorsProvider
|
||||
ActiveRectorsProvider $activeRectorsProvider,
|
||||
NodeFinder $nodeFinder,
|
||||
CurrentFileInfoProvider $currentFileInfoProvider
|
||||
) {
|
||||
/** @var PhpRectorInterface[] $phpRectors */
|
||||
$phpRectors = $activeRectorsProvider->provideByType(PhpRectorInterface::class);
|
||||
|
@ -45,6 +62,9 @@ final class RectorNodeTraverser extends NodeTraverser
|
|||
|
||||
$this->addVisitor($phpRector);
|
||||
}
|
||||
|
||||
$this->nodeFinder = $nodeFinder;
|
||||
$this->currentFileInfoProvider = $currentFileInfoProvider;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -57,6 +77,16 @@ final class RectorNodeTraverser extends NodeTraverser
|
|||
$this->configureEnabledRectorsOnly();
|
||||
}
|
||||
|
||||
$hasNamespace = (bool) $this->nodeFinder->findFirstInstanceOf($nodes, Namespace_::class);
|
||||
if (! $hasNamespace) {
|
||||
$fileWithoutNamespace = new FileWithoutNamespace($nodes);
|
||||
$fileWithoutNamespace->setAttribute(
|
||||
AttributeKey::FILE_INFO,
|
||||
$this->currentFileInfoProvider->getSmartFileInfo()
|
||||
);
|
||||
return parent::traverse([$fileWithoutNamespace]);
|
||||
}
|
||||
|
||||
return parent::traverse($nodes);
|
||||
}
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@ use PhpParser\Node\Stmt\Nop;
|
|||
use PhpParser\Node\Stmt\TraitUse;
|
||||
use PhpParser\Node\Stmt\Use_;
|
||||
use PhpParser\PrettyPrinter\Standard;
|
||||
use Rector\Core\PhpParser\Node\CustomNode\FileWithoutNamespace;
|
||||
use Rector\NodeTypeResolver\Node\AttributeKey;
|
||||
use Rector\NodeTypeResolver\PhpDoc\NodeAnalyzer\DocBlockManipulator;
|
||||
use Symplify\SmartFileSystem\SmartFileInfo;
|
||||
|
@ -115,10 +116,12 @@ final class BetterStandardPrinter extends Standard
|
|||
|
||||
public function printFormatPreserving(array $stmts, array $origStmts, array $origTokens): string
|
||||
{
|
||||
// detect per print
|
||||
$this->detectTabOrSpaceIndentCharacter($stmts);
|
||||
$newStmts = $this->resolveNewStmts($stmts);
|
||||
|
||||
$content = parent::printFormatPreserving($stmts, $origStmts, $origTokens);
|
||||
// detect per print
|
||||
$this->detectTabOrSpaceIndentCharacter($newStmts);
|
||||
|
||||
$content = parent::printFormatPreserving($newStmts, $origStmts, $origTokens);
|
||||
|
||||
// add new line in case of added stmts
|
||||
if (count($stmts) !== count($origStmts) && ! (bool) Strings::match($content, self::NEWLINE_END_REGEX)) {
|
||||
|
@ -189,6 +192,13 @@ final class BetterStandardPrinter extends Standard
|
|||
return parent::prettyPrintFile($stmts) . PHP_EOL;
|
||||
}
|
||||
|
||||
public function pFileWithoutNamespace(FileWithoutNamespace $fileWithoutNamespace): string
|
||||
{
|
||||
$content = self::pStmts((array) $fileWithoutNamespace->stmts, false);
|
||||
|
||||
return ltrim($content);
|
||||
}
|
||||
|
||||
/**
|
||||
* This allows to use both spaces and tabs vs. original space-only
|
||||
*/
|
||||
|
@ -424,6 +434,21 @@ final class BetterStandardPrinter extends Standard
|
|||
return parent::pStmt_Use($use);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Node[]|mixed[]
|
||||
*/
|
||||
private function resolveNewStmts(array $stmts): array
|
||||
{
|
||||
if (count($stmts) === 1) {
|
||||
$onlyStmt = $stmts[0];
|
||||
if ($onlyStmt instanceof FileWithoutNamespace) {
|
||||
return $onlyStmt->stmts;
|
||||
}
|
||||
}
|
||||
|
||||
return $stmts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Solves https://github.com/rectorphp/rector/issues/1964
|
||||
*
|
||||
|
|
|
@ -5,6 +5,7 @@ declare(strict_types=1);
|
|||
namespace Rector\Core\PhpParser\Printer;
|
||||
|
||||
use PhpParser\Node;
|
||||
use Rector\Core\PhpParser\Node\CustomNode\FileWithoutNamespace;
|
||||
use Rector\Core\ValueObject\Application\ParsedStmtsAndTokens;
|
||||
use Symplify\SmartFileSystem\SmartFileInfo;
|
||||
use Symplify\SmartFileSystem\SmartFileSystem;
|
||||
|
@ -57,8 +58,13 @@ final class FormatPerservingPrinter
|
|||
|
||||
public function printParsedStmstAndTokensToString(ParsedStmtsAndTokens $parsedStmtsAndTokens): string
|
||||
{
|
||||
return $this->betterStandardPrinter->printFormatPreserving($parsedStmtsAndTokens->getNewStmts(),
|
||||
$parsedStmtsAndTokens->getOldStmts(), $parsedStmtsAndTokens->getOldTokens());
|
||||
$newStmts = $this->resolveNewStmts($parsedStmtsAndTokens);
|
||||
|
||||
return $this->betterStandardPrinter->printFormatPreserving(
|
||||
$newStmts,
|
||||
$parsedStmtsAndTokens->getOldStmts(),
|
||||
$parsedStmtsAndTokens->getOldTokens()
|
||||
);
|
||||
}
|
||||
|
||||
public function printParsedStmstAndTokens(
|
||||
|
@ -72,4 +78,19 @@ final class FormatPerservingPrinter
|
|||
$parsedStmtsAndTokens->getOldTokens()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Node[]
|
||||
*/
|
||||
private function resolveNewStmts(ParsedStmtsAndTokens $parsedStmtsAndTokens): array
|
||||
{
|
||||
if (count($parsedStmtsAndTokens->getNewStmts()) === 1) {
|
||||
$onlyStmt = $parsedStmtsAndTokens->getNewStmts()[0];
|
||||
if ($onlyStmt instanceof FileWithoutNamespace) {
|
||||
return $onlyStmt->stmts;
|
||||
}
|
||||
}
|
||||
|
||||
return $parsedStmtsAndTokens->getNewStmts();
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user