2019-10-13 05:59:52 +00:00
< ? php
2021-05-09 20:15:43 +00:00
declare ( strict_types = 1 );
2019-07-10 07:35:03 +00:00
namespace Rector\CodingStyle\Rector\Encapsed ;
2021-05-11 10:40:34 +00:00
use RectorPrefix20210511\Nette\Utils\Strings ;
2021-01-02 21:59:58 +00:00
use const PHP_EOL ;
2019-07-10 07:35:03 +00:00
use PhpParser\Node ;
2019-07-06 21:27:44 +00:00
use PhpParser\Node\Arg ;
2019-10-10 14:26:03 +00:00
use PhpParser\Node\Expr ;
2019-11-07 23:02:26 +00:00
use PhpParser\Node\Expr\BinaryOp\Concat ;
use PhpParser\Node\Expr\ConstFetch ;
2019-07-06 21:27:44 +00:00
use PhpParser\Node\Expr\FuncCall ;
2019-11-07 23:02:26 +00:00
use PhpParser\Node\Expr\Variable ;
2019-07-06 21:27:44 +00:00
use PhpParser\Node\Name ;
2019-07-10 07:35:03 +00:00
use PhpParser\Node\Scalar\Encapsed ;
2019-07-06 21:27:44 +00:00
use PhpParser\Node\Scalar\EncapsedStringPart ;
use PhpParser\Node\Scalar\String_ ;
2020-02-06 21:48:18 +00:00
use Rector\Core\Rector\AbstractRector ;
2019-11-07 23:02:26 +00:00
use Rector\NodeTypeResolver\Node\AttributeKey ;
2020-11-16 17:50:38 +00:00
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample ;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition ;
2019-07-10 07:35:03 +00:00
/**
2021-03-12 22:20:25 +00:00
* @ see \Rector\Tests\CodingStyle\Rector\Encapsed\EncapsedStringsToSprintfRector\EncapsedStringsToSprintfRectorTest
2019-07-10 07:35:03 +00:00
*/
2021-05-10 22:23:08 +00:00
final class EncapsedStringsToSprintfRector extends \Rector\Core\Rector\AbstractRector
2019-07-10 07:35:03 +00:00
{
2019-11-07 23:02:26 +00:00
/**
* @ var string
*/
private $sprintfFormat ;
/**
* @ var Expr []
*/
private $argumentVariables = [];
2021-05-10 22:23:08 +00:00
public function getRuleDefinition () : \Symplify\RuleDocGenerator\ValueObject\RuleDefinition
2019-07-10 07:35:03 +00:00
{
2021-05-10 22:23:08 +00:00
return new \Symplify\RuleDocGenerator\ValueObject\RuleDefinition ( 'Convert enscaped {$string} to more readable sprintf' , [ new \Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample ( <<< 'CODE_SAMPLE'
2019-07-10 07:35:03 +00:00
final class SomeClass
{
public function run ( string $format )
{
return " Unsupported format { $format } " ;
}
}
2020-09-15 08:23:13 +00:00
CODE_SAMPLE
2021-05-09 20:15:43 +00:00
, <<< 'CODE_SAMPLE'
2019-07-10 07:35:03 +00:00
final class SomeClass
{
public function run ( string $format )
{
return sprintf ( 'Unsupported format %s' , $format );
}
}
2020-09-15 08:23:13 +00:00
CODE_SAMPLE
2021-05-09 20:15:43 +00:00
)]);
2019-07-10 07:35:03 +00:00
}
/**
2021-02-27 00:06:15 +00:00
* @ return array < class - string < Node >>
2019-07-10 07:35:03 +00:00
*/
2021-05-09 20:15:43 +00:00
public function getNodeTypes () : array
2019-07-10 07:35:03 +00:00
{
2021-05-10 22:23:08 +00:00
return [ \PhpParser\Node\Scalar\Encapsed :: class ];
2019-07-10 07:35:03 +00:00
}
/**
* @ param Encapsed $node
*/
2021-05-10 22:23:08 +00:00
public function refactor ( \PhpParser\Node $node ) : ? \PhpParser\Node
2019-07-10 07:35:03 +00:00
{
2019-11-07 23:02:26 +00:00
$this -> sprintfFormat = '' ;
$this -> argumentVariables = [];
2019-07-10 07:35:03 +00:00
foreach ( $node -> parts as $part ) {
2021-05-10 22:23:08 +00:00
if ( $part instanceof \PhpParser\Node\Scalar\EncapsedStringPart ) {
2019-11-07 23:02:26 +00:00
$this -> collectEncapsedStringPart ( $part );
2021-05-10 22:23:08 +00:00
} elseif ( $part instanceof \PhpParser\Node\Expr ) {
2019-11-07 23:02:26 +00:00
$this -> collectExpr ( $part );
2019-07-10 07:35:03 +00:00
}
2019-11-07 23:02:26 +00:00
}
return $this -> createSprintfFuncCallOrConcat ( $this -> sprintfFormat , $this -> argumentVariables );
}
2021-05-10 22:23:08 +00:00
private function collectEncapsedStringPart ( \PhpParser\Node\Scalar\EncapsedStringPart $encapsedStringPart ) : void
2019-11-07 23:02:26 +00:00
{
$stringValue = $encapsedStringPart -> value ;
if ( $stringValue === " \n " ) {
2021-05-10 22:23:08 +00:00
$this -> argumentVariables [] = new \PhpParser\Node\Expr\ConstFetch ( new \PhpParser\Node\Name ( 'PHP_EOL' ));
2021-01-02 21:59:58 +00:00
$this -> sprintfFormat .= '%s' ;
2019-11-07 23:02:26 +00:00
return ;
}
$this -> sprintfFormat .= $stringValue ;
}
2021-05-10 22:23:08 +00:00
private function collectExpr ( \PhpParser\Node\Expr $expr ) : void
2019-11-07 23:02:26 +00:00
{
$this -> sprintfFormat .= '%s' ;
// remove: ${wrap} → $wrap
2021-05-10 22:23:08 +00:00
if ( $expr instanceof \PhpParser\Node\Expr\Variable ) {
$expr -> setAttribute ( \Rector\NodeTypeResolver\Node\AttributeKey :: ORIGINAL_NODE , null );
2019-11-07 23:02:26 +00:00
}
$this -> argumentVariables [] = $expr ;
}
2020-02-01 16:04:38 +00:00
/**
* @ param Expr [] $argumentVariables
2021-01-02 21:59:58 +00:00
* @ return Concat | FuncCall | null
2020-02-01 16:04:38 +00:00
*/
2021-05-10 22:23:08 +00:00
private function createSprintfFuncCallOrConcat ( string $string , array $argumentVariables ) : ? \PhpParser\Node
2020-02-01 16:04:38 +00:00
{
// special case for variable with PHP_EOL
2021-05-09 20:15:43 +00:00
if ( $string === '%s%s' && \count ( $argumentVariables ) === 2 && $this -> hasEndOfLine ( $argumentVariables )) {
2021-05-10 22:23:08 +00:00
return new \PhpParser\Node\Expr\BinaryOp\Concat ( $argumentVariables [ 0 ], $argumentVariables [ 1 ]);
2020-02-01 16:04:38 +00:00
}
2021-05-11 10:40:34 +00:00
if ( \RectorPrefix20210511\Nette\Utils\Strings :: contains ( $string , \PHP_EOL )) {
2021-01-02 21:59:58 +00:00
return null ;
}
2021-05-10 22:23:08 +00:00
$arguments = [ new \PhpParser\Node\Arg ( new \PhpParser\Node\Scalar\String_ ( $string ))];
2020-02-01 16:04:38 +00:00
foreach ( $argumentVariables as $argumentVariable ) {
2021-05-10 22:23:08 +00:00
$arguments [] = new \PhpParser\Node\Arg ( $argumentVariable );
2020-02-01 16:04:38 +00:00
}
2021-05-10 22:23:08 +00:00
return new \PhpParser\Node\Expr\FuncCall ( new \PhpParser\Node\Name ( 'sprintf' ), $arguments );
2020-02-01 16:04:38 +00:00
}
2021-01-02 21:59:58 +00:00
/**
* @ param Expr [] $argumentVariables
*/
2021-05-09 20:15:43 +00:00
private function hasEndOfLine ( array $argumentVariables ) : bool
2021-01-02 21:59:58 +00:00
{
foreach ( $argumentVariables as $argumentVariable ) {
2021-05-10 22:23:08 +00:00
if ( ! $argumentVariable instanceof \PhpParser\Node\Expr\ConstFetch ) {
2021-01-02 21:59:58 +00:00
continue ;
}
if ( $this -> isName ( $argumentVariable , 'PHP_EOL' )) {
2021-05-09 20:15:43 +00:00
return \true ;
2021-01-02 21:59:58 +00:00
}
}
2021-05-09 20:15:43 +00:00
return \false ;
2021-01-02 21:59:58 +00:00
}
2019-07-10 07:35:03 +00:00
}