Skip to content

Commit 9cd089e

Browse files
Majkl578kukulich
authored andcommitted
EmptyLinesAroundTypeBracesSniff: Allow configurable number of lines around braces
1 parent 9cfa50d commit 9cd089e

12 files changed

+287
-40
lines changed

SlevomatCodingStandard/Sniffs/Types/EmptyLinesAroundTypeBracesSniff.php

Lines changed: 97 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,29 @@
22

33
namespace SlevomatCodingStandard\Sniffs\Types;
44

5+
use SlevomatCodingStandard\Helpers\SniffSettingsHelper;
6+
57
class EmptyLinesAroundTypeBracesSniff implements \PHP_CodeSniffer_Sniff
68
{
79

810
const CODE_NO_EMPTY_LINE_AFTER_OPENING_BRACE = 'NoEmptyLineAfterOpeningBrace';
911

1012
const CODE_MULTIPLE_EMPTY_LINES_AFTER_OPENING_BRACE = 'MultipleEmptyLinesAfterOpeningBrace';
1113

14+
const CODE_INCORRECT_EMPTY_LINES_AFTER_OPENING_BRACE = 'IncorrectEmptyLinesAfterOpeningBrace';
15+
1216
const CODE_NO_EMPTY_LINE_BEFORE_CLOSING_BRACE = 'NoEmptyLineBeforeClosingBrace';
1317

1418
const CODE_MULTIPLE_EMPTY_LINES_BEFORE_CLOSING_BRACE = 'MultipleEmptyLinesBeforeClosingBrace';
1519

20+
const CODE_INCORRECT_EMPTY_LINES_BEFORE_CLOSING_BRACE = 'IncorrectEmptyLinesBeforeClosingBrace';
21+
22+
/** @var int */
23+
public $linesCountAfterOpeningBrace = 1;
24+
25+
/** @var int */
26+
public $linesCountBeforeClosingBrace = 1;
27+
1628
/**
1729
* @return int[]
1830
*/
@@ -31,74 +43,119 @@ public function register(): array
3143
* @param int $stackPointer
3244
*/
3345
public function process(\PHP_CodeSniffer_File $phpcsFile, $stackPointer)
46+
{
47+
$this->processOpeningBrace($phpcsFile, $stackPointer);
48+
$this->processClosingBrace($phpcsFile, $stackPointer);
49+
}
50+
51+
private function processOpeningBrace(\PHP_CodeSniffer_File $phpcsFile, int $stackPointer)
3452
{
3553
$tokens = $phpcsFile->getTokens();
3654
$typeToken = $tokens[$stackPointer];
3755
$openerPointer = $typeToken['scope_opener'];
3856
$openerToken = $tokens[$openerPointer];
3957
$nextPointerAfterOpeningBrace = $phpcsFile->findNext(T_WHITESPACE, $openerPointer + 1, null, true);
4058
$nextTokenAfterOpeningBrace = $tokens[$nextPointerAfterOpeningBrace];
41-
59+
$linesCountAfterOpeningBrace = SniffSettingsHelper::normalizeInteger($this->linesCountAfterOpeningBrace);
4260
$lines = $nextTokenAfterOpeningBrace['line'] - $openerToken['line'] - 1;
43-
if ($lines === 0) {
61+
62+
if ($lines === $linesCountAfterOpeningBrace) {
63+
return;
64+
}
65+
66+
if ($linesCountAfterOpeningBrace === 1) {
67+
if ($lines === 0) {
68+
$fix = $phpcsFile->addFixableError(sprintf(
69+
'There must be one empty line after %s opening brace.',
70+
$typeToken['content']
71+
), $openerPointer, self::CODE_NO_EMPTY_LINE_AFTER_OPENING_BRACE);
72+
} else {
73+
$fix = $phpcsFile->addFixableError(sprintf(
74+
'There must be one empty line after %s opening brace.',
75+
$typeToken['content']
76+
), $openerPointer, self::CODE_MULTIPLE_EMPTY_LINES_AFTER_OPENING_BRACE);
77+
}
78+
} else {
4479
$fix = $phpcsFile->addFixableError(sprintf(
45-
'There must be one empty line after %s opening brace.',
80+
'There must be exactly %d empty lines after %s opening brace.',
81+
$linesCountAfterOpeningBrace,
4682
$typeToken['content']
47-
), $openerPointer, self::CODE_NO_EMPTY_LINE_AFTER_OPENING_BRACE);
83+
), $openerPointer, self::CODE_INCORRECT_EMPTY_LINES_AFTER_OPENING_BRACE);
84+
}
85+
86+
if (!$fix) {
87+
return;
88+
}
4889

49-
if ($fix) {
50-
$phpcsFile->fixer->beginChangeset();
90+
if ($lines < $linesCountAfterOpeningBrace) {
91+
$phpcsFile->fixer->beginChangeset();
92+
for ($i = $lines; $i < $linesCountAfterOpeningBrace; $i++) {
5193
$phpcsFile->fixer->addNewline($openerPointer);
52-
$phpcsFile->fixer->endChangeset();
5394
}
54-
} elseif ($lines > 1) {
55-
$fix = $phpcsFile->addFixableError(sprintf(
56-
'There must be one empty line after %s opening brace.',
57-
$typeToken['content']
58-
), $openerPointer, self::CODE_MULTIPLE_EMPTY_LINES_AFTER_OPENING_BRACE);
59-
60-
if ($fix) {
61-
$phpcsFile->fixer->beginChangeset();
62-
for ($i = $openerPointer + 3; $i < $nextPointerAfterOpeningBrace; $i++) {
63-
if ($tokens[$i]['content'] !== $phpcsFile->eolChar) {
64-
break;
65-
}
66-
$phpcsFile->fixer->replaceToken($i, '');
95+
$phpcsFile->fixer->endChangeset();
96+
} else {
97+
$phpcsFile->fixer->beginChangeset();
98+
for ($i = $openerPointer + $linesCountAfterOpeningBrace + 2; $i < $nextPointerAfterOpeningBrace; $i++) {
99+
if ($tokens[$i]['content'] !== $phpcsFile->eolChar) {
100+
break;
67101
}
68-
$phpcsFile->fixer->endChangeset();
102+
$phpcsFile->fixer->replaceToken($i, '');
69103
}
104+
$phpcsFile->fixer->endChangeset();
70105
}
106+
}
71107

108+
private function processClosingBrace(\PHP_CodeSniffer_File $phpcsFile, int $stackPointer)
109+
{
110+
$tokens = $phpcsFile->getTokens();
111+
$typeToken = $tokens[$stackPointer];
72112
$closerPointer = $typeToken['scope_closer'];
73113
$closerToken = $tokens[$closerPointer];
74114
$previousPointerBeforeClosingBrace = $phpcsFile->findPrevious(T_WHITESPACE, $closerPointer - 1, null, true);
75115
$previousTokenBeforeClosingBrace = $tokens[$previousPointerBeforeClosingBrace];
76-
116+
$linesCountBeforeClosingBrace = SniffSettingsHelper::normalizeInteger($this->linesCountBeforeClosingBrace);
77117
$lines = $closerToken['line'] - $previousTokenBeforeClosingBrace['line'] - 1;
78-
if ($lines === 0) {
79-
$fix = $phpcsFile->addFixableError(sprintf(
80-
'There must be one empty line before %s closing brace.',
81-
$typeToken['content']
82-
), $closerPointer, self::CODE_NO_EMPTY_LINE_BEFORE_CLOSING_BRACE);
83118

84-
if ($fix) {
85-
$phpcsFile->fixer->beginChangeset();
86-
$phpcsFile->fixer->addNewlineBefore($closerPointer);
87-
$phpcsFile->fixer->endChangeset();
119+
if ($lines === $linesCountBeforeClosingBrace) {
120+
return;
121+
}
122+
123+
if ($linesCountBeforeClosingBrace === 1) {
124+
if ($lines === 0) {
125+
$fix = $phpcsFile->addFixableError(sprintf(
126+
'There must be one empty line before %s closing brace.',
127+
$typeToken['content']
128+
), $closerPointer, self::CODE_NO_EMPTY_LINE_BEFORE_CLOSING_BRACE);
129+
} else {
130+
$fix = $phpcsFile->addFixableError(sprintf(
131+
'There must be one empty line before %s closing brace.',
132+
$typeToken['content']
133+
), $closerPointer, self::CODE_MULTIPLE_EMPTY_LINES_BEFORE_CLOSING_BRACE);
88134
}
89-
} elseif ($lines > 1) {
135+
} else {
90136
$fix = $phpcsFile->addFixableError(sprintf(
91-
'There must be one empty line before %s closing brace.',
137+
'There must be exactly %d empty lines before %s closing brace.',
138+
$linesCountBeforeClosingBrace,
92139
$typeToken['content']
93-
), $closerPointer, self::CODE_MULTIPLE_EMPTY_LINES_BEFORE_CLOSING_BRACE);
140+
), $closerPointer, self::CODE_INCORRECT_EMPTY_LINES_BEFORE_CLOSING_BRACE);
141+
}
94142

95-
if ($fix) {
96-
$phpcsFile->fixer->beginChangeset();
97-
for ($i = $previousPointerBeforeClosingBrace + 3; $i < $closerPointer; $i++) {
98-
$phpcsFile->fixer->replaceToken($i, '');
99-
}
100-
$phpcsFile->fixer->endChangeset();
143+
if (!$fix) {
144+
return;
145+
}
146+
147+
if ($lines < $linesCountBeforeClosingBrace) {
148+
$phpcsFile->fixer->beginChangeset();
149+
for ($i = $lines; $i < $linesCountBeforeClosingBrace; $i++) {
150+
$phpcsFile->fixer->addNewlineBefore($closerPointer);
151+
}
152+
$phpcsFile->fixer->endChangeset();
153+
} else {
154+
$phpcsFile->fixer->beginChangeset();
155+
for ($i = $previousPointerBeforeClosingBrace + $linesCountBeforeClosingBrace + 2; $i < $closerPointer; $i++) {
156+
$phpcsFile->fixer->replaceToken($i, '');
101157
}
158+
$phpcsFile->fixer->endChangeset();
102159
}
103160
}
104161

tests/Sniffs/Types/EmptyLinesAroundTypeBracesSniffTest.php

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,4 +54,84 @@ public function testMultipleEmptyLinesBeforeClosingBrace()
5454
$this->assertAllFixedInFile($report);
5555
}
5656

57+
public function testCorrectCorrectEmptyLinesWithZeroLines()
58+
{
59+
$report = $this->checkFile(__DIR__ . '/data/correctEmptyLinesZeroLines.php', [
60+
'linesCountAfterOpeningBrace' => 0,
61+
'linesCountBeforeClosingBrace' => 0,
62+
]);
63+
64+
$this->assertNoSniffErrorInFile($report);
65+
}
66+
67+
public function testOneLineAfterOpeningBraceWithZeroExpected()
68+
{
69+
$report = $this->checkFile(
70+
__DIR__ . '/data/oneEmptyLineAfterOpeningBraceWithZeroExpected.php',
71+
['linesCountAfterOpeningBrace' => 0],
72+
[EmptyLinesAroundTypeBracesSniff::CODE_INCORRECT_EMPTY_LINES_AFTER_OPENING_BRACE]
73+
);
74+
75+
$this->assertSame(1, $report->getErrorCount());
76+
77+
$this->assertSniffError($report, 4, EmptyLinesAroundTypeBracesSniff::CODE_INCORRECT_EMPTY_LINES_AFTER_OPENING_BRACE);
78+
79+
$this->assertAllFixedInFile($report);
80+
}
81+
82+
public function testOneLineBeforeClosingBraceWithZeroExpected()
83+
{
84+
$report = $this->checkFile(
85+
__DIR__ . '/data/oneEmptyLineBeforeClosingBraceWithZeroExpected.php',
86+
['linesCountBeforeClosingBrace' => 0],
87+
[EmptyLinesAroundTypeBracesSniff::CODE_INCORRECT_EMPTY_LINES_BEFORE_CLOSING_BRACE]
88+
);
89+
90+
$this->assertSame(1, $report->getErrorCount());
91+
92+
$this->assertSniffError($report, 10, EmptyLinesAroundTypeBracesSniff::CODE_INCORRECT_EMPTY_LINES_BEFORE_CLOSING_BRACE);
93+
94+
$this->assertAllFixedInFile($report);
95+
}
96+
97+
public function testCorrectCorrectEmptyLinesWithTwoLines()
98+
{
99+
$report = $this->checkFile(__DIR__ . '/data/correctEmptyLinesTwoLines.php', [
100+
'linesCountAfterOpeningBrace' => 2,
101+
'linesCountBeforeClosingBrace' => 2,
102+
]);
103+
104+
$this->assertNoSniffErrorInFile($report);
105+
}
106+
107+
public function testOneLineAfterOpeningBraceWithTwoExpected()
108+
{
109+
$report = $this->checkFile(
110+
__DIR__ . '/data/oneEmptyLineAfterOpeningBraceWithTwoExpected.php',
111+
['linesCountAfterOpeningBrace' => 2],
112+
[EmptyLinesAroundTypeBracesSniff::CODE_INCORRECT_EMPTY_LINES_AFTER_OPENING_BRACE]
113+
);
114+
115+
$this->assertSame(1, $report->getErrorCount());
116+
117+
$this->assertSniffError($report, 4, EmptyLinesAroundTypeBracesSniff::CODE_INCORRECT_EMPTY_LINES_AFTER_OPENING_BRACE);
118+
119+
$this->assertAllFixedInFile($report);
120+
}
121+
122+
public function testOneLineBeforeClosingBraceWithTwoExpected()
123+
{
124+
$report = $this->checkFile(
125+
__DIR__ . '/data/oneEmptyLineBeforeClosingBraceWithTwoExpected.php',
126+
['linesCountBeforeClosingBrace' => 2],
127+
[EmptyLinesAroundTypeBracesSniff::CODE_INCORRECT_EMPTY_LINES_BEFORE_CLOSING_BRACE]
128+
);
129+
130+
$this->assertSame(1, $report->getErrorCount());
131+
132+
$this->assertSniffError($report, 12, EmptyLinesAroundTypeBracesSniff::CODE_INCORRECT_EMPTY_LINES_BEFORE_CLOSING_BRACE);
133+
134+
$this->assertAllFixedInFile($report);
135+
}
136+
57137
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?php
2+
3+
class Foo
4+
{
5+
6+
7+
public function bar()
8+
{
9+
10+
}
11+
12+
13+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<?php
2+
3+
class Foo
4+
{
5+
public function bar()
6+
{
7+
8+
}
9+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?php
2+
3+
class Foo
4+
{
5+
6+
7+
public function bar()
8+
{
9+
10+
}
11+
12+
13+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<?php
2+
3+
class Foo
4+
{
5+
6+
public function bar()
7+
{
8+
9+
}
10+
11+
12+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<?php
2+
3+
class Foo
4+
{
5+
public function bar()
6+
{
7+
8+
}
9+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?php
2+
3+
class Foo
4+
{
5+
6+
public function bar()
7+
{
8+
9+
}
10+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?php
2+
3+
class Foo
4+
{
5+
6+
7+
public function bar()
8+
{
9+
10+
}
11+
12+
13+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<?php
2+
3+
class Foo
4+
{
5+
6+
7+
public function bar()
8+
{
9+
10+
}
11+
12+
}

0 commit comments

Comments
 (0)