SquareBraceTransformerTest.php 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390
  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 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. static::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. static::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. static::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 function provideIsShortArrayCases(): array
  58. {
  59. return [
  60. ['<?php $a=[];', [3], false],
  61. ['<?php [$a] = [$b];', [7], false],
  62. ['<?php [$a] = $b;', [1], false],
  63. ['<?php [$a] = [$b] = [$b];', [1], false],
  64. ['<?php function A(){}[$a] = [$b] = [$b];', [8], false],
  65. ['<?php [$foo, $bar] = [$baz, $bat] = [$a, $b];', [10], false],
  66. ['<?php [[$a, $b], [$c, $d]] = [[1, 2], [3, 4]];', [1], false],
  67. ['<?php ["a" => $a, "b" => $b, "c" => $c] = $array;', [1], false],
  68. ['<?php [$a, $b,, [$c, $d]] = $a;', [1, 9], false],
  69. ];
  70. }
  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 function provideProcessCases(): array
  88. {
  89. return [
  90. 'Array offset only.' => [
  91. '<?php $a = array(); $a[] = 0; $a[1] = 2;',
  92. ],
  93. 'Short array construction.' => [
  94. '<?php $b = [1, 2, 3];',
  95. [
  96. 5 => CT::T_ARRAY_SQUARE_BRACE_OPEN,
  97. 13 => CT::T_ARRAY_SQUARE_BRACE_CLOSE,
  98. ],
  99. ],
  100. [
  101. '<?php function foo(array $c = [ ]) {}',
  102. [
  103. 11 => CT::T_ARRAY_SQUARE_BRACE_OPEN,
  104. 13 => CT::T_ARRAY_SQUARE_BRACE_CLOSE,
  105. ],
  106. ],
  107. [
  108. '<?php [];',
  109. [
  110. 1 => CT::T_ARRAY_SQUARE_BRACE_OPEN,
  111. 2 => CT::T_ARRAY_SQUARE_BRACE_CLOSE,
  112. ],
  113. ],
  114. [
  115. '<?php [1, "foo"];',
  116. [
  117. 1 => CT::T_ARRAY_SQUARE_BRACE_OPEN,
  118. 6 => CT::T_ARRAY_SQUARE_BRACE_CLOSE,
  119. ],
  120. ],
  121. [
  122. '<?php [[]];',
  123. [
  124. 1 => CT::T_ARRAY_SQUARE_BRACE_OPEN,
  125. 2 => CT::T_ARRAY_SQUARE_BRACE_OPEN,
  126. 3 => CT::T_ARRAY_SQUARE_BRACE_CLOSE,
  127. 4 => CT::T_ARRAY_SQUARE_BRACE_CLOSE,
  128. ],
  129. ],
  130. [
  131. '<?php ["foo", ["bar", "baz"]];',
  132. [
  133. 1 => CT::T_ARRAY_SQUARE_BRACE_OPEN,
  134. 5 => CT::T_ARRAY_SQUARE_BRACE_OPEN,
  135. 10 => CT::T_ARRAY_SQUARE_BRACE_CLOSE,
  136. 11 => CT::T_ARRAY_SQUARE_BRACE_CLOSE,
  137. ],
  138. ],
  139. [
  140. '<?php (array) [1, 2];',
  141. [
  142. 3 => CT::T_ARRAY_SQUARE_BRACE_OPEN,
  143. 8 => CT::T_ARRAY_SQUARE_BRACE_CLOSE,
  144. ],
  145. ],
  146. [
  147. '<?php [1,2][$x];',
  148. [
  149. 1 => CT::T_ARRAY_SQUARE_BRACE_OPEN,
  150. 5 => CT::T_ARRAY_SQUARE_BRACE_CLOSE,
  151. ],
  152. ],
  153. [
  154. '<?php $a[] = []?>',
  155. [
  156. 7 => CT::T_ARRAY_SQUARE_BRACE_OPEN,
  157. 8 => CT::T_ARRAY_SQUARE_BRACE_CLOSE,
  158. ],
  159. ],
  160. [
  161. '<?php $b = [1];',
  162. [
  163. 5 => CT::T_ARRAY_SQUARE_BRACE_OPEN,
  164. 7 => CT::T_ARRAY_SQUARE_BRACE_CLOSE,
  165. ],
  166. ],
  167. [
  168. '<?php $c[] = 2?>',
  169. ],
  170. [
  171. '<?php $d[3] = 4;',
  172. ],
  173. [
  174. '<?php $e = [];',
  175. [
  176. 5 => CT::T_ARRAY_SQUARE_BRACE_OPEN,
  177. 6 => CT::T_ARRAY_SQUARE_BRACE_CLOSE,
  178. ],
  179. ],
  180. [
  181. '<?php array();',
  182. ],
  183. [
  184. '<?php $x[] = 1;',
  185. ],
  186. [
  187. '<?php $x[1];',
  188. ],
  189. [
  190. '<?php $x [ 1 ];',
  191. ],
  192. [
  193. '<?php ${"x"}[1];',
  194. ],
  195. [
  196. '<?php FOO[1];',
  197. ],
  198. [
  199. '<?php array("foo")[1];',
  200. ],
  201. [
  202. '<?php foo()[1];',
  203. ],
  204. [
  205. '<?php "foo"[1];//[]',
  206. ],
  207. [
  208. '<?php
  209. class Test
  210. {
  211. public function updateAttributeKey($key, $value)
  212. {
  213. $this->{camel_case($attributes)}[$key] = $value;
  214. }
  215. }',
  216. ],
  217. [
  218. '<?php [$a, $b, $c] = [1, 2, 3];',
  219. [
  220. 1 => CT::T_DESTRUCTURING_SQUARE_BRACE_OPEN,
  221. 9 => CT::T_DESTRUCTURING_SQUARE_BRACE_CLOSE,
  222. 13 => CT::T_ARRAY_SQUARE_BRACE_OPEN,
  223. 21 => CT::T_ARRAY_SQUARE_BRACE_CLOSE,
  224. ],
  225. ],
  226. [
  227. '<?php ["a" => $a, "b" => $b, "c" => $c] = $array;',
  228. [
  229. 1 => CT::T_DESTRUCTURING_SQUARE_BRACE_OPEN,
  230. 21 => CT::T_DESTRUCTURING_SQUARE_BRACE_CLOSE,
  231. ],
  232. ],
  233. [
  234. '<?php [$e] = $d; if ($a){}[$a, $b] = b();',
  235. [
  236. 1 => CT::T_DESTRUCTURING_SQUARE_BRACE_OPEN,
  237. 3 => CT::T_DESTRUCTURING_SQUARE_BRACE_CLOSE,
  238. 17 => CT::T_DESTRUCTURING_SQUARE_BRACE_OPEN,
  239. 22 => CT::T_DESTRUCTURING_SQUARE_BRACE_CLOSE,
  240. ],
  241. ],
  242. [
  243. '<?php $a = [$x] = [$y] = [$z] = [];', // this sample makes no sense, however is in valid syntax
  244. [
  245. 5 => CT::T_DESTRUCTURING_SQUARE_BRACE_OPEN,
  246. 7 => CT::T_DESTRUCTURING_SQUARE_BRACE_CLOSE,
  247. 11 => CT::T_DESTRUCTURING_SQUARE_BRACE_OPEN,
  248. 13 => CT::T_DESTRUCTURING_SQUARE_BRACE_CLOSE,
  249. 17 => CT::T_DESTRUCTURING_SQUARE_BRACE_OPEN,
  250. 19 => CT::T_DESTRUCTURING_SQUARE_BRACE_CLOSE,
  251. 23 => CT::T_ARRAY_SQUARE_BRACE_OPEN,
  252. 24 => CT::T_ARRAY_SQUARE_BRACE_CLOSE,
  253. ],
  254. ],
  255. [
  256. '<?php [$$a, $b] = $array;',
  257. [
  258. 1 => CT::T_DESTRUCTURING_SQUARE_BRACE_OPEN,
  259. 7 => CT::T_DESTRUCTURING_SQUARE_BRACE_CLOSE,
  260. ],
  261. ],
  262. [
  263. '<?php [$a, $b,, [$c, $d]] = $a;',
  264. [
  265. 1 => CT::T_DESTRUCTURING_SQUARE_BRACE_OPEN,
  266. 9 => CT::T_DESTRUCTURING_SQUARE_BRACE_OPEN,
  267. 14 => CT::T_DESTRUCTURING_SQUARE_BRACE_CLOSE,
  268. 15 => CT::T_DESTRUCTURING_SQUARE_BRACE_CLOSE,
  269. ],
  270. ],
  271. 'nested I' => [
  272. '<?php [$a[]] = $b;',
  273. [
  274. 1 => CT::T_DESTRUCTURING_SQUARE_BRACE_OPEN,
  275. 5 => CT::T_DESTRUCTURING_SQUARE_BRACE_CLOSE,
  276. ],
  277. ],
  278. 'nested II (with array offset)' => [
  279. '<?php [$a[1]] = $b;',
  280. [
  281. 1 => CT::T_DESTRUCTURING_SQUARE_BRACE_OPEN,
  282. 6 => CT::T_DESTRUCTURING_SQUARE_BRACE_CLOSE,
  283. ],
  284. ],
  285. 'nested III' => [
  286. '<?php [$a[1], [$b], $c[2]] = $d;',
  287. [
  288. 1 => CT::T_DESTRUCTURING_SQUARE_BRACE_OPEN,
  289. 8 => CT::T_DESTRUCTURING_SQUARE_BRACE_OPEN,
  290. 10 => CT::T_DESTRUCTURING_SQUARE_BRACE_CLOSE,
  291. 17 => CT::T_DESTRUCTURING_SQUARE_BRACE_CLOSE,
  292. ],
  293. ],
  294. [
  295. '<?php [[[$a]/**/], $b[1], [/**/[$c]] /** */ ] = $d[1][2][3];',
  296. [
  297. 1 => CT::T_DESTRUCTURING_SQUARE_BRACE_OPEN,
  298. 2 => CT::T_DESTRUCTURING_SQUARE_BRACE_OPEN,
  299. 3 => CT::T_DESTRUCTURING_SQUARE_BRACE_OPEN,
  300. 5 => CT::T_DESTRUCTURING_SQUARE_BRACE_CLOSE,
  301. 7 => CT::T_DESTRUCTURING_SQUARE_BRACE_CLOSE,
  302. 16 => CT::T_DESTRUCTURING_SQUARE_BRACE_OPEN,
  303. 18 => CT::T_DESTRUCTURING_SQUARE_BRACE_OPEN,
  304. 20 => CT::T_DESTRUCTURING_SQUARE_BRACE_CLOSE,
  305. 21 => CT::T_DESTRUCTURING_SQUARE_BRACE_CLOSE,
  306. 25 => CT::T_DESTRUCTURING_SQUARE_BRACE_CLOSE,
  307. ],
  308. ],
  309. [
  310. '<?php foreach ($z as [$a, $b]) {}',
  311. [
  312. 8 => CT::T_DESTRUCTURING_SQUARE_BRACE_OPEN,
  313. 13 => CT::T_DESTRUCTURING_SQUARE_BRACE_CLOSE,
  314. ],
  315. ],
  316. ];
  317. }
  318. /**
  319. * @param array<int, int> $expectedTokens
  320. *
  321. * @dataProvider provideProcess72Cases
  322. * @requires PHP 7.2
  323. */
  324. public function testProcess72(string $source, array $expectedTokens): void
  325. {
  326. $this->doTest(
  327. $source,
  328. $expectedTokens,
  329. [
  330. CT::T_DESTRUCTURING_SQUARE_BRACE_OPEN,
  331. CT::T_DESTRUCTURING_SQUARE_BRACE_CLOSE,
  332. ]
  333. );
  334. }
  335. public function provideProcess72Cases(): array
  336. {
  337. return [
  338. [
  339. '<?php [&$a, $b] = $a;',
  340. [
  341. 1 => CT::T_DESTRUCTURING_SQUARE_BRACE_OPEN,
  342. 7 => CT::T_DESTRUCTURING_SQUARE_BRACE_CLOSE,
  343. ],
  344. ],
  345. [
  346. '<?php [$a, &$b] = $a;',
  347. [
  348. 1 => CT::T_DESTRUCTURING_SQUARE_BRACE_OPEN,
  349. 7 => CT::T_DESTRUCTURING_SQUARE_BRACE_CLOSE,
  350. ],
  351. ],
  352. [
  353. '<?php [&$a, &$b] = $a;',
  354. [
  355. 1 => CT::T_DESTRUCTURING_SQUARE_BRACE_OPEN,
  356. 8 => CT::T_DESTRUCTURING_SQUARE_BRACE_CLOSE,
  357. ],
  358. ],
  359. [
  360. '<?php [[ [&$a, &$b], [&$c] ], [&$d/* */]] = $e;',
  361. [
  362. 1 => CT::T_DESTRUCTURING_SQUARE_BRACE_OPEN,
  363. 2 => CT::T_DESTRUCTURING_SQUARE_BRACE_OPEN,
  364. 4 => CT::T_DESTRUCTURING_SQUARE_BRACE_OPEN,
  365. 11 => CT::T_DESTRUCTURING_SQUARE_BRACE_CLOSE,
  366. 14 => CT::T_DESTRUCTURING_SQUARE_BRACE_OPEN,
  367. 17 => CT::T_DESTRUCTURING_SQUARE_BRACE_CLOSE,
  368. 19 => CT::T_DESTRUCTURING_SQUARE_BRACE_CLOSE,
  369. 22 => CT::T_DESTRUCTURING_SQUARE_BRACE_OPEN,
  370. 26 => CT::T_DESTRUCTURING_SQUARE_BRACE_CLOSE,
  371. 27 => CT::T_DESTRUCTURING_SQUARE_BRACE_CLOSE,
  372. ],
  373. ],
  374. ];
  375. }
  376. }