Fix parent interface, extends, implements same name as short name

This commit is contained in:
TomasVotruba 2019-11-14 17:48:46 +01:00
parent 9b99212da9
commit 8d4ec5152b
12 changed files with 137 additions and 6 deletions

View File

@ -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",

View File

@ -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
<br>
### `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);
}
}
```
<br>
### `SimplifyForeachInstanceOfRector`
- class: `Rector\PHPUnit\Rector\Foreach_\SimplifyForeachInstanceOfRector`

View File

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

View File

@ -6,7 +6,12 @@ namespace Rector\CodingStyle\Imports;
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 @@ final class ImportSkipper
return true;
}
if ($this->isClassExtendsShortNameSameAsClassName($node, $fullyQualifiedObjectType)) {
return true;
}
return ! $this->useAddingCommander->canImportBeAdded($node, $fullyQualifiedObjectType);
}
@ -83,4 +99,54 @@ final class ImportSkipper
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;
}
}

View File

@ -5,6 +5,7 @@ declare(strict_types=1);
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 @@ final class ClassNaming
}
/**
* @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();

View File

@ -69,7 +69,7 @@ final class AddDoesNotPerformAssertionToNonAssertingTestRector extends AbstractP
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

View File

@ -11,6 +11,9 @@ use Rector\Renaming\Tests\Rector\Class_\RenameClassRector\Source\NewClass;
use Rector\Renaming\Tests\Rector\Class_\RenameClassRector\Source\OldClass;
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
/**
* @see \Rector\CodingStyle\Application\NameImportingCommander
*/
final class AutoImportNamesParameterTest extends AbstractRectorTestCase
{
/**

View File

@ -0,0 +1,7 @@
<?php
namespace Rector\Renaming\Tests\Rector\Class_\RenameClassRector\Fixture\AutoImportNamesParameter;
class ClassImportingSameName implements \ClassImportingSameName
{
}

View File

@ -0,0 +1,7 @@
<?php
namespace Rector\Renaming\Tests\Rector\Class_\RenameClassRector\Fixture\AutoImportNamesParameter;
interface SomeInterface extends \SomeInterface
{
}

View File

@ -0,0 +1,8 @@
<?php
declare(strict_types=1);
interface ClassImportingSameName
{
}

View File

@ -0,0 +1,8 @@
<?php
declare(strict_types=1);
interface SomeInterface
{
}

View File

@ -221,3 +221,6 @@ parameters:
# test
- '#Class Rector\\DynamicTypeAnalysis\\Tests\\Rector\\ClassMethod\\AddArgumentTypeWithProbeDataRector\\Fixture\\SomeClass not found#'
# known value
- '#Parameter \#1 \$name of method Rector\\CodingStyle\\Naming\\ClassNaming\:\:getShortName\(\) expects PhpParser\\Node\\Identifier\|PhpParser\\Node\\Name\|string, PhpParser\\Node\\Identifier\|null given#'