123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275 |
- <?php
- declare(strict_types=1);
- /*
- * This file is part of PHP CS Fixer.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- * Dariusz Rumiński <dariusz.ruminski@gmail.com>
- *
- * This source file is subject to the MIT license that is bundled
- * with this source code in the file LICENSE.
- */
- namespace PhpCsFixer\Tests\Tokenizer\Analyzer;
- use PhpCsFixer\Tests\TestCase;
- use PhpCsFixer\Tokenizer\Analyzer\ClassyAnalyzer;
- use PhpCsFixer\Tokenizer\Tokens;
- /**
- * @internal
- *
- * @covers \PhpCsFixer\Tokenizer\Analyzer\ClassyAnalyzer
- */
- final class ClassyAnalyzerTest extends TestCase
- {
- /**
- * @param array<int, bool> $expected
- *
- * @dataProvider provideIsClassyInvocationCases
- */
- public function testIsClassyInvocation(string $source, array $expected): void
- {
- self::assertClassyInvocation($source, $expected);
- }
- public static function provideIsClassyInvocationCases(): iterable
- {
- yield [
- '<?php new Foo;',
- [3 => true],
- ];
- yield [
- '<?php new \Foo;',
- [4 => true],
- ];
- yield [
- '<?php new Bar\Foo;',
- [3 => false, 5 => true],
- ];
- yield [
- '<?php new namespace\Foo;',
- [5 => true],
- ];
- yield [
- '<?php Foo::bar();',
- [1 => true, 3 => false],
- ];
- yield [
- '<?php \Foo::bar();',
- [2 => true, 4 => false],
- ];
- yield [
- '<?php Bar\Foo::bar();',
- [1 => false, 3 => true, 5 => false],
- ];
- yield [
- '<?php $foo instanceof Foo;',
- [5 => true],
- ];
- yield [
- '<?php class Foo extends \A {}',
- [3 => false, 8 => true],
- ];
- yield [
- '<?php class Foo implements A, B\C, \D, E {}',
- [3 => false, 7 => true, 10 => false, 12 => true, 16 => true, 19 => true],
- ];
- yield [
- '<?php class Foo { use A, B\C, \D, E { A::bar insteadof \E; } }',
- [3 => false, 9 => true, 12 => false, 14 => true, 18 => true, 21 => true, 25 => true, 32 => true],
- ];
- yield 'with reference' => [
- '<?php function foo(Foo $foo, Bar &$bar, \Baz ...$baz, Foo\Bar $fooBar) {}',
- [3 => false, 5 => true, 10 => true, 17 => true, 23 => false, 25 => true],
- ];
- yield [
- '<?php class Foo { function bar() { parent::bar(); self::baz(); $a instanceof self; } }',
- [3 => false, 9 => false, 15 => false, 17 => false, 22 => false, 24 => false, 33 => false],
- ];
- yield [
- '<?php echo FOO, \BAR;',
- [3 => false, 7 => false],
- ];
- yield [
- '<?php FOO & $bar;',
- [1 => false],
- ];
- yield [
- '<?php foo(); \bar();',
- [1 => false, 7 => false],
- ];
- yield [
- '<?php function foo(): \Foo {}',
- [3 => false, 9 => true],
- ];
- yield [
- '<?php function foo(?Foo $foo, ?Foo\Bar $fooBar): ?\Foo {}',
- [3 => false, 6 => true, 12 => false, 14 => true, 22 => true],
- ];
- yield [
- '<?php function foo(iterable $foo): string {}',
- [3 => false, 5 => false, 11 => false],
- ];
- yield [
- '<?php function foo(?int $foo): ?string {}',
- [3 => false, 6 => false, 13 => false],
- ];
- yield [
- '<?php function foo(int $foo, string &$bar): self {}',
- [3 => false, 5 => false, 10 => false, 17 => false],
- ];
- yield [
- '<?php function foo(): Foo {}',
- [3 => false, 8 => true],
- ];
- foreach (['bool', 'float', 'int', 'parent', 'self', 'string', 'void'] as $returnType) {
- yield [
- \sprintf('<?php function foo(): %s {}', $returnType),
- [3 => false, 8 => false],
- ];
- }
- yield [
- '<?php try {} catch (Foo $e) {}',
- [9 => true],
- ];
- yield [
- '<?php try {} catch (\Foo $e) {}',
- [10 => true],
- ];
- yield [
- '<?php try {} catch (/* ... */ Foo $e /* ... */) {}',
- [11 => true],
- ];
- yield [
- '<?php try {} catch (/* ... */ \Foo $e /* ... */) {}',
- [12 => true],
- ];
- }
- /**
- * @param array<int, bool> $expected
- *
- * @dataProvider provideIsClassyInvocation80Cases
- *
- * @requires PHP 8.0
- */
- public function testIsClassyInvocation80(string $source, array $expected): void
- {
- self::assertClassyInvocation($source, $expected);
- }
- public static function provideIsClassyInvocation80Cases(): iterable
- {
- yield [
- '<?php function foo(): \Foo|int {}',
- [3 => false, 9 => true, 11 => false],
- ];
- yield [
- '<?php function foo(): \Foo|A|int {}',
- [3 => false, 9 => true, 11 => true, 13 => false],
- ];
- yield [
- '<?php function foo(): int|A|NULL {}',
- [3 => false, 8 => false, 10 => true, 12 => false],
- ];
- yield [
- '<?php function foo(): int|A|false {}',
- [3 => false, 8 => false, 10 => true, 12 => false],
- ];
- yield [
- '<?php #[AnAttribute] class Foo {}',
- [2 => true],
- ];
- yield [
- '<?php try {} catch (Foo) {}',
- [9 => true],
- ];
- yield [
- '<?php try {} catch (\Foo) {}',
- [10 => true],
- ];
- yield [
- '<?php try {} catch (/* non-capturing catch */ Foo /* just because! */) {}',
- [11 => true],
- ];
- yield [
- '<?php try {} catch (/* non-capturing catch */ \Foo /* just because! */) {}',
- [12 => true],
- ];
- }
- /**
- * @param array<int, bool> $expected
- *
- * @dataProvider provideIsClassyInvocation81Cases
- *
- * @requires PHP 8.1
- */
- public function testIsClassyInvocation81(string $source, array $expected): void
- {
- self::assertClassyInvocation($source, $expected);
- }
- public static function provideIsClassyInvocation81Cases(): iterable
- {
- yield 'never' => [
- '<?php function foo(): never {}',
- [3 => false, 8 => false],
- ];
- yield 'intersection' => [
- '<?php function foo(): \Foo&Bar {}',
- [3 => false, 9 => true, 11 => true],
- ];
- }
- /**
- * @param array<int, bool> $expected
- */
- private static function assertClassyInvocation(string $source, array $expected): void
- {
- $tokens = Tokens::fromCode($source);
- $analyzer = new ClassyAnalyzer();
- foreach ($expected as $index => $isClassy) {
- self::assertSame($isClassy, $analyzer->isClassyInvocation($tokens, $index), \sprintf('Token at index %d should match the expected value "%s".', $index, true === $isClassy ? 'true' : 'false'));
- }
- }
- }
|