diff --git a/config/set/coding-style/coding-style.yaml b/config/set/coding-style/coding-style.yaml index 15d80249deb..875bdcf60aa 100644 --- a/config/set/coding-style/coding-style.yaml +++ b/config/set/coding-style/coding-style.yaml @@ -24,3 +24,4 @@ services: Rector\CodingStyle\Rector\ClassConst\VarConstantCommentRector: ~ Rector\CodingStyle\Rector\Encapsed\EncapsedStringsToSprintfRector: ~ + Rector\CodingStyle\Rector\ClassMethod\NewlineBeforeNewAssignSetRector: ~ diff --git a/packages/CodingStyle/src/Rector/ClassMethod/NewlineBeforeNewAssignSetRector.php b/packages/CodingStyle/src/Rector/ClassMethod/NewlineBeforeNewAssignSetRector.php new file mode 100644 index 00000000000..c4dfa6ba25d --- /dev/null +++ b/packages/CodingStyle/src/Rector/ClassMethod/NewlineBeforeNewAssignSetRector.php @@ -0,0 +1,109 @@ +setValue(5); + $value2 = new Value; + $value2->setValue(1); + } +} +CODE_SAMPLE + , + <<<'CODE_SAMPLE' +final class SomeClass +{ + public function run() + { + $value = new Value; + $value->setValue(5); + + $value2 = new Value; + $value2->setValue(1); + } +} +CODE_SAMPLE + ), + ]); + } + + /** + * @return string[] + */ + public function getNodeTypes(): array + { + return [Node\Stmt\ClassMethod::class, Node\Stmt\Function_::class, Node\Expr\Closure::class]; + } + + /** + * @param Node\Stmt\ClassMethod|Node\Stmt\Function_|Node\Expr\Closure $node + */ + public function refactor(Node $node): ?Node + { + $previousStmtVariableName = null; + + if ($node->stmts === null) { + return null; + } + + foreach ($node->stmts as $key => $stmt) { + $currentStmtVariableName = null; + + if ($stmt instanceof Expression) { + $stmt = $stmt->expr; + } + + if ($stmt instanceof Assign || $stmt instanceof MethodCall) { + if ($stmt->var instanceof Variable) { + $currentStmtVariableName = $this->getName($stmt->var); + } + } + + if ($this->isNewVariableThanBefore($previousStmtVariableName, $currentStmtVariableName)) { + // insert newline before + array_splice($node->stmts, $key, 0, [new Nop()]); + } + + $previousStmtVariableName = $currentStmtVariableName; + } + + return $node; + } + + private function isNewVariableThanBefore(?string $previousStmtVariableName, ?string $currentStmtVariableName): bool + { + if ($previousStmtVariableName === null) { + return false; + } + + if ($currentStmtVariableName === null) { + return false; + } + + return $previousStmtVariableName !== $currentStmtVariableName; + } +} diff --git a/packages/CodingStyle/tests/Rector/ClassMethod/NewlineBeforeNewAssignSetRector/Fixture/fixture.php.inc b/packages/CodingStyle/tests/Rector/ClassMethod/NewlineBeforeNewAssignSetRector/Fixture/fixture.php.inc new file mode 100644 index 00000000000..5ff77186483 --- /dev/null +++ b/packages/CodingStyle/tests/Rector/ClassMethod/NewlineBeforeNewAssignSetRector/Fixture/fixture.php.inc @@ -0,0 +1,34 @@ +setValue(5); + $value2 = new Value; + $value2->setValue(1); + } +} + +?> +----- +setValue(5); + + $value2 = new Value; + $value2->setValue(1); + } +} + +?> diff --git a/packages/CodingStyle/tests/Rector/ClassMethod/NewlineBeforeNewAssignSetRector/NewlineBeforeNewAssignSetRectorTest.php b/packages/CodingStyle/tests/Rector/ClassMethod/NewlineBeforeNewAssignSetRector/NewlineBeforeNewAssignSetRectorTest.php new file mode 100644 index 00000000000..04eab766073 --- /dev/null +++ b/packages/CodingStyle/tests/Rector/ClassMethod/NewlineBeforeNewAssignSetRector/NewlineBeforeNewAssignSetRectorTest.php @@ -0,0 +1,19 @@ +doTestFiles([__DIR__ . '/Fixture/fixture.php.inc']); + } + + protected function getRectorClass(): string + { + return NewlineBeforeNewAssignSetRector::class; + } +} diff --git a/src/PhpParser/Printer/BetterStandardPrinter.php b/src/PhpParser/Printer/BetterStandardPrinter.php index 31d4013e035..95c6e021b40 100644 --- a/src/PhpParser/Printer/BetterStandardPrinter.php +++ b/src/PhpParser/Printer/BetterStandardPrinter.php @@ -84,7 +84,19 @@ final class BetterStandardPrinter extends Standard // reindex positions for printer $nodes = array_values($nodes); - return parent::pArray($nodes, $origNodes, $pos, $indentAdjustment, $parentNodeType, $subNodeName, $fixup); + $content = parent::pArray($nodes, $origNodes, $pos, $indentAdjustment, $parentNodeType, $subNodeName, $fixup); + + if ($content === null) { + return $content; + } + + if (! $this->containsNop($nodes)) { + return $content; + } + + // remove extra spaces before new Nop_ nodes, @see https://regex101.com/r/iSvroO/1 + return Strings::replace($content, '#^[ \t]+$#m'); + return Strings::replace($content, '#^[ \t]+$#m'); } /** @@ -196,4 +208,18 @@ final class BetterStandardPrinter extends Standard return parent::pStmt_Class($class); } + + /** + * @param Node[] $nodes + */ + private function containsNop(array $nodes): bool + { + foreach ($nodes as $node) { + if ($node instanceof Node\Stmt\Nop) { + return true; + } + } + + return false; + } }