Skip to content

Commit eb4c986

Browse files
authored
Implement Sniff to ensure a blank line before an object's closing brace (#173)
2 parents 6bade42 + 346a2ae commit eb4c986

5 files changed

+232
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<documentation title="New Line Before Closing Brace">
2+
<standard>
3+
<![CDATA[
4+
Object structures should contain one blank newline before the closing brace.
5+
]]>
6+
</standard>
7+
<code_comparison>
8+
<code title="Valid: one blank line before closing brace.">
9+
<![CDATA[
10+
interface Foo {
11+
public function bar();<em>
12+
13+
</em>}
14+
]]>
15+
</code>
16+
<code title="Invalid: no blank linne before closing brace.">
17+
<![CDATA[
18+
interface Foo {
19+
public function bar();<em>
20+
</em>}
21+
22+
]]>
23+
</code>
24+
</code_comparison>
25+
</documentation>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
<?php
2+
/**
3+
* BigBite Coding Standards.
4+
*
5+
* @package BigBiteCS\BigBite
6+
* @link https://github.com/bigbite/phpcs-config
7+
* @license https://opensource.org/licenses/MIT MIT
8+
*/
9+
10+
namespace BigBiteCS\BigBite\Sniffs\Objects;
11+
12+
use PHP_CodeSniffer\Files\File;
13+
use PHP_CodeSniffer\Sniffs\Sniff;
14+
15+
/**
16+
* Ensures a blank line between the last content and closing brace of an object declaration.
17+
*/
18+
final class NewLineBeforeClosingBraceSniff implements Sniff {
19+
20+
/**
21+
* A list of tokenizers this sniff supports.
22+
*
23+
* @var array<int,string>
24+
*/
25+
public $supportedTokenizers = array(
26+
'PHP',
27+
);
28+
29+
/**
30+
* Returns an array of tokens this test wants to listen for.
31+
*
32+
* @return array<int,int|string>
33+
*/
34+
public function register() {
35+
return array(
36+
\T_CLASS,
37+
\T_ENUM,
38+
\T_INTERFACE,
39+
\T_TRAIT,
40+
);
41+
}
42+
43+
/**
44+
* Processes this test, when one of its tokens is encountered.
45+
*
46+
* @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned.
47+
* @param int $stackPtr The position of the current token
48+
* in the stack passed in $tokens.
49+
*
50+
* @return void
51+
*/
52+
public function process( File $phpcsFile, $stackPtr ) {
53+
$tokens = $phpcsFile->getTokens();
54+
55+
$openingLineNo = $tokens[ $stackPtr ]['line'];
56+
$closingBrace = $tokens[ $stackPtr ]['scope_closer'];
57+
$closingLineNo = $tokens[ $closingBrace ]['line'];
58+
59+
// Other sniffs will handle objects with empty or malformed bodies.
60+
if ( $openingLineNo === $closingLineNo || ( $openingLineNo + 1 ) === $closingLineNo ) {
61+
return;
62+
}
63+
64+
$prevContent = $phpcsFile->findPrevious( \T_WHITESPACE, ( $closingBrace - 1 ), null, true );
65+
66+
if ( ( $closingLineNo - 2 ) === $tokens[ $prevContent ]['line'] ) {
67+
return;
68+
}
69+
70+
$error = 'There must be exactly one blank line between the body of a %s and its closing brace.';
71+
$data = array( $tokens[ $stackPtr ]['content'] );
72+
$fix = $phpcsFile->addFixableError( $error, $closingBrace, 'NotFound', $data );
73+
74+
if ( true !== $fix ) {
75+
return;
76+
}
77+
78+
$phpcsFile->fixer->beginChangeset();
79+
$phpcsFile->fixer->addNewlineBefore( $closingBrace );
80+
$phpcsFile->fixer->endChangeset();
81+
}
82+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<?php
2+
3+
interface FooInterface {
4+
5+
public function foo();
6+
}
7+
8+
trait FooTrait {
9+
10+
final public foo() {
11+
}
12+
}
13+
14+
enum FooEnum {
15+
case Bar;
16+
}
17+
18+
class FooClass {
19+
public array $foo = [];
20+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<?php
2+
3+
interface FooInterface {
4+
5+
public function foo();
6+
7+
}
8+
9+
trait FooTrait {
10+
11+
final public foo() {
12+
}
13+
14+
}
15+
16+
enum FooEnum {
17+
case Bar;
18+
19+
}
20+
21+
class FooClass {
22+
public array $foo = [];
23+
24+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
<?php
2+
/**
3+
* Unit test class for BigBite Coding Standard.
4+
*
5+
* @package BigBiteCS\BigBite
6+
* @link https://github.com/bigbite/phpcs-config
7+
* @license https://opensource.org/licenses/MIT MIT
8+
*/
9+
10+
namespace BigBiteCS\BigBite\Tests\Objects;
11+
12+
use BigBiteCS\BigBite\Tests\AbstractSniffUnitTest;
13+
14+
/**
15+
* Unit test class for the NewLineBeforeClosingBrace sniff.
16+
*
17+
* @package BigBiteCS\BigBite
18+
*/
19+
final class NewLineBeforeClosingBraceUnitTest extends AbstractSniffUnitTest {
20+
21+
/**
22+
* A list of tokenizers this sniff supports.
23+
*
24+
* @var array<int,string>
25+
*/
26+
public $supportedTokenizers = array(
27+
'PHP',
28+
);
29+
30+
/**
31+
* Returns an array of tokens this test wants to listen for.
32+
*
33+
* @return array<int,int|string>
34+
*/
35+
public function register() {
36+
return array(
37+
\T_CLASS,
38+
\T_ENUM,
39+
\T_INTERFACE,
40+
\T_TRAIT,
41+
);
42+
}
43+
44+
/**
45+
* Returns the lines where errors should occur.
46+
*
47+
* The key of the array should represent the line number and the value
48+
* should represent the number of errors that should occur on that line.
49+
*
50+
* @param string $testFile The name of the file being tested.
51+
*
52+
* @return array<int,int>
53+
*/
54+
public function getErrorList( $testFile = '' ) {
55+
switch ( $testFile ) {
56+
case 'NewLineBeforeClosingBraceUnitTest.1.inc':
57+
return array(
58+
6 => 1,
59+
12 => 1,
60+
16 => 1,
61+
20 => 1,
62+
);
63+
default:
64+
return array();
65+
}
66+
}
67+
68+
/**
69+
* Returns the lines where warnings should occur.
70+
*
71+
* The key of the array should represent the line number and the value
72+
* should represent the number of warnings that should occur on that line.
73+
*
74+
* @param string $testFile The name of the file being tested.
75+
*
76+
* @return array<int,int>
77+
*/
78+
public function getWarningList( $testFile = '' ) {
79+
return array();
80+
}
81+
}

0 commit comments

Comments
 (0)