2019-10-13 05:59:52 +00:00
|
|
|
<?php
|
|
|
|
|
2021-05-09 20:15:43 +00:00
|
|
|
declare (strict_types=1);
|
2024-01-02 02:40:38 +00:00
|
|
|
namespace Rector\PhpParser\Printer;
|
2017-12-01 19:52:33 +00:00
|
|
|
|
2024-03-01 20:02:28 +00:00
|
|
|
use RectorPrefix202403\Nette\Utils\Strings;
|
2022-06-06 17:12:56 +00:00
|
|
|
use PhpParser\Comment;
|
|
|
|
use PhpParser\Node;
|
2024-03-28 16:05:42 +00:00
|
|
|
use PhpParser\Node\Arg;
|
2024-02-25 00:28:21 +00:00
|
|
|
use PhpParser\Node\AttributeGroup;
|
2022-06-06 17:12:56 +00:00
|
|
|
use PhpParser\Node\Expr;
|
|
|
|
use PhpParser\Node\Expr\Array_;
|
|
|
|
use PhpParser\Node\Expr\ArrowFunction;
|
2024-03-28 16:05:42 +00:00
|
|
|
use PhpParser\Node\Expr\CallLike;
|
2022-06-06 17:12:56 +00:00
|
|
|
use PhpParser\Node\Expr\Closure;
|
2024-03-28 16:05:42 +00:00
|
|
|
use PhpParser\Node\Expr\MethodCall;
|
2022-06-06 17:12:56 +00:00
|
|
|
use PhpParser\Node\Expr\Ternary;
|
|
|
|
use PhpParser\Node\Expr\Yield_;
|
2022-10-15 22:34:17 +00:00
|
|
|
use PhpParser\Node\Param;
|
2022-06-06 17:12:56 +00:00
|
|
|
use PhpParser\Node\Scalar\DNumber;
|
|
|
|
use PhpParser\Node\Scalar\EncapsedStringPart;
|
2022-09-05 17:52:37 +00:00
|
|
|
use PhpParser\Node\Scalar\LNumber;
|
2022-06-06 17:12:56 +00:00
|
|
|
use PhpParser\Node\Scalar\String_;
|
|
|
|
use PhpParser\Node\Stmt\Class_;
|
|
|
|
use PhpParser\Node\Stmt\ClassMethod;
|
|
|
|
use PhpParser\Node\Stmt\Declare_;
|
|
|
|
use PhpParser\Node\Stmt\Nop;
|
|
|
|
use PhpParser\PrettyPrinter\Standard;
|
2023-08-03 09:57:07 +00:00
|
|
|
use PHPStan\Node\Expr\AlwaysRememberedExpr;
|
2024-01-02 02:40:38 +00:00
|
|
|
use Rector\Configuration\Option;
|
|
|
|
use Rector\Configuration\Parameter\SimpleParameterProvider;
|
2022-06-06 17:12:56 +00:00
|
|
|
use Rector\NodeTypeResolver\Node\AttributeKey;
|
2024-01-02 02:40:38 +00:00
|
|
|
use Rector\PhpParser\Node\CustomNode\FileWithoutNamespace;
|
2019-09-03 09:11:45 +00:00
|
|
|
/**
|
2024-01-01 09:05:02 +00:00
|
|
|
* @see \Rector\Tests\PhpParser\Printer\BetterStandardPrinterTest
|
2022-03-07 11:34:50 +00:00
|
|
|
*
|
|
|
|
* @property array<string, array{string, bool, string, null}> $insertionMap
|
2019-09-03 09:11:45 +00:00
|
|
|
*/
|
2023-06-08 14:23:03 +00:00
|
|
|
final class BetterStandardPrinter extends Standard
|
2017-12-01 19:52:33 +00:00
|
|
|
{
|
2020-09-23 09:16:40 +00:00
|
|
|
/**
|
|
|
|
* @var string
|
2020-10-29 18:04:33 +00:00
|
|
|
* @see https://regex101.com/r/DrsMY4/1
|
2020-09-23 09:16:40 +00:00
|
|
|
*/
|
2021-05-09 20:15:43 +00:00
|
|
|
private const QUOTED_SLASH_REGEX = "#'|\\\\(?=[\\\\']|\$)#";
|
2020-09-23 09:16:40 +00:00
|
|
|
/**
|
2020-10-04 12:53:01 +00:00
|
|
|
* Remove extra spaces before new Nop_ nodes
|
|
|
|
* @see https://regex101.com/r/iSvroO/1
|
2020-09-23 09:16:40 +00:00
|
|
|
* @var string
|
|
|
|
*/
|
2021-05-09 20:15:43 +00:00
|
|
|
private const EXTRA_SPACE_BEFORE_NOP_REGEX = '#^[ \\t]+$#m';
|
2020-10-04 11:12:41 +00:00
|
|
|
/**
|
2021-07-22 17:04:20 +00:00
|
|
|
* @see https://regex101.com/r/qZiqGo/13
|
2020-10-04 11:12:41 +00:00
|
|
|
* @var string
|
|
|
|
*/
|
2021-07-22 17:04:20 +00:00
|
|
|
private const REPLACE_COLON_WITH_SPACE_REGEX = '#(^.*function .*\\(.*\\)) : #';
|
2023-09-11 21:30:42 +00:00
|
|
|
public function __construct()
|
2021-05-09 20:15:43 +00:00
|
|
|
{
|
2023-08-11 09:14:44 +00:00
|
|
|
parent::__construct(['shortArraySyntax' => \true]);
|
2018-11-28 23:56:59 +00:00
|
|
|
// print return type double colon right after the bracket "function(): string"
|
|
|
|
$this->initializeInsertionMap();
|
2021-05-09 20:15:43 +00:00
|
|
|
$this->insertionMap['Stmt_ClassMethod->returnType'] = [')', \false, ': ', null];
|
|
|
|
$this->insertionMap['Stmt_Function->returnType'] = [')', \false, ': ', null];
|
|
|
|
$this->insertionMap['Expr_Closure->returnType'] = [')', \false, ': ', null];
|
2021-08-05 05:49:38 +00:00
|
|
|
$this->insertionMap['Expr_ArrowFunction->returnType'] = [')', \false, ': ', null];
|
2020-01-29 13:36:09 +00:00
|
|
|
}
|
2020-10-11 14:17:43 +00:00
|
|
|
/**
|
|
|
|
* @param Node[] $stmts
|
|
|
|
* @param Node[] $origStmts
|
|
|
|
* @param mixed[] $origTokens
|
|
|
|
*/
|
2021-12-10 10:22:23 +00:00
|
|
|
public function printFormatPreserving(array $stmts, array $origStmts, array $origTokens) : string
|
2019-09-25 09:00:21 +00:00
|
|
|
{
|
2020-10-05 08:39:02 +00:00
|
|
|
$newStmts = $this->resolveNewStmts($stmts);
|
|
|
|
$content = parent::printFormatPreserving($newStmts, $origStmts, $origTokens);
|
2020-05-26 21:41:09 +00:00
|
|
|
// add new line in case of added stmts
|
2023-09-10 01:02:05 +00:00
|
|
|
if (\count($newStmts) !== \count($origStmts) && \substr_compare($content, "\n", -\strlen("\n")) !== 0) {
|
2020-05-26 21:41:09 +00:00
|
|
|
$content .= $this->nl;
|
|
|
|
}
|
2023-06-04 09:14:10 +00:00
|
|
|
return $content;
|
2019-09-25 09:00:21 +00:00
|
|
|
}
|
2018-12-25 21:31:48 +00:00
|
|
|
/**
|
2023-09-11 09:47:14 +00:00
|
|
|
* @param Node|Node[]|null $node
|
2018-12-25 21:31:48 +00:00
|
|
|
*/
|
2021-05-09 20:15:43 +00:00
|
|
|
public function print($node) : string
|
2018-12-25 21:31:48 +00:00
|
|
|
{
|
|
|
|
if ($node === null) {
|
|
|
|
$node = [];
|
|
|
|
}
|
2021-05-09 20:15:43 +00:00
|
|
|
if (!\is_array($node)) {
|
2018-12-25 21:31:48 +00:00
|
|
|
$node = [$node];
|
|
|
|
}
|
|
|
|
return $this->prettyPrint($node);
|
|
|
|
}
|
2020-04-19 23:58:50 +00:00
|
|
|
/**
|
2021-02-13 13:25:47 +00:00
|
|
|
* @param Node[] $stmts
|
2020-04-19 23:58:50 +00:00
|
|
|
*/
|
2021-12-10 10:22:23 +00:00
|
|
|
public function prettyPrintFile(array $stmts) : string
|
2020-04-19 23:58:50 +00:00
|
|
|
{
|
2020-06-21 09:51:50 +00:00
|
|
|
// to keep indexes from 0
|
2021-05-09 20:15:43 +00:00
|
|
|
$stmts = \array_values($stmts);
|
|
|
|
return parent::prettyPrintFile($stmts) . \PHP_EOL;
|
2020-04-19 23:58:50 +00:00
|
|
|
}
|
2022-12-23 17:10:25 +00:00
|
|
|
/**
|
|
|
|
* @api magic method in parent
|
|
|
|
*/
|
2022-06-07 08:22:29 +00:00
|
|
|
public function pFileWithoutNamespace(FileWithoutNamespace $fileWithoutNamespace) : string
|
2020-10-05 08:39:02 +00:00
|
|
|
{
|
2021-05-09 20:15:43 +00:00
|
|
|
$content = $this->pStmts($fileWithoutNamespace->stmts, \false);
|
|
|
|
return \ltrim($content);
|
2020-10-05 08:39:02 +00:00
|
|
|
}
|
2022-06-07 08:22:29 +00:00
|
|
|
protected function p(Node $node, $parentFormatPreserved = \false) : string
|
2021-12-09 17:01:18 +00:00
|
|
|
{
|
2023-08-03 09:57:07 +00:00
|
|
|
while ($node instanceof AlwaysRememberedExpr) {
|
|
|
|
$node = $node->getExpr();
|
|
|
|
}
|
2021-12-09 17:01:18 +00:00
|
|
|
$content = parent::p($node, $parentFormatPreserved);
|
2022-06-07 08:22:29 +00:00
|
|
|
return $node->getAttribute(AttributeKey::WRAPPED_IN_PARENTHESES) === \true ? '(' . $content . ')' : $content;
|
2021-12-09 17:01:18 +00:00
|
|
|
}
|
2024-02-21 15:30:52 +00:00
|
|
|
protected function pAttributeGroup(AttributeGroup $attributeGroup) : string
|
2024-02-21 15:17:39 +00:00
|
|
|
{
|
2024-02-21 15:30:52 +00:00
|
|
|
$ret = parent::pAttributeGroup($attributeGroup);
|
|
|
|
$comment = $attributeGroup->getAttribute(AttributeKey::ATTRIBUTE_COMMENT);
|
2024-02-21 15:17:39 +00:00
|
|
|
if (!\in_array($comment, ['', null], \true)) {
|
|
|
|
$ret .= ' // ' . $comment;
|
|
|
|
}
|
|
|
|
return $ret;
|
|
|
|
}
|
2023-05-15 08:40:30 +00:00
|
|
|
protected function pExpr_ArrowFunction(ArrowFunction $arrowFunction) : string
|
|
|
|
{
|
|
|
|
if (!$arrowFunction->hasAttribute(AttributeKey::COMMENT_CLOSURE_RETURN_MIRRORED)) {
|
|
|
|
return parent::pExpr_ArrowFunction($arrowFunction);
|
|
|
|
}
|
|
|
|
$expr = $arrowFunction->expr;
|
|
|
|
/** @var Comment[] $comments */
|
|
|
|
$comments = $expr->getAttribute(AttributeKey::COMMENTS) ?? [];
|
|
|
|
if ($comments === []) {
|
|
|
|
return parent::pExpr_ArrowFunction($arrowFunction);
|
|
|
|
}
|
2024-03-28 16:05:42 +00:00
|
|
|
$indent = $this->resolveIndentSpaces();
|
2023-05-15 08:40:30 +00:00
|
|
|
$text = "\n" . $indent;
|
|
|
|
foreach ($comments as $key => $comment) {
|
|
|
|
$commentText = $key > 0 ? $indent . $comment->getText() : $comment->getText();
|
|
|
|
$text .= $commentText . "\n";
|
|
|
|
}
|
|
|
|
return $this->pAttrGroups($arrowFunction->attrGroups, \true) . ($arrowFunction->static ? 'static ' : '') . 'fn' . ($arrowFunction->byRef ? '&' : '') . '(' . $this->pCommaSeparated($arrowFunction->params) . ')' . ($arrowFunction->returnType !== null ? ': ' . $this->p($arrowFunction->returnType) : '') . ' =>' . $text . $indent . $this->p($arrowFunction->expr);
|
|
|
|
}
|
2019-09-25 09:00:21 +00:00
|
|
|
/**
|
|
|
|
* This allows to use both spaces and tabs vs. original space-only
|
|
|
|
*/
|
2021-12-10 10:22:23 +00:00
|
|
|
protected function setIndentLevel(int $level) : void
|
2019-09-25 09:00:21 +00:00
|
|
|
{
|
2021-05-09 20:15:43 +00:00
|
|
|
$level = \max($level, 0);
|
2019-09-25 09:00:21 +00:00
|
|
|
$this->indentLevel = $level;
|
2023-08-11 09:14:44 +00:00
|
|
|
$this->nl = "\n" . \str_repeat($this->getIndentCharacter(), $level);
|
2019-09-25 09:00:21 +00:00
|
|
|
}
|
|
|
|
/**
|
|
|
|
* This allows to use both spaces and tabs vs. original space-only
|
|
|
|
*/
|
2021-05-09 20:15:43 +00:00
|
|
|
protected function indent() : void
|
2019-09-25 09:00:21 +00:00
|
|
|
{
|
2023-07-09 13:51:12 +00:00
|
|
|
$indentSize = SimpleParameterProvider::provideIntParameter(Option::INDENT_SIZE);
|
2022-12-03 10:40:36 +00:00
|
|
|
$this->indentLevel += $indentSize;
|
2023-08-11 09:14:44 +00:00
|
|
|
$this->nl .= \str_repeat($this->getIndentCharacter(), $indentSize);
|
2019-09-25 09:00:21 +00:00
|
|
|
}
|
|
|
|
/**
|
|
|
|
* This allows to use both spaces and tabs vs. original space-only
|
|
|
|
*/
|
2021-05-09 20:15:43 +00:00
|
|
|
protected function outdent() : void
|
2019-09-25 09:00:21 +00:00
|
|
|
{
|
2023-08-11 09:14:44 +00:00
|
|
|
if ($this->getIndentCharacter() === ' ') {
|
2024-01-19 15:01:25 +00:00
|
|
|
$indentSize = SimpleParameterProvider::provideIntParameter(Option::INDENT_SIZE);
|
|
|
|
\assert($this->indentLevel >= $indentSize);
|
|
|
|
$this->indentLevel -= $indentSize;
|
2019-09-25 09:00:21 +00:00
|
|
|
} else {
|
|
|
|
// - 1 tab
|
2021-05-09 20:15:43 +00:00
|
|
|
\assert($this->indentLevel >= 1);
|
2019-09-25 09:00:21 +00:00
|
|
|
--$this->indentLevel;
|
|
|
|
}
|
2023-08-11 09:14:44 +00:00
|
|
|
$this->nl = "\n" . \str_repeat($this->getIndentCharacter(), $this->indentLevel);
|
2019-09-25 09:00:21 +00:00
|
|
|
}
|
2019-01-22 19:40:27 +00:00
|
|
|
/**
|
|
|
|
* @param mixed[] $nodes
|
|
|
|
* @param mixed[] $origNodes
|
|
|
|
* @param int|null $fixup
|
|
|
|
*/
|
2021-12-10 10:22:23 +00:00
|
|
|
protected function pArray(array $nodes, array $origNodes, int &$pos, int $indentAdjustment, string $parentNodeType, string $subNodeName, $fixup) : ?string
|
2021-05-09 20:15:43 +00:00
|
|
|
{
|
2019-01-22 19:40:27 +00:00
|
|
|
// reindex positions for printer
|
2021-05-09 20:15:43 +00:00
|
|
|
$nodes = \array_values($nodes);
|
2019-07-14 12:54:02 +00:00
|
|
|
$content = parent::pArray($nodes, $origNodes, $pos, $indentAdjustment, $parentNodeType, $subNodeName, $fixup);
|
|
|
|
if ($content === null) {
|
|
|
|
return $content;
|
|
|
|
}
|
2021-05-09 20:15:43 +00:00
|
|
|
if (!$this->containsNop($nodes)) {
|
2019-07-14 12:54:02 +00:00
|
|
|
return $content;
|
|
|
|
}
|
2023-01-10 11:07:38 +00:00
|
|
|
return Strings::replace($content, self::EXTRA_SPACE_BEFORE_NOP_REGEX);
|
2019-01-22 19:40:27 +00:00
|
|
|
}
|
2017-12-01 19:56:06 +00:00
|
|
|
/**
|
2017-12-01 20:17:16 +00:00
|
|
|
* Do not preslash all slashes (parent behavior), but only those:
|
|
|
|
*
|
|
|
|
* - followed by "\"
|
|
|
|
* - by "'"
|
|
|
|
* - or the end of the string
|
|
|
|
*
|
|
|
|
* Prevents `Vendor\Class` => `Vendor\\Class`.
|
2017-12-01 19:56:06 +00:00
|
|
|
*/
|
2021-12-10 10:22:23 +00:00
|
|
|
protected function pSingleQuotedString(string $string) : string
|
2017-12-01 19:52:33 +00:00
|
|
|
{
|
2022-06-07 08:22:29 +00:00
|
|
|
return "'" . Strings::replace($string, self::QUOTED_SLASH_REGEX, '\\\\$0') . "'";
|
2017-12-01 19:52:33 +00:00
|
|
|
}
|
2019-08-13 11:13:09 +00:00
|
|
|
/**
|
|
|
|
* Emulates 1_000 in PHP 7.3- version
|
|
|
|
*/
|
2022-06-07 08:22:29 +00:00
|
|
|
protected function pScalar_DNumber(DNumber $dNumber) : string
|
2019-08-13 11:13:09 +00:00
|
|
|
{
|
2022-09-05 17:52:37 +00:00
|
|
|
if ($this->shouldPrintNewRawValue($dNumber)) {
|
|
|
|
return (string) $dNumber->getAttribute(AttributeKey::RAW_VALUE);
|
2019-08-13 11:13:09 +00:00
|
|
|
}
|
2020-05-03 11:38:00 +00:00
|
|
|
return parent::pScalar_DNumber($dNumber);
|
2019-08-13 11:13:09 +00:00
|
|
|
}
|
2018-12-15 21:05:44 +00:00
|
|
|
/**
|
2020-01-29 13:36:09 +00:00
|
|
|
* Add space:
|
|
|
|
* "use("
|
|
|
|
* ↓
|
|
|
|
* "use ("
|
2018-12-15 21:05:44 +00:00
|
|
|
*/
|
2022-06-07 08:22:29 +00:00
|
|
|
protected function pExpr_Closure(Closure $closure) : string
|
2018-12-15 21:05:44 +00:00
|
|
|
{
|
2020-01-29 13:36:09 +00:00
|
|
|
$closureContent = parent::pExpr_Closure($closure);
|
2022-01-10 00:03:45 +00:00
|
|
|
if ($closure->uses === []) {
|
|
|
|
return $closureContent;
|
|
|
|
}
|
2023-09-10 18:48:21 +00:00
|
|
|
return \str_replace(' use(', ' use (', (string) $closureContent);
|
2018-12-15 21:05:44 +00:00
|
|
|
}
|
2018-04-14 18:17:59 +00:00
|
|
|
/**
|
2018-04-14 18:24:45 +00:00
|
|
|
* Do not add "()" on Expressions
|
2018-04-14 18:17:59 +00:00
|
|
|
* @see https://github.com/rectorphp/rector/pull/401#discussion_r181487199
|
|
|
|
*/
|
2022-06-07 08:22:29 +00:00
|
|
|
protected function pExpr_Yield(Yield_ $yield) : string
|
2018-04-14 18:17:59 +00:00
|
|
|
{
|
2023-03-23 23:21:34 +00:00
|
|
|
if (!$yield->value instanceof Expr) {
|
2018-04-14 18:17:59 +00:00
|
|
|
return 'yield';
|
2018-04-14 18:24:45 +00:00
|
|
|
}
|
2021-11-25 19:11:55 +00:00
|
|
|
// brackets are needed only in case of assign, @see https://www.php.net/manual/en/language.generators.syntax.php
|
2023-06-11 23:01:39 +00:00
|
|
|
$shouldAddBrackets = (bool) $yield->getAttribute(AttributeKey::IS_ASSIGNED_TO);
|
2023-03-23 23:21:34 +00:00
|
|
|
return \sprintf('%syield %s%s%s', $shouldAddBrackets ? '(' : '', $yield->key instanceof Expr ? $this->p($yield->key) . ' => ' : '', $this->p($yield->value), $shouldAddBrackets ? ')' : '');
|
2018-04-14 18:17:59 +00:00
|
|
|
}
|
2018-10-07 13:38:35 +00:00
|
|
|
/**
|
|
|
|
* Print arrays in short [] by default,
|
|
|
|
* to prevent manual explicit array shortening.
|
|
|
|
*/
|
2022-06-07 08:22:29 +00:00
|
|
|
protected function pExpr_Array(Array_ $array) : string
|
2018-10-07 13:38:35 +00:00
|
|
|
{
|
2022-06-07 08:22:29 +00:00
|
|
|
if (!$array->hasAttribute(AttributeKey::KIND)) {
|
|
|
|
$array->setAttribute(AttributeKey::KIND, Array_::KIND_SHORT);
|
2018-10-07 13:38:35 +00:00
|
|
|
}
|
2023-01-10 11:07:38 +00:00
|
|
|
if ($array->getAttribute(AttributeKey::NEWLINED_ARRAY_PRINT) === \true) {
|
|
|
|
$printedArray = '[';
|
|
|
|
$printedArray .= $this->pCommaSeparatedMultiline($array->items, \true);
|
|
|
|
return $printedArray . ($this->nl . ']');
|
|
|
|
}
|
2020-06-29 21:19:37 +00:00
|
|
|
return parent::pExpr_Array($array);
|
2018-10-07 13:38:35 +00:00
|
|
|
}
|
2018-12-16 12:09:08 +00:00
|
|
|
/**
|
|
|
|
* Fixes escaping of regular patterns
|
|
|
|
*/
|
2022-06-07 08:22:29 +00:00
|
|
|
protected function pScalar_String(String_ $string) : string
|
2018-12-16 12:09:08 +00:00
|
|
|
{
|
2022-06-07 08:22:29 +00:00
|
|
|
$isRegularPattern = (bool) $string->getAttribute(AttributeKey::IS_REGULAR_PATTERN, \false);
|
2021-05-09 20:15:43 +00:00
|
|
|
if (!$isRegularPattern) {
|
2021-02-02 15:11:31 +00:00
|
|
|
return parent::pScalar_String($string);
|
|
|
|
}
|
2022-06-07 08:22:29 +00:00
|
|
|
$kind = $string->getAttribute(AttributeKey::KIND, String_::KIND_SINGLE_QUOTED);
|
|
|
|
if ($kind === String_::KIND_DOUBLE_QUOTED) {
|
2021-02-02 15:11:31 +00:00
|
|
|
return $this->wrapValueWith($string, '"');
|
|
|
|
}
|
2022-06-07 08:22:29 +00:00
|
|
|
if ($kind === String_::KIND_SINGLE_QUOTED) {
|
2021-02-02 15:11:31 +00:00
|
|
|
return $this->wrapValueWith($string, "'");
|
2018-12-16 12:09:08 +00:00
|
|
|
}
|
2020-06-29 21:19:37 +00:00
|
|
|
return parent::pScalar_String($string);
|
2018-12-16 12:09:08 +00:00
|
|
|
}
|
2018-12-17 00:27:38 +00:00
|
|
|
/**
|
|
|
|
* "...$params) : ReturnType"
|
|
|
|
* ↓
|
|
|
|
* "...$params): ReturnType"
|
|
|
|
*/
|
2022-06-07 08:22:29 +00:00
|
|
|
protected function pStmt_ClassMethod(ClassMethod $classMethod) : string
|
2018-12-17 00:27:38 +00:00
|
|
|
{
|
2020-10-04 11:12:41 +00:00
|
|
|
$content = parent::pStmt_ClassMethod($classMethod);
|
2022-06-07 08:22:29 +00:00
|
|
|
if (!$classMethod->returnType instanceof Node) {
|
2022-01-10 00:03:45 +00:00
|
|
|
return $content;
|
|
|
|
}
|
2020-10-04 11:12:41 +00:00
|
|
|
// this approach is chosen, to keep changes in parent pStmt_ClassMethod() updated
|
2022-06-07 08:22:29 +00:00
|
|
|
return Strings::replace($content, self::REPLACE_COLON_WITH_SPACE_REGEX, '$1: ');
|
2018-12-17 00:27:38 +00:00
|
|
|
}
|
2019-09-15 18:45:58 +00:00
|
|
|
/**
|
|
|
|
* It remove all spaces extra to parent
|
|
|
|
*/
|
2022-06-07 08:22:29 +00:00
|
|
|
protected function pStmt_Declare(Declare_ $declare) : string
|
2019-09-15 18:45:58 +00:00
|
|
|
{
|
|
|
|
$declareString = parent::pStmt_Declare($declare);
|
2023-01-10 11:07:38 +00:00
|
|
|
return Strings::replace($declareString, '#\\s+#');
|
2019-09-15 18:45:58 +00:00
|
|
|
}
|
2022-06-07 08:22:29 +00:00
|
|
|
protected function pExpr_Ternary(Ternary $ternary) : string
|
2021-07-07 14:27:09 +00:00
|
|
|
{
|
2022-06-07 08:22:29 +00:00
|
|
|
$kind = $ternary->getAttribute(AttributeKey::KIND);
|
2021-07-07 14:27:09 +00:00
|
|
|
if ($kind === 'wrapped_with_brackets') {
|
|
|
|
$pExprTernary = parent::pExpr_Ternary($ternary);
|
|
|
|
return '(' . $pExprTernary . ')';
|
|
|
|
}
|
|
|
|
return parent::pExpr_Ternary($ternary);
|
|
|
|
}
|
2022-06-07 08:22:29 +00:00
|
|
|
protected function pScalar_EncapsedStringPart(EncapsedStringPart $encapsedStringPart) : string
|
2020-10-31 16:20:30 +00:00
|
|
|
{
|
|
|
|
// parent throws exception, but we need to compare string
|
|
|
|
return '`' . $encapsedStringPart->value . '`';
|
|
|
|
}
|
2021-12-10 10:22:23 +00:00
|
|
|
protected function pCommaSeparated(array $nodes) : string
|
2020-12-05 21:40:10 +00:00
|
|
|
{
|
|
|
|
$result = parent::pCommaSeparated($nodes);
|
2021-05-09 20:15:43 +00:00
|
|
|
$last = \end($nodes);
|
2022-06-07 08:22:29 +00:00
|
|
|
if ($last instanceof Node) {
|
|
|
|
$trailingComma = $last->getAttribute(AttributeKey::FUNC_ARGS_TRAILING_COMMA);
|
2021-05-09 20:15:43 +00:00
|
|
|
if ($trailingComma === \false) {
|
|
|
|
$result = \rtrim($result, ',');
|
2020-12-05 21:40:10 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return $result;
|
|
|
|
}
|
2022-05-18 10:48:11 +00:00
|
|
|
/**
|
|
|
|
* Override parent pModifiers to set position of final and abstract modifier early, so instead of
|
|
|
|
*
|
|
|
|
* public final const MY_CONSTANT = "Hello world!";
|
|
|
|
*
|
|
|
|
* it should be
|
|
|
|
*
|
|
|
|
* final public const MY_CONSTANT = "Hello world!";
|
|
|
|
*
|
|
|
|
* @see https://github.com/rectorphp/rector/issues/6963
|
|
|
|
* @see https://github.com/nikic/PHP-Parser/pull/826
|
|
|
|
*/
|
|
|
|
protected function pModifiers(int $modifiers) : string
|
|
|
|
{
|
2022-06-07 08:22:29 +00:00
|
|
|
return (($modifiers & Class_::MODIFIER_FINAL) !== 0 ? 'final ' : '') . (($modifiers & Class_::MODIFIER_ABSTRACT) !== 0 ? 'abstract ' : '') . (($modifiers & Class_::MODIFIER_PUBLIC) !== 0 ? 'public ' : '') . (($modifiers & Class_::MODIFIER_PROTECTED) !== 0 ? 'protected ' : '') . (($modifiers & Class_::MODIFIER_PRIVATE) !== 0 ? 'private ' : '') . (($modifiers & Class_::MODIFIER_STATIC) !== 0 ? 'static ' : '') . (($modifiers & Class_::MODIFIER_READONLY) !== 0 ? 'readonly ' : '');
|
2022-05-18 10:48:11 +00:00
|
|
|
}
|
2022-09-05 17:52:37 +00:00
|
|
|
/**
|
|
|
|
* Invoke re-print even if only raw value was changed.
|
|
|
|
* That allows PHPStan to use int strict types, while changing the value with literal "_"
|
|
|
|
* @return string|int
|
|
|
|
*/
|
|
|
|
protected function pScalar_LNumber(LNumber $lNumber)
|
|
|
|
{
|
|
|
|
if ($this->shouldPrintNewRawValue($lNumber)) {
|
|
|
|
return (string) $lNumber->getAttribute(AttributeKey::RAW_VALUE);
|
|
|
|
}
|
|
|
|
return parent::pScalar_LNumber($lNumber);
|
|
|
|
}
|
2024-03-28 16:05:42 +00:00
|
|
|
private function resolveIndentSpaces() : string
|
|
|
|
{
|
|
|
|
$indentSize = SimpleParameterProvider::provideIntParameter(Option::INDENT_SIZE);
|
|
|
|
return \str_repeat($this->getIndentCharacter(), $this->indentLevel) . \str_repeat($this->getIndentCharacter(), $indentSize);
|
|
|
|
}
|
|
|
|
protected function pExpr_MethodCall(MethodCall $methodCall) : string
|
|
|
|
{
|
|
|
|
if (SimpleParameterProvider::provideBoolParameter(Option::NEW_LINE_ON_FLUENT_CALL) === \false) {
|
|
|
|
return parent::pExpr_MethodCall($methodCall);
|
|
|
|
}
|
|
|
|
if ($methodCall->var instanceof CallLike) {
|
|
|
|
foreach ($methodCall->args as $arg) {
|
|
|
|
if (!$arg instanceof Arg) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
$arg->value->setAttribute(AttributeKey::ORIGINAL_NODE, null);
|
|
|
|
}
|
|
|
|
return $this->pDereferenceLhs($methodCall->var) . "\n" . $this->resolveIndentSpaces() . "->" . $this->pObjectProperty($methodCall->name) . '(' . $this->pMaybeMultiline($methodCall->args) . ')';
|
|
|
|
}
|
|
|
|
return parent::pExpr_MethodCall($methodCall);
|
|
|
|
}
|
2022-10-15 22:34:17 +00:00
|
|
|
/**
|
|
|
|
* Keep attributes on newlines
|
|
|
|
*/
|
|
|
|
protected function pParam(Param $param) : string
|
|
|
|
{
|
|
|
|
return $this->pAttrGroups($param->attrGroups) . $this->pModifiers($param->flags) . ($param->type instanceof Node ? $this->p($param->type) . ' ' : '') . ($param->byRef ? '&' : '') . ($param->variadic ? '...' : '') . $this->p($param->var) . ($param->default instanceof Expr ? ' = ' . $this->p($param->default) : '');
|
|
|
|
}
|
2023-08-11 09:14:44 +00:00
|
|
|
/**
|
|
|
|
* Must be a method to be able to react to changed parameter in tests
|
|
|
|
*/
|
|
|
|
private function getIndentCharacter() : string
|
|
|
|
{
|
|
|
|
return SimpleParameterProvider::provideStringParameter(Option::INDENT_CHAR, ' ');
|
|
|
|
}
|
2022-09-05 17:52:37 +00:00
|
|
|
/**
|
|
|
|
* @param \PhpParser\Node\Scalar\LNumber|\PhpParser\Node\Scalar\DNumber $lNumber
|
|
|
|
*/
|
|
|
|
private function shouldPrintNewRawValue($lNumber) : bool
|
|
|
|
{
|
|
|
|
return $lNumber->getAttribute(AttributeKey::REPRINT_RAW_VALUE) === \true;
|
|
|
|
}
|
2020-10-05 08:39:02 +00:00
|
|
|
/**
|
2020-10-11 14:17:43 +00:00
|
|
|
* @param Node[] $stmts
|
2020-10-05 08:39:02 +00:00
|
|
|
* @return Node[]|mixed[]
|
|
|
|
*/
|
2021-07-05 23:06:30 +00:00
|
|
|
private function resolveNewStmts(array $stmts) : array
|
2020-10-05 08:39:02 +00:00
|
|
|
{
|
2023-03-05 23:49:34 +00:00
|
|
|
$stmts = \array_values($stmts);
|
2022-06-07 08:22:29 +00:00
|
|
|
if (\count($stmts) === 1 && $stmts[0] instanceof FileWithoutNamespace) {
|
2023-06-07 02:01:28 +00:00
|
|
|
return $stmts[0]->stmts;
|
2020-10-05 08:39:02 +00:00
|
|
|
}
|
|
|
|
return $stmts;
|
|
|
|
}
|
2020-02-01 16:04:38 +00:00
|
|
|
/**
|
|
|
|
* @param Node[] $nodes
|
|
|
|
*/
|
2021-07-05 23:06:30 +00:00
|
|
|
private function containsNop(array $nodes) : bool
|
2020-01-29 13:36:09 +00:00
|
|
|
{
|
2020-02-01 16:04:38 +00:00
|
|
|
foreach ($nodes as $node) {
|
2022-06-07 08:22:29 +00:00
|
|
|
if ($node instanceof Nop) {
|
2021-05-09 20:15:43 +00:00
|
|
|
return \true;
|
2020-02-01 16:04:38 +00:00
|
|
|
}
|
|
|
|
}
|
2021-05-09 20:15:43 +00:00
|
|
|
return \false;
|
2020-01-29 13:36:09 +00:00
|
|
|
}
|
2022-06-07 08:22:29 +00:00
|
|
|
private function wrapValueWith(String_ $string, string $wrap) : string
|
2020-04-18 19:11:06 +00:00
|
|
|
{
|
2020-06-29 21:19:37 +00:00
|
|
|
return $wrap . $string->value . $wrap;
|
2020-04-18 19:11:06 +00:00
|
|
|
}
|
2017-12-01 19:52:33 +00:00
|
|
|
}
|