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

webimpress / coding-standard / 4086684577

pending completion
4086684577

Pull #178

github

GitHub
Merge 75aa3b533 into 18aa29088
Pull Request #178: Bump phpunit/phpunit from 9.5.20 to 9.6.0

6985 of 6999 relevant lines covered (99.8%)

1.13 hits per line

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

99.67
/src/WebimpressCodingStandard/Sniffs/PHP/DisallowFqnSniff.php
1
<?php
2

3
declare(strict_types=1);
4

5
namespace WebimpressCodingStandard\Sniffs\PHP;
6

7
use PHP_CodeSniffer\Files\File;
8
use PHP_CodeSniffer\Sniffs\Sniff;
9
use PHP_CodeSniffer\Util\Tokens;
10
use WebimpressCodingStandard\CodingStandard;
11
use WebimpressCodingStandard\Helper\NamespacesTrait;
12

13
use function array_merge;
14
use function basename;
15
use function dirname;
16
use function end;
17
use function explode;
18
use function file_exists;
19
use function glob;
20
use function implode;
21
use function in_array;
22
use function ltrim;
23
use function preg_match;
24
use function preg_match_all;
25
use function preg_quote;
26
use function preg_replace;
27
use function sprintf;
28
use function str_replace;
29
use function stripos;
30
use function strlen;
31
use function strpos;
32
use function strstr;
33
use function strtolower;
34
use function strtoupper;
35
use function substr;
36

37
use const DIRECTORY_SEPARATOR;
38
use const GLOB_NOSORT;
39
use const T_BITWISE_AND;
40
use const T_BITWISE_OR;
41
use const T_CASE;
42
use const T_CATCH;
43
use const T_CLOSE_PARENTHESIS;
44
use const T_CLOSURE;
45
use const T_COLON;
46
use const T_COMMA;
47
use const T_DOC_COMMENT_STRING;
48
use const T_DOC_COMMENT_TAG;
49
use const T_DOC_COMMENT_WHITESPACE;
50
use const T_DOUBLE_COLON;
51
use const T_ECHO;
52
use const T_ELLIPSIS;
53
use const T_EXTENDS;
54
use const T_FN;
55
use const T_FUNCTION;
56
use const T_IMPLEMENTS;
57
use const T_INCLUDE;
58
use const T_INCLUDE_ONCE;
59
use const T_INSTANCEOF;
60
use const T_INSTEADOF;
61
use const T_LOGICAL_AND;
62
use const T_LOGICAL_OR;
63
use const T_LOGICAL_XOR;
64
use const T_NAMESPACE;
65
use const T_NEW;
66
use const T_NS_SEPARATOR;
67
use const T_NULLABLE;
68
use const T_OPEN_PARENTHESIS;
69
use const T_PRINT;
70
use const T_REQUIRE;
71
use const T_REQUIRE_ONCE;
72
use const T_RETURN;
73
use const T_STRING;
74
use const T_THROW;
75
use const T_USE;
76
use const T_VARIABLE;
77

78
class DisallowFqnSniff implements Sniff
79
{
80
    use NamespacesTrait;
81

82
    /**
83
     * @var array Array of imported classes, constants and functions in current namespace.
84
     */
85
    private $imported;
86

87
    /**
88
     * @var array Hash map of all php built in constant names.
89
     */
90
    private $builtInConstants;
91

92
    /**
93
     * @var array Hash map of all php built in function names.
94
     */
95
    private $builtInFunctions;
96

97
    public function __construct()
98
    {
99
        $this->builtInConstants = $this->getBuiltInConstants();
1✔
100
        $this->builtInFunctions = $this->getBuiltInFunctions();
1✔
101
    }
102

103
    /**
104
     * @return int[]
105
     */
106
    public function register() : array
107
    {
108
        return [
1✔
109
            T_DOC_COMMENT_TAG,
1✔
110
            T_NS_SEPARATOR,
1✔
111
        ];
1✔
112
    }
113

114
    /**
115
     * @param int $stackPtr
116
     * @return int
117
     */
118
    public function process(File $phpcsFile, $stackPtr)
119
    {
120
        $tokens = $phpcsFile->getTokens();
1✔
121

122
        $namespace = '';
1✔
123
        $currentNamespacePtr = null;
1✔
124
        $toImport = [];
1✔
125
        $toFix = [];
1✔
126

127
        do {
128
            $namespacePtr = $phpcsFile->findPrevious(T_NAMESPACE, $stackPtr - 1) ?: null;
1✔
129

130
            if ($namespacePtr !== $currentNamespacePtr) {
1✔
131
                $namespace = $namespacePtr ? $this->getName($phpcsFile, $namespacePtr + 1) : '';
1✔
132
                if ($toImport || $toFix) {
1✔
133
                    $phpcsFile->fixer->beginChangeset();
1✔
134
                    if ($currentNamespacePtr) {
1✔
135
                        $this->importReferences($phpcsFile, $currentNamespacePtr, $toImport);
1✔
136
                    }
137
                    $this->fixErrors($phpcsFile, $toFix);
1✔
138
                    $phpcsFile->fixer->endChangeset();
1✔
139
                }
140

141
                $currentNamespacePtr = $namespacePtr;
1✔
142
                $toImport = [];
1✔
143
                $toFix = [];
1✔
144

145
                $this->imported = $this->getGlobalUses($phpcsFile, $stackPtr, 'all');
1✔
146
            }
147

148
            if ($tokens[$stackPtr]['code'] === T_DOC_COMMENT_TAG) {
1✔
149
                $this->processTag($phpcsFile, $stackPtr, $namespace, $toImport, $toFix);
1✔
150
            } else {
151
                $this->processString($phpcsFile, $stackPtr, $namespace, $toImport, $toFix);
1✔
152
            }
153
        } while ($stackPtr = $phpcsFile->findNext($this->register(), $stackPtr + 1));
1✔
154

155
        if ($toImport || $toFix) {
1✔
156
            $phpcsFile->fixer->beginChangeset();
1✔
157
            if ($currentNamespacePtr) {
1✔
158
                $this->importReferences($phpcsFile, $currentNamespacePtr, $toImport);
1✔
159
            }
160
            $this->fixErrors($phpcsFile, $toFix);
1✔
161
            $phpcsFile->fixer->endChangeset();
1✔
162
        }
163

164
        return $phpcsFile->numTokens + 1;
1✔
165
    }
166

167
    private function processTag(
168
        File $phpcsFile,
169
        int $stackPtr,
170
        string $namespace,
171
        array &$toImport,
172
        array &$toFix
173
    ) : void {
174
        $tokens = $phpcsFile->getTokens();
1✔
175

176
        if (! in_array($tokens[$stackPtr]['content'], CodingStandard::TAG_WITH_TYPE, true)
1✔
177
            || $tokens[$stackPtr + 1]['code'] !== T_DOC_COMMENT_WHITESPACE
1✔
178
            || $tokens[$stackPtr + 2]['code'] !== T_DOC_COMMENT_STRING
1✔
179
        ) {
180
            return;
1✔
181
        }
182

183
        $string = $tokens[$stackPtr + 2]['content'];
1✔
184
        [$type] = explode(' ', $string);
1✔
185
        $types = [$type];
1✔
186

187
        if ($tokens[$stackPtr]['content'] === '@method'
1✔
188
            && preg_match_all('/(?<=[\s(,])[^(\s,]+?(?=\s+\$)/', $string, $matches)
1✔
189
        ) {
190
            $types = array_merge($types, $matches[0]);
1✔
191
        }
192

193
        foreach ($types as $typesString) {
1✔
194
            $typesArr = explode('|', $typesString);
1✔
195

196
            // Create local array with classes to import, as we want to update main one only in fix mode
197
            $localToImport = [];
1✔
198
            $newTypesArr = [];
1✔
199
            foreach ($typesArr as $name) {
1✔
200
                $newTypesArr[] = $this->getExpectedName($phpcsFile, $stackPtr + 2, $namespace, $name, $localToImport);
1✔
201
            }
202

203
            $newTypes = implode('|', $newTypesArr);
1✔
204

205
            if ($newTypes !== $typesString) {
1✔
206
                $error = 'Invalid class name references: expected %s; found %s';
1✔
207
                $data = [
1✔
208
                    $newTypes,
1✔
209
                    $typesString,
1✔
210
                ];
1✔
211
                $fix = $phpcsFile->addFixableError($error, $stackPtr + 2, 'InvalidInPhpDocs', $data);
1✔
212

213
                if ($fix) {
1✔
214
                    // Update array with references to import
215
                    if ($localToImport) {
1✔
216
                        $toImport = array_merge($toImport, $localToImport);
1✔
217
                    }
218

219
                    $string = preg_replace(
1✔
220
                        '/(^|\s|,|\()' . preg_quote($typesString, '/') . '/',
1✔
221
                        '\\1' . $newTypes,
1✔
222
                        $string
1✔
223
                    );
1✔
224
                    $toFix[$stackPtr + 2] = $string;
1✔
225
                }
226
            }
227
        }
228
    }
229

230
    private function getExpectedName(
231
        File $phpcsFile,
232
        int $stackPtr,
233
        string $namespace,
234
        string $name,
235
        array &$toImport
236
    ) : string {
237
        if (! $namespace) {
1✔
238
            return ltrim($name, '\\');
1✔
239
        }
240

241
        if (strpos($name, '\\') !== 0) {
1✔
242
            return $name;
1✔
243
        }
244

245
        $suffix = strstr($name, '[');
1✔
246
        if ($suffix && ! preg_match('/^(\[\])+$/', $suffix)) {
1✔
247
            return $name;
1✔
248
        }
249

250
        $clear = str_replace(['[', ']'], '', ltrim($name, '\\'));
1✔
251

252
        if (stripos($clear . '\\', $namespace . '\\') === 0) {
1✔
253
            return substr($clear, strlen($namespace) + 1) . $suffix;
1✔
254
        }
255

256
        $alias = $this->getAliasFromName($clear);
1✔
257
        foreach ($this->imported['class'] ?? [] as $class) {
1✔
258
            if (strtolower($class['fqn']) === strtolower($clear)) {
1✔
259
                return $class['name'] . $suffix;
1✔
260
            }
261

262
            // If namespace or part of it is already imported
263
            if (stripos($clear, $class['fqn'] . '\\') === 0) {
1✔
264
                $name = substr($clear, strlen($class['fqn']));
1✔
265
                return $class['name'] . $name . $suffix;
1✔
266
            }
267
        }
268

269
        // We can't suggest anything in that case
270
        if (! $this->isValidClassName($phpcsFile, $stackPtr, $alias, $clear)) {
1✔
271
            return '\\' . $clear . $suffix;
1✔
272
        }
273

274
        // We need to import it
275
        $toImport += $this->import('class', $clear, $alias);
1✔
276

277
        return $alias . $suffix;
1✔
278
    }
279

280
    private function processString(
281
        File $phpcsFile,
282
        int $stackPtr,
283
        string $namespace,
284
        array &$toImport,
285
        array &$toFix
286
    ) : void {
287
        $tokens = $phpcsFile->getTokens();
1✔
288

289
        $prev = $phpcsFile->findPrevious(Tokens::$emptyTokens, $stackPtr - 1, null, true);
1✔
290

291
        // Part of the name
292
        if ($tokens[$prev]['code'] === T_STRING || $tokens[$prev]['code'] === T_NAMESPACE) {
1✔
293
            return;
1✔
294
        }
295

296
        // In the global use statement
297
        if ($tokens[$prev]['code'] === T_USE && CodingStandard::isGlobalUse($phpcsFile, $prev)) {
1✔
298
            return;
1✔
299
        }
300

301
        if (! $namespace) {
1✔
302
            $error = 'FQN is not needed here, as file not have defined namespace';
1✔
303
            $fix = $phpcsFile->addFixableError($error, $stackPtr, 'NoNamespace');
1✔
304
            if ($fix) {
1✔
305
                $phpcsFile->fixer->replaceToken($stackPtr, '');
1✔
306
            }
307

308
            return;
1✔
309
        }
310

311
        $next = $phpcsFile->findNext(
1✔
312
            Tokens::$emptyTokens + [T_NS_SEPARATOR => T_NS_SEPARATOR, T_STRING => T_STRING],
1✔
313
            $stackPtr + 1,
1✔
314
            null,
1✔
315
            true
1✔
316
        );
1✔
317

318
        $prevClassTokens = [
1✔
319
            T_NEW,
1✔
320
            T_USE,
1✔
321
            T_EXTENDS,
1✔
322
            T_IMPLEMENTS,
1✔
323
            T_INSTANCEOF,
1✔
324
            T_INSTEADOF,
1✔
325
            T_NULLABLE,
1✔
326
        ];
1✔
327

328
        $functionTokens = [
1✔
329
            T_CLOSURE,
1✔
330
            T_FN,
1✔
331
            T_FUNCTION,
1✔
332
        ];
1✔
333

334
        if (in_array($tokens[$prev]['code'], $prevClassTokens, true)
1✔
335
            || in_array($tokens[$next]['code'], [T_VARIABLE, T_ELLIPSIS, T_DOUBLE_COLON], true)
1✔
336
        ) {
337
            $type = 'class';
1✔
338
        } elseif ($tokens[$next]['code'] === T_OPEN_PARENTHESIS) {
1✔
339
            $type = 'function';
1✔
340
        } else {
341
            $type = 'const';
1✔
342
            if ($tokens[$prev]['code'] === T_COLON) {
1✔
343
                $before = $phpcsFile->findPrevious(Tokens::$emptyTokens, $prev - 1, null, true);
1✔
344

345
                if ($tokens[$before]['code'] === T_CLOSE_PARENTHESIS
1✔
346
                    && isset($tokens[$before]['parenthesis_owner'])
1✔
347
                    && in_array($tokens[$tokens[$before]['parenthesis_owner']]['code'], $functionTokens, true)
1✔
348
                ) {
349
                    $type = 'class';
1✔
350
                }
351
            } elseif ($tokens[$next]['code'] === T_BITWISE_AND) {
1✔
352
                if (! empty($tokens[$stackPtr]['nested_parenthesis'])
1✔
353
                    && ($owner = $tokens[end($tokens[$stackPtr]['nested_parenthesis'])]['parenthesis_owner'] ?? 0)
1✔
354
                    && in_array($tokens[$owner]['code'], $functionTokens, true)
1✔
355
                ) {
356
                    $type = 'class';
1✔
357
                }
358
            } elseif ($tokens[$next]['code'] === T_BITWISE_OR) {
1✔
359
                if (! empty($tokens[$stackPtr]['nested_parenthesis'])
1✔
360
                    && ($owner = $tokens[end($tokens[$stackPtr]['nested_parenthesis'])]['parenthesis_owner'] ?? 0)
1✔
361
                    && $tokens[$owner]['code'] === T_CATCH
1✔
362
                ) {
363
                    $type = 'class';
1✔
364
                }
365
            } elseif ($tokens[$prev]['code'] === T_COMMA) {
1✔
366
                $before = $phpcsFile->findPrevious(
1✔
367
                    Tokens::$emptyTokens + [T_STRING => T_STRING, T_NS_SEPARATOR => T_NS_SEPARATOR],
1✔
368
                    $prev - 1,
1✔
369
                    null,
1✔
370
                    true
1✔
371
                );
1✔
372

373
                if ($tokens[$before]['code'] === T_IMPLEMENTS) {
1✔
374
                    $type = 'class';
1✔
375
                }
376
            }
377
        }
378

379
        $name = $this->getName($phpcsFile, $stackPtr);
1✔
380

381
        // If the found name is in the same namespace
382
        if (stripos($name . '\\', $namespace . '\\') === 0) {
1✔
383
            $error = 'FQN is disallowed for %s in namespace %s';
1✔
384
            $data = [
1✔
385
                $name,
1✔
386
                $namespace,
1✔
387
            ];
1✔
388

389
            $fix = $phpcsFile->addFixableError($error, $stackPtr, 'SameNamespace', $data);
1✔
390
            if ($fix) {
1✔
391
                $phpcsFile->fixer->beginChangeset();
1✔
392
                $phpcsFile->fixer->replaceToken($stackPtr, substr($name, strlen($namespace) + 1));
1✔
393
                $i = $stackPtr;
1✔
394
                while (isset($tokens[++$i])) {
1✔
395
                    if (in_array($tokens[$i]['code'], Tokens::$emptyTokens, true)) {
1✔
396
                        continue;
1✔
397
                    }
398

399
                    if (! in_array($tokens[$i]['code'], [T_NS_SEPARATOR, T_STRING], true)) {
1✔
400
                        break;
1✔
401
                    }
402

403
                    $phpcsFile->fixer->replaceToken($i, '');
1✔
404
                }
405
                $phpcsFile->fixer->endChangeset();
1✔
406
            }
407

408
            return;
1✔
409
        }
410

411
        // If function is built-in function; skip
412
        if ($type === 'function' && isset($this->builtInFunctions[strtolower($name)])) {
1✔
413
            return;
1✔
414
        }
415

416
        // If constant is built-in constant; skip
417
        if ($type === 'const' && isset($this->builtInConstants[strtoupper($name)])) {
1✔
418
            return;
1✔
419
        }
420

421
        foreach ($this->imported['class'] ?? [] as $class) {
1✔
422
            // If namespace or part of it is already imported
423
            if (stripos($name . '\\', $class['fqn'] . '\\') === 0) {
1✔
424
                $error = 'Namespace %s is already imported';
1✔
425
                $data = [$class['fqn']];
1✔
426

427
                $fix = $phpcsFile->addFixableError($error, $stackPtr, 'NamespaceImported', $data);
1✔
428
                if ($fix) {
1✔
429
                    $additional = substr($name, strlen($class['fqn']) + 1);
1✔
430
                    $expected = $class['name'] . ($additional ? '\\' . $additional : '');
1✔
431

432
                    $phpcsFile->fixer->beginChangeset();
1✔
433
                    $this->fixError($phpcsFile, $stackPtr, $expected);
1✔
434
                    $phpcsFile->fixer->endChangeset();
1✔
435
                }
436

437
                return;
1✔
438
            }
439
        }
440

441
        $alias = $this->getAliasFromName($name);
1✔
442

443
        if ($type === 'function') {
1✔
444
            foreach ($this->imported['function'] ?? [] as $function) {
1✔
445
                // If function is already imported
446
                if (strtolower($function['fqn']) === strtolower($name)) {
1✔
447
                    $error = 'Function %s is already imported';
1✔
448
                    $data = [$function['fqn']];
1✔
449

450
                    $fix = $phpcsFile->addFixableError($error, $stackPtr, 'FunctionImported', $data);
1✔
451
                    if ($fix) {
1✔
452
                        $phpcsFile->fixer->beginChangeset();
1✔
453
                        $this->fixError($phpcsFile, $stackPtr, $function['name']);
1✔
454
                        $phpcsFile->fixer->endChangeset();
1✔
455
                    }
456

457
                    return;
1✔
458
                }
459
            }
460

461
            // If alias is in use
462
            if (isset($this->imported['function'][strtolower($alias)])) {
1✔
463
                $error = 'Function %s must be imported, but alias %s is already in use';
1✔
464
                $data = [$name, $alias];
1✔
465
                $phpcsFile->addError($error, $stackPtr, 'FunctionAliasUsed', $data);
1✔
466

467
                return;
1✔
468
            }
469
        }
470

471
        if ($type === 'const') {
1✔
472
            foreach ($this->imported['const'] ?? [] as $const) {
1✔
473
                // If constant is already imported
474
                if (strtolower($const['fqn']) === strtolower($name)) {
1✔
475
                    $error = 'Constant %s is already imported';
1✔
476
                    $data = [$const['fqn']];
1✔
477

478
                    $fix = $phpcsFile->addFixableError($error, $stackPtr, 'ConstantImported', $data);
1✔
479
                    if ($fix) {
1✔
480
                        $phpcsFile->fixer->beginChangeset();
1✔
481
                        $this->fixError($phpcsFile, $stackPtr, $const['name']);
1✔
482
                        $phpcsFile->fixer->endChangeset();
1✔
483
                    }
484

485
                    return;
1✔
486
                }
487
            }
488

489
            // If alias is in use
490
            if (isset($this->imported['const'][strtoupper($alias)])) {
1✔
491
                $error = 'Constant %s must be imported, but alias %s is already in use';
1✔
492
                $data = [$name, $alias];
1✔
493
                $phpcsFile->addError($error, $stackPtr, 'ConstantAliasUsed', $data);
1✔
494

495
                return;
1✔
496
            }
497
        }
498

499
        if ($type === 'class' && ! $this->isValidClassName($phpcsFile, $stackPtr, $alias, $name)) {
1✔
500
            return;
1✔
501
        }
502

503
        $error = '%s must be imported as %s';
1✔
504
        $data = [$name, $alias];
1✔
505

506
        $fix = $phpcsFile->addFixableError($error, $stackPtr, 'Import', $data);
1✔
507
        if ($fix) {
1✔
508
            $toFix[$stackPtr] = $alias;
1✔
509
            $toImport += $this->import($type, $name, $alias);
1✔
510
        }
511
    }
512

513
    private function isValidClassName(File $phpcsFile, int $stackPtr, string $alias, string $name) : bool
514
    {
515
        // If alias is in use
516
        if (isset($this->imported['class'][strtolower($alias)])) {
1✔
517
            $error = 'Class %s must be imported, but alias %s is already in use';
1✔
518
            $data = [$name, $alias];
1✔
519
            $phpcsFile->addError($error, $stackPtr, 'ClassAliasUsed', $data);
1✔
520

521
            return false;
1✔
522
        }
523

524
        $dirname = dirname($phpcsFile->getFilename());
1✔
525
        if (file_exists($dirname . DIRECTORY_SEPARATOR . $alias)) {
1✔
526
            $error = '%s must be imported but directory with name %s exists in the namespace';
1✔
527
            $data = [$name, $alias];
1✔
528
            $phpcsFile->addError($error, $stackPtr, 'DirName', $data);
1✔
529

530
            return false;
1✔
531
        }
532

533
        $files = glob($dirname . '/*', GLOB_NOSORT);
1✔
534
        foreach ($files as $file) {
1✔
535
            if (stripos(basename($file), $alias . '.') === 0) {
1✔
536
                $error = '%s must be imported but file with name %s exists in the namespace';
1✔
537
                $data = [$name, $alias];
1✔
538
                $phpcsFile->addError($error, $stackPtr, 'FileName', $data);
1✔
539

540
                return false;
1✔
541
            }
542
        }
543

544
        return true;
1✔
545
    }
546

547
    private function fixError(File $phpcsFile, int $stackPtr, string $expected) : void
548
    {
549
        $tokens = $phpcsFile->getTokens();
1✔
550

551
        if ($tokens[$stackPtr]['code'] === T_DOC_COMMENT_STRING) {
1✔
552
            $phpcsFile->fixer->replaceToken($stackPtr, $expected);
1✔
553
            return;
1✔
554
        }
555

556
        if (in_array($tokens[$stackPtr - 1]['code'], [
1✔
557
            T_NEW,
1✔
558
            T_USE,
1✔
559
            T_EXTENDS,
1✔
560
            T_IMPLEMENTS,
1✔
561
            T_INSTANCEOF,
1✔
562
            T_INSTEADOF,
1✔
563
            T_CASE,
1✔
564
            T_PRINT,
1✔
565
            T_ECHO,
1✔
566
            T_REQUIRE,
1✔
567
            T_REQUIRE_ONCE,
1✔
568
            T_INCLUDE,
1✔
569
            T_INCLUDE_ONCE,
1✔
570
            T_RETURN,
1✔
571
            T_LOGICAL_AND,
1✔
572
            T_LOGICAL_OR,
1✔
573
            T_LOGICAL_XOR,
1✔
574
            T_THROW,
1✔
575
        ], true)) {
1✔
576
            $expected = ' ' . $expected;
×
577
        }
578

579
        $phpcsFile->fixer->replaceToken($stackPtr, $expected);
1✔
580
        $i = $stackPtr;
1✔
581
        while (isset($tokens[++$i])) {
1✔
582
            if (in_array($tokens[$i]['code'], Tokens::$emptyTokens, true)) {
1✔
583
                continue;
1✔
584
            }
585

586
            if (! in_array($tokens[$i]['code'], [T_NS_SEPARATOR, T_STRING], true)) {
1✔
587
                break;
1✔
588
            }
589

590
            $phpcsFile->fixer->replaceToken($i, '');
1✔
591
        }
592
    }
593

594
    private function import(string $type, string $fqn, string $alias) : array
595
    {
596
        $this->imported[$type][$type === 'const' ? strtoupper($alias) : strtolower($alias)] = [
1✔
597
            'name' => $alias,
1✔
598
            'fqn' => $fqn,
1✔
599
        ];
1✔
600

601
        return [$fqn => $type];
1✔
602
    }
603

604
    /**
605
     * @param string[][] $references
606
     */
607
    private function importReferences(File $phpcsFile, int $namespacePtr, array $references) : void
608
    {
609
        $tokens = $phpcsFile->getTokens();
1✔
610
        if (isset($tokens[$namespacePtr]['scope_opener'])) {
1✔
611
            $ptr = $tokens[$namespacePtr]['scope_opener'];
1✔
612
        } else {
613
            $ptr = $phpcsFile->findEndOfStatement($namespacePtr);
1✔
614
            $phpcsFile->fixer->addNewline($ptr);
1✔
615
        }
616

617
        $content = '';
1✔
618
        foreach ($references as $fqn => $type) {
1✔
619
            $content .= sprintf(
1✔
620
                '%suse %s%s;',
1✔
621
                $phpcsFile->eolChar,
1✔
622
                $type === 'class' ? '' : $type . ' ',
1✔
623
                $fqn
1✔
624
            );
1✔
625
        }
626

627
        $phpcsFile->fixer->addContent($ptr, $content);
1✔
628
    }
629

630
    private function fixErrors(File $phpcsFile, array $replacements)
631
    {
632
        foreach ($replacements as $ptr => $alias) {
1✔
633
            $this->fixError($phpcsFile, $ptr, $alias);
1✔
634
        }
635
    }
636
}
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