Skip to content

Commit

Permalink
Add a fixer used to add ! prefix to the first argument of DateTime:…
Browse files Browse the repository at this point in the history
…:createFromFormat
  • Loading branch information
liquid207 committed Feb 14, 2022
1 parent 37e2cbd commit 5b42629
Show file tree
Hide file tree
Showing 5 changed files with 166 additions and 0 deletions.
5 changes: 5 additions & 0 deletions doc/list.rst
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,11 @@ List of Available Rules

`Source PhpCsFixer\\Fixer\\ControlStructure\\ControlStructureContinuationPositionFixer <./../src/Fixer/ControlStructure/ControlStructureContinuationPositionFixer.php>`_
- `create_from_format_call <./rules/function_notation/create_from_format_call.rst>`_

The first argument of function ``createFromFormat`` must start with ``!``.

`Source PhpCsFixer\\Fixer\\FunctionNotation\\CreateFromFormatCallFixer <./../src/Fixer/FunctionNotation/CreateFromFormatCallFixer.php>`_
- `date_time_immutable <./rules/class_usage/date_time_immutable.rst>`_

Class ``DateTimeImmutable`` should be used instead of ``DateTime``.
Expand Down
18 changes: 18 additions & 0 deletions doc/rules/function_notation/create_from_format_call.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
================================
Rule ``create_from_format_call``
================================

The first argument of function ``createFromFormat`` must start with ``!``.

Examples
--------

Example #1
~~~~~~~~~~

.. code-block:: diff
--- Original
+++ New
-<?php \DateTime::createFromFormat('Y-m-d', '2022-02-11');
+<?php \DateTime::createFromFormat('!Y-m-d', '2022-02-11');
3 changes: 3 additions & 0 deletions doc/rules/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,9 @@ Function Notation
- `combine_nested_dirname <./function_notation/combine_nested_dirname.rst>`_ *(risky)*

Replace multiple nested calls of ``dirname`` by only one call with second ``$level`` parameter. Requires PHP >= 7.0.
- `create_from_format_call <./function_notation/create_from_format_call.rst>`_

The first argument of function ``createFromFormat`` must start with ``!``.
- `fopen_flag_order <./function_notation/fopen_flag_order.rst>`_ *(risky)*

Order the flags in ``fopen`` calls, ``b`` and ``t`` must be last.
Expand Down
95 changes: 95 additions & 0 deletions src/Fixer/FunctionNotation/CreateFromFormatCallFixer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
<?php

declare(strict_types=1);

/*
* This file is part of PHP CS Fixer.
*
* (c) Fabien Potencier <fabien@symfony.com>
* Dariusz Rumiński <dariusz.ruminski@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/

namespace PhpCsFixer\Fixer\FunctionNotation;

use PhpCsFixer\AbstractFixer;
use PhpCsFixer\FixerDefinition\CodeSample;
use PhpCsFixer\FixerDefinition\FixerDefinition;
use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
use PhpCsFixer\Tokenizer\Analyzer\NamespaceUsesAnalyzer;
use PhpCsFixer\Tokenizer\Token;
use PhpCsFixer\Tokenizer\Tokens;

final class CreateFromFormatCallFixer extends AbstractFixer
{
public function getDefinition(): FixerDefinitionInterface
{
return new FixerDefinition(
'The first argument of function `createFromFormat` must start with `!`.',
[
new CodeSample("<?php \\DateTime::createFromFormat('Y-m-d', '2022-02-11');\n"),
],
);
}

public function isCandidate(Tokens $tokens): bool
{
return $tokens->isTokenKindFound(T_STRING);
}

protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
{
$useDeclarations = (new NamespaceUsesAnalyzer())->getDeclarationsFromTokens($tokens);

for ($index = 0; $index < \count($tokens); ++$index) {
if (!$tokens[$index]->equals([T_STRING, 'createFromFormat'], false)) {
continue;
}

if (!$tokens[$index - 1]->isGivenKind(T_DOUBLE_COLON)) {
continue;
}

if (!$tokens[$index + 1]->equals('(')) {
continue;
}

$classNamePreviousIndex = $tokens->getTokenNotOfKindsSibling($index, -1, [T_DOUBLE_COLON, T_NS_SEPARATOR, T_STRING]);
$className = $tokens->generatePartialCode($classNamePreviousIndex + 1, $index - 2);

if (str_contains($className, '\\')) {
$classFullName = $className;
} else {
$classFullName = null;

foreach ($useDeclarations as $useDeclaration) {
if ($useDeclaration->getShortName() === $className) {
$classFullName = $useDeclaration->getFullName();

break;
}
}

if (null === $classFullName) {
throw new \RuntimeException("{$classFullName} is not imported.");
}
}

if (\DateTime::class !== str_replace('\\', '', $classFullName)) {
continue;
}

$formatArgumentIndex = $index + 2;
$format = $tokens[$formatArgumentIndex]->getContent();

if (!\in_array(substr($format, 0, 1), ['\'', '"'], true) || '!' === substr($format, 1, 1)) {
continue;
}

$tokens->clearAt($formatArgumentIndex);
$tokens->insertAt($formatArgumentIndex, new Token([T_CONSTANT_ENCAPSED_STRING, substr_replace($format, '!', 1, 0)]));
}
}
}
45 changes: 45 additions & 0 deletions tests/Fixer/FunctionNotation/CreateFromFormatCallFixerTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<?php

declare(strict_types=1);

/*
* This file is part of PHP CS Fixer.
*
* (c) Fabien Potencier <fabien@symfony.com>
* Dariusz Rumiński <dariusz.ruminski@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/

namespace PhpCsFixer\Tests\Fixer\FunctionNotation;

use PhpCsFixer\Tests\Test\AbstractFixerTestCase;

/**
* @internal
* @covers \PhpCsFixer\Fixer\FunctionNotation\CreateFromFormatCallFixer
*/
final class CreateFromFormatCallFixerTest extends AbstractFixerTestCase
{
/**
* @dataProvider provideFixCases
*/
public function testFix(string $expected, ?string $input = null): void
{
$this->doTest($expected, $input);
}

public function provideFixCases(): \Generator
{
yield [
'<?php \DateTime::createFromFormat(\'!Y-m-d\', \'2022-02-11\');',
'<?php \DateTime::createFromFormat(\'Y-m-d\', \'2022-02-11\');',
];

yield [
'<?php use DateTime; DateTime::createFromFormat(\'!Y-m-d\', \'2022-02-11\');',
'<?php use DateTime; DateTime::createFromFormat(\'Y-m-d\', \'2022-02-11\');',
];
}
}

0 comments on commit 5b42629

Please sign in to comment.