decouple ControlFactoryInterfaceAnalyzer

This commit is contained in:
TomasVotruba 2020-06-19 15:49:42 +02:00
parent afe189d355
commit f83c6c080e
7 changed files with 110 additions and 71 deletions

View File

@ -23,6 +23,7 @@ parameters:
required_see_types:
- PHPStan\Rules\Rule
- Rector\Core\Rector\AbstractRector
- Rector\FileSystemRector\Rector\AbstractFileSystemRector
# to allow installing with various phsptan versions without reporting old errors here
reportUnmatchedIgnoredErrors: false

View File

@ -5,14 +5,12 @@ declare(strict_types=1);
namespace Rector\Autodiscovery\Rector\FileSystem;
use PhpParser\Node;
use PhpParser\Node\Stmt\ClassLike;
use PhpParser\Node\Stmt\Interface_;
use PHPStan\Type\TypeWithClassName;
use Rector\Autodiscovery\FileMover\FileMover;
use Rector\Core\RectorDefinition\CodeSample;
use Rector\Core\RectorDefinition\RectorDefinition;
use Rector\FileSystemRector\Rector\AbstractFileSystemRector;
use Rector\TypeDeclaration\TypeInferer\ReturnTypeInferer;
use Rector\NetteToSymfony\Analyzer\ControlFactoryInterfaceAnalyzer;
use Symplify\SmartFileSystem\SmartFileInfo;
/**
@ -30,14 +28,14 @@ final class MoveInterfacesToContractNamespaceDirectoryRector extends AbstractFil
private $fileMover;
/**
* @var ReturnTypeInferer
* @var ControlFactoryInterfaceAnalyzer
*/
private $returnTypeInferer;
private $controlFactoryInterfaceAnalyzer;
public function __construct(FileMover $fileMover, ReturnTypeInferer $returnTypeInferer)
public function __construct(FileMover $fileMover, ControlFactoryInterfaceAnalyzer $controlFactoryInterfaceAnalyzer)
{
$this->fileMover = $fileMover;
$this->returnTypeInferer = $returnTypeInferer;
$this->controlFactoryInterfaceAnalyzer = $controlFactoryInterfaceAnalyzer;
}
public function getDefinition(): RectorDefinition
@ -83,7 +81,7 @@ PHP
return;
}
if ($this->isNetteMagicGeneratedFactory($interface)) {
if ($this->controlFactoryInterfaceAnalyzer->isComponentFactoryInterface($interface)) {
return;
}
@ -103,29 +101,4 @@ PHP
$this->printNodesWithFileDestination($nodesWithFileDestination);
}
/**
* @see https://doc.nette.org/en/3.0/components#toc-components-with-dependencies
*/
private function isNetteMagicGeneratedFactory(ClassLike $classLike): bool
{
foreach ($classLike->getMethods() as $classMethod) {
$returnType = $this->returnTypeInferer->inferFunctionLike($classMethod);
if (! $returnType instanceof TypeWithClassName) {
continue;
}
$className = $returnType->getClassName();
if (is_a($className, 'Nette\Application\UI\Control', true)) {
return true;
}
if (is_a($className, 'Nette\Application\UI\Form', true)) {
return true;
}
}
return false;
}
}

View File

@ -0,0 +1,47 @@
<?php
declare(strict_types=1);
namespace Rector\NetteToSymfony\Analyzer;
use PhpParser\Node\Stmt\Interface_;
use PHPStan\Type\TypeWithClassName;
use Rector\TypeDeclaration\TypeInferer\ReturnTypeInferer;
final class ControlFactoryInterfaceAnalyzer
{
/**
* @var ReturnTypeInferer
*/
private $returnTypeInferer;
public function __construct(ReturnTypeInferer $returnTypeInferer)
{
$this->returnTypeInferer = $returnTypeInferer;
}
/**
* @see https://doc.nette.org/en/3.0/components#toc-components-with-dependencies
*/
public function isComponentFactoryInterface(Interface_ $interface): bool
{
foreach ($interface->getMethods() as $classMethod) {
$returnType = $this->returnTypeInferer->inferFunctionLike($classMethod);
if (! $returnType instanceof TypeWithClassName) {
return false;
}
$className = $returnType->getClassName();
if (is_a($className, 'Nette\Application\UI\Control', true)) {
return true;
}
if (is_a($className, 'Nette\Application\UI\Form', true)) {
return true;
}
}
return false;
}
}

View File

@ -4,28 +4,26 @@ declare(strict_types=1);
namespace Rector\NetteToSymfony\Rector\FileSystem;
use Nette\Application\UI\Control;
use PhpParser\Node;
use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Stmt\Interface_;
use PhpParser\NodeTraverser;
use PHPStan\Type\ObjectType;
use Rector\Core\RectorDefinition\CodeSample;
use Rector\Core\RectorDefinition\RectorDefinition;
use Rector\FileSystemRector\Rector\AbstractFileSystemRector;
use Rector\TypeDeclaration\TypeInferer\ReturnTypeInferer;
use Rector\NetteToSymfony\Analyzer\ControlFactoryInterfaceAnalyzer;
use Symplify\SmartFileSystem\SmartFileInfo;
/**
* @see \Rector\NetteToSymfony\Tests\Rector\FIleSystem\DeleteFactoryInterfaceRector\DeleteFactoryInterfaceFileSystemRectorTest
*/
final class DeleteFactoryInterfaceRector extends AbstractFileSystemRector
{
/**
* @var ReturnTypeInferer
* @var ControlFactoryInterfaceAnalyzer
*/
private $returnTypeInferer;
private $controlFactoryInterfaceAnalyzer;
public function __construct(ReturnTypeInferer $returnTypeInferer)
public function __construct(ControlFactoryInterfaceAnalyzer $controlFactoryInterfaceAnalyzer)
{
$this->returnTypeInferer = $returnTypeInferer;
$this->controlFactoryInterfaceAnalyzer = $controlFactoryInterfaceAnalyzer;
}
public function getDefinition(): RectorDefinition
@ -57,37 +55,10 @@ CODE_SAMPLE
return;
}
if (! $this->isComponentFactoryInterface($interface)) {
if (! $this->controlFactoryInterfaceAnalyzer->isComponentFactoryInterface($interface)) {
return;
}
$this->removeFile($smartFileInfo);
}
private function isComponentFactoryInterface(Interface_ $interface): bool
{
$isComponentFactoryInteface = false;
$this->traverseNodesWithCallable($interface->stmts, function (Node $node) use (
&$isComponentFactoryInteface
): int {
if (! $node instanceof ClassMethod) {
return NodeTraverser::STOP_TRAVERSAL;
}
$returnType = $this->returnTypeInferer->inferFunctionLike($node);
if (! $returnType instanceof ObjectType) {
return NodeTraverser::STOP_TRAVERSAL;
}
if (! is_a($returnType->getClassName(), Control::class, true)) {
return NodeTraverser::STOP_TRAVERSAL;
}
$isComponentFactoryInteface = true;
return NodeTraverser::STOP_TRAVERSAL;
});
return $isComponentFactoryInteface;
}
}

View File

@ -0,0 +1,22 @@
<?php
declare(strict_types=1);
namespace Rector\NetteToSymfony\Tests\Rector\FIleSystem\DeleteFactoryInterfaceRector;
use Rector\Core\Testing\PHPUnit\AbstractFileSystemRectorTestCase;
use Rector\NetteToSymfony\Rector\FileSystem\DeleteFactoryInterfaceRector;
final class DeleteFactoryInterfaceFileSystemRectorTest extends AbstractFileSystemRectorTestCase
{
public function test(): void
{
$this->doTestFile(__DIR__ . '/Source/SomeFactoryInterface.php');
$this->assertFileDoesNotExist($this->getFixtureTempDirectory() . '/Source/SomeFactoryInterface.php');
}
protected function getRectorClass(): string
{
return DeleteFactoryInterfaceRector::class;
}
}

View File

@ -0,0 +1,12 @@
<?php
declare(strict_types=1);
namespace Rector\NetteToSymfony\Tests\Rector\FIleSystem\DeleteFactoryInterfaceRector\Source;
use Nette\Application\UI\Control;
final class SomeControl extends Control
{
}

View File

@ -0,0 +1,13 @@
<?php
declare(strict_types=1);
namespace Rector\NetteToSymfony\Tests\Rector\FIleSystem\DeleteFactoryInterfaceRector\Source;
interface SomeFactoryInterface
{
/**
* @return SomeControl
*/
public function create();
}