diff --git a/composer.json b/composer.json index 327ad070a59d..67663b83c66f 100644 --- a/composer.json +++ b/composer.json @@ -172,6 +172,8 @@ "files": [ "packages/DeadCode/tests/Rector/MethodCall/RemoveDefaultArgumentValueRector/Source/UserDefined.php", "packages/TypeDeclaration/tests/Rector/Property/CompleteVarDocTypePropertyRector/Source/EventDispatcher.php", + "packages/Renaming/tests/Rector/Class_/RenameClassRector/Source/SomeInterface.php", + "packages/Renaming/tests/Rector/Class_/RenameClassRector/Source/ClassImportingSameName.php", "tests/Rector/Namespace_/PseudoNamespaceToNamespaceRector/Source/ChangeMeAnotherNamespace.php", "packages/TypeDeclaration/tests/Rector/FunctionLike/ReturnTypeDeclarationRector/Source/MyBar.php", "packages/Renaming/tests/Rector/Class_/RenameClassRector/Source/Twig_Extension_Sandbox.php", diff --git a/docs/AllRectorsOverview.md b/docs/AllRectorsOverview.md index 0b9d35b821e7..f026ac8d3ac1 100644 --- a/docs/AllRectorsOverview.md +++ b/docs/AllRectorsOverview.md @@ -1,4 +1,4 @@ -# All 390 Rectors Overview +# All 391 Rectors Overview - [Projects](#projects) - [General](#general) @@ -3425,7 +3425,7 @@ Removes non-existing @var annotations above the code - class: `Rector\PHPUnit\Rector\ClassMethod\AddDoesNotPerformAssertionToNonAssertingTestRector` -Tests without assertion will have @doesNotPerformAssertion +Tests without assertion will have @doesNotPerformAssertion ```diff class SomeClass extends PHPUnit\Framework\TestCase @@ -3917,6 +3917,30 @@ Replace deprecated "assertArraySubset()" method with alternative methods
+### `ReplaceAssertArraySubsetWithDmsPolyfillRector` + +- class: `Rector\PHPUnit\Rector\MethodCall\ReplaceAssertArraySubsetWithDmsPolyfillRector` + +Change assertArraySubset() to static call of DMS\PHPUnitExtensions\ArraySubset\Assert + +```diff + use PHPUnit\Framework\TestCase; + + class SomeClass extends TestCase + { + public function test() + { +- self::assertArraySubset(['bar' => 0], ['bar' => '0'], true); ++ \DMS\PHPUnitExtensions\ArraySubset\Assert::assertArraySubset(['bar' => 0], ['bar' => '0'], true); + +- $this->assertArraySubset(['bar' => 0], ['bar' => '0'], true); ++ \DMS\PHPUnitExtensions\ArraySubset\Assert::assertArraySubset(['bar' => 0], ['bar' => '0'], true); + } + } +``` + +
+ ### `SimplifyForeachInstanceOfRector` - class: `Rector\PHPUnit\Rector\Foreach_\SimplifyForeachInstanceOfRector` diff --git a/ecs.yaml b/ecs.yaml index a90df52653e3..00299c28b578 100644 --- a/ecs.yaml +++ b/ecs.yaml @@ -13,6 +13,7 @@ services: - 'Exception' - 'ResourceBundle' - 'SimpleXMLElement' + - 'SomeInterface' Symplify\CodingStandard\Sniffs\CleanCode\CognitiveComplexitySniff: max_cognitive_complexity: 9 @@ -109,6 +110,7 @@ parameters: - 'packages/Php71/src/Rector/FuncCall/RemoveExtraParametersRector.php' - 'packages/SOLID/src/Analyzer/ClassConstantFetchAnalyzer.php' # tough logic + - 'packages/CodingStyle/src/Imports/ImportSkipper.php' - 'packages/PHPUnit/src/Rector/Class_/ArrayArgumentInTestToDataProviderRector.php' - 'packages/BetterPhpDocParser/src/Ast/PhpDoc/*/*TagValueNode.php' - 'packages/NodeTypeResolver/src/PhpDoc/NodeAnalyzer/FqnNamePhpDocNodeDecorator.php' diff --git a/packages/CodingStyle/src/Imports/ImportSkipper.php b/packages/CodingStyle/src/Imports/ImportSkipper.php index 8c52b5069ea7..0b57654abbb3 100644 --- a/packages/CodingStyle/src/Imports/ImportSkipper.php +++ b/packages/CodingStyle/src/Imports/ImportSkipper.php @@ -6,7 +6,12 @@ use Nette\Utils\Strings; use PhpParser\Node; +use PhpParser\Node\Stmt\Class_; +use PhpParser\Node\Stmt\ClassLike; +use PhpParser\Node\Stmt\Interface_; use Rector\CodingStyle\Application\UseAddingCommander; +use Rector\CodingStyle\Naming\ClassNaming; +use Rector\NodeTypeResolver\Node\AttributeKey; use Rector\PHPStan\Type\FullyQualifiedObjectType; final class ImportSkipper @@ -26,14 +31,21 @@ final class ImportSkipper */ private $shortNameResolver; + /** + * @var ClassNaming + */ + private $classNaming; + public function __construct( UseAddingCommander $useAddingCommander, AliasUsesResolver $aliasUsesResolver, - ShortNameResolver $shortNameResolver + ShortNameResolver $shortNameResolver, + ClassNaming $classNaming ) { $this->useAddingCommander = $useAddingCommander; $this->aliasUsesResolver = $aliasUsesResolver; $this->shortNameResolver = $shortNameResolver; + $this->classNaming = $classNaming; } public function shouldSkipNameForFullyQualifiedObjectType( @@ -48,6 +60,10 @@ public function shouldSkipNameForFullyQualifiedObjectType( return true; } + if ($this->isClassExtendsShortNameSameAsClassName($node, $fullyQualifiedObjectType)) { + return true; + } + return ! $this->useAddingCommander->canImportBeAdded($node, $fullyQualifiedObjectType); } @@ -83,4 +99,54 @@ private function isShortNameAlreadyUsedInImportAlias( return false; } + + private function isClassExtendsShortNameSameAsClassName( + Node $node, + FullyQualifiedObjectType $fullyQualifiedObjectType + ): bool { + /** @var ClassLike|null $classLike */ + $classLike = $node->getAttribute(AttributeKey::CLASS_NODE); + if (! $classLike instanceof Class_ && ! $classLike instanceof Interface_) { + return false; + } + + $parentNode = $node->getAttribute(AttributeKey::PARENT_NODE); + if ($parentNode instanceof Class_) { + if ($parentNode->extends === $node) { + // are classLike and extends short name the same? + return $this->isClassLikeShortNameAndShortNameTypeEqual($fullyQualifiedObjectType, $classLike); + } + + foreach ($parentNode->implements as $implement) { + if ($implement !== $node) { + continue; + } + + return $this->isClassLikeShortNameAndShortNameTypeEqual($fullyQualifiedObjectType, $classLike); + } + } + + if ($parentNode instanceof Interface_) { + foreach ($parentNode->extends as $extend) { + if ($extend !== $node) { + continue; + } + + return $this->isClassLikeShortNameAndShortNameTypeEqual($fullyQualifiedObjectType, $classLike); + } + } + + return false; + } + + private function isClassLikeShortNameAndShortNameTypeEqual( + FullyQualifiedObjectType $fullyQualifiedObjectType, + ClassLike $classLike + ): bool { + $shortClassName = $this->classNaming->getShortName($classLike->name); + + $extendsShortName = $fullyQualifiedObjectType->getShortName(); + + return $shortClassName === $extendsShortName; + } } diff --git a/packages/CodingStyle/src/Naming/ClassNaming.php b/packages/CodingStyle/src/Naming/ClassNaming.php index 91ab79a0d822..8349cc3e7eb0 100644 --- a/packages/CodingStyle/src/Naming/ClassNaming.php +++ b/packages/CodingStyle/src/Naming/ClassNaming.php @@ -5,6 +5,7 @@ namespace Rector\CodingStyle\Naming; use Nette\Utils\Strings; +use PhpParser\Node\Identifier; use PhpParser\Node\Name; use Rector\Exception\ShouldNotHappenException; use Rector\PhpParser\Node\Resolver\NameResolver; @@ -22,12 +23,12 @@ public function __construct(NameResolver $nameResolver) } /** - * @param string|Name $name + * @param string|Name|Identifier $name * @return string */ public function getShortName($name): string { - if ($name instanceof Name) { + if ($name instanceof Name || $name instanceof Identifier) { $name = $this->nameResolver->getName($name); if ($name === null) { throw new ShouldNotHappenException(); diff --git a/packages/PHPUnit/src/Rector/ClassMethod/AddDoesNotPerformAssertionToNonAssertingTestRector.php b/packages/PHPUnit/src/Rector/ClassMethod/AddDoesNotPerformAssertionToNonAssertingTestRector.php index 28e28b5ce804..c2fa29bda220 100644 --- a/packages/PHPUnit/src/Rector/ClassMethod/AddDoesNotPerformAssertionToNonAssertingTestRector.php +++ b/packages/PHPUnit/src/Rector/ClassMethod/AddDoesNotPerformAssertionToNonAssertingTestRector.php @@ -69,7 +69,7 @@ public function __construct( public function getDefinition(): RectorDefinition { - return new RectorDefinition('Tests without assertion will have @doesNotPerformAssertion ', [ + return new RectorDefinition('Tests without assertion will have @doesNotPerformAssertion', [ new CodeSample( <<<'PHP' class SomeClass extends PHPUnit\Framework\TestCase diff --git a/packages/Renaming/tests/Rector/Class_/RenameClassRector/AutoImportNamesParameterTest.php b/packages/Renaming/tests/Rector/Class_/RenameClassRector/AutoImportNamesParameterTest.php index d9019feb3185..ea9340df3d1a 100644 --- a/packages/Renaming/tests/Rector/Class_/RenameClassRector/AutoImportNamesParameterTest.php +++ b/packages/Renaming/tests/Rector/Class_/RenameClassRector/AutoImportNamesParameterTest.php @@ -11,6 +11,9 @@ use Rector\Renaming\Tests\Rector\Class_\RenameClassRector\Source\OldClass; use Rector\Testing\PHPUnit\AbstractRectorTestCase; +/** + * @see \Rector\CodingStyle\Application\NameImportingCommander + */ final class AutoImportNamesParameterTest extends AbstractRectorTestCase { /** diff --git a/packages/Renaming/tests/Rector/Class_/RenameClassRector/FixtureAutoImportNames/class_importing_same_name.php.inc b/packages/Renaming/tests/Rector/Class_/RenameClassRector/FixtureAutoImportNames/class_importing_same_name.php.inc new file mode 100644 index 000000000000..4c094c10e884 --- /dev/null +++ b/packages/Renaming/tests/Rector/Class_/RenameClassRector/FixtureAutoImportNames/class_importing_same_name.php.inc @@ -0,0 +1,7 @@ +