Skip to content

Commit 9a29501

Browse files
committed
New LanguageConstructWithParenthesesSniff
1 parent 13ae2a0 commit 9a29501

File tree

7 files changed

+194
-1
lines changed

7 files changed

+194
-1
lines changed

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,10 @@ Commas after last element in an array make adding a new element easier and resul
132132

133133
This sniff enforces trailing commas in multi-line arrays and requires short array syntax `[]`.
134134

135+
#### SlevomatCodingStandard.ControlStructures.LanguageConstructWithParentheses 🔧
136+
137+
`LanguageConstructWithParenthesesSniff` checks and fixes language construct used with parentheses.
138+
135139
#### SlevomatCodingStandard.ControlStructures.YodaComparison 🔧
136140

137141
[Yoda conditions](https://en.wikipedia.org/wiki/Yoda_conditions) decrease code comprehensibility and readability by switching operands around comparison operators forcing the reader to read the code in an unnatural way.

SlevomatCodingStandard/Helpers/UseStatementHelper.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ public static function isTraitUse(\PHP_CodeSniffer\Files\File $phpcsFile, int $u
2323
$openerPointer = $typeToken['scope_opener'];
2424
$closerPointer = $typeToken['scope_closer'];
2525

26-
return ($usePointer > $openerPointer && $usePointer < $closerPointer);
26+
return $usePointer > $openerPointer && $usePointer < $closerPointer;
2727
}
2828

2929
return false;
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace SlevomatCodingStandard\Sniffs\ControlStructures;
4+
5+
use SlevomatCodingStandard\Helpers\TokenHelper;
6+
7+
class LanguageConstructWithParenthesesSniff implements \PHP_CodeSniffer\Sniffs\Sniff
8+
{
9+
10+
const CODE_USED_WITH_PARENTHESES = 'UsedWithParentheses';
11+
12+
/**
13+
* @return mixed[]
14+
*/
15+
public function register(): array
16+
{
17+
return [
18+
T_BREAK,
19+
T_CONTINUE,
20+
T_ECHO,
21+
T_INCLUDE,
22+
T_INCLUDE_ONCE,
23+
T_PRINT,
24+
T_REQUIRE,
25+
T_REQUIRE_ONCE,
26+
T_RETURN,
27+
T_THROW,
28+
T_YIELD,
29+
];
30+
}
31+
32+
/**
33+
* @phpcsSuppress SlevomatCodingStandard.TypeHints.TypeHintDeclaration.MissingParameterTypeHint
34+
* @param \PHP_CodeSniffer\Files\File $phpcsFile
35+
* @param int $languageConstructPointer
36+
*/
37+
public function process(\PHP_CodeSniffer\Files\File $phpcsFile, $languageConstructPointer)
38+
{
39+
$tokens = $phpcsFile->getTokens();
40+
41+
$nextTokenPointer = TokenHelper::findNextEffective($phpcsFile, $languageConstructPointer + 1);
42+
if ($tokens[$nextTokenPointer]['code'] === T_OPEN_PARENTHESIS) {
43+
$fix = $phpcsFile->addFixableError(sprintf('Usage of language construct "%s" with parentheses is disallowed.', $tokens[$languageConstructPointer]['content']), $languageConstructPointer, self::CODE_USED_WITH_PARENTHESES);
44+
if ($fix) {
45+
$phpcsFile->fixer->beginChangeset();
46+
$phpcsFile->fixer->replaceToken($nextTokenPointer, $tokens[$nextTokenPointer - 1]['code'] === T_WHITESPACE ? '' : ' ');
47+
$phpcsFile->fixer->replaceToken($tokens[$nextTokenPointer]['parenthesis_closer'], '');
48+
$phpcsFile->fixer->endChangeset();
49+
}
50+
}
51+
}
52+
53+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace SlevomatCodingStandard\Sniffs\ControlStructures;
4+
5+
class LanguageConstructWithParenthesesSniffTest extends \SlevomatCodingStandard\Sniffs\TestCase
6+
{
7+
8+
public function testNoErrors()
9+
{
10+
$this->assertNoSniffErrorInFile($this->checkFile(__DIR__ . '/data/languageConstructWithParenthesesNoErrors.php'));
11+
}
12+
13+
public function testErrors()
14+
{
15+
$report = $this->checkFile(__DIR__ . '/data/languageConstructWithParenthesesErrors.php', [], [LanguageConstructWithParenthesesSniff::CODE_USED_WITH_PARENTHESES]);
16+
17+
$this->assertSame(11, $report->getErrorCount());
18+
19+
$this->assertSniffError($report, 5, LanguageConstructWithParenthesesSniff::CODE_USED_WITH_PARENTHESES, 'Usage of language construct "continue" with parentheses is disallowed.');
20+
$this->assertSniffError($report, 8, LanguageConstructWithParenthesesSniff::CODE_USED_WITH_PARENTHESES, 'Usage of language construct "break" with parentheses is disallowed.');
21+
$this->assertSniffError($report, 12, LanguageConstructWithParenthesesSniff::CODE_USED_WITH_PARENTHESES, 'Usage of language construct "echo" with parentheses is disallowed.');
22+
$this->assertSniffError($report, 13, LanguageConstructWithParenthesesSniff::CODE_USED_WITH_PARENTHESES, 'Usage of language construct "print" with parentheses is disallowed.');
23+
$this->assertSniffError($report, 15, LanguageConstructWithParenthesesSniff::CODE_USED_WITH_PARENTHESES, 'Usage of language construct "include" with parentheses is disallowed.');
24+
$this->assertSniffError($report, 16, LanguageConstructWithParenthesesSniff::CODE_USED_WITH_PARENTHESES, 'Usage of language construct "include_once" with parentheses is disallowed.');
25+
$this->assertSniffError($report, 17, LanguageConstructWithParenthesesSniff::CODE_USED_WITH_PARENTHESES, 'Usage of language construct "require" with parentheses is disallowed.');
26+
$this->assertSniffError($report, 18, LanguageConstructWithParenthesesSniff::CODE_USED_WITH_PARENTHESES, 'Usage of language construct "require_once" with parentheses is disallowed.');
27+
$this->assertSniffError($report, 22, LanguageConstructWithParenthesesSniff::CODE_USED_WITH_PARENTHESES, 'Usage of language construct "return" with parentheses is disallowed.');
28+
$this->assertSniffError($report, 27, LanguageConstructWithParenthesesSniff::CODE_USED_WITH_PARENTHESES, 'Usage of language construct "yield" with parentheses is disallowed.');
29+
$this->assertSniffError($report, 31, LanguageConstructWithParenthesesSniff::CODE_USED_WITH_PARENTHESES, 'Usage of language construct "throw" with parentheses is disallowed.');
30+
31+
$this->assertAllFixedInFile($report);
32+
}
33+
34+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<?php
2+
3+
foreach ([true, false] as $value) {
4+
if (true) {
5+
continue 1;
6+
}
7+
if (false) {
8+
break 1;
9+
}
10+
}
11+
12+
echo 'a';
13+
print 'b';
14+
15+
include 'file.php';
16+
include_once 'file.php';
17+
require 'file.php';
18+
require_once 'file.php';
19+
20+
function foo()
21+
{
22+
return 'foo';
23+
}
24+
25+
function boo()
26+
{
27+
yield [];
28+
}
29+
30+
try {
31+
throw new \Exception();
32+
} catch (\Throwable $e) {
33+
34+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<?php
2+
3+
foreach ([true, false] as $value) {
4+
if (true) {
5+
continue (1);
6+
}
7+
if (false) {
8+
break (1);
9+
}
10+
}
11+
12+
echo('a');
13+
print('b');
14+
15+
include('file.php');
16+
include_once('file.php');
17+
require('file.php');
18+
require_once('file.php');
19+
20+
function foo()
21+
{
22+
return('foo');
23+
}
24+
25+
function boo()
26+
{
27+
yield([]);
28+
}
29+
30+
try {
31+
throw(new \Exception());
32+
} catch (\Throwable $e) {
33+
34+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<?php
2+
3+
foreach ([true, false] as $value) {
4+
if (true) {
5+
continue 1;
6+
}
7+
if (false) {
8+
break 1;
9+
}
10+
}
11+
12+
echo 'a';
13+
print 'b';
14+
15+
include 'file.php';
16+
include_once 'file.php';
17+
require 'file.php';
18+
require_once 'file.php';
19+
20+
function foo()
21+
{
22+
return 'foo';
23+
}
24+
25+
function boo()
26+
{
27+
yield [];
28+
}
29+
30+
try {
31+
throw new \Exception();
32+
} catch (\Throwable $e) {
33+
34+
}

0 commit comments

Comments
 (0)