BraceClassInstantiationTransformerTest.php 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533
  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. /**
  16. * @author Sebastiaans Stok <s.stok@rollerscapes.net>
  17. *
  18. * @internal
  19. *
  20. * @covers \PhpCsFixer\Tokenizer\Transformer\BraceClassInstantiationTransformer
  21. *
  22. * @phpstan-import-type _TransformerTestExpectedTokens from AbstractTransformerTestCase
  23. * @phpstan-import-type _TransformerTestObservedKindsOrPrototypes from AbstractTransformerTestCase
  24. */
  25. final class BraceClassInstantiationTransformerTest extends AbstractTransformerTestCase
  26. {
  27. /**
  28. * @param _TransformerTestExpectedTokens $expectedTokens
  29. * @param _TransformerTestObservedKindsOrPrototypes $observedKinds
  30. *
  31. * @dataProvider provideProcessCases
  32. */
  33. public function testProcess(string $source, array $expectedTokens, array $observedKinds = []): void
  34. {
  35. $this->doTest(
  36. $source,
  37. $expectedTokens,
  38. $observedKinds
  39. );
  40. }
  41. public static function provideProcessCases(): iterable
  42. {
  43. yield [
  44. '<?php echo (new Process())->getOutput();',
  45. [
  46. 3 => CT::T_BRACE_CLASS_INSTANTIATION_OPEN,
  47. 9 => CT::T_BRACE_CLASS_INSTANTIATION_CLOSE,
  48. ],
  49. [
  50. CT::T_BRACE_CLASS_INSTANTIATION_OPEN,
  51. CT::T_BRACE_CLASS_INSTANTIATION_CLOSE,
  52. ],
  53. ];
  54. yield [
  55. '<?php echo (new Process())::getOutput();',
  56. [
  57. 3 => CT::T_BRACE_CLASS_INSTANTIATION_OPEN,
  58. 9 => CT::T_BRACE_CLASS_INSTANTIATION_CLOSE,
  59. ],
  60. [
  61. CT::T_BRACE_CLASS_INSTANTIATION_OPEN,
  62. CT::T_BRACE_CLASS_INSTANTIATION_CLOSE,
  63. ],
  64. ];
  65. yield [
  66. '<?php return foo()->bar(new Foo())->bar();',
  67. [
  68. 4 => '(',
  69. 5 => ')',
  70. 8 => '(',
  71. 12 => '(',
  72. 13 => ')',
  73. 14 => ')',
  74. 17 => '(',
  75. 18 => ')',
  76. ],
  77. [
  78. '(',
  79. ')',
  80. CT::T_BRACE_CLASS_INSTANTIATION_OPEN,
  81. CT::T_BRACE_CLASS_INSTANTIATION_CLOSE,
  82. ],
  83. ];
  84. yield [
  85. '<?php $foo[0](new Foo())->bar();',
  86. [
  87. 5 => '(',
  88. 9 => '(',
  89. 10 => ')',
  90. 11 => ')',
  91. 14 => '(',
  92. 15 => ')',
  93. ],
  94. [
  95. '(',
  96. ')',
  97. CT::T_BRACE_CLASS_INSTANTIATION_OPEN,
  98. CT::T_BRACE_CLASS_INSTANTIATION_CLOSE,
  99. ],
  100. ];
  101. yield [
  102. '<?php $foo(new Foo())->bar();',
  103. [
  104. 2 => '(',
  105. 6 => '(',
  106. 7 => ')',
  107. 8 => ')',
  108. 11 => '(',
  109. 12 => ')',
  110. ],
  111. [
  112. '(',
  113. ')',
  114. CT::T_BRACE_CLASS_INSTANTIATION_OPEN,
  115. CT::T_BRACE_CLASS_INSTANTIATION_CLOSE,
  116. ],
  117. ];
  118. yield [
  119. '<?php $$foo(new Foo())->bar();',
  120. [
  121. 3 => '(',
  122. 7 => '(',
  123. 8 => ')',
  124. 9 => ')',
  125. 12 => '(',
  126. 13 => ')',
  127. ],
  128. [
  129. '(',
  130. ')',
  131. CT::T_BRACE_CLASS_INSTANTIATION_OPEN,
  132. CT::T_BRACE_CLASS_INSTANTIATION_CLOSE,
  133. ],
  134. ];
  135. yield [
  136. '<?php if ($foo){}(new Foo)->foo();',
  137. [
  138. 8 => CT::T_BRACE_CLASS_INSTANTIATION_OPEN,
  139. 12 => CT::T_BRACE_CLASS_INSTANTIATION_CLOSE,
  140. ],
  141. [
  142. CT::T_BRACE_CLASS_INSTANTIATION_OPEN,
  143. CT::T_BRACE_CLASS_INSTANTIATION_CLOSE,
  144. ],
  145. ];
  146. yield [
  147. '<?php echo (((new \stdClass()))->a);',
  148. [
  149. 5 => CT::T_BRACE_CLASS_INSTANTIATION_OPEN,
  150. 12 => CT::T_BRACE_CLASS_INSTANTIATION_CLOSE,
  151. ],
  152. [
  153. CT::T_BRACE_CLASS_INSTANTIATION_OPEN,
  154. CT::T_BRACE_CLASS_INSTANTIATION_CLOSE,
  155. ],
  156. ];
  157. yield [
  158. '<?php $foo = array(new Foo());',
  159. [
  160. 6 => '(',
  161. 10 => '(',
  162. 11 => ')',
  163. 12 => ')',
  164. ],
  165. [
  166. '(',
  167. ')',
  168. CT::T_BRACE_CLASS_INSTANTIATION_OPEN,
  169. CT::T_BRACE_CLASS_INSTANTIATION_CLOSE,
  170. ],
  171. ];
  172. yield [
  173. '<?php if (new Foo()) { } elseif (new Bar()) { } else if (new Baz()) { }',
  174. [
  175. 3 => '(',
  176. 7 => '(',
  177. 8 => ')',
  178. 9 => ')',
  179. 17 => '(',
  180. 21 => '(',
  181. 22 => ')',
  182. 23 => ')',
  183. 33 => '(',
  184. 37 => '(',
  185. 38 => ')',
  186. 39 => ')',
  187. ],
  188. [
  189. '(',
  190. ')',
  191. CT::T_BRACE_CLASS_INSTANTIATION_OPEN,
  192. CT::T_BRACE_CLASS_INSTANTIATION_CLOSE,
  193. ],
  194. ];
  195. yield [
  196. '<?php switch (new Foo()) { }',
  197. [
  198. 3 => '(',
  199. 7 => '(',
  200. 8 => ')',
  201. 9 => ')',
  202. ],
  203. [
  204. '(',
  205. ')',
  206. CT::T_BRACE_CLASS_INSTANTIATION_OPEN,
  207. CT::T_BRACE_CLASS_INSTANTIATION_CLOSE,
  208. ],
  209. ];
  210. yield [
  211. '<?php for (new Foo();;) { }',
  212. [
  213. 3 => '(',
  214. 7 => '(',
  215. 8 => ')',
  216. 11 => ')',
  217. ],
  218. [
  219. '(',
  220. ')',
  221. CT::T_BRACE_CLASS_INSTANTIATION_OPEN,
  222. CT::T_BRACE_CLASS_INSTANTIATION_CLOSE,
  223. ],
  224. ];
  225. yield [
  226. '<?php foreach (new Foo() as $foo) { }',
  227. [
  228. 3 => '(',
  229. 7 => '(',
  230. 8 => ')',
  231. 13 => ')',
  232. ],
  233. [
  234. '(',
  235. ')',
  236. CT::T_BRACE_CLASS_INSTANTIATION_OPEN,
  237. CT::T_BRACE_CLASS_INSTANTIATION_CLOSE,
  238. ],
  239. ];
  240. yield [
  241. '<?php while (new Foo()) { }',
  242. [
  243. 3 => '(',
  244. 7 => '(',
  245. 8 => ')',
  246. 9 => ')',
  247. ],
  248. [
  249. '(',
  250. ')',
  251. CT::T_BRACE_CLASS_INSTANTIATION_OPEN,
  252. CT::T_BRACE_CLASS_INSTANTIATION_CLOSE,
  253. ],
  254. ];
  255. yield [
  256. '<?php do { } while (new Foo());',
  257. [
  258. 9 => '(',
  259. 13 => '(',
  260. 14 => ')',
  261. 15 => ')',
  262. ],
  263. [
  264. '(',
  265. ')',
  266. CT::T_BRACE_CLASS_INSTANTIATION_OPEN,
  267. CT::T_BRACE_CLASS_INSTANTIATION_CLOSE,
  268. ],
  269. ];
  270. yield [
  271. '<?php $static = new static(new \SplFileInfo(__FILE__));',
  272. [
  273. 8 => '(',
  274. 13 => '(',
  275. 15 => ')',
  276. 16 => ')',
  277. ],
  278. [
  279. '(',
  280. ')',
  281. '(',
  282. ')',
  283. ],
  284. ];
  285. yield [
  286. '<?php $foo = new class(new \stdClass()) {};',
  287. [
  288. 8 => '(',
  289. 13 => '(',
  290. 14 => ')',
  291. 15 => ')',
  292. ],
  293. [
  294. '(',
  295. ')',
  296. ],
  297. ];
  298. yield [
  299. '<?php $foo = (new class(new \stdClass()) {});',
  300. [
  301. 5 => CT::T_BRACE_CLASS_INSTANTIATION_OPEN,
  302. 20 => CT::T_BRACE_CLASS_INSTANTIATION_CLOSE,
  303. ],
  304. [
  305. CT::T_BRACE_CLASS_INSTANTIATION_OPEN,
  306. CT::T_BRACE_CLASS_INSTANTIATION_CLOSE,
  307. ],
  308. ];
  309. yield [
  310. '<?php $fn = fn() => null;',
  311. [
  312. 6 => '(',
  313. 7 => ')',
  314. ],
  315. [
  316. '(',
  317. ')',
  318. CT::T_BRACE_CLASS_INSTANTIATION_OPEN,
  319. CT::T_BRACE_CLASS_INSTANTIATION_CLOSE,
  320. ],
  321. ];
  322. yield [
  323. '<?php $result = ($function)(new Argument());',
  324. [
  325. 5 => '(',
  326. 7 => ')',
  327. 8 => '(',
  328. 12 => '(',
  329. 13 => ')',
  330. 14 => ')',
  331. ],
  332. [
  333. '(',
  334. ')',
  335. CT::T_BRACE_CLASS_INSTANTIATION_OPEN,
  336. CT::T_BRACE_CLASS_INSTANTIATION_CLOSE,
  337. ],
  338. ];
  339. yield [
  340. '<?php $result = (new Invokable())(new Argument1());',
  341. [
  342. 5 => CT::T_BRACE_CLASS_INSTANTIATION_OPEN,
  343. 9 => '(',
  344. 10 => ')',
  345. 11 => CT::T_BRACE_CLASS_INSTANTIATION_CLOSE,
  346. 12 => '(',
  347. 16 => '(',
  348. 17 => ')',
  349. 18 => ')',
  350. ],
  351. [
  352. '(',
  353. ')',
  354. CT::T_BRACE_CLASS_INSTANTIATION_OPEN,
  355. CT::T_BRACE_CLASS_INSTANTIATION_CLOSE,
  356. ],
  357. ];
  358. }
  359. /**
  360. * @param _TransformerTestExpectedTokens $expectedTokens
  361. * @param _TransformerTestObservedKindsOrPrototypes $observedKinds
  362. *
  363. * @dataProvider provideProcessPhp80Cases
  364. *
  365. * @requires PHP 8.0
  366. */
  367. public function testProcessPhp80(array $expectedTokens, array $observedKinds, string $source): void
  368. {
  369. $this->doTest(
  370. $source,
  371. $expectedTokens,
  372. $observedKinds
  373. );
  374. }
  375. public static function provideProcessPhp80Cases(): iterable
  376. {
  377. yield [
  378. [
  379. 5 => CT::T_BRACE_CLASS_INSTANTIATION_OPEN,
  380. 8 => '(',
  381. 10 => '(',
  382. 11 => ')',
  383. 12 => ')',
  384. 13 => CT::T_BRACE_CLASS_INSTANTIATION_CLOSE,
  385. ],
  386. [
  387. '(',
  388. ')',
  389. CT::T_BRACE_CLASS_INSTANTIATION_OPEN,
  390. CT::T_BRACE_CLASS_INSTANTIATION_CLOSE,
  391. ],
  392. '<?php $a = (new (foo()));',
  393. ];
  394. yield [
  395. [
  396. 5 => CT::T_BRACE_CLASS_INSTANTIATION_OPEN,
  397. 15 => CT::T_BRACE_CLASS_INSTANTIATION_CLOSE,
  398. ],
  399. [
  400. CT::T_BRACE_CLASS_INSTANTIATION_OPEN,
  401. CT::T_BRACE_CLASS_INSTANTIATION_CLOSE,
  402. ],
  403. '<?php $a = (new #[Foo]
  404. class{}) ?>',
  405. ];
  406. }
  407. /**
  408. * @param _TransformerTestExpectedTokens $expectedTokens
  409. * @param _TransformerTestObservedKindsOrPrototypes $observedKinds
  410. *
  411. * @dataProvider provideProcessPhp81Cases
  412. *
  413. * @requires PHP 8.1
  414. */
  415. public function testProcessPhp81(array $expectedTokens, array $observedKinds, string $source): void
  416. {
  417. $this->doTest(
  418. $source,
  419. $expectedTokens,
  420. $observedKinds
  421. );
  422. }
  423. public static function provideProcessPhp81Cases(): iterable
  424. {
  425. yield [
  426. [
  427. 20 => CT::T_BRACE_CLASS_INSTANTIATION_OPEN,
  428. 24 => CT::T_BRACE_CLASS_INSTANTIATION_CLOSE,
  429. 43 => CT::T_BRACE_CLASS_INSTANTIATION_OPEN,
  430. 47 => CT::T_BRACE_CLASS_INSTANTIATION_CLOSE,
  431. 54 => CT::T_BRACE_CLASS_INSTANTIATION_OPEN,
  432. 64 => CT::T_BRACE_CLASS_INSTANTIATION_CLOSE,
  433. 107 => CT::T_BRACE_CLASS_INSTANTIATION_OPEN,
  434. 111 => CT::T_BRACE_CLASS_INSTANTIATION_CLOSE,
  435. ],
  436. [
  437. CT::T_BRACE_CLASS_INSTANTIATION_OPEN,
  438. CT::T_BRACE_CLASS_INSTANTIATION_CLOSE,
  439. ],
  440. '<?php
  441. class Test {
  442. public function __construct(
  443. public $prop = (new Foo),
  444. ) {}
  445. }
  446. function test(
  447. $foo = (new A),
  448. $baz = (new C(x: 2)),
  449. ) {
  450. }
  451. static $x = new (Foo);
  452. const C = new (Foo);
  453. function test2($param = (new Foo)) {}
  454. ',
  455. ];
  456. }
  457. /**
  458. * @param _TransformerTestExpectedTokens $expectedTokens
  459. * @param _TransformerTestObservedKindsOrPrototypes $observedKinds
  460. *
  461. * @dataProvider provideProcessPrePhp84Cases
  462. *
  463. * @requires PHP <8.4
  464. */
  465. public function testProcessPrePhp84(string $source, array $expectedTokens, array $observedKinds = []): void
  466. {
  467. $this->doTest(
  468. $source,
  469. $expectedTokens,
  470. $observedKinds
  471. );
  472. }
  473. /**
  474. * @return iterable<array{string, _TransformerTestExpectedTokens, _TransformerTestObservedKindsOrPrototypes}>
  475. */
  476. public static function provideProcessPrePhp84Cases(): iterable
  477. {
  478. yield [
  479. '<?php $foo{0}(new Foo())->bar();',
  480. [
  481. 5 => '(',
  482. 9 => '(',
  483. 10 => ')',
  484. 11 => ')',
  485. 14 => '(',
  486. 15 => ')',
  487. ],
  488. [
  489. '(',
  490. ')',
  491. CT::T_BRACE_CLASS_INSTANTIATION_OPEN,
  492. CT::T_BRACE_CLASS_INSTANTIATION_CLOSE,
  493. ],
  494. ];
  495. }
  496. }