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 @@
+