123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485 |
- <?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\Transformer;
- use PhpCsFixer\Tests\Test\AbstractTransformerTestCase;
- use PhpCsFixer\Tokenizer\CT;
- use PhpCsFixer\Tokenizer\Tokens;
- /**
- * @author Dariusz Rumiński <dariusz.ruminski@gmail.com>
- *
- * @internal
- *
- * @covers \PhpCsFixer\Tokenizer\Transformer\BraceTransformer
- *
- * @phpstan-import-type _TransformerTestExpectedTokens from AbstractTransformerTestCase
- */
- final class BraceTransformerTest extends AbstractTransformerTestCase
- {
- /**
- * @param _TransformerTestExpectedTokens $expectedTokens
- *
- * @dataProvider provideProcessCases
- */
- public function testProcess(string $source, array $expectedTokens = []): void
- {
- $this->doTest(
- $source,
- $expectedTokens,
- [
- T_CURLY_OPEN,
- CT::T_CURLY_CLOSE,
- T_DOLLAR_OPEN_CURLY_BRACES,
- CT::T_DOLLAR_CLOSE_CURLY_BRACES,
- CT::T_DYNAMIC_PROP_BRACE_OPEN,
- CT::T_DYNAMIC_PROP_BRACE_CLOSE,
- CT::T_DYNAMIC_VAR_BRACE_OPEN,
- CT::T_DYNAMIC_VAR_BRACE_CLOSE,
- CT::T_ARRAY_INDEX_CURLY_BRACE_OPEN,
- CT::T_ARRAY_INDEX_CURLY_BRACE_CLOSE,
- CT::T_GROUP_IMPORT_BRACE_OPEN,
- CT::T_GROUP_IMPORT_BRACE_CLOSE,
- ]
- );
- }
- public static function provideProcessCases(): iterable
- {
- yield 'curly open/close I' => [
- '<?php echo "This is {$great}";',
- [
- 5 => T_CURLY_OPEN,
- 7 => CT::T_CURLY_CLOSE,
- ],
- ];
- yield 'curly open/close II' => [
- '<?php $a = "a{$b->c()}d";',
- [
- 7 => T_CURLY_OPEN,
- 13 => CT::T_CURLY_CLOSE,
- ],
- ];
- yield 'dynamic var brace open/close' => [
- '<?php echo "I\'d like an {${beers::$ale}}\n";',
- [
- 5 => T_CURLY_OPEN,
- 7 => CT::T_DYNAMIC_VAR_BRACE_OPEN,
- 11 => CT::T_DYNAMIC_VAR_BRACE_CLOSE,
- 12 => CT::T_CURLY_CLOSE,
- ],
- ];
- yield 'dollar curly brace open/close' => [
- '<?php echo "This is ${great}";',
- [
- 5 => T_DOLLAR_OPEN_CURLY_BRACES,
- 7 => CT::T_DOLLAR_CLOSE_CURLY_BRACES,
- ],
- ];
- yield 'dynamic property brace open/close' => [
- '<?php $foo->{$bar};',
- [
- 3 => CT::T_DYNAMIC_PROP_BRACE_OPEN,
- 5 => CT::T_DYNAMIC_PROP_BRACE_CLOSE,
- ],
- ];
- yield 'dynamic variable brace open/close' => [
- '<?php ${$bar};',
- [
- 2 => CT::T_DYNAMIC_VAR_BRACE_OPEN,
- 4 => CT::T_DYNAMIC_VAR_BRACE_CLOSE,
- ],
- ];
- yield 'mixed' => [
- '<?php echo "This is {$great}";
- $a = "a{$b->c()}d";
- echo "I\'d like an {${beers::$ale}}\n";
- ',
- [
- 5 => T_CURLY_OPEN,
- 7 => CT::T_CURLY_CLOSE,
- 17 => T_CURLY_OPEN,
- 23 => CT::T_CURLY_CLOSE,
- 32 => T_CURLY_OPEN,
- 34 => CT::T_DYNAMIC_VAR_BRACE_OPEN,
- 38 => CT::T_DYNAMIC_VAR_BRACE_CLOSE,
- 39 => CT::T_CURLY_CLOSE,
- ],
- ];
- yield 'do not touch' => [
- '<?php if (1) {} class Foo{ } function bar(){ }',
- ];
- yield 'dynamic property with string with variable' => [
- '<?php $object->{"set_{$name}"}(42);',
- [
- 3 => CT::T_DYNAMIC_PROP_BRACE_OPEN,
- 6 => T_CURLY_OPEN,
- 8 => CT::T_CURLY_CLOSE,
- 10 => CT::T_DYNAMIC_PROP_BRACE_CLOSE,
- ],
- ];
- yield 'group import' => [
- '<?php use some\a\{ClassA, ClassB, ClassC as C};',
- [
- 7 => CT::T_GROUP_IMPORT_BRACE_OPEN,
- 19 => CT::T_GROUP_IMPORT_BRACE_CLOSE,
- ],
- ];
- yield 'nested curly open + close' => [
- '<?php echo "{$foo->{"{$bar}"}}";',
- [
- 4 => T_CURLY_OPEN,
- 7 => CT::T_DYNAMIC_PROP_BRACE_OPEN,
- 9 => T_CURLY_OPEN,
- 11 => CT::T_CURLY_CLOSE,
- 13 => CT::T_DYNAMIC_PROP_BRACE_CLOSE,
- 14 => CT::T_CURLY_CLOSE,
- ],
- ];
- }
- /**
- * @param _TransformerTestExpectedTokens $expectedTokens
- *
- * @dataProvider provideProcess80Cases
- *
- * @requires PHP 8.0
- */
- public function testProcess80(string $source, array $expectedTokens = []): void
- {
- $this->doTest(
- $source,
- $expectedTokens,
- [
- T_CURLY_OPEN,
- CT::T_CURLY_CLOSE,
- T_DOLLAR_OPEN_CURLY_BRACES,
- CT::T_DOLLAR_CLOSE_CURLY_BRACES,
- CT::T_DYNAMIC_PROP_BRACE_OPEN,
- CT::T_DYNAMIC_PROP_BRACE_CLOSE,
- CT::T_DYNAMIC_VAR_BRACE_OPEN,
- CT::T_DYNAMIC_VAR_BRACE_CLOSE,
- CT::T_ARRAY_INDEX_CURLY_BRACE_OPEN,
- CT::T_ARRAY_INDEX_CURLY_BRACE_CLOSE,
- CT::T_GROUP_IMPORT_BRACE_OPEN,
- CT::T_GROUP_IMPORT_BRACE_CLOSE,
- ]
- );
- }
- public static function provideProcess80Cases(): iterable
- {
- yield 'dynamic nullable property brace open/close' => [
- '<?php $foo?->{$bar};',
- [
- 3 => CT::T_DYNAMIC_PROP_BRACE_OPEN,
- 5 => CT::T_DYNAMIC_PROP_BRACE_CLOSE,
- ],
- ];
- }
- /**
- * @param _TransformerTestExpectedTokens $expectedTokens
- *
- * @dataProvider providePre84ProcessCases
- *
- * @requires PHP <8.4
- */
- public function testPre84Process(string $source, array $expectedTokens = []): void
- {
- $this->doTest(
- $source,
- $expectedTokens,
- [
- T_CURLY_OPEN,
- CT::T_CURLY_CLOSE,
- T_DOLLAR_OPEN_CURLY_BRACES,
- CT::T_DOLLAR_CLOSE_CURLY_BRACES,
- CT::T_DYNAMIC_PROP_BRACE_OPEN,
- CT::T_DYNAMIC_PROP_BRACE_CLOSE,
- CT::T_DYNAMIC_VAR_BRACE_OPEN,
- CT::T_DYNAMIC_VAR_BRACE_CLOSE,
- CT::T_ARRAY_INDEX_CURLY_BRACE_OPEN,
- CT::T_ARRAY_INDEX_CURLY_BRACE_CLOSE,
- CT::T_GROUP_IMPORT_BRACE_OPEN,
- CT::T_GROUP_IMPORT_BRACE_CLOSE,
- ]
- );
- }
- /**
- * @return iterable<array{string, array<int, int>}>
- */
- public static function providePre84ProcessCases(): iterable
- {
- yield 'array index curly brace open/close' => [
- '<?php
- echo $arr{$index};
- echo $arr[$index];
- if (1) {}
- ',
- [
- 5 => CT::T_ARRAY_INDEX_CURLY_BRACE_OPEN,
- 7 => CT::T_ARRAY_INDEX_CURLY_BRACE_CLOSE,
- ],
- ];
- yield 'array index curly brace open/close, after square index' => [
- '<?php $b = [1]{0};
- ',
- [
- 8 => CT::T_ARRAY_INDEX_CURLY_BRACE_OPEN,
- 10 => CT::T_ARRAY_INDEX_CURLY_BRACE_CLOSE,
- ],
- ];
- yield 'array index curly brace open/close, nested' => [
- '<?php
- echo $nestedArray{$index}{$index2}[$index3]{$index4};
- ',
- [
- 5 => CT::T_ARRAY_INDEX_CURLY_BRACE_OPEN,
- 7 => CT::T_ARRAY_INDEX_CURLY_BRACE_CLOSE,
- 8 => CT::T_ARRAY_INDEX_CURLY_BRACE_OPEN,
- 10 => CT::T_ARRAY_INDEX_CURLY_BRACE_CLOSE,
- 14 => CT::T_ARRAY_INDEX_CURLY_BRACE_OPEN,
- 16 => CT::T_ARRAY_INDEX_CURLY_BRACE_CLOSE,
- ],
- ];
- yield 'array index curly brace open/close, repeated' => [
- '<?php
- echo $array{0}->foo;
- echo $collection->items{1}->property;
- ',
- [
- 5 => CT::T_ARRAY_INDEX_CURLY_BRACE_OPEN,
- 7 => CT::T_ARRAY_INDEX_CURLY_BRACE_CLOSE,
- 17 => CT::T_ARRAY_INDEX_CURLY_BRACE_OPEN,
- 19 => CT::T_ARRAY_INDEX_CURLY_BRACE_CLOSE,
- ],
- ];
- yield 'array index curly brace open/close, minimal' => [
- '<?php
- echo [1]{0};
- echo array(1){0};
- ',
- [
- 7 => CT::T_ARRAY_INDEX_CURLY_BRACE_OPEN,
- 9 => CT::T_ARRAY_INDEX_CURLY_BRACE_CLOSE,
- 18 => CT::T_ARRAY_INDEX_CURLY_BRACE_OPEN,
- 20 => CT::T_ARRAY_INDEX_CURLY_BRACE_CLOSE,
- ],
- ];
- }
- /**
- * @dataProvider provideNotDynamicClassConstantFetchCases
- */
- public function testNotDynamicClassConstantFetch(string $source): void
- {
- Tokens::clearCache();
- $tokens = Tokens::fromCode($source);
- self::assertFalse(
- $tokens->isAnyTokenKindsFound(
- [
- CT::T_DYNAMIC_CLASS_CONSTANT_FETCH_CURLY_BRACE_OPEN,
- CT::T_DYNAMIC_CLASS_CONSTANT_FETCH_CURLY_BRACE_CLOSE,
- ]
- )
- );
- }
- /**
- * @return iterable<string, array{string}>
- */
- public static function provideNotDynamicClassConstantFetchCases(): iterable
- {
- yield 'negatives' => [
- '<?php
- namespace B {$b = Z::B;};
- echo $c::{$static_method}();
- echo Foo::{$static_method}();
- echo Foo::${static_property};
- echo Foo::${$static_property};
- echo Foo::class;
- echo $foo::$bar;
- echo $foo::bar();
- echo foo()::A();
- {$z = A::C;}
- ',
- ];
- }
- /**
- * @param _TransformerTestExpectedTokens $expectedTokens
- *
- * @dataProvider provideDynamicClassConstantFetchCases
- *
- * @requires PHP 8.3
- */
- public function testDynamicClassConstantFetch(array $expectedTokens, string $source): void
- {
- $this->doTest(
- $source,
- $expectedTokens,
- [
- CT::T_DYNAMIC_CLASS_CONSTANT_FETCH_CURLY_BRACE_OPEN,
- CT::T_DYNAMIC_CLASS_CONSTANT_FETCH_CURLY_BRACE_CLOSE,
- ],
- );
- }
- public static function provideDynamicClassConstantFetchCases(): iterable
- {
- yield 'simple' => [
- [
- 5 => CT::T_DYNAMIC_CLASS_CONSTANT_FETCH_CURLY_BRACE_OPEN,
- 7 => CT::T_DYNAMIC_CLASS_CONSTANT_FETCH_CURLY_BRACE_CLOSE,
- ],
- '<?php echo Foo::{$bar};',
- ];
- yield 'long way of writing `Bar::class`' => [
- [
- 5 => CT::T_DYNAMIC_CLASS_CONSTANT_FETCH_CURLY_BRACE_OPEN,
- 7 => CT::T_DYNAMIC_CLASS_CONSTANT_FETCH_CURLY_BRACE_CLOSE,
- ],
- "<?php echo Bar::{'class'};",
- ];
- yield 'variable variable wrapped, close tag' => [
- [
- 5 => CT::T_DYNAMIC_CLASS_CONSTANT_FETCH_CURLY_BRACE_OPEN,
- 10 => CT::T_DYNAMIC_CLASS_CONSTANT_FETCH_CURLY_BRACE_CLOSE,
- ],
- '<?php echo Foo::{${$var}}?>',
- ];
- yield 'variable variable, comment' => [
- [
- 5 => CT::T_DYNAMIC_CLASS_CONSTANT_FETCH_CURLY_BRACE_OPEN,
- 8 => CT::T_DYNAMIC_CLASS_CONSTANT_FETCH_CURLY_BRACE_CLOSE,
- ],
- '<?php echo Foo::{$$var}/* */;?>',
- ];
- yield 'static, self' => [
- [
- 37 => CT::T_DYNAMIC_CLASS_CONSTANT_FETCH_CURLY_BRACE_OPEN,
- 39 => CT::T_DYNAMIC_CLASS_CONSTANT_FETCH_CURLY_BRACE_CLOSE,
- 46 => CT::T_DYNAMIC_CLASS_CONSTANT_FETCH_CURLY_BRACE_OPEN,
- 48 => CT::T_DYNAMIC_CLASS_CONSTANT_FETCH_CURLY_BRACE_CLOSE,
- 55 => CT::T_DYNAMIC_CLASS_CONSTANT_FETCH_CURLY_BRACE_OPEN,
- 57 => CT::T_DYNAMIC_CLASS_CONSTANT_FETCH_CURLY_BRACE_CLOSE,
- ],
- '<?php
- class Foo
- {
- private const X = 1;
- public function Bar($var): void
- {
- echo self::{$var};
- echo static::{$var};
- echo static::{"X"};
- }
- }
- ',
- ];
- yield 'chained' => [
- [
- 5 => CT::T_DYNAMIC_CLASS_CONSTANT_FETCH_CURLY_BRACE_OPEN,
- 7 => CT::T_DYNAMIC_CLASS_CONSTANT_FETCH_CURLY_BRACE_CLOSE,
- 9 => CT::T_DYNAMIC_CLASS_CONSTANT_FETCH_CURLY_BRACE_OPEN,
- 11 => CT::T_DYNAMIC_CLASS_CONSTANT_FETCH_CURLY_BRACE_CLOSE,
- ],
- "<?php echo Foo::{'BAR'}::{'BLA'}::{static_method}(1,2) ?>",
- ];
- yield 'mixed chain' => [
- [
- 21 => CT::T_DYNAMIC_CLASS_CONSTANT_FETCH_CURLY_BRACE_OPEN,
- 23 => CT::T_DYNAMIC_CLASS_CONSTANT_FETCH_CURLY_BRACE_CLOSE,
- 25 => CT::T_DYNAMIC_CLASS_CONSTANT_FETCH_CURLY_BRACE_OPEN,
- 27 => CT::T_DYNAMIC_CLASS_CONSTANT_FETCH_CURLY_BRACE_CLOSE,
- ],
- '<?php echo Foo::{\'static_method\'}()::{$$a}()["const"]::{some_const}::{$other_const}::{$last_static_method}();',
- ];
- }
- /**
- * @param _TransformerTestExpectedTokens $expectedTokens
- *
- * @dataProvider provideDynamicClassConstantFetchPhp83Cases
- *
- * @requires PHP ~8.3.0
- */
- public function testDynamicClassConstantFetchPhp83(array $expectedTokens, string $source): void
- {
- $this->doTest(
- $source,
- $expectedTokens,
- [
- CT::T_DYNAMIC_CLASS_CONSTANT_FETCH_CURLY_BRACE_OPEN,
- CT::T_DYNAMIC_CLASS_CONSTANT_FETCH_CURLY_BRACE_CLOSE,
- ],
- );
- }
- /**
- * @return iterable<array{array<int, int>, string}>
- */
- public static function provideDynamicClassConstantFetchPhp83Cases(): iterable
- {
- yield 'static method var, string' => [
- [
- 10 => CT::T_DYNAMIC_CLASS_CONSTANT_FETCH_CURLY_BRACE_OPEN,
- 12 => CT::T_DYNAMIC_CLASS_CONSTANT_FETCH_CURLY_BRACE_CLOSE,
- ],
- "<?php echo Foo::{\$static_method}(){'XYZ'};",
- ];
- yield 'mixed chain' => [
- [
- 17 => CT::T_DYNAMIC_CLASS_CONSTANT_FETCH_CURLY_BRACE_OPEN,
- 19 => CT::T_DYNAMIC_CLASS_CONSTANT_FETCH_CURLY_BRACE_CLOSE,
- 21 => CT::T_DYNAMIC_CLASS_CONSTANT_FETCH_CURLY_BRACE_OPEN,
- 23 => CT::T_DYNAMIC_CLASS_CONSTANT_FETCH_CURLY_BRACE_CLOSE,
- 25 => CT::T_DYNAMIC_CLASS_CONSTANT_FETCH_CURLY_BRACE_OPEN,
- 27 => CT::T_DYNAMIC_CLASS_CONSTANT_FETCH_CURLY_BRACE_CLOSE,
- ],
- '<?php echo Foo::{\'static_method\'}()::{$$a}(){"const"}::{some_const}::{$other_const}::{$last_static_method}();',
- ];
- }
- }
|