diff --git a/packages/NodeTypeResolver/src/PhpDoc/NodeAnalyzer/DocBlockAnalyzer.php b/packages/NodeTypeResolver/src/PhpDoc/NodeAnalyzer/DocBlockAnalyzer.php index cead6cc08bd..e9b9348c868 100644 --- a/packages/NodeTypeResolver/src/PhpDoc/NodeAnalyzer/DocBlockAnalyzer.php +++ b/packages/NodeTypeResolver/src/PhpDoc/NodeAnalyzer/DocBlockAnalyzer.php @@ -46,8 +46,6 @@ final class DocBlockAnalyzer } return Strings::contains($node->getDocComment()->getText(), '@' . $name); -// $phpDocInfo = $this->createPhpDocInfoFromNode($node); -// return $phpDocInfo->hasTag($name); } public function removeParamTagByName(Node $node, string $name): void diff --git a/packages/PHPUnit/tests/Rector/ExceptionAnnotationRector/ExceptionAnnotationRectorTest.php b/packages/PHPUnit/tests/Rector/ExceptionAnnotationRector/ExceptionAnnotationRectorTest.php index a438194e307..cd3db435098 100644 --- a/packages/PHPUnit/tests/Rector/ExceptionAnnotationRector/ExceptionAnnotationRectorTest.php +++ b/packages/PHPUnit/tests/Rector/ExceptionAnnotationRector/ExceptionAnnotationRectorTest.php @@ -20,9 +20,9 @@ final class ExceptionAnnotationRectorTest extends AbstractRectorTestCase public function provideWrongToFixedFiles(): Iterator { -// yield [__DIR__ . '/Wrong/wrong.php.inc', __DIR__ . '/Correct/correct.php.inc']; -// yield [__DIR__ . '/Wrong/wrong2.php.inc', __DIR__ . '/Correct/correct2.php.inc']; -// yield [__DIR__ . '/Wrong/wrong3.php.inc', __DIR__ . '/Correct/correct3.php.inc']; + yield [__DIR__ . '/Wrong/wrong.php.inc', __DIR__ . '/Correct/correct.php.inc']; + yield [__DIR__ . '/Wrong/wrong2.php.inc', __DIR__ . '/Correct/correct2.php.inc']; + yield [__DIR__ . '/Wrong/wrong3.php.inc', __DIR__ . '/Correct/correct3.php.inc']; yield [__DIR__ . '/Wrong/wrong4.php.inc', __DIR__ . '/Correct/correct4.php.inc']; } diff --git a/packages/Symfony/src/Rector/Form/Helper/FormTypeStringToTypeProvider.php b/packages/Symfony/src/Rector/Form/Helper/FormTypeStringToTypeProvider.php index 60c3cd6c0b3..70d4cb01e5c 100644 --- a/packages/Symfony/src/Rector/Form/Helper/FormTypeStringToTypeProvider.php +++ b/packages/Symfony/src/Rector/Form/Helper/FormTypeStringToTypeProvider.php @@ -45,6 +45,10 @@ final class FormTypeStringToTypeProvider public function hasClassForNameWithPrefix(string $name): bool { + if (! Strings::startsWith($name, 'form.type.')) { + return false; + } + $name = $this->removeFormTypePrefix($name); return $this->hasClassForName($name); diff --git a/packages/Symfony/src/Rector/Form/StringFormTypeToClassRector.php b/packages/Symfony/src/Rector/Form/StringFormTypeToClassRector.php index 37fe90aa81b..c38cf73da5f 100644 --- a/packages/Symfony/src/Rector/Form/StringFormTypeToClassRector.php +++ b/packages/Symfony/src/Rector/Form/StringFormTypeToClassRector.php @@ -3,9 +3,10 @@ namespace Rector\Symfony\Rector\Form; use PhpParser\Node; +use PhpParser\Node\Expr\MethodCall; use PhpParser\Node\Scalar\String_; use Rector\Node\NodeFactory; -use Rector\NodeTypeResolver\Node\Attribute; +use Rector\NodeAnalyzer\MethodCallAnalyzer; use Rector\Rector\AbstractRector; use Rector\RectorDefinition\CodeSample; use Rector\RectorDefinition\RectorDefinition; @@ -26,9 +27,25 @@ final class StringFormTypeToClassRector extends AbstractRector */ private $formTypeStringToTypeProvider; - public function __construct(NodeFactory $nodeFactory, FormTypeStringToTypeProvider $formTypeStringToTypeProvider) - { + /** + * @var string + */ + private $formBuilderClass; + + /** + * @var MethodCallAnalyzer + */ + private $methodCallAnalyzer; + + public function __construct( + NodeFactory $nodeFactory, + FormTypeStringToTypeProvider $formTypeStringToTypeProvider, + MethodCallAnalyzer $methodCallAnalyzer, + string $formBuilderClass = 'Symfony\Component\Form\FormBuilderInterface' + ) { $this->nodeFactory = $nodeFactory; + $this->formBuilderClass = $formBuilderClass; + $this->methodCallAnalyzer = $methodCallAnalyzer; $this->formTypeStringToTypeProvider = $formTypeStringToTypeProvider; } @@ -41,8 +58,15 @@ final class StringFormTypeToClassRector extends AbstractRector 'Turns string Form Type references to their CONSTANT alternatives in FormTypes in Form in Symfony', [ new CodeSample( - '$form->add("name", "form.type.text");', - '$form->add("name", \Symfony\Component\Form\Extension\Core\Type\TextType::class);' +<<<'CODE_SAMPLE' +$formBuilder = new Symfony\Component\Form\FormBuilder; +$formBuilder->add('name', 'form.type.text'); +CODE_SAMPLE + , + <<<'CODE_SAMPLE' +$formBuilder = new Symfony\Component\Form\FormBuilder; +$form->add('name', \Symfony\Component\Form\Extension\Core\Type\TextType::class); +CODE_SAMPLE ), ] ); @@ -53,22 +77,40 @@ final class StringFormTypeToClassRector extends AbstractRector */ public function getNodeTypes(): array { - return [String_::class]; + return [MethodCall::class]; } /** - * @param String_ $stringNode + * @param MethodCall $methodCallNode */ - public function refactor(Node $stringNode): ?Node + public function refactor(Node $methodCallNode): ?Node { + if (! $this->methodCallAnalyzer->isTypeAndMethod($methodCallNode, $this->formBuilderClass, 'add')) { + return null; + } + + // just one argument + if (! isset($methodCallNode->args[1])) { + return null; + } + + // not a string + if (! $methodCallNode->args[1]->value instanceof String_) { + return null; + } + + /** @var String_ $stringNode */ + $stringNode = $methodCallNode->args[1]->value; + + // not a form type string if (! $this->formTypeStringToTypeProvider->hasClassForNameWithPrefix($stringNode->value)) { return null; } - if (((string) $stringNode->getAttribute(Attribute::METHOD_CALL_NAME) === 'add') === false) { - return null; - } + $class = $this->formTypeStringToTypeProvider->getClassForNameWithPrefix($stringNode->value); - return $this->nodeFactory->createClassConstantReference($class); + $methodCallNode->args[1]->value = $this->nodeFactory->createClassConstantReference($class); + + return $methodCallNode; } } diff --git a/packages/Symfony/tests/Rector/Form/StringFormTypeToClassRector/Correct/correct.php.inc b/packages/Symfony/tests/Rector/Form/StringFormTypeToClassRector/Correct/correct.php.inc index cb459e3b392..0711633c19f 100644 --- a/packages/Symfony/tests/Rector/Form/StringFormTypeToClassRector/Correct/correct.php.inc +++ b/packages/Symfony/tests/Rector/Form/StringFormTypeToClassRector/Correct/correct.php.inc @@ -1,6 +1,8 @@ add('task', \Symfony\Component\Form\Extension\Core\Type\TextType::class); $variable = 'form.type.text'; diff --git a/packages/Symfony/tests/Rector/Form/StringFormTypeToClassRector/Correct/correct2.php.inc b/packages/Symfony/tests/Rector/Form/StringFormTypeToClassRector/Correct/correct2.php.inc new file mode 100644 index 00000000000..64188a31e52 --- /dev/null +++ b/packages/Symfony/tests/Rector/Form/StringFormTypeToClassRector/Correct/correct2.php.inc @@ -0,0 +1,23 @@ +add('email', EmailType::class, [ + 'label' => 'sylius.ui.email', + ]) + ; + } +} diff --git a/packages/Symfony/tests/Rector/Form/StringFormTypeToClassRector/Source/FormBuilder.php b/packages/Symfony/tests/Rector/Form/StringFormTypeToClassRector/Source/FormBuilder.php new file mode 100644 index 00000000000..d631efe01ce --- /dev/null +++ b/packages/Symfony/tests/Rector/Form/StringFormTypeToClassRector/Source/FormBuilder.php @@ -0,0 +1,8 @@ +add('task', 'form.type.text'); $variable = 'form.type.text'; diff --git a/packages/Symfony/tests/Rector/Form/StringFormTypeToClassRector/Wrong/wrong2.php.inc b/packages/Symfony/tests/Rector/Form/StringFormTypeToClassRector/Wrong/wrong2.php.inc new file mode 100644 index 00000000000..64188a31e52 --- /dev/null +++ b/packages/Symfony/tests/Rector/Form/StringFormTypeToClassRector/Wrong/wrong2.php.inc @@ -0,0 +1,23 @@ +add('email', EmailType::class, [ + 'label' => 'sylius.ui.email', + ]) + ; + } +} diff --git a/packages/Symfony/tests/Rector/Form/StringFormTypeToClassRector/config.yml b/packages/Symfony/tests/Rector/Form/StringFormTypeToClassRector/config.yml index 0c2959cbd4e..feffa616765 100644 --- a/packages/Symfony/tests/Rector/Form/StringFormTypeToClassRector/config.yml +++ b/packages/Symfony/tests/Rector/Form/StringFormTypeToClassRector/config.yml @@ -1,2 +1,3 @@ services: - Rector\Symfony\Rector\Form\StringFormTypeToClassRector: ~ + Rector\Symfony\Rector\Form\StringFormTypeToClassRector: + $formBuilderClass: 'Rector\Symfony\Tests\Rector\Form\StringFormTypeToClassRector\Source\FormBuilder' diff --git a/src/Autoloading/AdditionalAutoloader.php b/src/Autoloading/AdditionalAutoloader.php index f906dfa96f8..85fead586cf 100644 --- a/src/Autoloading/AdditionalAutoloader.php +++ b/src/Autoloading/AdditionalAutoloader.php @@ -7,6 +7,7 @@ use Rector\Configuration\Option; use Rector\FileSystem\FileGuard; use Rector\Utils\FilesystemTweaker; use Symfony\Component\Console\Input\InputInterface; +use Throwable; /** * Should it pass autoload files/directories to PHPStan analyzer? @@ -110,7 +111,7 @@ final class AdditionalAutoloader // sometimes tests can include ambiguous classes try { $robotLoader->register(); - } catch (\Throwable $throwable) { + } catch (Throwable $throwable) { } } diff --git a/src/Console/Command/ProcessCommand.php b/src/Console/Command/ProcessCommand.php index 5764d7a94de..beed348ac02 100644 --- a/src/Console/Command/ProcessCommand.php +++ b/src/Console/Command/ProcessCommand.php @@ -200,30 +200,7 @@ final class ProcessCommand extends Command $this->consoleStyle->progressStart($totalFiles); foreach ($fileInfos as $fileInfo) { - try { - // php - if ($fileInfo->getExtension() === 'php') { - $this->processFile($fileInfo); - // yml - } elseif ($fileInfo->getExtension() === 'yml') { - $this->processYamlFile($fileInfo); - } - } catch (AnalysedCodeException $analysedCodeException) { - if ($shouldHideAutoloadErrors) { - continue; - } - - $message = sprintf( - 'Analyze error: %s Try to include your files in "parameters > autoload_files" or "parameters > autoload_directories".%sSee https://github.com/rectorphp/rector#extra-autoloading', - $analysedCodeException->getMessage(), - PHP_EOL - ); - - $this->errors[] = new Error($fileInfo, $message, null); - } catch (Throwable $throwable) { - $this->errors[] = new Error($fileInfo, $throwable->getMessage(), $throwable->getCode()); - } - + $this->processFileInfo($fileInfo, $shouldHideAutoloadErrors); $this->consoleStyle->progressAdvance(); } @@ -271,4 +248,31 @@ final class ProcessCommand extends Command } } } + + private function processFileInfo(SplFileInfo $fileInfo, bool $shouldHideAutoloadErrors): void + { + try { + // php + if ($fileInfo->getExtension() === 'php') { + $this->processFile($fileInfo); + // yml + } elseif ($fileInfo->getExtension() === 'yml') { + $this->processYamlFile($fileInfo); + } + } catch (AnalysedCodeException $analysedCodeException) { + if ($shouldHideAutoloadErrors) { + return; + } + + $message = sprintf( + 'Analyze error: %s Try to include your files in "parameters > autoload_files" or "parameters > autoload_directories".%sSee https://github.com/rectorphp/rector#extra-autoloading', + $analysedCodeException->getMessage(), + PHP_EOL + ); + + $this->errors[] = new Error($fileInfo, $message, null); + } catch (Throwable $throwable) { + $this->errors[] = new Error($fileInfo, $throwable->getMessage(), $throwable->getCode()); + } + } } diff --git a/src/FileSystem/FilesFinder.php b/src/FileSystem/FilesFinder.php index 42db7d17232..9ec24264686 100644 --- a/src/FileSystem/FilesFinder.php +++ b/src/FileSystem/FilesFinder.php @@ -107,7 +107,7 @@ final class FilesFinder $finder->filter(function (NativeSplFileInfo $splFileInfo) { // return false to remove file foreach ($this->excludePaths as $excludePath) { - if (Strings::match($splFileInfo->getRealPath(), '#' . preg_quote($excludePath, '#') . '#' )) { + if (Strings::match($splFileInfo->getRealPath(), '#' . preg_quote($excludePath, '#') . '#')) { return false; }