[Defluent] Allow DateTime to be fluent (#3947)

* ignore prefixed conflcits

* note

* skip date-time from defluencing

* drop parameter name guard, not needed anymore

* make use of addNodesAfterNode()
This commit is contained in:
Tomas Votruba 2020-08-12 14:32:45 +02:00 committed by GitHub
parent c25cd2e178
commit f71b242924
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 76 additions and 110 deletions

View File

@ -34,7 +34,6 @@
"symplify/autowire-array-parameter": "^8.1.20",
"symplify/console-color-diff": "^8.1.20",
"symplify/package-builder": "^8.1.20",
"symplify/parameter-name-guard": "^8.1.20",
"symplify/set-config-resolver": "^8.1.20",
"symplify/smart-file-system": "^8.1.20",
"tracy/tracy": "^2.7"

View File

@ -12,8 +12,6 @@ return static function (ContainerConfigurator $containerConfigurator): void {
$containerConfigurator->import(__DIR__ . '/services.php');
$containerConfigurator->import(__DIR__ . '/parameters/parameter_name_guard.php');
$containerConfigurator->import(__DIR__ . '/../utils/**/config/config.php', null, true);
$parameters = $containerConfigurator->parameters();

View File

@ -1,62 +0,0 @@
<?php
declare(strict_types=1);
use Rector\Core\Configuration\Option;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
return static function (ContainerConfigurator $containerConfigurator): void {
$parameters = $containerConfigurator->parameters();
$parameters->set('correct_to_typos', [
Option::EXCLUDE_PATHS => [
'exclude',
'excluded',
'exclude_path',
'excluded_path',
'exclude_dir',
'excluded_dir',
'exclude_dirs',
'excluded_dirs',
'exclude_file',
'excluded_file',
'exclude_files',
'excluded_files',
'ignore_path',
'ignored_path',
'ignore_paths',
'ignored_paths',
'ignore_dir',
'ignored_dir',
'ignore_dirs',
'ignored_dirs',
'ignore_file',
'ignored_file',
'ignore_files',
'ignored_files',
'skip_path',
'skip_paths',
'skip_dir',
'skip_dirs',
'skip_file',
'skip_files',
],
Option::EXCLUDE_RECTORS => [
'exclude_rector',
'excluded_rector',
'excluded_rectors',
'skip_rector',
'skip_rectors',
],
Option::AUTOLOAD_PATHS => ['#(autolaod|autoload|include|bootstrap)((ed)?_(path(s)?|dir(s)?|file(s)?))?#'],
Option::AUTO_IMPORT_NAMES => [
'auto_imort_names',
'auto_import_name',
'auto_imports_names',
'auto_imports_name',
'auto_names',
'import_name(space)?(s)?',
],
Option::PATHS => ['path', 'source'],
]);
};

View File

@ -11,6 +11,7 @@ use PhpParser\Node\Stmt\Expression;
use PhpParser\Node\Stmt\If_;
use Rector\Core\Exception\ShouldNotHappenException;
use Rector\Core\PhpParser\Node\BetterNodeFinder;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Rector\PostRector\Contract\Collector\NodeCollectorInterface;
final class NodesToAddCollector implements NodeCollectorInterface
@ -51,6 +52,19 @@ final class NodesToAddCollector implements NodeCollectorInterface
$this->nodesToAddBefore[$position][] = $this->wrapToExpression($addedNode);
}
/**
* @param Node[] $addedNodes
*/
public function addNodesAfterNode(array $addedNodes, Node $positionNode): void
{
$position = $this->resolveNearestExpressionPosition($positionNode);
foreach ($addedNodes as $addedNode) {
// prevent fluent method weird indent
$addedNode->setAttribute(AttributeKey::ORIGINAL_NODE, null);
$this->nodesToAddAfter[$position][] = $this->wrapToExpression($addedNode);
}
}
public function addNodeAfterNode(Node $addedNode, Node $positionNode): void
{
$position = $this->resolveNearestExpressionPosition($positionNode);

View File

@ -93,11 +93,8 @@ trait NodeCommandersTrait
*/
protected function addNodesAfterNode(array $newNodes, Node $positionNode): void
{
foreach ($newNodes as $newNode) {
// prevent fluent method weird indent
$newNode->setAttribute(AttributeKey::ORIGINAL_NODE, null);
$this->addNodeAfterNode($newNode, $positionNode);
}
$this->nodesToAddCollector->addNodesAfterNode($newNodes, $positionNode);
$this->rectorChangeCollector->notifyNodeFileInfo($positionNode);
}
/**

View File

@ -379,8 +379,6 @@ parameters:
- '#Static property Rector\\Core\\Testing\\PHPUnit\\AbstractGenericRectorTestCase\:\:\$allRectorContainer \(Rector\\Naming\\Tests\\Rector\\Class_\\RenamePropertyToMatchTypeRector\\Source\\ContainerInterface\|Symfony\\Component\\DependencyInjection\\Container\|null\) does not accept Psr\\Container\\ContainerInterface#'
# stubs
- '#Class Nette\\DI\\CompilerExtension not found#'
- '#Class Latte\\Macros\\MacroSet not found#'
- '#Static property Symplify\\PackageBuilder\\Tests\\AbstractKernelTestCase\:\:\$container \(Psr\\Container\\ContainerInterface\) does not accept Rector\\Naming\\Tests\\Rector\\Class_\\RenamePropertyToMatchTypeRector\\Source\\ContainerInterface\|Symfony\\Component\\DependencyInjection\\Container#'
@ -390,9 +388,7 @@ parameters:
path: 'rules/psr4/src/Composer/PSR4NamespaceMatcher.php'
# false positive
- '#Empty array passed to foreach#'
- '#Parameter \#1 \$arrayItem of method Rector\\NetteKdyby\\NodeResolver\\ListeningMethodsCollector\:\:resolveCustomClassMethodAndEventClass\(\) expects PhpParser\\Node\\Expr\\ArrayItem, PhpParser\\Node given#'
- '#Method Rector\\CodeQuality\\Rector\\Class_\\CompleteDynamicPropertiesRector\:\:resolvePropertiesToComplete\(\) should return array<int, PhpParser\\Node\\Stmt\\Property\> but returns array<int, \(int\|string\)\>#'
- '#Parameter \#1 \$type of method Rector\\NodeCollector\\NodeCollector\\ParsedNodeCollector<TNodeType of PhpParser\\Node\>\:\:getNodesByType\(\) expects class\-string<TNodeType of PhpParser\\Node\>, string given#'
- '#Class with base "(.*?)" name is already used in "_HumbugBox(.*?)"#'

View File

@ -71,9 +71,7 @@ PHP
$rightArray = $node->expr;
$standaloneAssigns = $this->createStandaloneAssigns($leftArray, $rightArray);
foreach ($standaloneAssigns as $standaloneAssign) {
$this->addNodeAfterNode($standaloneAssign, $node);
}
$this->addNodesAfterNode($standaloneAssigns, $node);
$this->removeNode($node);

View File

@ -73,16 +73,15 @@ PHP
return null;
}
/** @var Const_[] $allConsts */
$allConsts = $node->consts;
/** @var Const_ $firstConst */
$firstConst = array_shift($allConsts);
$node->consts = [$firstConst];
foreach ($allConsts as $anotherConstant) {
$nextClassConst = new ClassConst([$anotherConstant], $node->flags, $node->getAttributes());
$this->addNodeAfterNode($nextClassConst, $node);
}
$nextClassConsts = $this->createNextClassConsts($allConsts, $node);
$this->addNodesAfterNode($nextClassConsts, $node);
return $node;
}
@ -103,4 +102,19 @@ PHP
return $node;
}
/**
* @param Const_[] $consts
* @return ClassConst[]
*/
private function createNextClassConsts(array $consts, ClassConst $classConst): array
{
$decoratedConsts = [];
foreach ($consts as $const) {
$decoratedConsts[] = new ClassConst([$const], $classConst->flags, $classConst->getAttributes());
}
return $decoratedConsts;
}
}

View File

@ -81,9 +81,7 @@ PHP
return null;
}
foreach ($node->stmts as $tryStmt) {
$this->addNodeAfterNode($tryStmt, $node);
}
$this->addNodesAfterNode((array) $node->stmts, $node);
$this->removeNode($node);

View File

@ -114,10 +114,7 @@ PHP
$node->else = null;
foreach ($elseStmts as $elseStmt) {
$this->addNodeAfterNode($elseStmt, $node);
}
$this->addNodesAfterNode($elseStmts, $node);
$this->removeNode($nextNode);
return $node;

View File

@ -98,7 +98,7 @@ abstract class AbstractFluentChainMethodCallRector extends AbstractConfigurableM
{
// skip query and builder
// @see https://ocramius.github.io/blog/fluent-interfaces-are-evil/ "When does a fluent interface make sense?"
if ((bool) Strings::match($class, '#(Finder|Query|Builder|MutatingScope)$#')) {
if ((bool) Strings::match($class, '#(Finder|DateTime|DateTimeInterface|Query|Builder|MutatingScope)$#')) {
return true;
}

View File

@ -63,8 +63,7 @@ PHP
$variableReturn = new Return_($methodCall->var);
$this->addNodeAfterNode($methodCall, $node);
$this->addNodeAfterNode($variableReturn, $node);
$this->addNodesAfterNode([$methodCall, $variableReturn], $node);
$this->removeNode($node);

View File

@ -0,0 +1,16 @@
<?php
namespace Rector\MagicDisclosure\Tests\Rector\MethodCall\FluentChainMethodCallToNormalMethodCallRector\Fixture;
use DateTime;
class SkipDateTime
{
public function run($values)
{
$dateTime = new DateTime();
foreach ($values as $value) {
$dateTime->modify(1)->format('Y-m-D');
}
}
}

View File

@ -0,0 +1,13 @@
<?php
namespace Rector\MagicDisclosure\Tests\Rector\Return_\DefluentReturnMethodCallRector\Fixture;
use DateTime;
class SkipDateTime
{
public function someFunction()
{
$nextMonth = (new DateTime())->modify('+1 month')->format('Y-m-d');
}
}

View File

@ -230,9 +230,7 @@ final class AssertManipulator
/** @var Closure $closure */
$closure = $staticCall->args[0]->value;
foreach ((array) $closure->stmts as $callableStmt) {
$this->nodesToAddCollector->addNodeAfterNode($callableStmt, $staticCall);
}
$this->nodesToAddCollector->addNodesAfterNode((array) $closure->stmts, $staticCall);
$this->nodesToRemoveCollector->addNodeToRemove($staticCall);
}
@ -259,10 +257,7 @@ final class AssertManipulator
/** @var Closure $closure */
$closure = $staticCall->args[0]->value;
foreach ((array) $closure->stmts as $callableStmt) {
$this->nodesToAddCollector->addNodeAfterNode($callableStmt, $staticCall);
}
$this->nodesToAddCollector->addNodesAfterNode((array) $closure->stmts, $staticCall);
$this->nodesToRemoveCollector->addNodeToRemove($staticCall);
/** @var ClassMethod|null $classMethod */

View File

@ -300,8 +300,7 @@ final class PhpSpecPromisesToPHPUnitAssertRector extends AbstractPhpSpecToPHPUni
$methodCall->args = [];
$funcCall->args[] = new Arg($methodCall);
$this->addNodeAfterNode($assign, $methodCall);
$this->addNodeAfterNode($funcCall, $methodCall);
$this->addNodesAfterNode([$assign, $funcCall], $methodCall);
$this->removeNode($methodCall);

View File

@ -116,10 +116,7 @@ PHP
$elseStmts[$lastElseStmtKey] = new Return_($assign->expr);
$node->else = null;
foreach ($elseStmts as $elseStmt) {
$this->addNodeAfterNode($elseStmt, $node);
}
$this->addNodesAfterNode($elseStmts, $node);
$this->removeNode($nextNode);

View File

@ -88,9 +88,7 @@ PHP
}
if ($node->else !== null) {
foreach ($node->else->stmts as $stmt) {
$this->addNodeAfterNode($stmt, $node);
}
$this->addNodesAfterNode((array) $node->else->stmts, $node);
$node->else = null;
return $node;
}

View File

@ -17,6 +17,7 @@ use Symfony\Component\Config\Loader\LoaderResolver;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\DependencyInjection\Loader\PhpFileLoader;
use Symfony\Component\HttpKernel\Bundle\BundleInterface;
use Symfony\Component\HttpKernel\Config\FileLocator;
use Symfony\Component\HttpKernel\Kernel;
use Symplify\AutoBindParameter\DependencyInjection\CompilerPass\AutoBindParameterCompilerPass;
@ -24,7 +25,6 @@ use Symplify\AutowireArrayParameter\DependencyInjection\CompilerPass\AutowireArr
use Symplify\ConsoleColorDiff\ConsoleColorDiffBundle;
use Symplify\PackageBuilder\Contract\HttpKernel\ExtraConfigAwareKernelInterface;
use Symplify\PackageBuilder\DependencyInjection\CompilerPass\AutowireInterfacesCompilerPass;
use Symplify\ParameterNameGuard\Bundle\ParameterNameGuardBundle;
final class RectorKernel extends Kernel implements ExtraConfigAwareKernelInterface
{
@ -75,11 +75,11 @@ final class RectorKernel extends Kernel implements ExtraConfigAwareKernelInterfa
}
/**
* @return ConsoleColorDiffBundle[]|ParameterNameGuardBundle[]
* @return BundleInterface[]
*/
public function registerBundles(): array
{
return [new ConsoleColorDiffBundle(), new ParameterNameGuardBundle()];
return [new ConsoleColorDiffBundle()];
}
protected function build(ContainerBuilder $containerBuilder): void