NoUselessElseFixerTest.php 27 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066
  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\Fixer\ControlStructure;
  13. use PhpCsFixer\Tests\Test\AbstractFixerTestCase;
  14. use PhpCsFixer\Tokenizer\Tokens;
  15. /**
  16. * @internal
  17. *
  18. * @covers \PhpCsFixer\AbstractNoUselessElseFixer
  19. * @covers \PhpCsFixer\Fixer\ControlStructure\NoUselessElseFixer
  20. */
  21. final class NoUselessElseFixerTest extends AbstractFixerTestCase
  22. {
  23. /**
  24. * @dataProvider provideCloseTagCases
  25. */
  26. public function testCloseTag(string $expected, ?string $input = null): void
  27. {
  28. $this->doTest($expected, $input);
  29. }
  30. public static function provideCloseTagCases(): iterable
  31. {
  32. yield [
  33. '<?php
  34. if (true) {
  35. $b = $a > 2 ? "" : die
  36. ?>
  37. <?php
  38. } else {
  39. echo 798;
  40. }',
  41. ];
  42. yield [
  43. '<?php
  44. if (true) {
  45. $b = $a > 2 ? "" : die
  46. ?>
  47. <?php ; // useless semicolon case
  48. } else {
  49. echo 798;
  50. }',
  51. ];
  52. yield [
  53. '<?php
  54. if (true) {
  55. if($a) die
  56. ?>
  57. <?php ; // useless semicolon case
  58. } else {
  59. echo 798;
  60. }',
  61. ];
  62. yield [
  63. '<?php
  64. if (true) {
  65. echo 1;
  66. ?>
  67. <?php ; // useless semicolon case
  68. } else {
  69. echo 798;
  70. }',
  71. ];
  72. yield [
  73. '<?php
  74. if (true) {
  75. echo 777;
  76. if(false) die ?>
  77. <?php
  78. } else {
  79. echo 778;
  80. }',
  81. ];
  82. yield [
  83. '<?php
  84. if (true)
  85. echo 3;
  86. else {
  87. ?><?php
  88. echo 4;
  89. }
  90. ',
  91. ];
  92. yield [
  93. '<?php
  94. if (true)
  95. echo 3;
  96. '.'
  97. ?><?php
  98. echo 4;
  99. ',
  100. '<?php
  101. if (true)
  102. echo 3;
  103. else
  104. ?><?php
  105. echo 4;
  106. ',
  107. ];
  108. yield [
  109. '<?php
  110. if (true)
  111. echo 4;
  112. ?><?php echo 5;',
  113. '<?php
  114. if (true)
  115. echo 4;
  116. else?><?php echo 5;',
  117. ];
  118. }
  119. /**
  120. * @dataProvider provideFixIfElseIfElseCases
  121. */
  122. public function testFixIfElseIfElse(string $expected, ?string $input = null): void
  123. {
  124. $this->doTest($expected, $input);
  125. }
  126. public static function provideFixIfElseIfElseCases(): iterable
  127. {
  128. $expected =
  129. '<?php
  130. while(true) {
  131. while(true) {
  132. if ($provideFixIfElseIfElseCases) {
  133. return;
  134. } elseif($a1) {
  135. if ($b) {echo 1; die;} echo 552;
  136. return 1;
  137. } elseif($b) {
  138. %s
  139. } '.'
  140. echo 662;
  141. '.'
  142. }
  143. }
  144. ';
  145. $input =
  146. '<?php
  147. while(true) {
  148. while(true) {
  149. if ($provideFixIfElseIfElseCases) {
  150. return;
  151. } elseif($a1) {
  152. if ($b) {echo 1; die;} else {echo 552;}
  153. return 1;
  154. } elseif($b) {
  155. %s
  156. } else {
  157. echo 662;
  158. }
  159. }
  160. }
  161. ';
  162. yield from self::generateCases($expected, $input);
  163. $expected =
  164. '<?php
  165. while(true) {
  166. while(true) {
  167. if($a) {
  168. echo 100;
  169. } elseif($b) {
  170. %s
  171. } else {
  172. echo 3;
  173. }
  174. }
  175. }
  176. ';
  177. yield from self::generateCases($expected);
  178. $expected =
  179. '<?php
  180. while(true) {
  181. while(true) {
  182. if ($a) {
  183. echo 100;
  184. } elseif ($a1) {
  185. echo 99887;
  186. } elseif ($b) {
  187. echo $b+1; //
  188. /* test */
  189. %s
  190. } else {
  191. echo 321;
  192. }
  193. }
  194. }
  195. ';
  196. yield from self::generateCases($expected);
  197. yield [
  198. '<?php
  199. if ($a)
  200. echo 1789;
  201. else if($b)
  202. echo 256;
  203. elseif($c)
  204. echo 3;
  205. if ($a) {
  206. }elseif($d) {
  207. return 1;
  208. }
  209. else
  210. echo 4;
  211. ',
  212. ];
  213. yield [
  214. '<?php
  215. if ($a)
  216. echo 1789;
  217. else if($b) {
  218. echo 256;
  219. } elseif($c) {
  220. echo 3;
  221. if ($d) {
  222. echo 4;
  223. } elseif($e)
  224. return 1;
  225. } else
  226. echo 4;
  227. ',
  228. ];
  229. }
  230. /**
  231. * @dataProvider provideFixIfElseCases
  232. */
  233. public function testFixIfElse(string $expected, ?string $input = null): void
  234. {
  235. $this->doTest($expected, $input);
  236. }
  237. public static function provideFixIfElseCases(): iterable
  238. {
  239. $expected = '<?php
  240. while(true) {
  241. while(true) {
  242. if ($a) {
  243. %s
  244. } '.'
  245. echo 1;
  246. '.'
  247. }
  248. }
  249. ';
  250. $input = '<?php
  251. while(true) {
  252. while(true) {
  253. if ($a) {
  254. %s
  255. } else {
  256. echo 1;
  257. }
  258. }
  259. }
  260. ';
  261. yield from self::generateCases($expected, $input);
  262. yield [
  263. '<?php
  264. if ($a) {
  265. GOTO jump;
  266. } '.'
  267. echo 1789;
  268. '.'
  269. jump:
  270. ',
  271. '<?php
  272. if ($a) {
  273. GOTO jump;
  274. } else {
  275. echo 1789;
  276. }
  277. jump:
  278. ',
  279. ];
  280. }
  281. /**
  282. * @dataProvider provideFixNestedIfCases
  283. */
  284. public function testFixNestedIf(string $expected, ?string $input = null): void
  285. {
  286. $this->doTest($expected, $input);
  287. }
  288. public static function provideFixNestedIfCases(): iterable
  289. {
  290. yield [
  291. '<?php
  292. if ($x) {
  293. if ($y) {
  294. return 1;
  295. } '.'
  296. return 2;
  297. '.'
  298. } '.'
  299. return 3;
  300. '.'
  301. ',
  302. '<?php
  303. if ($x) {
  304. if ($y) {
  305. return 1;
  306. } else {
  307. return 2;
  308. }
  309. } else {
  310. return 3;
  311. }
  312. ',
  313. ];
  314. }
  315. /**
  316. * @dataProvider provideFixEmptyElseCases
  317. */
  318. public function testFixEmptyElse(string $expected, ?string $input = null): void
  319. {
  320. $this->doTest($expected, $input);
  321. }
  322. public static function provideFixEmptyElseCases(): iterable
  323. {
  324. yield [
  325. '<?php
  326. if (false)
  327. echo 1;
  328. '.'
  329. ',
  330. '<?php
  331. if (false)
  332. echo 1;
  333. else{}
  334. ',
  335. ];
  336. yield [
  337. '<?php if($a){}',
  338. '<?php if($a){}else{}',
  339. ];
  340. yield [
  341. '<?php if($a){ $a = ($b); } ',
  342. '<?php if($a){ $a = ($b); } else {}',
  343. ];
  344. yield [
  345. '<?php if ($a) {;} if ($a) {;} /**/ if($a){}',
  346. '<?php if ($a) {;} else {} if ($a) {;} else {/**/} if($a){}else{}',
  347. ];
  348. yield [
  349. '<?php
  350. if /**/($a) /**/{ //
  351. /**/
  352. /**/return/**/1/**/;
  353. //
  354. }/**/ /**/
  355. /**/
  356. //
  357. /**/
  358. ',
  359. '<?php
  360. if /**/($a) /**/{ //
  361. /**/
  362. /**/return/**/1/**/;
  363. //
  364. }/**/ else /**/{
  365. /**/
  366. //
  367. }/**/
  368. ',
  369. ];
  370. yield [
  371. '<?php
  372. if ($a) {
  373. if ($b) {
  374. if ($c) {
  375. } elseif ($d) {
  376. return;
  377. } //
  378. //
  379. return;
  380. } //
  381. //
  382. return;
  383. } //
  384. //
  385. ',
  386. '<?php
  387. if ($a) {
  388. if ($b) {
  389. if ($c) {
  390. } elseif ($d) {
  391. return;
  392. } else {//
  393. }//
  394. return;
  395. } else {//
  396. }//
  397. return;
  398. } else {//
  399. }//
  400. ',
  401. ];
  402. }
  403. /**
  404. * @dataProvider provideNegativeCases
  405. */
  406. public function testNegative(string $expected): void
  407. {
  408. $this->doTest($expected);
  409. }
  410. public static function provideNegativeCases(): iterable
  411. {
  412. yield [
  413. '<?php
  414. if ($a0) {
  415. //
  416. } else {
  417. echo 0;
  418. }
  419. ',
  420. ];
  421. yield [
  422. '<?php
  423. if (false)
  424. echo "a";
  425. else
  426. echo "a";
  427. ',
  428. ];
  429. yield [
  430. '<?php if($a2){;} else {echo 27;}',
  431. ];
  432. yield [
  433. '<?php if ($a3) {test();} else {echo 3;}',
  434. ];
  435. yield [
  436. '<?php if ($a4) {$b = function () {};} else {echo 4;}',
  437. ];
  438. yield [
  439. '<?php if ($a5) {$b = function () use ($a){};} else {echo 5;}',
  440. ];
  441. yield [
  442. '<?php
  443. if ($a) {
  444. if ($b) return;
  445. } else {
  446. echo 1;
  447. }
  448. ',
  449. ];
  450. yield [
  451. '<?php
  452. if ($a) {
  453. if ($b) throw new \Exception();
  454. } else {
  455. echo 1;
  456. }
  457. ',
  458. ];
  459. yield [
  460. '<?php
  461. if ($a) {
  462. if ($b) { throw new \Exception(); }
  463. } else {
  464. echo 1;
  465. }
  466. ',
  467. ];
  468. yield [
  469. '<?php
  470. $a = true; // 6
  471. if (true === $a)
  472. $b = true === $a ? 1 : die;
  473. else
  474. echo 40;
  475. echo "end";
  476. ',
  477. ];
  478. yield [
  479. '<?php
  480. $a = true; // 6
  481. if (true === $a)
  482. $b = true === $a ? 1 : exit(1);
  483. else
  484. echo 40;
  485. echo "end";
  486. ',
  487. ];
  488. yield [
  489. '<?php
  490. $a = true; // 6
  491. if (true === $a)
  492. $b = true === $a ? 1 : exit(1);
  493. else
  494. echo 4;
  495. echo "end";
  496. ',
  497. ];
  498. yield [
  499. '<?php
  500. if (false)
  501. die;
  502. elseif (true)
  503. if(true)echo 777;else die;
  504. else if (true)
  505. die;
  506. elseif (false)
  507. die;
  508. else
  509. echo 7;
  510. ',
  511. ];
  512. yield [
  513. '<?php
  514. $tmp = function($b){$b();};
  515. $a =1;
  516. return $tmp(function () use ($a) {
  517. if ($a) {
  518. $a++;
  519. } else {
  520. $a--;
  521. }
  522. });
  523. ',
  524. ];
  525. yield [
  526. '<?php
  527. $tmp = function($b){$b();};
  528. $a =1;
  529. return $tmp(function () use ($a) {
  530. if ($a) {
  531. $a++;
  532. } elseif($a > 2) {
  533. return 1;
  534. } else {
  535. $a--;
  536. }
  537. });
  538. ',
  539. ];
  540. yield [
  541. '<?php
  542. return function() {
  543. if (false) {
  544. } elseif (3 > 2) {
  545. } else {
  546. echo 1;
  547. }
  548. };',
  549. ];
  550. yield [
  551. '<?php
  552. return function() {
  553. if (false) {
  554. return 1;
  555. } elseif (3 > 2) {
  556. } else {
  557. echo 1;
  558. }
  559. };',
  560. ];
  561. }
  562. /**
  563. * @dataProvider provideNegativePhp80Cases
  564. *
  565. * @requires PHP 8.0
  566. */
  567. public function testNegativePhp80(string $expected): void
  568. {
  569. $this->doTest($expected);
  570. }
  571. public static function provideNegativePhp80Cases(): iterable
  572. {
  573. $cases = [
  574. '$bar = $foo1 ?? throw new \Exception($e);',
  575. '$callable = fn() => throw new Exception();',
  576. '$value = $falsableValue ?: throw new InvalidArgumentException();',
  577. '$value = !empty($array)
  578. ? reset($array)
  579. : throw new InvalidArgumentException();',
  580. '$a = $condition && throw new Exception();',
  581. '$a = $condition || throw new Exception();',
  582. '$a = $condition and throw new Exception();',
  583. '$a = $condition or throw new Exception();',
  584. ];
  585. $template = '<?php
  586. if ($foo) {
  587. %s
  588. } else {
  589. echo 123;
  590. }
  591. ';
  592. foreach ($cases as $index => $case) {
  593. yield [sprintf('PHP8 Negative case %d', $index) => sprintf($template, $case)];
  594. }
  595. }
  596. /**
  597. * @param list<int> $expected
  598. *
  599. * @dataProvider provideBlockDetectionCases
  600. */
  601. public function testBlockDetection(array $expected, string $source, int $index): void
  602. {
  603. Tokens::clearCache();
  604. $tokens = Tokens::fromCode($source);
  605. $method = new \ReflectionMethod(get_parent_class($this->fixer), 'getPreviousBlock');
  606. $method->setAccessible(true);
  607. $result = $method->invoke($this->fixer, $tokens, $index);
  608. self::assertSame($expected, $result);
  609. }
  610. public static function provideBlockDetectionCases(): iterable
  611. {
  612. $source = '<?php
  613. if ($a)
  614. echo 1;
  615. elseif ($a) ///
  616. echo 2;
  617. else if ($b) /**/ echo 3;
  618. else
  619. echo 4;
  620. ';
  621. yield [[2, 11], $source, 13];
  622. yield [[13, 24], $source, 26];
  623. yield [[13, 24], $source, 26];
  624. yield [[26, 39], $source, 41];
  625. $source = '<?php
  626. if ($a) {
  627. if ($b) {
  628. }
  629. echo 1;
  630. } elseif (true) {
  631. echo 2;
  632. } else if (false) {
  633. echo 3;
  634. } elseif ($c) {
  635. echo 4;
  636. } else
  637. echo 1;
  638. ';
  639. yield [[2, 25], $source, 27];
  640. yield [[27, 40], $source, 42];
  641. yield [[59, 72], $source, 74];
  642. }
  643. /**
  644. * @dataProvider provideConditionsWithoutBracesCases
  645. */
  646. public function testConditionsWithoutBraces(string $expected, ?string $input = null): void
  647. {
  648. $this->doTest($expected, $input);
  649. }
  650. public static function provideConditionsWithoutBracesCases(): iterable
  651. {
  652. $statements = [
  653. 'die;',
  654. 'throw new Exception($i);',
  655. 'while($i < 1) throw/*{}*/new Exception($i);',
  656. 'while($i < 1){throw new Exception($i);}',
  657. 'do{throw new Exception($i);}while($i < 1);',
  658. 'foreach($a as $b)throw new Exception($i);',
  659. 'foreach($a as $b){throw new Exception($i);}',
  660. ];
  661. foreach ($statements as $statement) {
  662. yield from self::generateConditionsWithoutBracesCase($statement);
  663. }
  664. yield [
  665. '<?php
  666. if ($a === false)
  667. {
  668. if ($v) { $ret = "foo"; if($d){return 1;}echo $a;}
  669. }
  670. else
  671. $ret .= $value;
  672. return $ret;',
  673. '<?php
  674. if ($a === false)
  675. {
  676. if ($v) { $ret = "foo"; if($d){return 1;}else{echo $a;}}
  677. }
  678. else
  679. $ret .= $value;
  680. return $ret;',
  681. ];
  682. yield from self::generateConditionsWithoutBracesCase('throw new class extends Exception{};');
  683. yield from self::generateConditionsWithoutBracesCase('throw new class ($a, 9) extends Exception{ public function z($a, $b){ echo 7;} };');
  684. }
  685. /**
  686. * @dataProvider provideConditionsWithoutBraces80Cases
  687. *
  688. * @requires PHP 8.0
  689. */
  690. public function testConditionsWithoutBraces80(string $expected): void
  691. {
  692. $this->doTest($expected);
  693. }
  694. public static function provideConditionsWithoutBraces80Cases(): iterable
  695. {
  696. yield from self::generateConditionsWithoutBracesCase('$b = $a ?? throw new Exception($i);');
  697. }
  698. /**
  699. * @param array<int, bool> $indexes
  700. *
  701. * @dataProvider provideIsInConditionWithoutBracesCases
  702. */
  703. public function testIsInConditionWithoutBraces(array $indexes, string $input): void
  704. {
  705. $reflection = new \ReflectionObject($this->fixer);
  706. $method = $reflection->getMethod('isInConditionWithoutBraces');
  707. $method->setAccessible(true);
  708. $tokens = Tokens::fromCode($input);
  709. foreach ($indexes as $index => $expected) {
  710. self::assertSame(
  711. $expected,
  712. $method->invoke($this->fixer, $tokens, $index, 0),
  713. sprintf('Failed in condition without braces check for index %d', $index)
  714. );
  715. }
  716. }
  717. public static function provideIsInConditionWithoutBracesCases(): iterable
  718. {
  719. yield [
  720. [
  721. 18 => false, // return
  722. 25 => false, // return
  723. 36 => false, // return
  724. ],
  725. '<?php
  726. if ($x) {
  727. if ($y) {
  728. return 1;
  729. }
  730. return 2;
  731. } else {
  732. return 3;
  733. }
  734. ',
  735. ];
  736. yield [
  737. [
  738. 0 => false,
  739. 29 => false, // throw
  740. ],
  741. '<?php
  742. if ($v) { $ret = "foo"; }
  743. else
  744. if($a){}else{throw new Exception($i);}
  745. ',
  746. ];
  747. yield [
  748. [
  749. 0 => false,
  750. 38 => true, // throw
  751. ],
  752. '<?php
  753. if ($v) { $ret = "foo"; }
  754. else
  755. for($i =0;$i < 1;++$i) throw new Exception($i);
  756. ',
  757. ];
  758. yield [
  759. [
  760. 0 => false,
  761. 26 => true, // throw
  762. 28 => true, // new
  763. 30 => true, // Exception
  764. ],
  765. '<?php
  766. if ($v) { $ret = "foo"; }
  767. else
  768. while(false){throw new Exception($i);}
  769. ',
  770. ];
  771. yield [
  772. [
  773. 0 => false,
  774. 30 => true, // throw
  775. 32 => true, // new
  776. 34 => true, // Exception
  777. ],
  778. '<?php
  779. if ($v) { $ret = "foo"; }
  780. else
  781. foreach($a as $b){throw new Exception($i);}
  782. ',
  783. ];
  784. yield [
  785. [
  786. 0 => false,
  787. 25 => true, // throw
  788. 27 => true, // new
  789. 29 => true, // Exception
  790. ],
  791. '<?php
  792. if ($v) { $ret = "foo"; }
  793. else
  794. while(false)throw new Exception($i);
  795. ',
  796. ];
  797. yield [
  798. [
  799. 26 => true, // throw
  800. ],
  801. '<?php
  802. if ($v) { $ret = "foo"; }
  803. elseif($a)
  804. do{throw new Exception($i);}while(false);
  805. ',
  806. ];
  807. yield [
  808. [
  809. 4 => false, // 1
  810. 13 => true, // if (2nd)
  811. 21 => true, // true
  812. 33 => true, // while
  813. 43 => false, // echo
  814. 45 => false, // 2
  815. 46 => false, // ;
  816. 51 => false, // echo (123)
  817. ],
  818. '<?php
  819. echo 1;
  820. if ($a) if ($a) while(true)echo 1;
  821. elseif($c) while(true){if($d){echo 2;}};
  822. echo 123;
  823. ',
  824. ];
  825. yield [
  826. [
  827. 2 => false, // echo
  828. 13 => true, // echo
  829. 15 => true, // 2
  830. 20 => true, // die
  831. 23 => false, // echo
  832. ],
  833. '<?php
  834. echo 1;
  835. if ($a) echo 2;
  836. else die; echo 3;
  837. ',
  838. ];
  839. yield [
  840. [
  841. 8 => true, // die
  842. 9 => true, // /**/
  843. 15 => true, // die
  844. ],
  845. '<?php
  846. if ($a)
  847. die/**/;
  848. else
  849. /**/die/**/;#
  850. ',
  851. ];
  852. yield [
  853. [
  854. 8 => true, // die
  855. 9 => true, // /**/
  856. 15 => true, // die
  857. ],
  858. '<?php
  859. if ($a)
  860. die/**/;
  861. else
  862. /**/die/**/?>
  863. ',
  864. ];
  865. }
  866. /**
  867. * @return iterable<array{0: non-empty-string, 1?: non-empty-string}>
  868. */
  869. private static function generateConditionsWithoutBracesCase(string $statement): iterable
  870. {
  871. $ifTemplate = '<?php
  872. if ($a === false)
  873. {
  874. if ($v) %s
  875. }
  876. else
  877. $ret .= $value;
  878. return $ret;';
  879. $ifElseIfTemplate = '<?php
  880. if ($a === false)
  881. {
  882. if ($v) { $ret = "foo"; }
  883. elseif($a)
  884. %s
  885. }
  886. else
  887. $ret .= $value;
  888. return $ret;';
  889. $ifElseTemplate = '<?php
  890. if ($a === false)
  891. {
  892. if ($v) { $ret = "foo"; }
  893. else
  894. %s
  895. }
  896. else
  897. $ret .= $value;
  898. return $ret;';
  899. yield [sprintf($ifTemplate, $statement)];
  900. yield [sprintf($ifElseTemplate, $statement)];
  901. yield [sprintf($ifElseIfTemplate, $statement)];
  902. }
  903. /**
  904. * @return array<array<string>>
  905. */
  906. private static function generateCases(string $expected, ?string $input = null): array
  907. {
  908. $cases = [];
  909. foreach ([
  910. 'exit;',
  911. 'exit();',
  912. 'exit(1);',
  913. 'die;',
  914. 'die();',
  915. 'die(1);',
  916. 'break;',
  917. 'break 2;',
  918. 'break (2);',
  919. 'continue;',
  920. 'continue 2;',
  921. 'continue (2);',
  922. 'return;',
  923. 'return 1;',
  924. 'return (1);',
  925. 'return "a";',
  926. 'return 8+2;',
  927. 'return null;',
  928. 'return sum(1+8*6, 2);',
  929. 'throw $e;',
  930. 'throw ($e);',
  931. 'throw new \Exception;',
  932. 'throw new \Exception();',
  933. 'throw new \Exception((string)12+1);',
  934. ] as $case) {
  935. if (null === $input) {
  936. $cases[] = [sprintf($expected, $case)];
  937. $cases[] = [sprintf($expected, strtoupper($case))];
  938. $cases[] = [sprintf($expected, strtolower($case))];
  939. } else {
  940. $cases[] = [sprintf($expected, $case), sprintf($input, $case)];
  941. $cases[] = [sprintf($expected, strtoupper($case)), sprintf($input, strtoupper($case))];
  942. $cases[] = [sprintf($expected, strtolower($case)), sprintf($input, strtolower($case))];
  943. }
  944. }
  945. return $cases;
  946. }
  947. }