ReturnAssignmentFixerTest.php 34 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454
  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\ReturnNotation;
  13. use PhpCsFixer\Tests\Test\AbstractFixerTestCase;
  14. /**
  15. * @internal
  16. *
  17. * @covers \PhpCsFixer\Fixer\ReturnNotation\ReturnAssignmentFixer
  18. *
  19. * @extends AbstractFixerTestCase<\PhpCsFixer\Fixer\ReturnNotation\ReturnAssignmentFixer>
  20. */
  21. final class ReturnAssignmentFixerTest extends AbstractFixerTestCase
  22. {
  23. /**
  24. * @dataProvider provideFixNestedFunctionsCases
  25. */
  26. public function testFixNestedFunctions(string $expected, string $input): void
  27. {
  28. $this->doTest($expected, $input);
  29. }
  30. /**
  31. * @return iterable<array{0: non-empty-string, 1?: non-empty-string}>
  32. */
  33. public static function provideFixNestedFunctionsCases(): iterable
  34. {
  35. yield [
  36. '<?php
  37. function A($a0,$a1,$a2,$d)
  38. {
  39. if ($a0) {
  40. return 1;
  41. // fix me
  42. }
  43. if ($a1) {
  44. return 2;
  45. // fix me
  46. }
  47. $nested0 = function() {
  48. global $a;
  49. ++$a;
  50. $d = 2;
  51. $nested1 = function () use ($d) {
  52. if ($d) {
  53. return 3;
  54. // fix me
  55. }
  56. $nested2 = function (&$d) {
  57. if ($d) {
  58. $f = 1;
  59. return $f; // fix me not
  60. }
  61. $d = function () {
  62. return 4;
  63. // fix me
  64. };
  65. if ($d+1) {
  66. $f = 1;
  67. return $f; // fix me not
  68. }
  69. };
  70. return $nested2();
  71. };
  72. return $a; // fix me not
  73. };
  74. if ($a2) {
  75. return 5;
  76. // fix me
  77. }
  78. }
  79. function B($b0, $b1, $b2)
  80. {
  81. if ($b0) {
  82. return 10;
  83. // fix me
  84. }
  85. if ($b1) {
  86. return 20;
  87. // fix me
  88. }
  89. if ($b2) {
  90. return 30;
  91. // fix me
  92. }
  93. }
  94. ',
  95. '<?php
  96. function A($a0,$a1,$a2,$d)
  97. {
  98. if ($a0) {
  99. $b = 1;
  100. return $b; // fix me
  101. }
  102. if ($a1) {
  103. $c = 2;
  104. return $c; // fix me
  105. }
  106. $nested0 = function() {
  107. global $a;
  108. ++$a;
  109. $d = 2;
  110. $nested1 = function () use ($d) {
  111. if ($d) {
  112. $f = 3;
  113. return $f; // fix me
  114. }
  115. $nested2 = function (&$d) {
  116. if ($d) {
  117. $f = 1;
  118. return $f; // fix me not
  119. }
  120. $d = function () {
  121. $a = 4;
  122. return $a; // fix me
  123. };
  124. if ($d+1) {
  125. $f = 1;
  126. return $f; // fix me not
  127. }
  128. };
  129. return $nested2();
  130. };
  131. return $a; // fix me not
  132. };
  133. if ($a2) {
  134. $d = 5;
  135. return $d; // fix me
  136. }
  137. }
  138. function B($b0, $b1, $b2)
  139. {
  140. if ($b0) {
  141. $b = 10;
  142. return $b; // fix me
  143. }
  144. if ($b1) {
  145. $c = 20;
  146. return $c; // fix me
  147. }
  148. if ($b2) {
  149. $d = 30;
  150. return $d; // fix me
  151. }
  152. }
  153. ',
  154. ];
  155. }
  156. /**
  157. * @dataProvider provideFixCases
  158. */
  159. public function testFix(string $expected, string $input): void
  160. {
  161. $this->doTest($expected, $input);
  162. }
  163. /**
  164. * @return iterable<array{0: non-empty-string, 1?: non-empty-string}>
  165. */
  166. public static function provideFixCases(): iterable
  167. {
  168. yield [
  169. '<?php
  170. function A()
  171. {
  172. return 15;
  173. }
  174. ',
  175. '<?php
  176. function A()
  177. {
  178. $a = 15;
  179. return $a;
  180. }
  181. ',
  182. ];
  183. yield [
  184. '<?php
  185. function A()
  186. {
  187. /*0*/return /*1*//*2*/15;/*3*//*4*/ /*5*/ /*6*//*7*//*8*/
  188. }
  189. ',
  190. '<?php
  191. function A()
  192. {
  193. /*0*/$a/*1*/=/*2*/15;/*3*//*4*/ /*5*/ return/*6*/$a/*7*/;/*8*/
  194. }
  195. ',
  196. ];
  197. yield 'comments with leading space' => [
  198. '<?php
  199. function A()
  200. { #1
  201. #2
  202. return #3
  203. #4
  204. #5
  205. #6
  206. 15 #7
  207. ; #8
  208. #9
  209. #10
  210. #11
  211. #12
  212. #13
  213. #14
  214. #15
  215. }
  216. ',
  217. '<?php
  218. function A()
  219. { #1
  220. #2
  221. $a #3
  222. #4
  223. = #5
  224. #6
  225. 15 #7
  226. ; #8
  227. #9
  228. return #10
  229. #11
  230. $a #12
  231. #13
  232. ; #14
  233. #15
  234. }
  235. ',
  236. ];
  237. yield [
  238. '<?php
  239. abstract class B
  240. {
  241. abstract protected function Z();public function A()
  242. {
  243. return 16;
  244. }
  245. }
  246. ',
  247. '<?php
  248. abstract class B
  249. {
  250. abstract protected function Z();public function A()
  251. {
  252. $a = 16; return $a;
  253. }
  254. }
  255. ',
  256. ];
  257. yield [
  258. '<?php
  259. function b() {
  260. if ($c) {
  261. return 0;
  262. }
  263. return testFunction(654+1);
  264. }
  265. ',
  266. '<?php
  267. function b() {
  268. if ($c) {
  269. $b = 0;
  270. return $b;
  271. }
  272. $a = testFunction(654+1);
  273. return $a;
  274. }
  275. ',
  276. ];
  277. yield 'minimal notation' => [
  278. '<?php $e=function(){return 1;};$f=function(){return 1;};$g=function(){return 1;};',
  279. '<?php $e=function(){$a=1;return$a;};$f=function(){$a=1;return$a;};$g=function(){$a=1;return$a;};',
  280. ];
  281. yield [
  282. '<?php
  283. function A()
  284. {#1
  285. #2 '.'
  286. return #3
  287. #4
  288. #5
  289. #6
  290. 15#7
  291. ;#8
  292. #9
  293. #10
  294. #11
  295. #12
  296. #13
  297. #14
  298. #15
  299. }
  300. ',
  301. '<?php
  302. function A()
  303. {#1
  304. #2 '.'
  305. $a#3
  306. #4
  307. =#5
  308. #6
  309. 15#7
  310. ;#8
  311. #9
  312. return#10
  313. #11
  314. $a#12
  315. #13
  316. ;#14
  317. #15
  318. }
  319. ',
  320. ];
  321. yield [
  322. '<?php
  323. function A($b)
  324. {
  325. // Comment
  326. return a("2", 4, $b);
  327. }
  328. ',
  329. '<?php
  330. function A($b)
  331. {
  332. // Comment
  333. $value = a("2", 4, $b);
  334. return $value;
  335. }
  336. ',
  337. ];
  338. yield [
  339. '<?php function a($b,$c) {if($c>1){echo 1;} return (1 + 2 + $b); }',
  340. '<?php function a($b,$c) {if($c>1){echo 1;} $a= (1 + 2 + $b);return $a; }',
  341. ];
  342. yield [
  343. '<?php function a($b,$c) {return (3 * 4 + $b); }',
  344. '<?php function a($b,$c) {$zz= (3 * 4 + $b);return $zz; }',
  345. ];
  346. yield [
  347. '<?php
  348. function a() {
  349. return 4563;
  350. ?> <?php
  351. }
  352. ',
  353. '<?php
  354. function a() {
  355. $a = 4563;
  356. return $a ?> <?php
  357. }
  358. ',
  359. ];
  360. yield [
  361. '<?php
  362. function a()
  363. {
  364. return $c + 1; /*
  365. var names are case-insensitive */ }
  366. ',
  367. '<?php
  368. function a()
  369. {
  370. $A = $c + 1; /*
  371. var names are case-insensitive */ return $a ;}
  372. ',
  373. ];
  374. yield [
  375. '<?php
  376. function A()
  377. {
  378. return $f[1]->a();
  379. }
  380. ',
  381. '<?php
  382. function A()
  383. {
  384. $a = $f[1]->a();
  385. return $a;
  386. }
  387. ',
  388. [
  389. '<?php
  390. function a($foos) {
  391. return array_map(function ($foo) {
  392. return (string) $foo;
  393. }, $foos);
  394. }',
  395. '<?php
  396. function a($foos) {
  397. $bars = array_map(function ($foo) {
  398. return (string) $foo;
  399. }, $foos);
  400. return $bars;
  401. }',
  402. ],
  403. [
  404. '<?php
  405. function a($foos) {
  406. return ($foos = [\'bar\']);
  407. }',
  408. '<?php
  409. function a($foos) {
  410. $bars = ($foos = [\'bar\']);
  411. return $bars;
  412. }',
  413. ],
  414. ];
  415. yield [
  416. '<?php
  417. function a($foos) {
  418. return (function ($foos) {
  419. return $foos;
  420. })($foos);
  421. }',
  422. '<?php
  423. function a($foos) {
  424. $bars = (function ($foos) {
  425. return $foos;
  426. })($foos);
  427. return $bars;
  428. }',
  429. ];
  430. yield 'anonymous classes' => [
  431. '<?php
  432. function A()
  433. {
  434. return new class {};
  435. }
  436. function B()
  437. {
  438. return new class() {};
  439. }
  440. function C()
  441. {
  442. return new class(1,2) { public function Z(Foo $d){} };
  443. }
  444. function D()
  445. {
  446. return new class extends Y {};
  447. }
  448. function E()
  449. {
  450. return new class extends Y implements A\O,P {};
  451. }
  452. ',
  453. '<?php
  454. function A()
  455. {
  456. $a = new class {};
  457. return $a;
  458. }
  459. function B()
  460. {
  461. $b = new class() {};
  462. return $b;
  463. }
  464. function C()
  465. {
  466. $c = new class(1,2) { public function Z(Foo $d){} };
  467. return $c;
  468. }
  469. function D()
  470. {
  471. $c = new class extends Y {};
  472. return $c;
  473. }
  474. function E()
  475. {
  476. $c = new class extends Y implements A\O,P {};
  477. return $c;
  478. }
  479. ',
  480. ];
  481. yield 'lambda' => [
  482. '<?php
  483. function A()
  484. {
  485. return function () {};
  486. }
  487. function B()
  488. {
  489. return function ($a, $b) use ($z) {};
  490. }
  491. function C()
  492. {
  493. return static function ($a, $b) use ($z) {};
  494. }
  495. function D()
  496. {
  497. return function &() use(&$b) {
  498. return $b; // do not fix
  499. };
  500. // fix
  501. }
  502. function E()
  503. {
  504. return function &() {
  505. $z = new A(); return $z; // do not fix
  506. };
  507. // fix
  508. }
  509. function A99()
  510. {
  511. $v = static function ($a, $b) use ($z) {};
  512. return 15;
  513. }
  514. ',
  515. '<?php
  516. function A()
  517. {
  518. $a = function () {};
  519. return $a;
  520. }
  521. function B()
  522. {
  523. $b = function ($a, $b) use ($z) {};
  524. return $b;
  525. }
  526. function C()
  527. {
  528. $c = static function ($a, $b) use ($z) {};
  529. return $c;
  530. }
  531. function D()
  532. {
  533. $a = function &() use(&$b) {
  534. return $b; // do not fix
  535. };
  536. return $a; // fix
  537. }
  538. function E()
  539. {
  540. $a = function &() {
  541. $z = new A(); return $z; // do not fix
  542. };
  543. return $a; // fix
  544. }
  545. function A99()
  546. {
  547. $v = static function ($a, $b) use ($z) {};
  548. $a = 15;
  549. return $a;
  550. }
  551. ',
  552. ];
  553. yield 'arrow functions' => [
  554. '<?php
  555. function Foo() {
  556. return fn($x) => $x + $y;
  557. }
  558. ',
  559. '<?php
  560. function Foo() {
  561. $fn1 = fn($x) => $x + $y;
  562. return $fn1;
  563. }
  564. ',
  565. ];
  566. yield 'try catch' => [
  567. '<?php
  568. function foo()
  569. {
  570. if (isSomeCondition()) {
  571. return getSomeResult();
  572. }
  573. try {
  574. $result = getResult();
  575. return $result;
  576. } catch (\Throwable $exception) {
  577. baz($result ?? null);
  578. }
  579. }
  580. ',
  581. '<?php
  582. function foo()
  583. {
  584. if (isSomeCondition()) {
  585. $result = getSomeResult();
  586. return $result;
  587. }
  588. try {
  589. $result = getResult();
  590. return $result;
  591. } catch (\Throwable $exception) {
  592. baz($result ?? null);
  593. }
  594. }
  595. ',
  596. ];
  597. yield 'multiple try/catch blocks separated with conditional return' => [
  598. '<?php
  599. function foo()
  600. {
  601. try {
  602. return getResult();
  603. } catch (\Throwable $exception) {
  604. error_log($exception->getMessage());
  605. }
  606. if (isSomeCondition()) {
  607. return getSomeResult();
  608. }
  609. try {
  610. $result = $a + $b;
  611. return $result;
  612. } catch (\Throwable $th) {
  613. var_dump($result ?? null);
  614. }
  615. }
  616. ',
  617. '<?php
  618. function foo()
  619. {
  620. try {
  621. $result = getResult();
  622. return $result;
  623. } catch (\Throwable $exception) {
  624. error_log($exception->getMessage());
  625. }
  626. if (isSomeCondition()) {
  627. $result = getSomeResult();
  628. return $result;
  629. }
  630. try {
  631. $result = $a + $b;
  632. return $result;
  633. } catch (\Throwable $th) {
  634. var_dump($result ?? null);
  635. }
  636. }
  637. ',
  638. ];
  639. yield 'try/catch/finally' => [
  640. '<?php
  641. function foo()
  642. {
  643. if (isSomeCondition()) {
  644. return getSomeResult();
  645. }
  646. try {
  647. $result = getResult();
  648. return $result;
  649. } catch (\Throwable $exception) {
  650. error_log($exception->getMessage());
  651. } finally {
  652. baz($result);
  653. }
  654. }
  655. ',
  656. '<?php
  657. function foo()
  658. {
  659. if (isSomeCondition()) {
  660. $result = getSomeResult();
  661. return $result;
  662. }
  663. try {
  664. $result = getResult();
  665. return $result;
  666. } catch (\Throwable $exception) {
  667. error_log($exception->getMessage());
  668. } finally {
  669. baz($result);
  670. }
  671. }
  672. ',
  673. ];
  674. yield 'multiple try/catch separated with conditional return, with finally block' => [
  675. '<?php
  676. function foo()
  677. {
  678. try {
  679. return getResult();
  680. } catch (\Throwable $exception) {
  681. error_log($exception->getMessage());
  682. }
  683. if (isSomeCondition()) {
  684. return getSomeResult();
  685. }
  686. try {
  687. $result = $a + $b;
  688. return $result;
  689. } catch (\Throwable $th) {
  690. throw $th;
  691. } finally {
  692. echo "result:", $result, \PHP_EOL;
  693. }
  694. }
  695. ',
  696. '<?php
  697. function foo()
  698. {
  699. try {
  700. $result = getResult();
  701. return $result;
  702. } catch (\Throwable $exception) {
  703. error_log($exception->getMessage());
  704. }
  705. if (isSomeCondition()) {
  706. $result = getSomeResult();
  707. return $result;
  708. }
  709. try {
  710. $result = $a + $b;
  711. return $result;
  712. } catch (\Throwable $th) {
  713. throw $th;
  714. } finally {
  715. echo "result:", $result, \PHP_EOL;
  716. }
  717. }
  718. ',
  719. ];
  720. }
  721. /**
  722. * @dataProvider provideDoNotFixCases
  723. */
  724. public function testDoNotFix(string $expected): void
  725. {
  726. $this->doTest($expected);
  727. }
  728. /**
  729. * @return iterable<array{0: non-empty-string, 1?: non-empty-string}>
  730. */
  731. public static function provideDoNotFixCases(): iterable
  732. {
  733. yield 'invalid reference stays invalid' => [
  734. '<?php
  735. function bar() {
  736. $foo = &foo();
  737. return $foo;
  738. }',
  739. ];
  740. yield 'static' => [
  741. '<?php
  742. function a() {
  743. static $a;
  744. $a = time();
  745. return $a;
  746. }
  747. ',
  748. ];
  749. yield 'global' => [
  750. '<?php
  751. function a() {
  752. global $a;
  753. $a = time();
  754. return $a;
  755. }
  756. ',
  757. ];
  758. yield 'passed by reference' => [
  759. '<?php
  760. function foo(&$var)
  761. {
  762. $var = 1;
  763. return $var;
  764. }
  765. ',
  766. ];
  767. yield 'not in function scope' => [
  768. '<?php
  769. $a = 1; // var might be global here
  770. return $a;
  771. ',
  772. ];
  773. yield 'open-close with ;' => [
  774. '<?php
  775. function a()
  776. {
  777. $a = 1;
  778. ?>
  779. <?php
  780. ;
  781. return $a;
  782. }
  783. ',
  784. ];
  785. yield 'open-close single line' => [
  786. '<?php
  787. function a()
  788. {
  789. $a = 1 ?><?php return $a;
  790. }',
  791. ];
  792. yield 'open-close' => [
  793. '<?php
  794. function a()
  795. {
  796. $a = 1
  797. ?>
  798. <?php
  799. return $a;
  800. }
  801. ',
  802. ];
  803. yield 'open-close before function' => [
  804. '<?php
  805. $zz = 1 ?><?php
  806. function a($zz)
  807. {
  808. ;
  809. return $zz;
  810. }
  811. ',
  812. ];
  813. yield 'return complex statement' => [
  814. '<?php
  815. function a($c)
  816. {
  817. $a = 1;
  818. return $a + $c;
  819. }
  820. ',
  821. ];
  822. yield 'array assign' => [
  823. '<?php
  824. function a($c)
  825. {
  826. $_SERVER["abc"] = 3;
  827. return $_SERVER;
  828. }
  829. ',
  830. ];
  831. yield 'if assign' => [
  832. '<?php
  833. function foo ($bar)
  834. {
  835. $a = 123;
  836. if ($bar)
  837. $a = 12345;
  838. return $a;
  839. }
  840. ',
  841. ];
  842. yield 'else assign' => [
  843. '<?php
  844. function foo ($bar)
  845. {
  846. $a = 123;
  847. if ($bar)
  848. ;
  849. else
  850. $a = 12345;
  851. return $a;
  852. }
  853. ',
  854. ];
  855. yield 'elseif assign' => [
  856. '<?php
  857. function foo ($bar)
  858. {
  859. $a = 123;
  860. if ($bar)
  861. ;
  862. elseif($b)
  863. $a = 12345;
  864. return $a;
  865. }
  866. ',
  867. ];
  868. yield 'echo $a = N / comment $a = N;' => [
  869. '<?php
  870. function a($c)
  871. {
  872. $a = 1;
  873. echo $a."=1";
  874. return $a;
  875. }
  876. function b($c)
  877. {
  878. $a = 1;
  879. echo $a."=1;";
  880. return $a;
  881. }
  882. function c($c)
  883. {
  884. $a = 1;
  885. echo $a;
  886. // $a =1;
  887. return $a;
  888. }
  889. ',
  890. ];
  891. yield 'if ($a = N)' => [
  892. '<?php
  893. function a($c)
  894. {
  895. if ($a = 1)
  896. return $a;
  897. }
  898. ',
  899. ];
  900. yield 'changed after declaration' => [
  901. '<?php
  902. function a($c)
  903. {
  904. $a = 1;
  905. $a += 1;
  906. return $a;
  907. }
  908. function b($c)
  909. {
  910. $a = 1;
  911. $a -= 1;
  912. return $a;
  913. }
  914. ',
  915. ];
  916. yield 'complex statement' => [
  917. '<?php
  918. function a($c)
  919. {
  920. $d = $c && $a = 1;
  921. return $a;
  922. }
  923. ',
  924. ];
  925. yield 'PHP close tag within function' => [
  926. '<?php
  927. function a($zz)
  928. {
  929. $zz = 1 ?><?php
  930. ;
  931. return $zz;
  932. }
  933. ',
  934. ];
  935. yield 'import global using "require"' => [
  936. '<?php
  937. function a()
  938. {
  939. require __DIR__."/test3.php";
  940. $b = 1;
  941. return $b;
  942. }
  943. ',
  944. ];
  945. yield 'import global using "require_once"' => [
  946. '<?php
  947. function a()
  948. {
  949. require_once __DIR__."/test3.php";
  950. $b = 1;
  951. return $b;
  952. }
  953. ',
  954. ];
  955. yield 'import global using "include"' => [
  956. '<?php
  957. function a()
  958. {
  959. include __DIR__."/test3.php";
  960. $b = 1;
  961. return $b;
  962. }
  963. ',
  964. ];
  965. yield 'import global using "include_once"' => [
  966. '<?php
  967. function a()
  968. {
  969. include_once __DIR__."/test3.php";
  970. $b = 1;
  971. return $b;
  972. }
  973. ',
  974. ];
  975. yield 'eval' => [
  976. '<?php
  977. $b = function ($z) {
  978. $c = eval($z);
  979. return $c;
  980. };
  981. $c = function ($x) {
  982. $x = eval($x);
  983. $x = 1;
  984. return $x;
  985. };
  986. ',
  987. ];
  988. yield '${X}' => [
  989. '<?php
  990. function A($g)
  991. {
  992. $h = ${$g};
  993. return $h;
  994. }
  995. ',
  996. ];
  997. yield '$$' => [
  998. '<?php
  999. function B($c)
  1000. {
  1001. $b = $$c;
  1002. return $b;
  1003. }
  1004. ',
  1005. ];
  1006. yield [
  1007. '<?php
  1008. class XYZ
  1009. {
  1010. public function test1()
  1011. {
  1012. $GLOBALS[\'a\'] = 2;
  1013. return $GLOBALS;
  1014. }
  1015. public function test2()
  1016. {
  1017. $_server = 2;
  1018. return $_server;
  1019. }
  1020. public function __destruct()
  1021. {
  1022. $GLOBALS[\'a\'] = 2;
  1023. return $GLOBALS[\'a\']; // destruct cannot return but still lints
  1024. }
  1025. };
  1026. $a = new XYZ();
  1027. $a = 1;
  1028. var_dump($a); // $a = 2 here _╯°□°╯︵┻━┻
  1029. ',
  1030. ];
  1031. yield 'variable returned by reference in function' => [
  1032. '<?php
  1033. function &foo() {
  1034. $var = 1;
  1035. return $var;
  1036. }',
  1037. ];
  1038. yield 'variable returned by reference in method' => [
  1039. '<?php
  1040. class Foo {
  1041. public function &bar() {
  1042. $var = 1;
  1043. return $var;
  1044. }
  1045. }',
  1046. ];
  1047. yield 'variable returned by reference in lambda' => [
  1048. '<?php $a = function &() {$z = new A(); return $z;};',
  1049. ];
  1050. yield [
  1051. '<?php
  1052. function F() {
  1053. $a = 1;
  1054. while(bar()) {
  1055. ++$a;
  1056. }; // keep this
  1057. return $a;
  1058. }
  1059. ',
  1060. ];
  1061. yield 'try/catch/finally' => [
  1062. '<?php
  1063. function add($a, $b): mixed
  1064. {
  1065. try {
  1066. $result = $a + $b;
  1067. return $result;
  1068. } catch (\Throwable $th) {
  1069. throw $th;
  1070. } finally {
  1071. echo \'result:\', $result, \PHP_EOL;
  1072. }
  1073. }
  1074. ',
  1075. ];
  1076. yield 'try with multiple catch blocks' => [
  1077. '<?php
  1078. function foo() {
  1079. try {
  1080. $bar = bar();
  1081. return $bar;
  1082. } catch (\LogicException $e) {
  1083. echo "catch ... ";
  1084. } catch (\RuntimeException $e) {
  1085. echo $bar;
  1086. }
  1087. }',
  1088. ];
  1089. yield 'try/catch/finally with some comments' => [
  1090. '<?php
  1091. function add($a, $b): mixed
  1092. {
  1093. try {
  1094. $result = $a + $b;
  1095. return $result;
  1096. } /* foo */ catch /** bar */ (\LogicException $th) {
  1097. throw $th;
  1098. }
  1099. // Or maybe this....
  1100. catch (\RuntimeException $th) {
  1101. throw $th;
  1102. }
  1103. # Print the result anyway
  1104. finally {
  1105. echo \'result:\', $result, \PHP_EOL;
  1106. }
  1107. }
  1108. ',
  1109. ];
  1110. }
  1111. /**
  1112. * @dataProvider provideDoNotFix80Cases
  1113. *
  1114. * @requires PHP 8.0
  1115. */
  1116. public function testDoNotFix80(string $expected): void
  1117. {
  1118. $this->doTest($expected);
  1119. }
  1120. /**
  1121. * @return iterable<array{0: non-empty-string, 1?: non-empty-string}>
  1122. */
  1123. public static function provideDoNotFix80Cases(): iterable
  1124. {
  1125. yield 'try with non-capturing catch block' => [
  1126. '<?php
  1127. function add($a, $b): mixed
  1128. {
  1129. try {
  1130. $result = $a + $b;
  1131. return $result;
  1132. }
  1133. catch (\Throwable) {
  1134. noop();
  1135. }
  1136. finally {
  1137. echo \'result:\', $result, \PHP_EOL;
  1138. }
  1139. }
  1140. ',
  1141. ];
  1142. }
  1143. /**
  1144. * @dataProvider provideRepetitiveFixCases
  1145. */
  1146. public function testRepetitiveFix(string $expected, ?string $input = null): void
  1147. {
  1148. $this->doTest($expected, $input);
  1149. }
  1150. /**
  1151. * @return iterable<array{0: non-empty-string, 1?: non-empty-string}>
  1152. */
  1153. public static function provideRepetitiveFixCases(): iterable
  1154. {
  1155. yield [
  1156. '<?php
  1157. function foo() {
  1158. return bar();
  1159. }
  1160. ',
  1161. '<?php
  1162. function foo() {
  1163. $a = bar();
  1164. $b = $a;
  1165. return $b;
  1166. }
  1167. ',
  1168. ];
  1169. yield [
  1170. '<?php
  1171. function foo(&$c) {
  1172. $a = $c;
  1173. $b = $a;
  1174. return $b;
  1175. }
  1176. ',
  1177. ];
  1178. $expected = "<?php\n";
  1179. $input = "<?php\n";
  1180. for ($i = 0; $i < 10; ++$i) {
  1181. $expected .= \sprintf("\nfunction foo%d() {\n\treturn bar();\n}", $i);
  1182. $input .= \sprintf("\nfunction foo%d() {\n\t\$a = bar();\n\t\$b = \$a;\n\nreturn \$b;\n}", $i);
  1183. }
  1184. yield [$expected, $input];
  1185. }
  1186. /**
  1187. * @requires PHP 8.0
  1188. *
  1189. * @dataProvider provideFix80Cases
  1190. */
  1191. public function testFix80(string $expected, ?string $input = null): void
  1192. {
  1193. $this->doTest($expected, $input);
  1194. }
  1195. /**
  1196. * @return iterable<array{0: non-empty-string, 1?: non-empty-string}>
  1197. */
  1198. public static function provideFix80Cases(): iterable
  1199. {
  1200. yield 'match' => [
  1201. '<?php
  1202. function Foo($food) {
  1203. return match ($food) {
  1204. "apple" => "This food is an apple",
  1205. "cake" => "This food is a cake",
  1206. };
  1207. }
  1208. ',
  1209. '<?php
  1210. function Foo($food) {
  1211. $return_value = match ($food) {
  1212. "apple" => "This food is an apple",
  1213. "cake" => "This food is a cake",
  1214. };
  1215. return $return_value;
  1216. }
  1217. ',
  1218. ];
  1219. yield 'attribute before anonymous `class`' => [
  1220. '<?php
  1221. function A()
  1222. {
  1223. return new #[Foo] class {};
  1224. }
  1225. ',
  1226. '<?php
  1227. function A()
  1228. {
  1229. $a = new #[Foo] class {};
  1230. return $a;
  1231. }
  1232. ',
  1233. ];
  1234. }
  1235. /**
  1236. * @requires PHP 8.3
  1237. *
  1238. * @dataProvider provideFixPhp83Cases
  1239. */
  1240. public function testFixPhp83(string $expected, ?string $input = null): void
  1241. {
  1242. $this->doTest($expected, $input);
  1243. }
  1244. /**
  1245. * @return iterable<array{0: non-empty-string, 1?: non-empty-string}>
  1246. */
  1247. public static function provideFixPhp83Cases(): iterable
  1248. {
  1249. yield 'anonymous readonly class' => [
  1250. '<?php
  1251. function A()
  1252. {
  1253. return new readonly class {};
  1254. }
  1255. ',
  1256. '<?php
  1257. function A()
  1258. {
  1259. $a = new readonly class {};
  1260. return $a;
  1261. }
  1262. ',
  1263. ];
  1264. yield 'attribute before anonymous `readonly class`' => [
  1265. '<?php
  1266. function A()
  1267. {
  1268. return new #[Foo] readonly class {};
  1269. }
  1270. ',
  1271. '<?php
  1272. function A()
  1273. {
  1274. $a = new #[Foo] readonly class {};
  1275. return $a;
  1276. }
  1277. ',
  1278. ];
  1279. }
  1280. }