SquareBraceTransformerTest.php 13 KB

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