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

keradus / PHP-CS-Fixer / 19958239208

05 Dec 2025 09:13AM UTC coverage: 93.181% (-1.0%) from 94.158%
19958239208

push

github

keradus
chore: .php-cs-fixer.dist.php - remove no longer needed rule, 'expectedDeprecation' annotation does not exist for long time

28928 of 31045 relevant lines covered (93.18%)

44.49 hits per line

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

87.5
/src/Fixer/PhpUnit/PhpUnitTestCaseStaticMethodCallsFixer.php
1
<?php
2

3
declare(strict_types=1);
4

5
/*
6
 * This file is part of PHP CS Fixer.
7
 *
8
 * (c) Fabien Potencier <fabien@symfony.com>
9
 *     Dariusz Rumiński <dariusz.ruminski@gmail.com>
10
 *
11
 * This source file is subject to the MIT license that is bundled
12
 * with this source code in the file LICENSE.
13
 */
14

15
namespace PhpCsFixer\Fixer\PhpUnit;
16

17
use PhpCsFixer\ConfigurationException\InvalidFixerConfigurationException;
18
use PhpCsFixer\Fixer\AbstractPhpUnitFixer;
19
use PhpCsFixer\Fixer\ConfigurableFixerInterface;
20
use PhpCsFixer\Fixer\ConfigurableFixerTrait;
21
use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
22
use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
23
use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
24
use PhpCsFixer\FixerDefinition\CodeSample;
25
use PhpCsFixer\FixerDefinition\FixerDefinition;
26
use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
27
use PhpCsFixer\Future;
28
use PhpCsFixer\Tokenizer\Analyzer\FunctionsAnalyzer;
29
use PhpCsFixer\Tokenizer\CT;
30
use PhpCsFixer\Tokenizer\Token;
31
use PhpCsFixer\Tokenizer\Tokens;
32
use PhpCsFixer\Tokenizer\TokensAnalyzer;
33
use PhpCsFixer\Utils;
34
use Symfony\Component\OptionsResolver\Exception\InvalidOptionsException;
35

36
/**
37
 * @phpstan-type _AutogeneratedInputConfiguration array{
38
 *  call_type?: 'self'|'static'|'this',
39
 *  methods?: array<string, string>,
40
 *  target?: '10.0'|'11.0'|'newest',
41
 * }
42
 * @phpstan-type _AutogeneratedComputedConfiguration array{
43
 *  call_type: 'self'|'static'|'this',
44
 *  methods: array<string, string>,
45
 *  target: '10.0'|'11.0'|'newest',
46
 * }
47
 *
48
 * @implements ConfigurableFixerInterface<_AutogeneratedInputConfiguration, _AutogeneratedComputedConfiguration>
49
 *
50
 * @phpstan-import-type _PhpTokenArray from Token
51
 *
52
 * @author Filippo Tessarotto <zoeslam@gmail.com>
53
 *
54
 * @no-named-arguments Parameter names are not covered by the backward compatibility promise.
55
 */
56
final class PhpUnitTestCaseStaticMethodCallsFixer extends AbstractPhpUnitFixer implements ConfigurableFixerInterface
57
{
58
    /** @use ConfigurableFixerTrait<_AutogeneratedInputConfiguration, _AutogeneratedComputedConfiguration> */
59
    use ConfigurableFixerTrait;
60

61
    /**
62
     * @internal
63
     */
64
    public const CALL_TYPE_THIS = 'this';
65

66
    /**
67
     * @internal
68
     */
69
    public const CALL_TYPE_SELF = 'self';
70

71
    /**
72
     * @internal
73
     */
74
    public const CALL_TYPE_STATIC = 'static';
75

76
    /**
77
     * @var array<string, true>
78
     */
79
    private const METHODS = [
80
        // Assert methods
81
        'anything' => true,
82
        'arrayHasKey' => true,
83
        'assertArrayHasKey' => true,
84
        'assertArrayIsEqualToArrayIgnoringListOfKeys' => true,
85
        'assertArrayIsEqualToArrayOnlyConsideringListOfKeys' => true,
86
        'assertArrayIsIdenticalToArrayIgnoringListOfKeys' => true,
87
        'assertArrayIsIdenticalToArrayOnlyConsideringListOfKeys' => true,
88
        'assertArrayNotHasKey' => true,
89
        'assertArraySubset' => true,
90
        'assertAttributeContains' => true,
91
        'assertAttributeContainsOnly' => true,
92
        'assertAttributeCount' => true,
93
        'assertAttributeEmpty' => true,
94
        'assertAttributeEquals' => true,
95
        'assertAttributeGreaterThan' => true,
96
        'assertAttributeGreaterThanOrEqual' => true,
97
        'assertAttributeInstanceOf' => true,
98
        'assertAttributeInternalType' => true,
99
        'assertAttributeLessThan' => true,
100
        'assertAttributeLessThanOrEqual' => true,
101
        'assertAttributeNotContains' => true,
102
        'assertAttributeNotContainsOnly' => true,
103
        'assertAttributeNotCount' => true,
104
        'assertAttributeNotEmpty' => true,
105
        'assertAttributeNotEquals' => true,
106
        'assertAttributeNotInstanceOf' => true,
107
        'assertAttributeNotInternalType' => true,
108
        'assertAttributeNotSame' => true,
109
        'assertAttributeSame' => true,
110
        'assertClassHasAttribute' => true,
111
        'assertClassHasStaticAttribute' => true,
112
        'assertClassNotHasAttribute' => true,
113
        'assertClassNotHasStaticAttribute' => true,
114
        'assertContains' => true,
115
        'assertContainsEquals' => true,
116
        'assertContainsNotOnlyArray' => true,
117
        'assertContainsNotOnlyBool' => true,
118
        'assertContainsNotOnlyCallable' => true,
119
        'assertContainsNotOnlyClosedResource' => true,
120
        'assertContainsNotOnlyFloat' => true,
121
        'assertContainsNotOnlyInstancesOf' => true,
122
        'assertContainsNotOnlyInt' => true,
123
        'assertContainsNotOnlyIterable' => true,
124
        'assertContainsNotOnlyNull' => true,
125
        'assertContainsNotOnlyNumeric' => true,
126
        'assertContainsNotOnlyObject' => true,
127
        'assertContainsNotOnlyResource' => true,
128
        'assertContainsNotOnlyScalar' => true,
129
        'assertContainsNotOnlyString' => true,
130
        'assertContainsOnly' => true,
131
        'assertContainsOnlyArray' => true,
132
        'assertContainsOnlyBool' => true,
133
        'assertContainsOnlyCallable' => true,
134
        'assertContainsOnlyClosedResource' => true,
135
        'assertContainsOnlyFloat' => true,
136
        'assertContainsOnlyInstancesOf' => true,
137
        'assertContainsOnlyInt' => true,
138
        'assertContainsOnlyIterable' => true,
139
        'assertContainsOnlyNull' => true,
140
        'assertContainsOnlyNumeric' => true,
141
        'assertContainsOnlyObject' => true,
142
        'assertContainsOnlyResource' => true,
143
        'assertContainsOnlyScalar' => true,
144
        'assertContainsOnlyString' => true,
145
        'assertCount' => true,
146
        'assertDirectoryDoesNotExist' => true,
147
        'assertDirectoryExists' => true,
148
        'assertDirectoryIsNotReadable' => true,
149
        'assertDirectoryIsNotWritable' => true,
150
        'assertDirectoryIsReadable' => true,
151
        'assertDirectoryIsWritable' => true,
152
        'assertDirectoryNotExists' => true,
153
        'assertDirectoryNotIsReadable' => true,
154
        'assertDirectoryNotIsWritable' => true,
155
        'assertDoesNotMatchRegularExpression' => true,
156
        'assertEmpty' => true,
157
        'assertEquals' => true,
158
        'assertEqualsCanonicalizing' => true,
159
        'assertEqualsIgnoringCase' => true,
160
        'assertEqualsWithDelta' => true,
161
        'assertEqualXMLStructure' => true,
162
        'assertFalse' => true,
163
        'assertFileDoesNotExist' => true,
164
        'assertFileEquals' => true,
165
        'assertFileEqualsCanonicalizing' => true,
166
        'assertFileEqualsIgnoringCase' => true,
167
        'assertFileExists' => true,
168
        'assertFileIsNotReadable' => true,
169
        'assertFileIsNotWritable' => true,
170
        'assertFileIsReadable' => true,
171
        'assertFileIsWritable' => true,
172
        'assertFileMatchesFormat' => true,
173
        'assertFileMatchesFormatFile' => true,
174
        'assertFileNotEquals' => true,
175
        'assertFileNotEqualsCanonicalizing' => true,
176
        'assertFileNotEqualsIgnoringCase' => true,
177
        'assertFileNotExists' => true,
178
        'assertFileNotIsReadable' => true,
179
        'assertFileNotIsWritable' => true,
180
        'assertFinite' => true,
181
        'assertGreaterThan' => true,
182
        'assertGreaterThanOrEqual' => true,
183
        'assertInfinite' => true,
184
        'assertInstanceOf' => true,
185
        'assertInternalType' => true,
186
        'assertIsArray' => true,
187
        'assertIsBool' => true,
188
        'assertIsCallable' => true,
189
        'assertIsClosedResource' => true,
190
        'assertIsFloat' => true,
191
        'assertIsInt' => true,
192
        'assertIsIterable' => true,
193
        'assertIsList' => true,
194
        'assertIsNotArray' => true,
195
        'assertIsNotBool' => true,
196
        'assertIsNotCallable' => true,
197
        'assertIsNotClosedResource' => true,
198
        'assertIsNotFloat' => true,
199
        'assertIsNotInt' => true,
200
        'assertIsNotIterable' => true,
201
        'assertIsNotNumeric' => true,
202
        'assertIsNotObject' => true,
203
        'assertIsNotReadable' => true,
204
        'assertIsNotResource' => true,
205
        'assertIsNotScalar' => true,
206
        'assertIsNotString' => true,
207
        'assertIsNotWritable' => true,
208
        'assertIsNumeric' => true,
209
        'assertIsObject' => true,
210
        'assertIsReadable' => true,
211
        'assertIsResource' => true,
212
        'assertIsScalar' => true,
213
        'assertIsString' => true,
214
        'assertIsWritable' => true,
215
        'assertJson' => true,
216
        'assertJsonFileEqualsJsonFile' => true,
217
        'assertJsonFileNotEqualsJsonFile' => true,
218
        'assertJsonStringEqualsJsonFile' => true,
219
        'assertJsonStringEqualsJsonString' => true,
220
        'assertJsonStringNotEqualsJsonFile' => true,
221
        'assertJsonStringNotEqualsJsonString' => true,
222
        'assertLessThan' => true,
223
        'assertLessThanOrEqual' => true,
224
        'assertMatchesRegularExpression' => true,
225
        'assertNan' => true,
226
        'assertNotContains' => true,
227
        'assertNotContainsEquals' => true,
228
        'assertNotContainsOnly' => true,
229
        'assertNotCount' => true,
230
        'assertNotEmpty' => true,
231
        'assertNotEquals' => true,
232
        'assertNotEqualsCanonicalizing' => true,
233
        'assertNotEqualsIgnoringCase' => true,
234
        'assertNotEqualsWithDelta' => true,
235
        'assertNotFalse' => true,
236
        'assertNotInstanceOf' => true,
237
        'assertNotInternalType' => true,
238
        'assertNotIsReadable' => true,
239
        'assertNotIsWritable' => true,
240
        'assertNotNull' => true,
241
        'assertNotRegExp' => true,
242
        'assertNotSame' => true,
243
        'assertNotSameSize' => true,
244
        'assertNotTrue' => true,
245
        'assertNull' => true,
246
        'assertObjectEquals' => true,
247
        'assertObjectHasAttribute' => true,
248
        'assertObjectHasProperty' => true,
249
        'assertObjectNotEquals' => true,
250
        'assertObjectNotHasAttribute' => true,
251
        'assertObjectNotHasProperty' => true,
252
        'assertRegExp' => true,
253
        'assertSame' => true,
254
        'assertSameSize' => true,
255
        'assertStringContainsString' => true,
256
        'assertStringContainsStringIgnoringCase' => true,
257
        'assertStringContainsStringIgnoringLineEndings' => true,
258
        'assertStringEndsNotWith' => true,
259
        'assertStringEndsWith' => true,
260
        'assertStringEqualsFile' => true,
261
        'assertStringEqualsFileCanonicalizing' => true,
262
        'assertStringEqualsFileIgnoringCase' => true,
263
        'assertStringEqualsStringIgnoringLineEndings' => true,
264
        'assertStringMatchesFormat' => true,
265
        'assertStringMatchesFormatFile' => true,
266
        'assertStringNotContainsString' => true,
267
        'assertStringNotContainsStringIgnoringCase' => true,
268
        'assertStringNotEqualsFile' => true,
269
        'assertStringNotEqualsFileCanonicalizing' => true,
270
        'assertStringNotEqualsFileIgnoringCase' => true,
271
        'assertStringNotMatchesFormat' => true,
272
        'assertStringNotMatchesFormatFile' => true,
273
        'assertStringStartsNotWith' => true,
274
        'assertStringStartsWith' => true,
275
        'assertThat' => true,
276
        'assertTrue' => true,
277
        'assertXmlFileEqualsXmlFile' => true,
278
        'assertXmlFileNotEqualsXmlFile' => true,
279
        'assertXmlStringEqualsXmlFile' => true,
280
        'assertXmlStringEqualsXmlString' => true,
281
        'assertXmlStringNotEqualsXmlFile' => true,
282
        'assertXmlStringNotEqualsXmlString' => true,
283
        'attribute' => true,
284
        'attributeEqualTo' => true,
285
        'callback' => true,
286
        'classHasAttribute' => true,
287
        'classHasStaticAttribute' => true,
288
        'contains' => true,
289
        'containsEqual' => true,
290
        'containsIdentical' => true,
291
        'containsOnly' => true,
292
        'containsOnlyArray' => true,
293
        'containsOnlyBool' => true,
294
        'containsOnlyCallable' => true,
295
        'containsOnlyClosedResource' => true,
296
        'containsOnlyFloat' => true,
297
        'containsOnlyInstancesOf' => true,
298
        'containsOnlyInt' => true,
299
        'containsOnlyIterable' => true,
300
        'containsOnlyNull' => true,
301
        'containsOnlyNumeric' => true,
302
        'containsOnlyObject' => true,
303
        'containsOnlyResource' => true,
304
        'containsOnlyScalar' => true,
305
        'containsOnlyString' => true,
306
        'countOf' => true,
307
        'directoryExists' => true,
308
        'equalTo' => true,
309
        'equalToCanonicalizing' => true,
310
        'equalToIgnoringCase' => true,
311
        'equalToWithDelta' => true,
312
        'fail' => true,
313
        'fileExists' => true,
314
        'getCount' => true,
315
        'getObjectAttribute' => true,
316
        'getStaticAttribute' => true,
317
        'greaterThan' => true,
318
        'greaterThanOrEqual' => true,
319
        'identicalTo' => true,
320
        'isArray' => true,
321
        'isBool' => true,
322
        'isCallable' => true,
323
        'isClosedResource' => true,
324
        'isEmpty' => true,
325
        'isFalse' => true,
326
        'isFinite' => true,
327
        'isFloat' => true,
328
        'isInfinite' => true,
329
        'isInstanceOf' => true,
330
        'isInt' => true,
331
        'isIterable' => true,
332
        'isJson' => true,
333
        'isList' => true,
334
        'isNan' => true,
335
        'isNull' => true,
336
        'isNumeric' => true,
337
        'isObject' => true,
338
        'isReadable' => true,
339
        'isResource' => true,
340
        'isScalar' => true,
341
        'isString' => true,
342
        'isTrue' => true,
343
        'isType' => true,
344
        'isWritable' => true,
345
        'lessThan' => true,
346
        'lessThanOrEqual' => true,
347
        'logicalAnd' => true,
348
        'logicalNot' => true,
349
        'logicalOr' => true,
350
        'logicalXor' => true,
351
        'markTestIncomplete' => true,
352
        'markTestSkipped' => true,
353
        'matches' => true,
354
        'matchesRegularExpression' => true,
355
        'objectEquals' => true,
356
        'objectHasAttribute' => true,
357
        'readAttribute' => true,
358
        'resetCount' => true,
359
        'stringContains' => true,
360
        'stringEndsWith' => true,
361
        'stringEqualsStringIgnoringLineEndings' => true,
362
        'stringStartsWith' => true,
363

364
        // TestCase methods
365
        'any' => true,
366
        'at' => true,
367
        'atLeast' => true,
368
        'atLeastOnce' => true,
369
        'atMost' => true,
370
        'createStub' => true,
371
        'createConfiguredStub' => true,
372
        'createStubForIntersectionOfInterfaces' => true,
373
        'exactly' => true,
374
        'never' => true,
375
        'once' => true,
376
        'onConsecutiveCalls' => true,
377
        'returnArgument' => true,
378
        'returnCallback' => true,
379
        'returnSelf' => true,
380
        'returnValue' => true,
381
        'returnValueMap' => true,
382
        'setUpBeforeClass' => true,
383
        'tearDownAfterClass' => true,
384
        'throwException' => true,
385
    ];
386

387
    /**
388
     * @var array<string, bool>
389
     */
390
    private const ALLOWED_VALUES = [
391
        self::CALL_TYPE_THIS => true,
392
        self::CALL_TYPE_SELF => true,
393
        self::CALL_TYPE_STATIC => true,
394
    ];
395

396
    /**
397
     * @var non-empty-array<string, non-empty-list<_PhpTokenArray>>
398
     */
399
    private array $conversionMap = [
400
        self::CALL_TYPE_THIS => [[\T_OBJECT_OPERATOR, '->'], [\T_VARIABLE, '$this']],
401
        self::CALL_TYPE_SELF => [[\T_DOUBLE_COLON, '::'], [\T_STRING, 'self']],
402
        self::CALL_TYPE_STATIC => [[\T_DOUBLE_COLON, '::'], [\T_STATIC, 'static']],
403
    ];
404

405
    public function getDefinition(): FixerDefinitionInterface
406
    {
407
        $codeSample = <<<'PHP'
3✔
408
            <?php
409
            final class MyTest extends \PHPUnit_Framework_TestCase
410
            {
411
                public function testMe()
412
                {
413
                    $this->assertSame(1, 2);
414
                    self::assertSame(1, 2);
415
                    static::assertSame(1, 2);
416
                    static::assertTrue(false);
417
                }
418
            }
419

420
            PHP;
3✔
421

422
        return new FixerDefinition(
3✔
423
            'Calls to `PHPUnit\Framework\TestCase` static methods must all be of the same type, either `$this->`, `self::` or `static::`.',
3✔
424
            [
3✔
425
                new CodeSample($codeSample),
3✔
426
                new CodeSample($codeSample, ['call_type' => self::CALL_TYPE_THIS]),
3✔
427
                new CodeSample($codeSample, ['methods' => ['assertTrue' => self::CALL_TYPE_THIS]]),
3✔
428
            ],
3✔
429
            null,
3✔
430
            'Risky when PHPUnit methods are overridden or not accessible, or when project has PHPUnit incompatibilities.'
3✔
431
        );
3✔
432
    }
433

434
    /**
435
     * {@inheritdoc}
436
     *
437
     * Must run before SelfStaticAccessorFixer.
438
     */
439
    public function getPriority(): int
440
    {
441
        return 0;
1✔
442
    }
443

444
    public function isRisky(): bool
445
    {
446
        return true;
1✔
447
    }
448

449
    protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
450
    {
451
        return new FixerConfigurationResolver([
30✔
452
            (new FixerOptionBuilder('call_type', 'The call type to use for referring to PHPUnit methods.'))
30✔
453
                ->setAllowedTypes(['string'])
30✔
454
                ->setAllowedValues(array_keys(self::ALLOWED_VALUES))
30✔
455
                ->setDefault(self::CALL_TYPE_STATIC)
30✔
456
                ->getOption(),
30✔
457
            (new FixerOptionBuilder('methods', 'Dictionary of `method` => `call_type` values that differ from the default strategy.'))
30✔
458
                ->setAllowedTypes(['array<string, string>'])
30✔
459
                ->setAllowedValues([static function (array $option): bool {
30✔
460
                    foreach ($option as $method => $value) {
30✔
461
                        if (!isset(self::METHODS[$method])) {
3✔
462
                            throw new InvalidOptionsException(
×
463
                                \sprintf(
×
464
                                    'Unexpected "methods" key, expected any of %s, got "%s".',
×
465
                                    Utils::naturalLanguageJoin(array_keys(self::METHODS)),
×
466
                                    \gettype($method).'#'.$method
×
467
                                )
×
468
                            );
×
469
                        }
470

471
                        if (!isset(self::ALLOWED_VALUES[$value])) {
3✔
472
                            throw new InvalidOptionsException(
×
473
                                \sprintf(
×
474
                                    'Unexpected value for method "%s", expected any of %s, got "%s".',
×
475
                                    $method,
×
476
                                    Utils::naturalLanguageJoin(array_keys(self::ALLOWED_VALUES)),
×
477
                                    \is_object($value) ? \get_class($value) : (null === $value ? 'null' : \gettype($value).'#'.$value)
×
478
                                )
×
479
                            );
×
480
                        }
481
                    }
482

483
                    return true;
30✔
484
                }])
30✔
485
                ->setDefault([])
30✔
486
                ->getOption(),
30✔
487
            (new FixerOptionBuilder('target', 'Target version of PHPUnit.'))
30✔
488
                ->setAllowedTypes(['string'])
30✔
489
                ->setAllowedValues([
30✔
490
                    PhpUnitTargetVersion::VERSION_10_0,
30✔
491
                    PhpUnitTargetVersion::VERSION_11_0,
30✔
492
                    PhpUnitTargetVersion::VERSION_NEWEST,
30✔
493
                ])
30✔
494
                ->setDefault(Future::getV4OrV3(PhpUnitTargetVersion::VERSION_NEWEST, PhpUnitTargetVersion::VERSION_10_0))
30✔
495
                ->getOption(),
30✔
496
        ]);
30✔
497
    }
498

499
    protected function configurePostNormalisation(): void
500
    {
501
        $dynamicMethods = [];
30✔
502
        if (PhpUnitTargetVersion::fulfills($this->configuration['target'], PhpUnitTargetVersion::VERSION_11_0)) {
30✔
503
            $dynamicMethods = [
2✔
504
                'any',
2✔
505
                'atLeast',
2✔
506
                'atLeastOnce',
2✔
507
                'atMost',
2✔
508
                'exactly',
2✔
509
                'never',
2✔
510
                'once',
2✔
511
                'throwException',
2✔
512
            ];
2✔
513
        }
514
        if (PhpUnitTargetVersion::VERSION_11_0 === $this->configuration['target']) {
30✔
515
            $dynamicMethods[] = 'onConsecutiveCalls';
2✔
516
            $dynamicMethods[] = 'returnArgument';
2✔
517
            $dynamicMethods[] = 'returnCallback';
2✔
518
            $dynamicMethods[] = 'returnSelf';
2✔
519
            $dynamicMethods[] = 'returnValue';
2✔
520
            $dynamicMethods[] = 'returnValueMap';
2✔
521
        }
522

523
        foreach ($dynamicMethods as $method) {
30✔
524
            if (isset($this->configuration['methods'][$method])) {
2✔
525
                throw new InvalidFixerConfigurationException(
1✔
526
                    $this->getName(),
1✔
527
                    \sprintf('Configuration cannot contain method "%s" and target "%s", it is dynamic in that PHPUnit version.', $method, $this->configuration['target'])
1✔
528
                );
1✔
529
            }
530

531
            $this->configuration['methods'][$method] = self::CALL_TYPE_THIS;
2✔
532
        }
533
    }
534

535
    protected function applyPhpUnitClassFix(Tokens $tokens, int $startIndex, int $endIndex): void
536
    {
537
        $analyzer = new TokensAnalyzer($tokens);
16✔
538

539
        for ($index = $startIndex; $index < $endIndex; ++$index) {
16✔
540
            // skip anonymous classes
541
            if ($tokens[$index]->isGivenKind(\T_CLASS)) {
16✔
542
                $index = $this->findEndOfNextBlock($tokens, $index);
1✔
543

544
                continue;
1✔
545
            }
546

547
            $callType = $this->configuration['call_type'];
16✔
548

549
            if ($tokens[$index]->isGivenKind(\T_FUNCTION)) {
16✔
550
                // skip lambda
551
                if ($analyzer->isLambda($index)) {
16✔
552
                    $index = $this->findEndOfNextBlock($tokens, $index);
3✔
553

554
                    continue;
3✔
555
                }
556

557
                // do not change `self` to `this` in static methods
558
                if (self::CALL_TYPE_THIS === $callType) {
16✔
559
                    $attributes = $analyzer->getMethodAttributes($index);
6✔
560

561
                    if (false !== $attributes['static']) {
6✔
562
                        $index = $this->findEndOfNextBlock($tokens, $index);
2✔
563

564
                        continue;
2✔
565
                    }
566
                }
567
            }
568

569
            if (!$tokens[$index]->isGivenKind(\T_STRING) || !isset(self::METHODS[$tokens[$index]->getContent()])) {
16✔
570
                continue;
16✔
571
            }
572

573
            $nextIndex = $tokens->getNextMeaningfulToken($index);
14✔
574

575
            if (!$tokens[$nextIndex]->equals('(')) {
14✔
576
                $index = $nextIndex;
1✔
577

578
                continue;
1✔
579
            }
580

581
            if ($tokens[$tokens->getNextMeaningfulToken($nextIndex)]->isGivenKind(CT::T_FIRST_CLASS_CALLABLE)) {
14✔
582
                continue;
1✔
583
            }
584

585
            $methodName = $tokens[$index]->getContent();
13✔
586

587
            if (isset($this->configuration['methods'][$methodName])) {
13✔
588
                $callType = $this->configuration['methods'][$methodName];
2✔
589
            }
590

591
            $operatorIndex = $tokens->getPrevMeaningfulToken($index);
13✔
592
            $referenceIndex = $tokens->getPrevMeaningfulToken($operatorIndex);
13✔
593

594
            if (!$this->needsConversion($tokens, $index, $referenceIndex, $callType)) {
13✔
595
                continue;
13✔
596
            }
597

598
            $tokens[$operatorIndex] = new Token($this->conversionMap[$callType][0]);
11✔
599
            $tokens[$referenceIndex] = new Token($this->conversionMap[$callType][1]);
11✔
600
        }
601
    }
602

603
    private function needsConversion(Tokens $tokens, int $index, int $referenceIndex, string $callType): bool
604
    {
605
        $functionsAnalyzer = new FunctionsAnalyzer();
13✔
606

607
        return $functionsAnalyzer->isTheSameClassCall($tokens, $index)
13✔
608
            && !$tokens[$referenceIndex]->equals($this->conversionMap[$callType][1], false);
13✔
609
    }
610

611
    private function findEndOfNextBlock(Tokens $tokens, int $index): int
612
    {
613
        $nextIndex = $tokens->getNextTokenOfKind($index, [';', '{']);
5✔
614

615
        return $tokens[$nextIndex]->equals('{')
5✔
616
            ? $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $nextIndex)
4✔
617
            : $nextIndex;
5✔
618
    }
619
}
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