[PHP] Add SensitiveHereNowDocRector

This commit is contained in:
Tomas Votruba 2018-10-17 03:47:21 +02:00
parent 25e3c6c511
commit 5de35b9706
7 changed files with 151 additions and 2 deletions

View File

@ -3,3 +3,4 @@ services:
Rector\Php\Rector\FuncCall\ArrayKeyFirstLastRector: ~
Rector\Php\Rector\FuncCall\SensitiveDefineRector: ~
Rector\Php\Rector\ConstFetch\SensitiveConstantNameRector: ~
Rector\Php\Rector\String\SensitiveHereNowDocRector: ~

View File

@ -115,9 +115,9 @@ final class CreateRectorCommand extends Command
'_Category_' => $configuration->getCategory(),
'_Description_' => $configuration->getDescription(),
'_Name_' => $configuration->getName(),
'_CodeBefore_' => $configuration->getCodeBefore(),
'_CodeBefore_' => trim($configuration->getCodeBefore()) . PHP_EOL,
'_CodeBeforeExample_' => $this->prepareCodeForDefinition($configuration->getCodeBefore()),
'_CodeAfter_' => $configuration->getCodeAfter(),
'_CodeAfter_' => trim($configuration->getCodeAfter()) . PHP_EOL,
'_CodeAfterExample_' => $this->prepareCodeForDefinition($configuration->getCodeAfter()),
];

View File

@ -0,0 +1,84 @@
<?php declare(strict_types=1);
namespace Rector\Php\Rector\String;
use Nette\Utils\Strings;
use PhpParser\Node;
use PhpParser\Node\Scalar\String_;
use Rector\NodeTypeResolver\Node\Attribute;
use Rector\Rector\AbstractRector;
use Rector\RectorDefinition\CodeSample;
use Rector\RectorDefinition\RectorDefinition;
use function Safe\sprintf;
final class SensitiveHereNowDocRector extends AbstractRector
{
/**
* @var string
*/
private const WRAP_SUFFIX = '_WRAP';
public function getDefinition(): RectorDefinition
{
return new RectorDefinition('Changes heredoc/nowdoc that contains closing word to safe wrapper name', [
new CodeSample(
<<<'CODE_SAMPLE'
$value = <<<A
A
A
CODE_SAMPLE
,
<<<'CODE_SAMPLE'
$value = <<<A_WRAP
A
A_WRAP
CODE_SAMPLE
),
]);
}
/**
* @return string[]
*/
public function getNodeTypes(): array
{
return [String_::class];
}
/**
* @param String_ $node
*/
public function refactor(Node $node): ?Node
{
if (! in_array($node->getAttribute('kind'), [String_::KIND_HEREDOC, String_::KIND_NOWDOC], true)) {
return null;
}
// the doc label is not in the string → ok
$docLabel = $node->getAttribute('docLabel');
if (! Strings::contains($node->value, $docLabel)) {
return null;
}
$node->setAttribute('docLabel', $this->uniquateDocLabel($node->value, $docLabel));
// invoke redraw
$node->setAttribute(Attribute::ORIGINAL_NODE, null);
return $node;
}
private function uniquateDocLabel(string $value, string $docLabel): string
{
$docLabel .= self::WRAP_SUFFIX;
$docLabelCounterTemplate = $docLabel . '_%d';
$i = 0;
while (Strings::contains($value, $docLabel)) {
$docLabel = sprintf($docLabelCounterTemplate, ++$i);
}
return $docLabel;
}
}

View File

@ -0,0 +1,16 @@
<?php
$value = <<<CODE_SAMPLE_WRAP
CODE_SAMPLE_2
CODE_SAMPLE_WRAP;
$value = <<<CODE_SAMPLE_WRAP_1
CODE_SAMPLE_WRAP_2
CODE_SAMPLE_WRAP_1;
// examples from RFC
$value = <<<END_WRAP
a
b
ENDING
END_WRAP;

View File

@ -0,0 +1,30 @@
<?php declare(strict_types=1);
namespace Rector\Php\Tests\Rector\String\SensitiveHereNowDocRector;
use Iterator;
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
/**
* @covers \Rector\Php\Rector\String\SensitiveHereNowDocRector
*/
final class SensitiveHereNowDocRectorTest extends AbstractRectorTestCase
{
/**
* @dataProvider provideWrongToFixedFiles()
*/
public function test(string $wrong, string $fixed): void
{
$this->doTestFileMatchesExpectedContent($wrong, $fixed);
}
public function provideWrongToFixedFiles(): Iterator
{
yield [__DIR__ . '/Wrong/wrong.php.inc', __DIR__ . '/Correct/correct.php.inc'];
}
protected function provideConfig(): string
{
return __DIR__ . '/config.yml';
}
}

View File

@ -0,0 +1,16 @@
<?php
$value = <<<CODE_SAMPLE
CODE_SAMPLE_2
CODE_SAMPLE;
$value = <<<CODE_SAMPLE
CODE_SAMPLE_WRAP_2
CODE_SAMPLE;
// examples from RFC
$value = <<<END
a
b
ENDING
END;

View File

@ -0,0 +1,2 @@
services:
Rector\Php\Rector\String\SensitiveHereNowDocRector: ~