Skip to content

Commit e10743c

Browse files
committed
Fixed bug #2628 : PSR12.Traits.UseDeclaration does not allow comments above a USE declaration
1 parent 515caec commit e10743c

File tree

5 files changed

+170
-40
lines changed

5 files changed

+170
-40
lines changed

package.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ http://pear.php.net/dtd/package-2.0.xsd">
3939
- Fixed bug #2623 : PSR12.ControlStructures.ControlStructureSpacing not ignoring indentation inside multi-line string arguments
4040
- Fixed bug #2624 : PSR12.Traits.UseDeclaration doesnt apply the correct indent during auto fixing
4141
- Fixed bug #2626 : PSR12.Files.FileHeader detects @var annotations as file docblocks
42+
- Fixed bug #2628 : PSR12.Traits.UseDeclaration does not allow comments above a USE declaration
4243
- Fixed bug #2641 : PSR12.Functions.NullableTypeDeclaration false positive when using new static()
4344
</notes>
4445
<contents>

src/Standards/PSR12/Sniffs/Traits/UseDeclarationSniff.php

Lines changed: 63 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -67,37 +67,74 @@ public function process(File $phpcsFile, $stackPtr)
6767
break;
6868
} while ($firstUse !== false);
6969

70-
if ($firstUse === $stackPtr
71-
&& $tokens[$firstUse]['line'] !== ($tokens[$opener]['line'] + 1)
72-
) {
73-
$error = 'The first trait import statement must be declared on the line after the %s opening brace';
74-
$data = [strtolower($tokens[$ooToken]['content'])];
75-
76-
// Figure out if we can fix this error.
77-
$prev = $phpcsFile->findPrevious(T_WHITESPACE, ($stackPtr - 1), ($opener - 1), true);
78-
if ($tokens[$prev]['line'] === $tokens[$opener]['line']) {
79-
$fix = $phpcsFile->addFixableError($error, $stackPtr, 'UseAfterBrace', $data);
80-
if ($fix === true) {
81-
$phpcsFile->fixer->beginChangeset();
82-
for ($i = ($opener + 1); $i < $stackPtr; $i++) {
83-
if ($tokens[$i]['line'] === $tokens[$opener]['line']) {
84-
continue;
85-
}
86-
87-
if ($tokens[$i]['line'] === $tokens[$stackPtr]['line']) {
88-
// Don't remove indents.
89-
break;
90-
}
70+
if ($firstUse === $stackPtr) {
71+
// The first non-comment line must be the use line.
72+
$lastValidContent = $stackPtr;
73+
for ($i = ($stackPtr - 1); $i > $opener; $i--) {
74+
if ($tokens[$i]['code'] === T_WHITESPACE
75+
&& ($tokens[($i - 1)]['line'] === $tokens[$i]['line']
76+
|| $tokens[($i + 1)]['line'] === $tokens[$i]['line'])
77+
) {
78+
continue;
79+
}
9180

92-
$phpcsFile->fixer->replaceToken($i, '');
81+
if (isset(Tokens::$commentTokens[$tokens[$i]['code']]) === true) {
82+
if ($tokens[$i]['code'] === T_DOC_COMMENT_CLOSE_TAG) {
83+
// Skip past the comment.
84+
$i = $tokens[$i]['comment_opener'];
9385
}
9486

95-
$phpcsFile->fixer->endChangeset();
87+
$lastValidContent = $i;
9688
}
97-
} else {
98-
$phpcsFile->addError($error, $stackPtr, 'UseAfterBrace', $data);
89+
90+
break;
91+
}
92+
93+
if ($tokens[$lastValidContent]['line'] !== ($tokens[$opener]['line'] + 1)) {
94+
$error = 'The first trait import statement must be declared on the first non-comment line after the %s opening brace';
95+
$data = [strtolower($tokens[$ooToken]['content'])];
96+
97+
// Figure out if we can fix this error.
98+
$prev = $phpcsFile->findPrevious(Tokens::$emptyTokens, ($stackPtr - 1), ($opener - 1), true);
99+
if ($tokens[$prev]['line'] === $tokens[$opener]['line']) {
100+
$fix = $phpcsFile->addFixableError($error, $stackPtr, 'UseAfterBrace', $data);
101+
if ($fix === true) {
102+
// We know that the USE statements is the first non-comment content
103+
// in the class, so we just need to remove blank lines.
104+
$phpcsFile->fixer->beginChangeset();
105+
for ($i = ($stackPtr - 1); $i > $opener; $i--) {
106+
if ($tokens[$i]['line'] === $tokens[$opener]['line']) {
107+
break;
108+
}
109+
110+
if ($tokens[$i]['line'] === $tokens[$stackPtr]['line']) {
111+
continue;
112+
}
113+
114+
if ($tokens[$i]['code'] === T_WHITESPACE
115+
&& $tokens[($i - 1)]['line'] !== $tokens[$i]['line']
116+
&& $tokens[($i + 1)]['line'] !== $tokens[$i]['line']
117+
) {
118+
$phpcsFile->fixer->replaceToken($i, '');
119+
}
120+
121+
if (isset(Tokens::$commentTokens[$tokens[$i]['code']]) === true) {
122+
if ($tokens[$i]['code'] === T_DOC_COMMENT_CLOSE_TAG) {
123+
// Skip past the comment.
124+
$i = $tokens[$i]['comment_opener'];
125+
}
126+
127+
$lastValidContent = $i;
128+
}
129+
}//end for
130+
131+
$phpcsFile->fixer->endChangeset();
132+
}//end if
133+
} else {
134+
$phpcsFile->addError($error, $stackPtr, 'UseAfterBrace', $data);
135+
}//end if
99136
}//end if
100-
} else if ($firstUse !== $stackPtr) {
137+
} else {
101138
// Make sure this use statement immediately follows the previous one.
102139
$prev = $phpcsFile->findPrevious(Tokens::$emptyTokens, ($stackPtr - 1), null, true);
103140
if ($prev !== false && $tokens[$prev]['line'] !== ($tokens[$stackPtr]['line'] - 1)) {

src/Standards/PSR12/Tests/Traits/UseDeclarationUnitTest.inc

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,3 +85,49 @@ class ClassName10
8585

8686
use FirstTrait; use SecondTrait; use ThirdTrait;
8787
}
88+
89+
class Foo implements Bar
90+
{
91+
/**
92+
* Comment here;
93+
*/
94+
use Baz;
95+
}
96+
97+
class Foo implements Bar
98+
{
99+
100+
/**
101+
* Comment here;
102+
*/
103+
use Baz;
104+
}
105+
106+
class Foo implements Bar
107+
{
108+
/**
109+
* Comment here;
110+
*/
111+
112+
use Baz;
113+
}
114+
115+
class Foo implements Bar
116+
{
117+
118+
/**
119+
* Comment here;
120+
*/
121+
122+
use Baz;
123+
}
124+
125+
class Foo implements Bar
126+
{
127+
public $foo;
128+
/**
129+
* Comment here;
130+
*/
131+
132+
use Baz;
133+
}

src/Standards/PSR12/Tests/Traits/UseDeclarationUnitTest.inc.fixed

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,3 +82,45 @@ class ClassName10
8282
use SecondTrait;
8383
use ThirdTrait;
8484
}
85+
86+
class Foo implements Bar
87+
{
88+
/**
89+
* Comment here;
90+
*/
91+
use Baz;
92+
}
93+
94+
class Foo implements Bar
95+
{
96+
/**
97+
* Comment here;
98+
*/
99+
use Baz;
100+
}
101+
102+
class Foo implements Bar
103+
{
104+
/**
105+
* Comment here;
106+
*/
107+
use Baz;
108+
}
109+
110+
class Foo implements Bar
111+
{
112+
/**
113+
* Comment here;
114+
*/
115+
use Baz;
116+
}
117+
118+
class Foo implements Bar
119+
{
120+
public $foo;
121+
/**
122+
* Comment here;
123+
*/
124+
125+
use Baz;
126+
}

src/Standards/PSR12/Tests/Traits/UseDeclarationUnitTest.php

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -26,20 +26,24 @@ class UseDeclarationUnitTest extends AbstractSniffUnitTest
2626
public function getErrorList()
2727
{
2828
return [
29-
15 => 1,
30-
29 => 2,
31-
30 => 1,
32-
42 => 1,
33-
57 => 3,
34-
59 => 3,
35-
61 => 1,
36-
63 => 5,
37-
65 => 1,
38-
71 => 1,
39-
73 => 2,
40-
76 => 1,
41-
84 => 1,
42-
86 => 3,
29+
15 => 1,
30+
29 => 2,
31+
30 => 1,
32+
42 => 1,
33+
57 => 3,
34+
59 => 3,
35+
61 => 1,
36+
63 => 5,
37+
65 => 1,
38+
71 => 1,
39+
73 => 2,
40+
76 => 1,
41+
84 => 1,
42+
86 => 3,
43+
103 => 1,
44+
112 => 1,
45+
122 => 1,
46+
132 => 1,
4347
];
4448

4549
}//end getErrorList()

0 commit comments

Comments
 (0)