Skip to content

Commit 6a79276

Browse files
roslovkukulich
authored andcommitted
Add SlevomatCodingStandard.Classes.RequireAbstractOrFinal
1 parent 2cc697e commit 6a79276

File tree

5 files changed

+180
-0
lines changed

5 files changed

+180
-0
lines changed

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,10 @@ Disallows late static binding for constants.
184184

185185
Disallows using public properties.
186186

187+
#### SlevomatCodingStandard.Classes.RequireAbstractOrFinal 🔧
188+
189+
Requires the class to be declared either as abstract or as final.
190+
187191
#### SlevomatCodingStandard.Classes.RequireConstructorPropertyPromotion 🔧
188192

189193
Requires use of constructor property promotion.
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace SlevomatCodingStandard\Sniffs\Classes;
4+
5+
use PHP_CodeSniffer\Files\File;
6+
use PHP_CodeSniffer\Sniffs\Sniff;
7+
use SlevomatCodingStandard\Helpers\TokenHelper;
8+
use function in_array;
9+
use const T_ABSTRACT;
10+
use const T_CLASS;
11+
use const T_FINAL;
12+
13+
class RequireAbstractOrFinalSniff implements Sniff
14+
{
15+
16+
public const CODE_NO_ABSTRACT_OR_FINAL = 'ClassNeitherAbstractNorFinal';
17+
18+
/**
19+
* @return array<int, (int|string)>
20+
*/
21+
public function register(): array
22+
{
23+
return [
24+
T_CLASS,
25+
];
26+
}
27+
28+
/**
29+
* @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
30+
* @param File $phpcsFile
31+
* @param int $classPointer
32+
*/
33+
public function process(File $phpcsFile, $classPointer): void
34+
{
35+
$previousPointer = TokenHelper::findPreviousEffective($phpcsFile, $classPointer - 1);
36+
37+
$tokens = $phpcsFile->getTokens();
38+
39+
if (in_array($tokens[$previousPointer]['code'], [T_ABSTRACT, T_FINAL], true)) {
40+
return;
41+
}
42+
43+
$fix = $phpcsFile->addFixableError(
44+
'All classes should be declared using either the "abstract" or "final" keyword.',
45+
$classPointer - 1,
46+
self::CODE_NO_ABSTRACT_OR_FINAL
47+
);
48+
49+
if (!$fix) {
50+
return;
51+
}
52+
53+
$phpcsFile->fixer->beginChangeset();
54+
$phpcsFile->fixer->addContent($classPointer - 1, 'final ');
55+
$phpcsFile->fixer->endChangeset();
56+
}
57+
58+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace SlevomatCodingStandard\Sniffs\Classes;
4+
5+
use SlevomatCodingStandard\Sniffs\TestCase;
6+
7+
class RequireAbstractOrFinalSniffTest extends TestCase
8+
{
9+
10+
public function testErrors(): void
11+
{
12+
$report = self::checkFile(__DIR__ . '/data/requireAbstractOrFinalErrors.php');
13+
14+
self::assertSame(4, $report->getErrorCount());
15+
16+
self::assertSniffError($report, 2, RequireAbstractOrFinalSniff::CODE_NO_ABSTRACT_OR_FINAL);
17+
self::assertSniffError($report, 17, RequireAbstractOrFinalSniff::CODE_NO_ABSTRACT_OR_FINAL);
18+
self::assertSniffError($report, 38, RequireAbstractOrFinalSniff::CODE_NO_ABSTRACT_OR_FINAL);
19+
self::assertSniffError($report, 44, RequireAbstractOrFinalSniff::CODE_NO_ABSTRACT_OR_FINAL);
20+
21+
self::assertAllFixedInFile($report);
22+
}
23+
24+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
<?php
2+
3+
final class C1
4+
{
5+
6+
}
7+
8+
abstract class A1
9+
{
10+
public $prop1;
11+
}
12+
13+
final class F1
14+
{
15+
16+
}
17+
18+
final class E1 extends \Exception
19+
{
20+
21+
}
22+
23+
final
24+
25+
class F2
26+
{
27+
28+
}
29+
30+
31+
final
32+
// Some comment
33+
class F3
34+
{
35+
36+
}
37+
38+
// Another comment
39+
final class C2
40+
{
41+
42+
}
43+
44+
/* One more comment */ final class E2 extends \Exception
45+
{
46+
47+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
<?php
2+
3+
class C1
4+
{
5+
6+
}
7+
8+
abstract class A1
9+
{
10+
public $prop1;
11+
}
12+
13+
final class F1
14+
{
15+
16+
}
17+
18+
class E1 extends \Exception
19+
{
20+
21+
}
22+
23+
final
24+
25+
class F2
26+
{
27+
28+
}
29+
30+
31+
final
32+
// Some comment
33+
class F3
34+
{
35+
36+
}
37+
38+
// Another comment
39+
class C2
40+
{
41+
42+
}
43+
44+
/* One more comment */ class E2 extends \Exception
45+
{
46+
47+
}

0 commit comments

Comments
 (0)