Skip to content

Commit 3d115e1

Browse files
committed
fix sniffer ruleset.
1 parent cece50e commit 3d115e1

File tree

4 files changed

+354
-0
lines changed

4 files changed

+354
-0
lines changed

PSR2R/Sniffs/ControlStructures/ControlStructureSpacingSniff.php

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,11 @@ public function process(File $phpcsFile, $stackPtr) {
6767
$this->requiredSpacesBeforeClose = (int)$this->requiredSpacesBeforeClose;
6868
$tokens = $phpcsFile->getTokens();
6969

70+
// Handle else/elseif brace positioning
71+
if ($tokens[$stackPtr]['code'] === T_ELSE || $tokens[$stackPtr]['code'] === T_ELSEIF) {
72+
$this->processElseSpacing($phpcsFile, $stackPtr);
73+
}
74+
7075
if (isset($tokens[$stackPtr]['parenthesis_opener']) === false
7176
|| isset($tokens[$stackPtr]['parenthesis_closer']) === false
7277
) {
@@ -139,4 +144,115 @@ public function process(File $phpcsFile, $stackPtr) {
139144
}
140145
}
141146

147+
/**
148+
* Process else/elseif spacing and brace positioning.
149+
*
150+
* @param \PHP_CodeSniffer\Files\File $phpcsFile
151+
* @param int $stackPtr Position of else/elseif token
152+
*
153+
* @return void
154+
*/
155+
protected function processElseSpacing(File $phpcsFile, int $stackPtr): void {
156+
$tokens = $phpcsFile->getTokens();
157+
158+
// Find the previous non-whitespace token (should be closing brace)
159+
$prevNonWhitespace = $phpcsFile->findPrevious(T_WHITESPACE, $stackPtr - 1, null, true);
160+
161+
if ($prevNonWhitespace === false || $tokens[$prevNonWhitespace]['code'] !== T_CLOSE_CURLY_BRACKET) {
162+
// No closing brace before else/elseif, skip
163+
return;
164+
}
165+
166+
$closingBrace = $prevNonWhitespace;
167+
$elseToken = $stackPtr;
168+
$keyword = $tokens[$elseToken]['code'] === T_ELSE ? 'else' : 'elseif';
169+
170+
// Check if closing brace and else/elseif are on the same line
171+
if ($tokens[$closingBrace]['line'] !== $tokens[$elseToken]['line']) {
172+
// They are on different lines - we need to fix this
173+
$error = sprintf('Expected "} %s" on the same line; found closing brace and %s on different lines', $keyword, $keyword);
174+
$fix = $phpcsFile->addFixableError($error, $elseToken, 'SpacingBetweenBraceAndKeyword');
175+
176+
if ($fix) {
177+
// Fix: Remove all whitespace between closing brace and else/elseif, add single space
178+
$phpcsFile->fixer->beginChangeset();
179+
180+
// Remove all tokens between closing brace and else/elseif
181+
for ($i = $closingBrace + 1; $i < $elseToken; $i++) {
182+
$phpcsFile->fixer->replaceToken($i, '');
183+
}
184+
185+
// Add single space after closing brace
186+
$phpcsFile->fixer->addContent($closingBrace, ' ');
187+
188+
$phpcsFile->fixer->endChangeset();
189+
}
190+
}
191+
192+
// Check opening brace position
193+
$this->checkOpeningBrace($phpcsFile, $stackPtr);
194+
}
195+
196+
/**
197+
* Check and fix the opening brace position for else/elseif.
198+
*
199+
* @param \PHP_CodeSniffer\Files\File $phpcsFile
200+
* @param int $stackPtr Position of else/elseif token
201+
*
202+
* @return void
203+
*/
204+
protected function checkOpeningBrace(File $phpcsFile, int $stackPtr): void {
205+
$tokens = $phpcsFile->getTokens();
206+
$elseToken = $stackPtr;
207+
$keyword = $tokens[$elseToken]['code'] === T_ELSE ? 'else' : 'elseif';
208+
209+
// For elseif, we need to find the closing parenthesis first
210+
if ($tokens[$elseToken]['code'] === T_ELSEIF) {
211+
$openParen = $phpcsFile->findNext(T_OPEN_PARENTHESIS, $elseToken + 1, null, false, null, true);
212+
if ($openParen === false || empty($tokens[$openParen]['parenthesis_closer'])) {
213+
return;
214+
}
215+
$closeParen = $tokens[$openParen]['parenthesis_closer'];
216+
$searchStart = $closeParen + 1;
217+
} else {
218+
// For else, search starts right after else keyword
219+
$searchStart = $elseToken + 1;
220+
}
221+
222+
// Find the opening brace
223+
$openingBrace = $phpcsFile->findNext(T_OPEN_CURLY_BRACKET, $searchStart, null, false, null, true);
224+
if ($openingBrace === false) {
225+
return;
226+
}
227+
228+
// Find the token right before the opening brace (should be closing paren for elseif, or else keyword)
229+
$prevNonWhitespace = $phpcsFile->findPrevious(T_WHITESPACE, $openingBrace - 1, null, true);
230+
if ($prevNonWhitespace === false) {
231+
return;
232+
}
233+
234+
// Check if they are on the same line
235+
if ($tokens[$prevNonWhitespace]['line'] !== $tokens[$openingBrace]['line']) {
236+
// They are on different lines - we need to fix this
237+
$expectedFormat = $tokens[$elseToken]['code'] === T_ELSEIF ? '} elseif (...) {' : '} else {';
238+
$error = sprintf('Expected "%s" with opening brace on the same line; found opening brace on different line', $expectedFormat);
239+
$fix = $phpcsFile->addFixableError($error, $openingBrace, 'OpeningBraceOnDifferentLine');
240+
241+
if ($fix) {
242+
// Fix: Remove all whitespace between previous token and opening brace, add single space
243+
$phpcsFile->fixer->beginChangeset();
244+
245+
// Remove all tokens between previous token and opening brace
246+
for ($i = $prevNonWhitespace + 1; $i < $openingBrace; $i++) {
247+
$phpcsFile->fixer->replaceToken($i, '');
248+
}
249+
250+
// Add single space after previous token
251+
$phpcsFile->fixer->addContent($prevNonWhitespace, ' ');
252+
253+
$phpcsFile->fixer->endChangeset();
254+
}
255+
}
256+
}
257+
142258
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<?php
2+
3+
/**
4+
* MIT License
5+
* For full license information, please view the LICENSE file that was distributed with this source code.
6+
*/
7+
8+
namespace PSR2R\Test\PSR2R\Sniffs\ControlStructures;
9+
10+
use PSR2R\Sniffs\ControlStructures\ControlStructureSpacingSniff;
11+
use PSR2R\Test\TestCase;
12+
13+
class ControlStructureSpacingSniffTest extends TestCase {
14+
15+
/**
16+
* @return void
17+
*/
18+
public function testControlStructureSpacingSniffer(): void {
19+
$this->assertSnifferFindsErrors(new ControlStructureSpacingSniff(), 13);
20+
}
21+
22+
/**
23+
* @return void
24+
*/
25+
public function testControlStructureSpacingFixer(): void {
26+
$this->assertSnifferCanFixErrors(new ControlStructureSpacingSniff());
27+
}
28+
29+
}
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PSR2R;
4+
5+
class ControlStructureSpacingExample {
6+
7+
/**
8+
* Test case: else if on different line from closing brace
9+
*
10+
* @param int $rating
11+
*
12+
* @return string
13+
*/
14+
public function testElseIfSpacing(int $rating): string {
15+
if ($rating >= 2400) {
16+
return 'Expert';
17+
} else if ($rating >= 1800) {
18+
return 'Advanced';
19+
} else {
20+
return 'Beginner';
21+
}
22+
}
23+
24+
/**
25+
* Test case: else if with opening brace on different line
26+
*
27+
* @param int $score
28+
*
29+
* @return string
30+
*/
31+
public function testElseIfBraceSpacing(int $score): string {
32+
if ($score >= 90) {
33+
return 'A';
34+
} else if ($score >= 80) {
35+
return 'B';
36+
} else {
37+
return 'F';
38+
}
39+
}
40+
41+
/**
42+
* Test case: elseif on different line from closing brace
43+
*
44+
* @param int $value
45+
*
46+
* @return string
47+
*/
48+
public function testElseifSpacing(int $value): string {
49+
if ($value > 100) {
50+
return 'high';
51+
} elseif ($value > 50) {
52+
return 'medium';
53+
} else {
54+
return 'low';
55+
}
56+
}
57+
58+
/**
59+
* Test case: Complex nested structure
60+
*
61+
* @param int $x
62+
* @param int $y
63+
*
64+
* @return string
65+
*/
66+
public function testNestedStructures(int $x, int $y): string {
67+
if ($x > 0) {
68+
if ($y > 0) {
69+
return 'both positive';
70+
} else {
71+
return 'x positive, y negative';
72+
}
73+
} else if ($x < 0) {
74+
if ($y > 0) {
75+
return 'x negative, y positive';
76+
} else {
77+
return 'both negative';
78+
}
79+
} else {
80+
return 'x is zero';
81+
}
82+
}
83+
84+
/**
85+
* Test case: Cookie handling example from user
86+
*
87+
* @return void
88+
*/
89+
public function testCookieHandling(): void {
90+
if (isset($_COOKIE['lastProfileLeft']) && $_COOKIE['lastProfileLeft'] != '0') {
91+
$lastProfileLeft = $_COOKIE['lastProfileLeft'];
92+
$this->lastProfileLeft = $lastProfileLeft;
93+
} else {
94+
$this->lastProfileLeft = null;
95+
}
96+
}
97+
98+
}
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PSR2R;
4+
5+
class ControlStructureSpacingExample {
6+
7+
/**
8+
* Test case: else if on different line from closing brace
9+
*
10+
* @param int $rating
11+
*
12+
* @return string
13+
*/
14+
public function testElseIfSpacing(int $rating): string {
15+
if ($rating >= 2400) {
16+
return 'Expert';
17+
}
18+
else if ($rating >= 1800) {
19+
return 'Advanced';
20+
}
21+
else {
22+
return 'Beginner';
23+
}
24+
}
25+
26+
/**
27+
* Test case: else if with opening brace on different line
28+
*
29+
* @param int $score
30+
*
31+
* @return string
32+
*/
33+
public function testElseIfBraceSpacing(int $score): string {
34+
if ($score >= 90) {
35+
return 'A';
36+
}
37+
else if ($score >= 80)
38+
{
39+
return 'B';
40+
}
41+
else
42+
{
43+
return 'F';
44+
}
45+
}
46+
47+
/**
48+
* Test case: elseif on different line from closing brace
49+
*
50+
* @param int $value
51+
*
52+
* @return string
53+
*/
54+
public function testElseifSpacing(int $value): string {
55+
if ($value > 100) {
56+
return 'high';
57+
}
58+
elseif ($value > 50) {
59+
return 'medium';
60+
}
61+
else {
62+
return 'low';
63+
}
64+
}
65+
66+
/**
67+
* Test case: Complex nested structure
68+
*
69+
* @param int $x
70+
* @param int $y
71+
*
72+
* @return string
73+
*/
74+
public function testNestedStructures(int $x, int $y): string {
75+
if ($x > 0) {
76+
if ($y > 0) {
77+
return 'both positive';
78+
}
79+
else {
80+
return 'x positive, y negative';
81+
}
82+
}
83+
else if ($x < 0) {
84+
if ($y > 0) {
85+
return 'x negative, y positive';
86+
}
87+
else {
88+
return 'both negative';
89+
}
90+
}
91+
else {
92+
return 'x is zero';
93+
}
94+
}
95+
96+
/**
97+
* Test case: Cookie handling example from user
98+
*
99+
* @return void
100+
*/
101+
public function testCookieHandling(): void {
102+
if (isset($_COOKIE['lastProfileLeft']) && $_COOKIE['lastProfileLeft'] != '0') {
103+
$lastProfileLeft = $_COOKIE['lastProfileLeft'];
104+
$this->lastProfileLeft = $lastProfileLeft;
105+
}
106+
else {
107+
$this->lastProfileLeft = null;
108+
}
109+
}
110+
111+
}

0 commit comments

Comments
 (0)