• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

PHPCSStandards / PHP_CodeSniffer / 17662127818

12 Sep 2025 01:50AM UTC coverage: 78.786%. Remained the same
17662127818

push

github

web-flow
Merge pull request #1241 from PHPCSStandards/phpcs-4.x/feature/155-normalize-some-code-style-rules-3

CS: normalize code style rules [3]

343 of 705 new or added lines in 108 files covered. (48.65%)

3 existing lines in 3 files now uncovered.

19732 of 25045 relevant lines covered (78.79%)

96.47 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

81.82
/src/Standards/PSR12/Sniffs/Traits/UseDeclarationSniff.php
1
<?php
2
/**
3
 * Verifies that trait import statements are defined correctly.
4
 *
5
 * @author    Greg Sherwood <gsherwood@squiz.net>
6
 * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600)
7
 * @license   https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
8
 */
9

10
namespace PHP_CodeSniffer\Standards\PSR12\Sniffs\Traits;
11

12
use PHP_CodeSniffer\Files\File;
13
use PHP_CodeSniffer\Sniffs\Sniff;
14
use PHP_CodeSniffer\Util\Tokens;
15

16
class UseDeclarationSniff implements Sniff
17
{
18

19

20
    /**
21
     * Returns an array of tokens this test wants to listen for.
22
     *
23
     * @return array<int|string>
24
     */
25
    public function register()
3✔
26
    {
27
        return [T_USE];
3✔
28

29
    }//end register()
30

31

32
    /**
33
     * Processes this test, when one of its tokens is encountered.
34
     *
35
     * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned.
36
     * @param int                         $stackPtr  The position of the current token in the
37
     *                                               stack passed in $tokens.
38
     *
39
     * @return void|int
40
     */
41
    public function process(File $phpcsFile, int $stackPtr)
3✔
42
    {
43
        $tokens = $phpcsFile->getTokens();
3✔
44

45
        // Needs to be a use statement directly inside a class.
46
        $conditions = $tokens[$stackPtr]['conditions'];
3✔
47
        end($conditions);
3✔
48
        if (isset(Tokens::OO_SCOPE_TOKENS[current($conditions)]) === false) {
3✔
49
            return;
3✔
50
        }
51

52
        $ooToken = key($conditions);
3✔
53
        $opener  = $tokens[$ooToken]['scope_opener'];
3✔
54

55
        // Figure out where all the use statements are.
56
        $useTokens = [$stackPtr];
3✔
57
        for ($i = ($stackPtr + 1); $i < $tokens[$ooToken]['scope_closer']; $i++) {
3✔
58
            if ($tokens[$i]['code'] === T_USE) {
3✔
59
                $useTokens[] = $i;
3✔
60
            }
61

62
            if (isset($tokens[$i]['scope_closer']) === true) {
3✔
63
                $i = $tokens[$i]['scope_closer'];
3✔
64
            }
65
        }
66

67
        $numUseTokens = count($useTokens);
3✔
68
        foreach ($useTokens as $usePos => $useToken) {
3✔
69
            if ($usePos === 0) {
3✔
70
                /*
71
                    This is the first use statement.
72
                */
73

74
                // The first non-comment line must be the use line.
75
                $lastValidContent = $useToken;
3✔
76
                for ($i = ($useToken - 1); $i > $opener; $i--) {
3✔
77
                    if ($tokens[$i]['code'] === T_WHITESPACE
3✔
78
                        && ($tokens[($i - 1)]['line'] === $tokens[$i]['line']
3✔
79
                        || $tokens[($i + 1)]['line'] === $tokens[$i]['line'])
3✔
80
                    ) {
81
                        continue;
3✔
82
                    }
83

84
                    if (isset(Tokens::COMMENT_TOKENS[$tokens[$i]['code']]) === true) {
3✔
85
                        if ($tokens[$i]['code'] === T_DOC_COMMENT_CLOSE_TAG) {
3✔
86
                            // Skip past the comment.
87
                            $i = $tokens[$i]['comment_opener'];
3✔
88
                        }
89

90
                        $lastValidContent = $i;
3✔
91

92
                        continue;
3✔
93
                    }
94

95
                    break;
3✔
96
                }//end for
97

98
                if ($tokens[$lastValidContent]['line'] !== ($tokens[$opener]['line'] + 1)) {
3✔
99
                    $error = 'The first trait import statement must be declared on the first non-comment line after the %s opening brace';
3✔
100
                    $data  = [strtolower($tokens[$ooToken]['content'])];
3✔
101

102
                    // Figure out if we can fix this error.
103
                    $prev = $phpcsFile->findPrevious(Tokens::EMPTY_TOKENS, ($useToken - 1), ($opener - 1), true);
3✔
104
                    if ($tokens[$prev]['line'] === $tokens[$opener]['line']) {
3✔
105
                        $fix = $phpcsFile->addFixableError($error, $useToken, 'UseAfterBrace', $data);
3✔
106
                        if ($fix === true) {
3✔
107
                            // We know that the USE statements is the first non-comment content
108
                            // in the class, so we just need to remove blank lines.
109
                            $phpcsFile->fixer->beginChangeset();
3✔
110
                            for ($i = ($useToken - 1); $i > $opener; $i--) {
3✔
111
                                if ($tokens[$i]['line'] === $tokens[$opener]['line']) {
3✔
112
                                    break;
3✔
113
                                }
114

115
                                if ($tokens[$i]['line'] === $tokens[$useToken]['line']) {
3✔
116
                                    continue;
3✔
117
                                }
118

119
                                if ($tokens[$i]['code'] === T_WHITESPACE
3✔
120
                                    && $tokens[($i - 1)]['line'] !== $tokens[$i]['line']
3✔
121
                                    && $tokens[($i + 1)]['line'] !== $tokens[$i]['line']
3✔
122
                                ) {
123
                                    $phpcsFile->fixer->replaceToken($i, '');
3✔
124
                                }
125

126
                                if (isset(Tokens::COMMENT_TOKENS[$tokens[$i]['code']]) === true) {
3✔
127
                                    if ($tokens[$i]['code'] === T_DOC_COMMENT_CLOSE_TAG) {
3✔
128
                                        // Skip past the comment.
129
                                        $i = $tokens[$i]['comment_opener'];
3✔
130
                                    }
131

132
                                    $lastValidContent = $i;
3✔
133
                                }
134
                            }//end for
135

136
                            $phpcsFile->fixer->endChangeset();
3✔
137
                        }//end if
138
                    } else {
139
                        $phpcsFile->addError($error, $useToken, 'UseAfterBrace', $data);
3✔
140
                    }//end if
141
                }//end if
142
            } else {
143
                // Make sure this use statement is not on the same line as the previous one.
144
                $prev = $phpcsFile->findPrevious(Tokens::EMPTY_TOKENS, ($useToken - 1), null, true);
3✔
145
                if ($prev !== false && $tokens[$prev]['line'] === $tokens[$useToken]['line']) {
3✔
146
                    $error     = 'Each imported trait must be on its own line';
3✔
147
                    $prevNonWs = $phpcsFile->findPrevious(T_WHITESPACE, ($useToken - 1), null, true);
3✔
148
                    if ($prevNonWs !== $prev) {
3✔
149
                        $phpcsFile->addError($error, $useToken, 'SpacingBeforeImport');
×
150
                    } else {
151
                        $fix = $phpcsFile->addFixableError($error, $useToken, 'SpacingBeforeImport');
3✔
152
                        if ($fix === true) {
3✔
153
                            $phpcsFile->fixer->beginChangeset();
3✔
154
                            for ($x = ($useToken - 1); $x > $prev; $x--) {
3✔
155
                                if ($tokens[$x]['line'] === $tokens[$useToken]['line']
3✔
156
                                ) {
157
                                    // Preserve indent.
158
                                    continue;
3✔
159
                                }
160

161
                                $phpcsFile->fixer->replaceToken($x, '');
×
162
                            }
163

164
                            $phpcsFile->fixer->addNewline($prev);
3✔
165
                            if ($tokens[$prev]['line'] === $tokens[$useToken]['line']) {
3✔
166
                                if ($tokens[($useToken - 1)]['code'] === T_WHITESPACE) {
3✔
167
                                    $phpcsFile->fixer->replaceToken(($useToken - 1), '');
3✔
168
                                }
169

170
                                $padding = str_repeat(' ', ($tokens[$useTokens[0]]['column'] - 1));
3✔
171
                                $phpcsFile->fixer->addContent($prev, $padding);
3✔
172
                            }
173

174
                            $phpcsFile->fixer->endChangeset();
3✔
175
                        }//end if
176
                    }//end if
177
                }//end if
178
            }//end if
179

180
            $error = 'Expected 1 space after USE in trait import statement; %s found';
3✔
181
            if ($tokens[($useToken + 1)]['code'] !== T_WHITESPACE) {
3✔
182
                $data = ['0'];
×
183
                $fix  = $phpcsFile->addFixableError($error, $useToken, 'SpaceAfterUse', $data);
×
184
                if ($fix === true) {
×
185
                    $phpcsFile->fixer->addContent($useToken, ' ');
×
186
                }
187
            } else if ($tokens[($useToken + 1)]['content'] !== ' ') {
3✔
188
                $next = $phpcsFile->findNext(T_WHITESPACE, ($useToken + 1), null, true);
3✔
189
                if ($tokens[$next]['line'] !== $tokens[$useToken]['line']) {
3✔
190
                    $found = 'newline';
×
191
                } else {
192
                    $found = $tokens[($useToken + 1)]['length'];
3✔
193
                }
194

195
                $data = [$found];
3✔
196
                $fix  = $phpcsFile->addFixableError($error, $useToken, 'SpaceAfterUse', $data);
3✔
197
                if ($fix === true) {
3✔
198
                    if ($found === 'newline') {
3✔
199
                        $phpcsFile->fixer->beginChangeset();
×
200
                        for ($x = ($useToken + 1); $x < $next; $x++) {
×
201
                            $phpcsFile->fixer->replaceToken($x, '');
×
202
                        }
203

204
                        $phpcsFile->fixer->addContent($useToken, ' ');
×
205
                        $phpcsFile->fixer->endChangeset();
×
206
                    } else {
207
                        $phpcsFile->fixer->replaceToken(($useToken + 1), ' ');
3✔
208
                    }
209
                }
210
            }//end if
211

212
            // Check the formatting of the statement.
213
            if (isset($tokens[$useToken]['scope_opener']) === true) {
3✔
214
                $this->processUseGroup($phpcsFile, $useToken);
3✔
215
                $end = $tokens[$useToken]['scope_closer'];
3✔
216
            } else {
217
                $this->processUseStatement($phpcsFile, $useToken);
3✔
218
                $end = $phpcsFile->findNext(T_SEMICOLON, ($useToken + 1));
3✔
219
                if ($end === false) {
3✔
220
                    // Syntax error.
221
                    return;
×
222
                }
223
            }
224

225
            if ($usePos === ($numUseTokens - 1)) {
3✔
226
                /*
227
                    This is the last use statement.
228
                */
229

230
                $next = $phpcsFile->findNext(T_WHITESPACE, ($end + 1), null, true);
3✔
231
                if ($next === $tokens[$ooToken]['scope_closer']) {
3✔
232
                    // Last content in the class.
233
                    $closer = $tokens[$ooToken]['scope_closer'];
3✔
234
                    if ($tokens[$closer]['line'] > ($tokens[$end]['line'] + 1)) {
3✔
235
                        $error = 'There must be no blank line after the last trait import statement at the bottom of a %s';
3✔
236
                        $data  = [strtolower($tokens[$ooToken]['content'])];
3✔
237
                        $fix   = $phpcsFile->addFixableError($error, $end, 'BlankLineAfterLastUse', $data);
3✔
238
                        if ($fix === true) {
3✔
239
                            $phpcsFile->fixer->beginChangeset();
3✔
240
                            for ($i = ($end + 1); $i < $closer; $i++) {
3✔
241
                                if ($tokens[$i]['line'] === $tokens[$end]['line']) {
3✔
242
                                    continue;
3✔
243
                                }
244

245
                                if ($tokens[$i]['line'] === $tokens[$closer]['line']) {
3✔
246
                                    // Don't remove indents.
247
                                    break;
×
248
                                }
249

250
                                $phpcsFile->fixer->replaceToken($i, '');
3✔
251
                            }
252

253
                            $phpcsFile->fixer->endChangeset();
3✔
254
                        }
255
                    }//end if
256
                } else if ($tokens[$next]['code'] !== T_USE) {
3✔
257
                    // Comments are allowed on the same line as the use statement, so make sure
258
                    // we don't error for those.
259
                    for ($next = ($end + 1); $next < $tokens[$ooToken]['scope_closer']; $next++) {
3✔
260
                        if ($tokens[$next]['code'] === T_WHITESPACE) {
3✔
261
                            continue;
3✔
262
                        }
263

264
                        if (isset(Tokens::COMMENT_TOKENS[$tokens[$next]['code']]) === true
3✔
265
                            && $tokens[$next]['line'] === $tokens[$end]['line']
3✔
266
                        ) {
267
                            continue;
×
268
                        }
269

270
                        break;
3✔
271
                    }
272

273
                    if ($tokens[$next]['line'] <= ($tokens[$end]['line'] + 1)) {
3✔
274
                        $error = 'There must be a blank line following the last trait import statement';
3✔
275
                        $fix   = $phpcsFile->addFixableError($error, $end, 'NoBlankLineAfterUse');
3✔
276
                        if ($fix === true) {
3✔
277
                            if ($tokens[$next]['line'] === $tokens[$useToken]['line']) {
3✔
NEW
278
                                $phpcsFile->fixer->addContentBefore($next, $phpcsFile->eolChar . $phpcsFile->eolChar);
×
279
                            } else {
280
                                for ($i = ($next - 1); $i > $end; $i--) {
3✔
281
                                    if ($tokens[$i]['line'] !== $tokens[$next]['line']) {
3✔
282
                                        break;
3✔
283
                                    }
284
                                }
285

286
                                $phpcsFile->fixer->addNewlineBefore(($i + 1));
3✔
287
                            }
288
                        }
289
                    }
290
                }//end if
291
            } else {
292
                // Ensure use statements are grouped.
293
                $next = $phpcsFile->findNext(Tokens::EMPTY_TOKENS, ($end + 1), null, true);
3✔
294
                if ($next !== $useTokens[($usePos + 1)]) {
3✔
295
                    $error = 'Imported traits must be grouped together';
3✔
296
                    $phpcsFile->addError($error, $useTokens[($usePos + 1)], 'NotGrouped');
3✔
297
                }
298
            }//end if
299
        }//end foreach
300

301
        return $tokens[$ooToken]['scope_closer'];
3✔
302

303
    }//end process()
304

305

306
    /**
307
     * Processes a group use statement.
308
     *
309
     * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned.
310
     * @param int                         $stackPtr  The position of the current token in the
311
     *                                               stack passed in $tokens.
312
     *
313
     * @return void
314
     */
315
    protected function processUseGroup(File $phpcsFile, int $stackPtr)
3✔
316
    {
317
        $tokens = $phpcsFile->getTokens();
3✔
318

319
        $opener = $tokens[$stackPtr]['scope_opener'];
3✔
320
        $closer = $tokens[$stackPtr]['scope_closer'];
3✔
321

322
        if ($tokens[$opener]['line'] !== $tokens[$stackPtr]['line']) {
3✔
323
            $error = 'The opening brace of a trait import statement must be on the same line as the USE keyword';
3✔
324
            // Figure out if we can fix this error.
325
            $canFix = true;
3✔
326
            for ($i = ($stackPtr + 1); $i < $opener; $i++) {
3✔
327
                if ($tokens[$i]['line'] !== $tokens[($i + 1)]['line']
3✔
328
                    && $tokens[$i]['code'] !== T_WHITESPACE
3✔
329
                ) {
330
                    $canFix = false;
×
331
                    break;
×
332
                }
333
            }
334

335
            if ($canFix === true) {
3✔
336
                $fix = $phpcsFile->addFixableError($error, $opener, 'OpenBraceNewLine');
3✔
337
                if ($fix === true) {
3✔
338
                    $phpcsFile->fixer->beginChangeset();
3✔
339
                    for ($i = ($stackPtr + 1); $i < $opener; $i++) {
3✔
340
                        if ($tokens[$i]['line'] !== $tokens[($i + 1)]['line']) {
3✔
341
                            // Everything should have a single space around it.
342
                            $phpcsFile->fixer->replaceToken($i, ' ');
3✔
343
                        }
344
                    }
345

346
                    $phpcsFile->fixer->endChangeset();
3✔
347
                }
348
            } else {
349
                $phpcsFile->addError($error, $opener, 'OpenBraceNewLine');
×
350
            }
351
        }//end if
352

353
        $error = 'Expected 1 space before opening brace in trait import statement; %s found';
3✔
354
        if ($tokens[($opener - 1)]['code'] !== T_WHITESPACE) {
3✔
355
            $data = ['0'];
×
356
            $fix  = $phpcsFile->addFixableError($error, $opener, 'SpaceBeforeOpeningBrace', $data);
×
357
            if ($fix === true) {
×
358
                $phpcsFile->fixer->addContentBefore($opener, ' ');
×
359
            }
360
        } else if ($tokens[($opener - 1)]['content'] !== ' ') {
3✔
361
            $prev = $phpcsFile->findPrevious(T_WHITESPACE, ($opener - 1), null, true);
3✔
362
            if ($tokens[$prev]['line'] !== $tokens[$opener]['line']) {
3✔
363
                $found = 'newline';
3✔
364
            } else {
365
                $found = $tokens[($opener - 1)]['length'];
3✔
366
            }
367

368
            $data = [$found];
3✔
369
            $fix  = $phpcsFile->addFixableError($error, $opener, 'SpaceBeforeOpeningBrace', $data);
3✔
370
            if ($fix === true) {
3✔
371
                if ($found === 'newline') {
3✔
372
                    $phpcsFile->fixer->beginChangeset();
3✔
373
                    for ($x = ($opener - 1); $x > $prev; $x--) {
3✔
374
                        $phpcsFile->fixer->replaceToken($x, '');
3✔
375
                    }
376

377
                    $phpcsFile->fixer->addContentBefore($opener, ' ');
3✔
378
                    $phpcsFile->fixer->endChangeset();
3✔
379
                } else {
380
                    $phpcsFile->fixer->replaceToken(($opener - 1), ' ');
3✔
381
                }
382
            }
383
        }//end if
384

385
        $next = $phpcsFile->findNext(Tokens::EMPTY_TOKENS, ($opener + 1), ($closer - 1), true);
3✔
386
        if ($next !== false && $tokens[$next]['line'] !== ($tokens[$opener]['line'] + 1)) {
3✔
387
            $error     = 'First trait conflict resolution statement must be on the line after the opening brace';
3✔
388
            $nextNonWs = $phpcsFile->findNext(T_WHITESPACE, ($opener + 1), ($closer - 1), true);
3✔
389
            if ($nextNonWs !== $next) {
3✔
390
                $phpcsFile->addError($error, $opener, 'SpaceAfterOpeningBrace');
×
391
            } else {
392
                $fix = $phpcsFile->addFixableError($error, $opener, 'SpaceAfterOpeningBrace');
3✔
393
                if ($fix === true) {
3✔
394
                    $phpcsFile->fixer->beginChangeset();
3✔
395
                    for ($x = ($opener + 1); $x < $next; $x++) {
3✔
396
                        if ($tokens[$x]['line'] === $tokens[$next]['line']) {
3✔
397
                            // Preserve indent.
398
                            break;
3✔
399
                        }
400

401
                        $phpcsFile->fixer->replaceToken($x, '');
3✔
402
                    }
403

404
                    $phpcsFile->fixer->addNewline($opener);
3✔
405
                    $phpcsFile->fixer->endChangeset();
3✔
406
                }
407
            }
408
        }//end if
409

410
        for ($i = ($stackPtr + 1); $i < $opener; $i++) {
3✔
411
            if ($tokens[$i]['code'] !== T_COMMA) {
3✔
412
                continue;
3✔
413
            }
414

415
            if ($tokens[($i - 1)]['code'] === T_WHITESPACE) {
3✔
416
                $error = 'Expected no space before comma in trait import statement; %s found';
3✔
417
                $data  = [$tokens[($i - 1)]['length']];
3✔
418
                $fix   = $phpcsFile->addFixableError($error, $i, 'SpaceBeforeComma', $data);
3✔
419
                if ($fix === true) {
3✔
420
                    $phpcsFile->fixer->replaceToken(($i - 1), '');
3✔
421
                }
422
            }
423

424
            $error = 'Expected 1 space after comma in trait import statement; %s found';
3✔
425
            if ($tokens[($i + 1)]['code'] !== T_WHITESPACE) {
3✔
426
                $data = ['0'];
×
427
                $fix  = $phpcsFile->addFixableError($error, $i, 'SpaceAfterComma', $data);
×
428
                if ($fix === true) {
×
429
                    $phpcsFile->fixer->addContent($i, ' ');
×
430
                }
431
            } else if ($tokens[($i + 1)]['content'] !== ' ') {
3✔
432
                $next = $phpcsFile->findNext(T_WHITESPACE, ($i + 1), $opener, true);
3✔
433
                if ($tokens[$next]['line'] !== $tokens[$i]['line']) {
3✔
434
                    $found = 'newline';
3✔
435
                } else {
436
                    $found = $tokens[($i + 1)]['length'];
3✔
437
                }
438

439
                $data = [$found];
3✔
440
                $fix  = $phpcsFile->addFixableError($error, $i, 'SpaceAfterComma', $data);
3✔
441
                if ($fix === true) {
3✔
442
                    if ($found === 'newline') {
3✔
443
                        $phpcsFile->fixer->beginChangeset();
3✔
444
                        for ($x = ($i + 1); $x < $next; $x++) {
3✔
445
                            $phpcsFile->fixer->replaceToken($x, '');
3✔
446
                        }
447

448
                        $phpcsFile->fixer->addContent($i, ' ');
3✔
449
                        $phpcsFile->fixer->endChangeset();
3✔
450
                    } else {
451
                        $phpcsFile->fixer->replaceToken(($i + 1), ' ');
3✔
452
                    }
453
                }
454
            }//end if
455
        }//end for
456

457
        for ($i = ($opener + 1); $i < $closer; $i++) {
3✔
458
            if ($tokens[$i]['code'] === T_INSTEADOF) {
3✔
459
                $error = 'Expected 1 space before INSTEADOF in trait import statement; %s found';
3✔
460
                if ($tokens[($i - 1)]['code'] !== T_WHITESPACE) {
3✔
461
                    $data = ['0'];
×
462
                    $fix  = $phpcsFile->addFixableError($error, $i, 'SpaceBeforeInsteadof', $data);
×
463
                    if ($fix === true) {
×
464
                        $phpcsFile->fixer->addContentBefore($i, ' ');
×
465
                    }
466
                } else if ($tokens[($i - 1)]['content'] !== ' ') {
3✔
467
                    $prev = $phpcsFile->findPrevious(T_WHITESPACE, ($i - 1), $opener, true);
3✔
468
                    if ($tokens[$prev]['line'] !== $tokens[$i]['line']) {
3✔
469
                        $found = 'newline';
3✔
470
                    } else {
471
                        $found = $tokens[($i - 1)]['length'];
3✔
472
                    }
473

474
                    $data = [$found];
3✔
475

476
                    $prevNonWs = $phpcsFile->findPrevious(Tokens::EMPTY_TOKENS, ($i - 1), $opener, true);
3✔
477
                    if ($prevNonWs !== $prev) {
3✔
478
                        $phpcsFile->addError($error, $i, 'SpaceBeforeInsteadof', $data);
3✔
479
                    } else {
480
                        $fix = $phpcsFile->addFixableError($error, $i, 'SpaceBeforeInsteadof', $data);
3✔
481
                        if ($fix === true) {
3✔
482
                            if ($found === 'newline') {
3✔
483
                                $phpcsFile->fixer->beginChangeset();
3✔
484
                                for ($x = ($i - 1); $x > $prev; $x--) {
3✔
485
                                    $phpcsFile->fixer->replaceToken($x, '');
3✔
486
                                }
487

488
                                $phpcsFile->fixer->addContentBefore($i, ' ');
3✔
489
                                $phpcsFile->fixer->endChangeset();
3✔
490
                            } else {
491
                                $phpcsFile->fixer->replaceToken(($i - 1), ' ');
3✔
492
                            }
493
                        }
494
                    }
495
                }//end if
496

497
                $error = 'Expected 1 space after INSTEADOF in trait import statement; %s found';
3✔
498
                if ($tokens[($i + 1)]['code'] !== T_WHITESPACE) {
3✔
499
                    $data = ['0'];
×
500
                    $fix  = $phpcsFile->addFixableError($error, $i, 'SpaceAfterInsteadof', $data);
×
501
                    if ($fix === true) {
×
502
                        $phpcsFile->fixer->addContent($i, ' ');
×
503
                    }
504
                } else if ($tokens[($i + 1)]['content'] !== ' ') {
3✔
505
                    $next = $phpcsFile->findNext(T_WHITESPACE, ($i + 1), $closer, true);
3✔
506
                    if ($tokens[$next]['line'] !== $tokens[$i]['line']) {
3✔
507
                        $found = 'newline';
×
508
                    } else {
509
                        $found = $tokens[($i + 1)]['length'];
3✔
510
                    }
511

512
                    $data = [$found];
3✔
513

514
                    $nextNonWs = $phpcsFile->findNext(Tokens::EMPTY_TOKENS, ($i + 1), $closer, true);
3✔
515
                    if ($nextNonWs !== $next) {
3✔
516
                        $phpcsFile->addError($error, $i, 'SpaceAfterInsteadof', $data);
3✔
517
                    } else {
518
                        $fix = $phpcsFile->addFixableError($error, $i, 'SpaceAfterInsteadof', $data);
3✔
519
                        if ($fix === true) {
3✔
520
                            if ($found === 'newline') {
3✔
521
                                $phpcsFile->fixer->beginChangeset();
×
522
                                for ($x = ($i + 1); $x < $next; $x++) {
×
523
                                    $phpcsFile->fixer->replaceToken($x, '');
×
524
                                }
525

526
                                $phpcsFile->fixer->addContent($i, ' ');
×
527
                                $phpcsFile->fixer->endChangeset();
×
528
                            } else {
529
                                $phpcsFile->fixer->replaceToken(($i + 1), ' ');
3✔
530
                            }
531
                        }
532
                    }
533
                }//end if
534
            }//end if
535

536
            if ($tokens[$i]['code'] === T_AS) {
3✔
537
                $error = 'Expected 1 space before AS in trait import statement; %s found';
3✔
538
                if ($tokens[($i - 1)]['code'] !== T_WHITESPACE) {
3✔
539
                    $data = ['0'];
×
540
                    $fix  = $phpcsFile->addFixableError($error, $i, 'SpaceBeforeAs', $data);
×
541
                    if ($fix === true) {
×
542
                        $phpcsFile->fixer->addContentBefore($i, ' ');
×
543
                    }
544
                } else if ($tokens[($i - 1)]['content'] !== ' ') {
3✔
545
                    $prev = $phpcsFile->findPrevious(T_WHITESPACE, ($i - 1), $opener, true);
3✔
546
                    if ($tokens[$prev]['line'] !== $tokens[$i]['line']) {
3✔
547
                        $found = 'newline';
3✔
548
                    } else {
549
                        $found = $tokens[($i - 1)]['length'];
×
550
                    }
551

552
                    $data = [$found];
3✔
553

554
                    $prevNonWs = $phpcsFile->findPrevious(Tokens::EMPTY_TOKENS, ($i - 1), $opener, true);
3✔
555
                    if ($prevNonWs !== $prev) {
3✔
556
                        $phpcsFile->addError($error, $i, 'SpaceBeforeAs', $data);
3✔
557
                    } else {
558
                        $fix = $phpcsFile->addFixableError($error, $i, 'SpaceBeforeAs', $data);
×
559
                        if ($fix === true) {
×
560
                            if ($found === 'newline') {
×
561
                                $phpcsFile->fixer->beginChangeset();
×
562
                                for ($x = ($i - 1); $x > $prev; $x--) {
×
563
                                    $phpcsFile->fixer->replaceToken($x, '');
×
564
                                }
565

566
                                $phpcsFile->fixer->addContentBefore($i, ' ');
×
567
                                $phpcsFile->fixer->endChangeset();
×
568
                            } else {
569
                                $phpcsFile->fixer->replaceToken(($i - 1), ' ');
×
570
                            }
571
                        }
572
                    }
573
                }//end if
574

575
                $error = 'Expected 1 space after AS in trait import statement; %s found';
3✔
576
                if ($tokens[($i + 1)]['code'] !== T_WHITESPACE) {
3✔
577
                    $data = ['0'];
×
578
                    $fix  = $phpcsFile->addFixableError($error, $i, 'SpaceAfterAs', $data);
×
579
                    if ($fix === true) {
×
580
                        $phpcsFile->fixer->addContent($i, ' ');
×
581
                    }
582
                } else if ($tokens[($i + 1)]['content'] !== ' ') {
3✔
583
                    $next = $phpcsFile->findNext(T_WHITESPACE, ($i + 1), $closer, true);
3✔
584
                    if ($tokens[$next]['line'] !== $tokens[$i]['line']) {
3✔
585
                        $found = 'newline';
×
586
                    } else {
587
                        $found = $tokens[($i + 1)]['length'];
3✔
588
                    }
589

590
                    $data = [$found];
3✔
591

592
                    $nextNonWs = $phpcsFile->findNext(Tokens::EMPTY_TOKENS, ($i + 1), $closer, true);
3✔
593
                    if ($nextNonWs !== $next) {
3✔
594
                        $phpcsFile->addError($error, $i, 'SpaceAfterAs', $data);
×
595
                    } else {
596
                        $fix = $phpcsFile->addFixableError($error, $i, 'SpaceAfterAs', $data);
3✔
597
                        if ($fix === true) {
3✔
598
                            if ($found === 'newline') {
3✔
599
                                $phpcsFile->fixer->beginChangeset();
×
600
                                for ($x = ($i + 1); $x < $next; $x++) {
×
601
                                    $phpcsFile->fixer->replaceToken($x, '');
×
602
                                }
603

604
                                $phpcsFile->fixer->addContent($i, ' ');
×
605
                                $phpcsFile->fixer->endChangeset();
×
606
                            } else {
607
                                $phpcsFile->fixer->replaceToken(($i + 1), ' ');
3✔
608
                            }
609
                        }
610
                    }
611
                }//end if
612
            }//end if
613

614
            if ($tokens[$i]['code'] === T_SEMICOLON) {
3✔
615
                if ($tokens[($i - 1)]['code'] === T_WHITESPACE) {
3✔
616
                    $error = 'Expected no space before semicolon in trait import statement; %s found';
3✔
617
                    $data  = [$tokens[($i - 1)]['length']];
3✔
618
                    $fix   = $phpcsFile->addFixableError($error, $i, 'SpaceBeforeSemicolon', $data);
3✔
619
                    if ($fix === true) {
3✔
620
                        $phpcsFile->fixer->replaceToken(($i - 1), '');
3✔
621
                    }
622
                }
623

624
                $next = $phpcsFile->findNext(Tokens::EMPTY_TOKENS, ($i + 1), ($closer - 1), true);
3✔
625
                if ($next !== false && $tokens[$next]['line'] === $tokens[$i]['line']) {
3✔
626
                    $error     = 'Each trait conflict resolution statement must be on a line by itself';
3✔
627
                    $nextNonWs = $phpcsFile->findNext(T_WHITESPACE, ($i + 1), ($closer - 1), true);
3✔
628
                    if ($nextNonWs !== $next) {
3✔
629
                        $phpcsFile->addError($error, $i, 'ConflictSameLine');
3✔
630
                    } else {
631
                        $fix = $phpcsFile->addFixableError($error, $i, 'ConflictSameLine');
3✔
632
                        if ($fix === true) {
3✔
633
                            $phpcsFile->fixer->beginChangeset();
3✔
634
                            if ($tokens[($i + 1)]['code'] === T_WHITESPACE) {
3✔
635
                                $phpcsFile->fixer->replaceToken(($i + 1), '');
3✔
636
                            }
637

638
                            $phpcsFile->fixer->addNewline($i);
3✔
639
                            $phpcsFile->fixer->endChangeset();
3✔
640
                        }
641
                    }
642
                }
643
            }//end if
644
        }//end for
645

646
        $prev = $phpcsFile->findPrevious(Tokens::EMPTY_TOKENS, ($closer - 1), ($opener + 1), true);
3✔
647
        if ($prev !== false && $tokens[$prev]['line'] !== ($tokens[$closer]['line'] - 1)) {
3✔
648
            $error     = 'Closing brace must be on the line after the last trait conflict resolution statement';
3✔
649
            $prevNonWs = $phpcsFile->findPrevious(T_WHITESPACE, ($closer - 1), ($opener + 1), true);
3✔
650
            if ($prevNonWs !== $prev) {
3✔
651
                $phpcsFile->addError($error, $closer, 'SpaceBeforeClosingBrace');
×
652
            } else {
653
                $fix = $phpcsFile->addFixableError($error, $closer, 'SpaceBeforeClosingBrace');
3✔
654
                if ($fix === true) {
3✔
655
                    $phpcsFile->fixer->beginChangeset();
3✔
656
                    for ($x = ($closer - 1); $x > $prev; $x--) {
3✔
657
                        if ($tokens[$x]['line'] === $tokens[$closer]['line']) {
3✔
658
                            // Preserve indent.
659
                            continue;
3✔
660
                        }
661

662
                        $phpcsFile->fixer->replaceToken($x, '');
3✔
663
                    }
664

665
                    $phpcsFile->fixer->addNewline($prev);
3✔
666
                    $phpcsFile->fixer->endChangeset();
3✔
667
                }
668
            }
669
        }//end if
670

671
    }//end processUseGroup()
1✔
672

673

674
    /**
675
     * Processes a single use statement.
676
     *
677
     * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned.
678
     * @param int                         $stackPtr  The position of the current token in the
679
     *                                               stack passed in $tokens.
680
     *
681
     * @return void
682
     */
683
    protected function processUseStatement(File $phpcsFile, int $stackPtr)
3✔
684
    {
685
        $tokens = $phpcsFile->getTokens();
3✔
686

687
        $next = $phpcsFile->findNext([T_COMMA, T_SEMICOLON], ($stackPtr + 1));
3✔
688
        if ($next !== false && $tokens[$next]['code'] === T_COMMA) {
3✔
689
            $error = 'Each imported trait must have its own "use" import statement';
3✔
690
            $fix   = $phpcsFile->addFixableError($error, $next, 'MultipleImport');
3✔
691
            if ($fix === true) {
3✔
692
                $padding = str_repeat(' ', ($tokens[$stackPtr]['column'] - 1));
3✔
693
                $phpcsFile->fixer->replaceToken($next, ';' . $phpcsFile->eolChar . $padding . 'use ');
3✔
694
            }
695
        }
696

697
    }//end processUseStatement()
1✔
698

699

700
}//end class
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc