SquareBraceTransformerTest.php 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465
  1. <?php
  2. declare(strict_types=1);
  3. /*
  4. * This file is part of PHP CS Fixer.
  5. *
  6. * (c) Fabien Potencier <fabien@symfony.com>
  7. * Dariusz Rumiński <dariusz.ruminski@gmail.com>
  8. *
  9. * This source file is subject to the MIT license that is bundled
  10. * with this source code in the file LICENSE.
  11. */
  12. namespace PhpCsFixer\Tests\Tokenizer\Transformer;
  13. use PhpCsFixer\Tests\Test\AbstractTransformerTestCase;
  14. use PhpCsFixer\Tokenizer\CT;
  15. use PhpCsFixer\Tokenizer\Tokens;
  16. use PhpCsFixer\Tokenizer\Transformer\SquareBraceTransformer;
  17. /**
  18. * @author Dariusz Rumiński <dariusz.ruminski@gmail.com>
  19. *
  20. * @internal
  21. *
  22. * @covers \PhpCsFixer\Tokenizer\Transformer\SquareBraceTransformer
  23. *
  24. * @phpstan-import-type _TransformerTestExpectedTokens from AbstractTransformerTestCase
  25. */
  26. final class SquareBraceTransformerTest extends AbstractTransformerTestCase
  27. {
  28. /**
  29. * @param list<int> $inspectIndexes
  30. *
  31. * @dataProvider provideIsShortArrayCases
  32. */
  33. public function testIsShortArray(string $source, array $inspectIndexes, bool $expected): void
  34. {
  35. $transformer = new SquareBraceTransformer();
  36. $tokens = Tokens::fromCode($source);
  37. foreach ($inspectIndexes as $index) {
  38. self::assertTrue($tokens->offsetExists($index), \sprintf('Index %d does not exist.', $index));
  39. }
  40. foreach ($tokens as $index => $token) {
  41. if (\in_array($index, $inspectIndexes, true)) {
  42. self::assertSame('[', $tokens[$index]->getContent(), \sprintf('Token @ index %d must have content \']\'', $index));
  43. $exp = $expected;
  44. } elseif ('[' === $tokens[$index]->getContent()) {
  45. $exp = !$expected;
  46. } else {
  47. continue;
  48. }
  49. self::assertSame(
  50. $expected,
  51. \Closure::bind(static fn (SquareBraceTransformer $transformer): bool => $transformer->isShortArray($tokens, $index), null, SquareBraceTransformer::class)($transformer),
  52. \sprintf('Excepted token "%s" @ index %d %sto be detected as short array.', $tokens[$index]->toJson(), $index, $exp ? '' : 'not ')
  53. );
  54. }
  55. }
  56. public static function provideIsShortArrayCases(): iterable
  57. {
  58. yield ['<?php $a=[];', [3], false];
  59. yield ['<?php [$a] = [$b];', [7], false];
  60. yield ['<?php [$a] = $b;', [1], false];
  61. yield ['<?php [$a] = [$b] = [$b];', [1], false];
  62. yield ['<?php function A(){}[$a] = [$b] = [$b];', [8], false];
  63. yield ['<?php [$foo, $bar] = [$baz, $bat] = [$a, $b];', [10], false];
  64. yield ['<?php [[$a, $b], [$c, $d]] = [[1, 2], [3, 4]];', [1], false];
  65. yield ['<?php ["a" => $a, "b" => $b, "c" => $c] = $array;', [1], false];
  66. yield ['<?php [$a, $b,, [$c, $d]] = $a;', [1, 9], false];
  67. }
  68. /**
  69. * @param _TransformerTestExpectedTokens $expectedTokens
  70. *
  71. * @dataProvider provideProcessCases
  72. */
  73. public function testProcess(string $source, array $expectedTokens = []): void
  74. {
  75. $this->doTest(
  76. $source,
  77. $expectedTokens,
  78. [
  79. CT::T_ARRAY_SQUARE_BRACE_OPEN,
  80. CT::T_ARRAY_SQUARE_BRACE_CLOSE,
  81. CT::T_DESTRUCTURING_SQUARE_BRACE_OPEN,
  82. CT::T_DESTRUCTURING_SQUARE_BRACE_CLOSE,
  83. ]
  84. );
  85. }
  86. public static function provideProcessCases(): iterable
  87. {
  88. yield 'Array offset only.' => [
  89. '<?php $a = array(); $a[] = 0; $a[1] = 2;',
  90. ];
  91. yield 'Short array construction.' => [
  92. '<?php $b = [1, 2, 3];',
  93. [
  94. 5 => CT::T_ARRAY_SQUARE_BRACE_OPEN,
  95. 13 => CT::T_ARRAY_SQUARE_BRACE_CLOSE,
  96. ],
  97. ];
  98. yield [
  99. '<?php function foo(array $c = [ ]) {}',
  100. [
  101. 11 => CT::T_ARRAY_SQUARE_BRACE_OPEN,
  102. 13 => CT::T_ARRAY_SQUARE_BRACE_CLOSE,
  103. ],
  104. ];
  105. yield [
  106. '<?php [];',
  107. [
  108. 1 => CT::T_ARRAY_SQUARE_BRACE_OPEN,
  109. 2 => CT::T_ARRAY_SQUARE_BRACE_CLOSE,
  110. ],
  111. ];
  112. yield [
  113. '<?php [1, "foo"];',
  114. [
  115. 1 => CT::T_ARRAY_SQUARE_BRACE_OPEN,
  116. 6 => CT::T_ARRAY_SQUARE_BRACE_CLOSE,
  117. ],
  118. ];
  119. yield [
  120. '<?php [[]];',
  121. [
  122. 1 => CT::T_ARRAY_SQUARE_BRACE_OPEN,
  123. 2 => CT::T_ARRAY_SQUARE_BRACE_OPEN,
  124. 3 => CT::T_ARRAY_SQUARE_BRACE_CLOSE,
  125. 4 => CT::T_ARRAY_SQUARE_BRACE_CLOSE,
  126. ],
  127. ];
  128. yield [
  129. '<?php ["foo", ["bar", "baz"]];',
  130. [
  131. 1 => CT::T_ARRAY_SQUARE_BRACE_OPEN,
  132. 5 => CT::T_ARRAY_SQUARE_BRACE_OPEN,
  133. 10 => CT::T_ARRAY_SQUARE_BRACE_CLOSE,
  134. 11 => CT::T_ARRAY_SQUARE_BRACE_CLOSE,
  135. ],
  136. ];
  137. yield [
  138. '<?php (array) [1, 2];',
  139. [
  140. 3 => CT::T_ARRAY_SQUARE_BRACE_OPEN,
  141. 8 => CT::T_ARRAY_SQUARE_BRACE_CLOSE,
  142. ],
  143. ];
  144. yield [
  145. '<?php [1,2][$x];',
  146. [
  147. 1 => CT::T_ARRAY_SQUARE_BRACE_OPEN,
  148. 5 => CT::T_ARRAY_SQUARE_BRACE_CLOSE,
  149. ],
  150. ];
  151. yield [
  152. '<?php $a[] = []?>',
  153. [
  154. 7 => CT::T_ARRAY_SQUARE_BRACE_OPEN,
  155. 8 => CT::T_ARRAY_SQUARE_BRACE_CLOSE,
  156. ],
  157. ];
  158. yield [
  159. '<?php $b = [1];',
  160. [
  161. 5 => CT::T_ARRAY_SQUARE_BRACE_OPEN,
  162. 7 => CT::T_ARRAY_SQUARE_BRACE_CLOSE,
  163. ],
  164. ];
  165. yield [
  166. '<?php $c[] = 2?>',
  167. ];
  168. yield [
  169. '<?php $d[3] = 4;',
  170. ];
  171. yield [
  172. '<?php $e = [];',
  173. [
  174. 5 => CT::T_ARRAY_SQUARE_BRACE_OPEN,
  175. 6 => CT::T_ARRAY_SQUARE_BRACE_CLOSE,
  176. ],
  177. ];
  178. yield [
  179. '<?php array();',
  180. ];
  181. yield [
  182. '<?php $x[] = 1;',
  183. ];
  184. yield [
  185. '<?php $x[1];',
  186. ];
  187. yield [
  188. '<?php $x [ 1 ];',
  189. ];
  190. yield [
  191. '<?php ${"x"}[1];',
  192. ];
  193. yield [
  194. '<?php FOO[1];',
  195. ];
  196. yield [
  197. '<?php array("foo")[1];',
  198. ];
  199. yield [
  200. '<?php foo()[1];',
  201. ];
  202. yield [
  203. '<?php "foo"[1];//[]',
  204. ];
  205. yield [
  206. '<?php
  207. class Test
  208. {
  209. public function updateAttributeKey($key, $value)
  210. {
  211. $this->{camel_case($attributes)}[$key] = $value;
  212. }
  213. }',
  214. ];
  215. yield [
  216. '<?php [$a, $b, $c] = [1, 2, 3];',
  217. [
  218. 1 => CT::T_DESTRUCTURING_SQUARE_BRACE_OPEN,
  219. 9 => CT::T_DESTRUCTURING_SQUARE_BRACE_CLOSE,
  220. 13 => CT::T_ARRAY_SQUARE_BRACE_OPEN,
  221. 21 => CT::T_ARRAY_SQUARE_BRACE_CLOSE,
  222. ],
  223. ];
  224. yield [
  225. '<?php ["a" => $a, "b" => $b, "c" => $c] = $array;',
  226. [
  227. 1 => CT::T_DESTRUCTURING_SQUARE_BRACE_OPEN,
  228. 21 => CT::T_DESTRUCTURING_SQUARE_BRACE_CLOSE,
  229. ],
  230. ];
  231. yield [
  232. '<?php [$e] = $d; if ($a){}[$a, $b] = b();',
  233. [
  234. 1 => CT::T_DESTRUCTURING_SQUARE_BRACE_OPEN,
  235. 3 => CT::T_DESTRUCTURING_SQUARE_BRACE_CLOSE,
  236. 17 => CT::T_DESTRUCTURING_SQUARE_BRACE_OPEN,
  237. 22 => CT::T_DESTRUCTURING_SQUARE_BRACE_CLOSE,
  238. ],
  239. ];
  240. yield [
  241. '<?php $a = [$x] = [$y] = [$z] = [];', // this sample makes no sense, however is in valid syntax
  242. [
  243. 5 => CT::T_DESTRUCTURING_SQUARE_BRACE_OPEN,
  244. 7 => CT::T_DESTRUCTURING_SQUARE_BRACE_CLOSE,
  245. 11 => CT::T_DESTRUCTURING_SQUARE_BRACE_OPEN,
  246. 13 => CT::T_DESTRUCTURING_SQUARE_BRACE_CLOSE,
  247. 17 => CT::T_DESTRUCTURING_SQUARE_BRACE_OPEN,
  248. 19 => CT::T_DESTRUCTURING_SQUARE_BRACE_CLOSE,
  249. 23 => CT::T_ARRAY_SQUARE_BRACE_OPEN,
  250. 24 => CT::T_ARRAY_SQUARE_BRACE_CLOSE,
  251. ],
  252. ];
  253. yield [
  254. '<?php [$$a, $b] = $array;',
  255. [
  256. 1 => CT::T_DESTRUCTURING_SQUARE_BRACE_OPEN,
  257. 7 => CT::T_DESTRUCTURING_SQUARE_BRACE_CLOSE,
  258. ],
  259. ];
  260. yield [
  261. '<?php [$a, $b,, [$c, $d]] = $a;',
  262. [
  263. 1 => CT::T_DESTRUCTURING_SQUARE_BRACE_OPEN,
  264. 9 => CT::T_DESTRUCTURING_SQUARE_BRACE_OPEN,
  265. 14 => CT::T_DESTRUCTURING_SQUARE_BRACE_CLOSE,
  266. 15 => CT::T_DESTRUCTURING_SQUARE_BRACE_CLOSE,
  267. ],
  268. ];
  269. yield 'nested I' => [
  270. '<?php [$a[]] = $b;',
  271. [
  272. 1 => CT::T_DESTRUCTURING_SQUARE_BRACE_OPEN,
  273. 5 => CT::T_DESTRUCTURING_SQUARE_BRACE_CLOSE,
  274. ],
  275. ];
  276. yield 'nested II (with array offset)' => [
  277. '<?php [$a[1]] = $b;',
  278. [
  279. 1 => CT::T_DESTRUCTURING_SQUARE_BRACE_OPEN,
  280. 6 => CT::T_DESTRUCTURING_SQUARE_BRACE_CLOSE,
  281. ],
  282. ];
  283. yield 'nested III' => [
  284. '<?php [$a[1], [$b], $c[2]] = $d;',
  285. [
  286. 1 => CT::T_DESTRUCTURING_SQUARE_BRACE_OPEN,
  287. 8 => CT::T_DESTRUCTURING_SQUARE_BRACE_OPEN,
  288. 10 => CT::T_DESTRUCTURING_SQUARE_BRACE_CLOSE,
  289. 17 => CT::T_DESTRUCTURING_SQUARE_BRACE_CLOSE,
  290. ],
  291. ];
  292. yield [
  293. '<?php [[[$a]/**/], $b[1], [/**/[$c]] /** */ ] = $d[1][2][3];',
  294. [
  295. 1 => CT::T_DESTRUCTURING_SQUARE_BRACE_OPEN,
  296. 2 => CT::T_DESTRUCTURING_SQUARE_BRACE_OPEN,
  297. 3 => CT::T_DESTRUCTURING_SQUARE_BRACE_OPEN,
  298. 5 => CT::T_DESTRUCTURING_SQUARE_BRACE_CLOSE,
  299. 7 => CT::T_DESTRUCTURING_SQUARE_BRACE_CLOSE,
  300. 16 => CT::T_DESTRUCTURING_SQUARE_BRACE_OPEN,
  301. 18 => CT::T_DESTRUCTURING_SQUARE_BRACE_OPEN,
  302. 20 => CT::T_DESTRUCTURING_SQUARE_BRACE_CLOSE,
  303. 21 => CT::T_DESTRUCTURING_SQUARE_BRACE_CLOSE,
  304. 25 => CT::T_DESTRUCTURING_SQUARE_BRACE_CLOSE,
  305. ],
  306. ];
  307. yield [
  308. '<?php foreach ($z as [$a, $b]) {}',
  309. [
  310. 8 => CT::T_DESTRUCTURING_SQUARE_BRACE_OPEN,
  311. 13 => CT::T_DESTRUCTURING_SQUARE_BRACE_CLOSE,
  312. ],
  313. ];
  314. yield [
  315. '<?php foreach ($a as $key => [$x, $y]) {}',
  316. [
  317. 12 => CT::T_DESTRUCTURING_SQUARE_BRACE_OPEN,
  318. 17 => CT::T_DESTRUCTURING_SQUARE_BRACE_CLOSE,
  319. ],
  320. ];
  321. yield [
  322. '<?php [$key => [$x, $y]];',
  323. [
  324. 1 => CT::T_ARRAY_SQUARE_BRACE_OPEN,
  325. 6 => CT::T_ARRAY_SQUARE_BRACE_OPEN,
  326. 11 => CT::T_ARRAY_SQUARE_BRACE_CLOSE,
  327. 12 => CT::T_ARRAY_SQUARE_BRACE_CLOSE,
  328. ],
  329. ];
  330. yield [
  331. '<?php array($key => [$x, $y]);',
  332. [
  333. 7 => CT::T_ARRAY_SQUARE_BRACE_OPEN,
  334. 12 => CT::T_ARRAY_SQUARE_BRACE_CLOSE,
  335. ],
  336. ];
  337. yield [
  338. '<?php [$key => [$x, $y] = foo()];',
  339. [
  340. 1 => CT::T_ARRAY_SQUARE_BRACE_OPEN,
  341. 6 => CT::T_DESTRUCTURING_SQUARE_BRACE_OPEN,
  342. 11 => CT::T_DESTRUCTURING_SQUARE_BRACE_CLOSE,
  343. 18 => CT::T_ARRAY_SQUARE_BRACE_CLOSE,
  344. ],
  345. ];
  346. }
  347. /**
  348. * @param _TransformerTestExpectedTokens $expectedTokens
  349. *
  350. * @dataProvider provideProcess72Cases
  351. */
  352. public function testProcess72(string $source, array $expectedTokens): void
  353. {
  354. $this->doTest(
  355. $source,
  356. $expectedTokens,
  357. [
  358. CT::T_DESTRUCTURING_SQUARE_BRACE_OPEN,
  359. CT::T_DESTRUCTURING_SQUARE_BRACE_CLOSE,
  360. ]
  361. );
  362. }
  363. public static function provideProcess72Cases(): iterable
  364. {
  365. yield [
  366. '<?php [&$a, $b] = $a;',
  367. [
  368. 1 => CT::T_DESTRUCTURING_SQUARE_BRACE_OPEN,
  369. 7 => CT::T_DESTRUCTURING_SQUARE_BRACE_CLOSE,
  370. ],
  371. ];
  372. yield [
  373. '<?php [$a, &$b] = $a;',
  374. [
  375. 1 => CT::T_DESTRUCTURING_SQUARE_BRACE_OPEN,
  376. 7 => CT::T_DESTRUCTURING_SQUARE_BRACE_CLOSE,
  377. ],
  378. ];
  379. yield [
  380. '<?php [&$a, &$b] = $a;',
  381. [
  382. 1 => CT::T_DESTRUCTURING_SQUARE_BRACE_OPEN,
  383. 8 => CT::T_DESTRUCTURING_SQUARE_BRACE_CLOSE,
  384. ],
  385. ];
  386. yield [
  387. '<?php [[ [&$a, &$b], [&$c] ], [&$d/* */]] = $e;',
  388. [
  389. 1 => CT::T_DESTRUCTURING_SQUARE_BRACE_OPEN,
  390. 2 => CT::T_DESTRUCTURING_SQUARE_BRACE_OPEN,
  391. 4 => CT::T_DESTRUCTURING_SQUARE_BRACE_OPEN,
  392. 11 => CT::T_DESTRUCTURING_SQUARE_BRACE_CLOSE,
  393. 14 => CT::T_DESTRUCTURING_SQUARE_BRACE_OPEN,
  394. 17 => CT::T_DESTRUCTURING_SQUARE_BRACE_CLOSE,
  395. 19 => CT::T_DESTRUCTURING_SQUARE_BRACE_CLOSE,
  396. 22 => CT::T_DESTRUCTURING_SQUARE_BRACE_OPEN,
  397. 26 => CT::T_DESTRUCTURING_SQUARE_BRACE_CLOSE,
  398. 27 => CT::T_DESTRUCTURING_SQUARE_BRACE_CLOSE,
  399. ],
  400. ];
  401. }
  402. }