SquareBraceTransformerTest.php 13 KB

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