GlobalNamespaceImportFixerTest.php 34 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342
  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\Import;
  13. use PhpCsFixer\Tests\Test\AbstractFixerTestCase;
  14. /**
  15. * @author Gregor Harlan <gharlan@web.de>
  16. *
  17. * @internal
  18. *
  19. * @covers \PhpCsFixer\Fixer\Import\GlobalNamespaceImportFixer
  20. *
  21. * @extends AbstractFixerTestCase<\PhpCsFixer\Fixer\Import\GlobalNamespaceImportFixer>
  22. *
  23. * @phpstan-import-type _AutogeneratedInputConfiguration from \PhpCsFixer\Fixer\Import\GlobalNamespaceImportFixer
  24. */
  25. final class GlobalNamespaceImportFixerTest extends AbstractFixerTestCase
  26. {
  27. /**
  28. * @dataProvider provideFixImportConstantsCases
  29. */
  30. public function testFixImportConstants(string $expected, ?string $input = null): void
  31. {
  32. $this->fixer->configure(['import_constants' => true]);
  33. $this->doTest($expected, $input);
  34. }
  35. /**
  36. * @return iterable<int|string, array{0: string, 1?: string}>
  37. */
  38. public static function provideFixImportConstantsCases(): iterable
  39. {
  40. yield 'non-global names' => [
  41. <<<'EXPECTED'
  42. <?php
  43. namespace Test;
  44. echo FOO, \Bar\BAZ, namespace\FOO2;
  45. EXPECTED,
  46. ];
  47. yield 'name already used [1]' => [
  48. <<<'EXPECTED'
  49. <?php
  50. namespace Test;
  51. echo \FOO, FOO, \FOO;
  52. EXPECTED,
  53. ];
  54. yield 'name already used [2]' => [
  55. <<<'EXPECTED'
  56. <?php
  57. namespace Test;
  58. use const Bar\FOO;
  59. echo \FOO;
  60. EXPECTED,
  61. ];
  62. yield 'name already used [3]' => [
  63. <<<'EXPECTED'
  64. <?php
  65. namespace Test;
  66. const FOO = 1;
  67. echo \FOO;
  68. EXPECTED,
  69. ];
  70. yield 'without namespace / do not import' => [
  71. <<<'INPUT'
  72. <?php
  73. echo \FOO, \BAR, \FOO;
  74. INPUT,
  75. ];
  76. yield 'with namespace' => [
  77. <<<'EXPECTED'
  78. <?php
  79. namespace Test;
  80. use const BAR;
  81. use const FOO;
  82. echo FOO, BAR;
  83. EXPECTED,
  84. <<<'INPUT'
  85. <?php
  86. namespace Test;
  87. echo \FOO, \BAR;
  88. INPUT,
  89. ];
  90. yield 'with namespace with {} syntax' => [
  91. <<<'EXPECTED'
  92. <?php
  93. namespace Test {
  94. use const BAR;
  95. use const FOO;
  96. echo FOO, BAR;
  97. }
  98. EXPECTED,
  99. <<<'INPUT'
  100. <?php
  101. namespace Test {
  102. echo \FOO, \BAR;
  103. }
  104. INPUT,
  105. ];
  106. yield 'ignore other imported types' => [
  107. <<<'EXPECTED'
  108. <?php
  109. namespace Test;
  110. use BAR;
  111. use const BAR;
  112. use const FOO;
  113. echo FOO, BAR;
  114. EXPECTED,
  115. <<<'INPUT'
  116. <?php
  117. namespace Test;
  118. use BAR;
  119. echo \FOO, \BAR;
  120. INPUT,
  121. ];
  122. yield 'respect already imported names [1]' => [
  123. <<<'EXPECTED'
  124. <?php
  125. namespace Test;
  126. use const BAR;
  127. use const FOO;
  128. echo FOO, BAR;
  129. EXPECTED,
  130. <<<'INPUT'
  131. <?php
  132. namespace Test;
  133. use const BAR;
  134. echo \FOO, \BAR;
  135. INPUT,
  136. ];
  137. yield 'respect already imported names [2]' => [
  138. <<<'EXPECTED'
  139. <?php
  140. namespace Test;
  141. use const \BAR;
  142. use const FOO;
  143. echo FOO, BAR, BAR;
  144. EXPECTED,
  145. <<<'INPUT'
  146. <?php
  147. namespace Test;
  148. use const \BAR;
  149. echo \FOO, \BAR, BAR;
  150. INPUT,
  151. ];
  152. yield 'handle case sensitivity' => [
  153. <<<'EXPECTED'
  154. <?php
  155. namespace Test;
  156. use const fOO;
  157. use const FOO;
  158. use const Foo;
  159. const foO = 1;
  160. echo FOO, Foo;
  161. EXPECTED,
  162. <<<'INPUT'
  163. <?php
  164. namespace Test;
  165. use const fOO;
  166. const foO = 1;
  167. echo \FOO, \Foo;
  168. INPUT,
  169. ];
  170. yield 'handle aliased imports' => [
  171. <<<'EXPECTED'
  172. <?php
  173. namespace Test;
  174. use const BAR as BAZ;
  175. use const FOO;
  176. echo FOO, BAZ;
  177. EXPECTED,
  178. <<<'INPUT'
  179. <?php
  180. namespace Test;
  181. use const BAR as BAZ;
  182. echo \FOO, \BAR;
  183. INPUT,
  184. ];
  185. yield 'ignore class constants' => [
  186. <<<'EXPECTED'
  187. <?php
  188. namespace Test;
  189. use const FOO;
  190. class Bar {
  191. const FOO = 1;
  192. }
  193. echo FOO;
  194. EXPECTED,
  195. <<<'INPUT'
  196. <?php
  197. namespace Test;
  198. class Bar {
  199. const FOO = 1;
  200. }
  201. echo \FOO;
  202. INPUT,
  203. ];
  204. yield 'global namespace' => [
  205. <<<'INPUT'
  206. <?php
  207. echo \FOO, \BAR;
  208. INPUT,
  209. ];
  210. yield [
  211. <<<'INPUT'
  212. <?php
  213. namespace {
  214. echo \FOO, \BAR;
  215. }
  216. INPUT,
  217. ];
  218. }
  219. /**
  220. * @dataProvider provideFixImportFunctionsCases
  221. */
  222. public function testFixImportFunctions(string $expected, ?string $input = null): void
  223. {
  224. $this->fixer->configure(['import_functions' => true]);
  225. $this->doTest($expected, $input);
  226. }
  227. /**
  228. * @return iterable<string, array{0: string, 1?: string}>
  229. */
  230. public static function provideFixImportFunctionsCases(): iterable
  231. {
  232. yield 'non-global names' => [
  233. <<<'EXPECTED'
  234. <?php
  235. namespace Test;
  236. foo();
  237. Bar\baz();
  238. namespace\foo2();
  239. EXPECTED,
  240. ];
  241. yield 'name already used [1]' => [
  242. <<<'EXPECTED'
  243. <?php
  244. namespace Test;
  245. \foo();
  246. Foo();
  247. \foo();
  248. EXPECTED,
  249. ];
  250. yield 'name already used [2]' => [
  251. <<<'EXPECTED'
  252. <?php
  253. namespace Test;
  254. use function Bar\foo;
  255. \Foo();
  256. EXPECTED,
  257. ];
  258. yield 'name already used [3]' => [
  259. <<<'EXPECTED'
  260. <?php
  261. namespace Test;
  262. function foo() {}
  263. \Foo();
  264. EXPECTED,
  265. ];
  266. yield 'without namespace / do not import' => [
  267. <<<'INPUT'
  268. <?php
  269. \foo();
  270. \bar();
  271. \Foo();
  272. INPUT,
  273. ];
  274. yield 'with namespace' => [
  275. <<<'EXPECTED'
  276. <?php
  277. namespace Test;
  278. use function bar;
  279. use function foo;
  280. foo();
  281. bar();
  282. EXPECTED,
  283. <<<'INPUT'
  284. <?php
  285. namespace Test;
  286. \foo();
  287. \bar();
  288. INPUT,
  289. ];
  290. yield 'with namespace with {} syntax' => [
  291. <<<'EXPECTED'
  292. <?php
  293. namespace Test {
  294. use function bar;
  295. use function foo;
  296. foo();
  297. bar();
  298. }
  299. EXPECTED,
  300. <<<'INPUT'
  301. <?php
  302. namespace Test {
  303. \foo();
  304. \bar();
  305. }
  306. INPUT,
  307. ];
  308. yield 'ignore other imported types' => [
  309. <<<'EXPECTED'
  310. <?php
  311. namespace Test;
  312. use bar;
  313. use function bar;
  314. use function foo;
  315. foo();
  316. bar();
  317. EXPECTED,
  318. <<<'INPUT'
  319. <?php
  320. namespace Test;
  321. use bar;
  322. \foo();
  323. \bar();
  324. INPUT,
  325. ];
  326. yield 'respect already imported names [1]' => [
  327. <<<'EXPECTED'
  328. <?php
  329. namespace Test;
  330. use function bar;
  331. use function foo;
  332. foo();
  333. Bar();
  334. EXPECTED,
  335. <<<'INPUT'
  336. <?php
  337. namespace Test;
  338. use function bar;
  339. \foo();
  340. \Bar();
  341. INPUT,
  342. ];
  343. yield 'respect already imported names [2]' => [
  344. <<<'EXPECTED'
  345. <?php
  346. namespace Test;
  347. use function \bar;
  348. use function foo;
  349. foo();
  350. Bar();
  351. bar();
  352. EXPECTED,
  353. <<<'INPUT'
  354. <?php
  355. namespace Test;
  356. use function \bar;
  357. \foo();
  358. \Bar();
  359. bar();
  360. INPUT,
  361. ];
  362. yield 'handle aliased imports' => [
  363. <<<'EXPECTED'
  364. <?php
  365. namespace Test;
  366. use function bar as baz;
  367. use function foo;
  368. foo();
  369. baz();
  370. EXPECTED,
  371. <<<'INPUT'
  372. <?php
  373. namespace Test;
  374. use function bar as baz;
  375. \foo();
  376. \Bar();
  377. INPUT,
  378. ];
  379. yield 'ignore class methods' => [
  380. <<<'EXPECTED'
  381. <?php
  382. namespace Test;
  383. use function foo;
  384. class Bar {
  385. function foo() {}
  386. }
  387. foo();
  388. EXPECTED,
  389. <<<'INPUT'
  390. <?php
  391. namespace Test;
  392. class Bar {
  393. function foo() {}
  394. }
  395. \foo();
  396. INPUT,
  397. ];
  398. yield 'name already used' => [
  399. <<<'EXPECTED'
  400. <?php
  401. namespace Test;
  402. class Bar {
  403. function baz() {
  404. new class() {
  405. function baz() {
  406. function foo() {}
  407. }
  408. };
  409. }
  410. }
  411. \foo();
  412. EXPECTED,
  413. ];
  414. }
  415. /**
  416. * @dataProvider provideFixImportClassesCases
  417. */
  418. public function testFixImportClasses(string $expected, ?string $input = null): void
  419. {
  420. $this->fixer->configure(['import_classes' => true]);
  421. $this->doTest($expected, $input);
  422. }
  423. /**
  424. * @return iterable<string, array{0: string, 1?: string}>
  425. */
  426. public static function provideFixImportClassesCases(): iterable
  427. {
  428. yield 'non-global names' => [
  429. <<<'EXPECTED'
  430. <?php
  431. namespace Test;
  432. new Foo();
  433. new Bar\Baz();
  434. new namespace\Foo2();
  435. /** @var Foo|Bar\Baz $x */
  436. $x = x();
  437. EXPECTED,
  438. ];
  439. yield 'name already used [1]' => [
  440. <<<'EXPECTED'
  441. <?php
  442. namespace Test;
  443. new \Foo();
  444. new foo();
  445. /** @var \Foo $foo */
  446. $foo = new \Foo();
  447. EXPECTED,
  448. ];
  449. yield 'name already used [2]' => [
  450. <<<'EXPECTED'
  451. <?php
  452. namespace Test;
  453. use Bar\foo;
  454. /** @var \Foo $foo */
  455. $foo = new \Foo();
  456. EXPECTED,
  457. ];
  458. yield 'name already used [3]' => [
  459. <<<'EXPECTED'
  460. <?php
  461. namespace Test;
  462. class foo {}
  463. /** @var \Foo $foo */
  464. $foo = new \Foo();
  465. EXPECTED,
  466. ];
  467. yield 'name already used [4]' => [
  468. <<<'EXPECTED'
  469. <?php
  470. namespace Test;
  471. /** @return array<string, foo> */
  472. function x() {}
  473. /** @var \Foo $foo */
  474. $foo = new \Foo();
  475. EXPECTED,
  476. ];
  477. yield 'without namespace / do not import' => [
  478. <<<'INPUT'
  479. <?php
  480. /** @var \Foo $foo */
  481. $foo = new \foo();
  482. new \Bar();
  483. \FOO::baz();
  484. INPUT,
  485. ];
  486. yield 'with namespace' => [
  487. <<<'EXPECTED'
  488. <?php
  489. namespace Test;
  490. use Bar;
  491. use Baz;
  492. use Foo;
  493. new Foo();
  494. Bar::baz();
  495. /** @return Baz<string, foo> */
  496. function x() {}
  497. EXPECTED,
  498. <<<'INPUT'
  499. <?php
  500. namespace Test;
  501. new \Foo();
  502. \Bar::baz();
  503. /** @return \Baz<string, \foo> */
  504. function x() {}
  505. INPUT,
  506. ];
  507. yield 'with namespace with {} syntax' => [
  508. <<<'EXPECTED'
  509. <?php
  510. namespace Test {
  511. use Bar;
  512. use Foo;
  513. new Foo();
  514. Bar::baz();
  515. }
  516. EXPECTED,
  517. <<<'INPUT'
  518. <?php
  519. namespace Test {
  520. new \Foo();
  521. \Bar::baz();
  522. }
  523. INPUT,
  524. ];
  525. yield 'phpdoc only' => [
  526. <<<'EXPECTED'
  527. <?php
  528. namespace Test;
  529. use Throwable;
  530. /** @throws Throwable */
  531. function x() {}
  532. EXPECTED,
  533. <<<'INPUT'
  534. <?php
  535. namespace Test;
  536. /** @throws \Throwable */
  537. function x() {}
  538. INPUT,
  539. ];
  540. yield 'ignore other imported types' => [
  541. <<<'EXPECTED'
  542. <?php
  543. namespace Test;
  544. use function Bar;
  545. use Bar;
  546. use Foo;
  547. new Foo();
  548. Bar::baz();
  549. EXPECTED,
  550. <<<'INPUT'
  551. <?php
  552. namespace Test;
  553. use function Bar;
  554. new \Foo();
  555. \Bar::baz();
  556. INPUT,
  557. ];
  558. yield 'respect already imported names [1]' => [
  559. <<<'EXPECTED'
  560. <?php
  561. namespace Test;
  562. use Bar;
  563. use Foo;
  564. new Foo();
  565. bar::baz();
  566. EXPECTED,
  567. <<<'INPUT'
  568. <?php
  569. namespace Test;
  570. use Bar;
  571. new \Foo();
  572. \bar::baz();
  573. INPUT,
  574. ];
  575. yield 'respect already imported names [2]' => [
  576. <<<'EXPECTED'
  577. <?php
  578. namespace Test;
  579. use \Bar;
  580. use Foo;
  581. new Foo();
  582. new bar();
  583. new Bar();
  584. EXPECTED,
  585. <<<'INPUT'
  586. <?php
  587. namespace Test;
  588. use \Bar;
  589. new \Foo();
  590. new \bar();
  591. new Bar();
  592. INPUT,
  593. ];
  594. yield 'respect already imported names [3]' => [
  595. <<<'EXPECTED'
  596. <?php
  597. namespace Test;
  598. use Throwable;
  599. /** @throws Throwable */
  600. function x() {}
  601. /** @throws Throwable */
  602. function y() {}
  603. EXPECTED,
  604. <<<'INPUT'
  605. <?php
  606. namespace Test;
  607. use Throwable;
  608. /** @throws Throwable */
  609. function x() {}
  610. /** @throws \Throwable */
  611. function y() {}
  612. INPUT,
  613. ];
  614. yield 'handle aliased imports' => [
  615. <<<'EXPECTED'
  616. <?php
  617. namespace Test;
  618. use Bar as Baz;
  619. use Foo;
  620. new Foo();
  621. /** @var Baz $bar */
  622. $bar = new Baz();
  623. EXPECTED,
  624. <<<'INPUT'
  625. <?php
  626. namespace Test;
  627. use Bar as Baz;
  628. new \Foo();
  629. /** @var \bar $bar */
  630. $bar = new \bar();
  631. INPUT,
  632. ];
  633. yield 'handle typehints' => [
  634. <<<'EXPECTED'
  635. <?php
  636. namespace Test;
  637. use Bar;
  638. use Baz;
  639. use Foo;
  640. class Abc {
  641. function bar(Foo $a, Bar $b, foo &$c, Baz ...$d) {}
  642. }
  643. EXPECTED,
  644. <<<'INPUT'
  645. <?php
  646. namespace Test;
  647. class Abc {
  648. function bar(\Foo $a, \Bar $b, \foo &$c, \Baz ...$d) {}
  649. }
  650. INPUT,
  651. ];
  652. yield 'handle typehints 2' => [
  653. <<<'EXPECTED'
  654. <?php
  655. namespace Test;
  656. use Bar;
  657. use Foo;
  658. class Abc {
  659. function bar(?Foo $a): ?Bar {}
  660. }
  661. EXPECTED,
  662. <<<'INPUT'
  663. <?php
  664. namespace Test;
  665. class Abc {
  666. function bar(?\Foo $a): ?\Bar {}
  667. }
  668. INPUT,
  669. ];
  670. yield 'try catch' => [
  671. <<<'EXPECTED'
  672. <?php
  673. namespace Test;
  674. use Exception;
  675. try {
  676. } catch (Exception $e) {
  677. }
  678. EXPECTED,
  679. <<<'INPUT'
  680. <?php
  681. namespace Test;
  682. try {
  683. } catch (\Exception $e) {
  684. }
  685. INPUT,
  686. ];
  687. yield 'try catch with comments' => [
  688. <<<'EXPECTED'
  689. <?php
  690. namespace Test;
  691. use Exception;
  692. try {
  693. } catch (/* ... */ Exception $e /* ... */) {
  694. }
  695. EXPECTED,
  696. <<<'INPUT'
  697. <?php
  698. namespace Test;
  699. try {
  700. } catch (/* ... */ \Exception $e /* ... */) {
  701. }
  702. INPUT,
  703. ];
  704. }
  705. /**
  706. * @dataProvider provideFixImportClasses80Cases
  707. *
  708. * @requires PHP 8.0
  709. */
  710. public function testFixImportClasses80(string $expected, string $input): void
  711. {
  712. $this->fixer->configure(['import_classes' => true]);
  713. $this->doTest($expected, $input);
  714. }
  715. /**
  716. * @return iterable<string, array{string, string}>
  717. */
  718. public static function provideFixImportClasses80Cases(): iterable
  719. {
  720. yield 'try catch without variable' => [
  721. <<<'EXPECTED'
  722. <?php
  723. namespace Test;
  724. use Exception;
  725. try {
  726. } catch (Exception) {
  727. }
  728. EXPECTED,
  729. <<<'INPUT'
  730. <?php
  731. namespace Test;
  732. try {
  733. } catch (\Exception) {
  734. }
  735. INPUT,
  736. ];
  737. yield 'try catch without variable and comments' => [
  738. <<<'EXPECTED'
  739. <?php
  740. namespace Test;
  741. use Exception;
  742. try {
  743. } catch (/* non-capturing catch */ Exception /* just because! */) {
  744. }
  745. EXPECTED,
  746. <<<'INPUT'
  747. <?php
  748. namespace Test;
  749. try {
  750. } catch (/* non-capturing catch */ \Exception /* just because! */) {
  751. }
  752. INPUT,
  753. ];
  754. }
  755. /**
  756. * @dataProvider provideFixFullyQualifyConstantsCases
  757. */
  758. public function testFixFullyQualifyConstants(string $expected, ?string $input = null): void
  759. {
  760. $this->fixer->configure(['import_constants' => false]);
  761. $this->doTest($expected, $input);
  762. }
  763. /**
  764. * @return iterable<string, array{0: string, 1?: string}>
  765. */
  766. public static function provideFixFullyQualifyConstantsCases(): iterable
  767. {
  768. yield 'already fqn or sub namespace' => [
  769. <<<'EXPECTED'
  770. <?php
  771. use const FOO;
  772. use const BAR;
  773. echo \FOO, Baz\BAR;
  774. EXPECTED,
  775. ];
  776. yield 'handle all occurrences' => [
  777. <<<'EXPECTED'
  778. <?php
  779. namespace X;
  780. use const FOO;
  781. use const BAR;
  782. echo \FOO, \BAR, \FOO;
  783. EXPECTED,
  784. <<<'INPUT'
  785. <?php
  786. namespace X;
  787. use const FOO;
  788. use const BAR;
  789. echo FOO, BAR, FOO;
  790. INPUT,
  791. ];
  792. yield 'ignore other imports and non-imported names' => [
  793. <<<'EXPECTED'
  794. <?php
  795. namespace Test;
  796. use FOO;
  797. use const BAR;
  798. use const Baz;
  799. echo FOO, \BAR, BAZ, QUX;
  800. EXPECTED,
  801. <<<'INPUT'
  802. <?php
  803. namespace Test;
  804. use FOO;
  805. use const BAR;
  806. use const Baz;
  807. echo FOO, BAR, BAZ, QUX;
  808. INPUT,
  809. ];
  810. }
  811. /**
  812. * @dataProvider provideFixFullyQualifyFunctionsCases
  813. */
  814. public function testFixFullyQualifyFunctions(string $expected, ?string $input = null): void
  815. {
  816. $this->fixer->configure(['import_functions' => false]);
  817. $this->doTest($expected, $input);
  818. }
  819. /**
  820. * @return iterable<string, array{0: string, 1?: string}>
  821. */
  822. public static function provideFixFullyQualifyFunctionsCases(): iterable
  823. {
  824. yield 'already fqn or sub namespace' => [
  825. <<<'EXPECTED'
  826. <?php
  827. use function foo;
  828. use function bar;
  829. \foo();
  830. Baz\bar();
  831. EXPECTED,
  832. ];
  833. yield 'handle all occurrences' => [
  834. <<<'EXPECTED'
  835. <?php
  836. namespace X;
  837. use function foo;
  838. use function bar;
  839. \foo();
  840. \bar();
  841. \Foo();
  842. EXPECTED,
  843. <<<'INPUT'
  844. <?php
  845. namespace X;
  846. use function foo;
  847. use function bar;
  848. foo();
  849. bar();
  850. Foo();
  851. INPUT,
  852. ];
  853. yield 'ignore other imports and non-imported names' => [
  854. <<<'EXPECTED'
  855. <?php
  856. namespace Test;
  857. use foo;
  858. use function bar;
  859. foo();
  860. \bar();
  861. baz();
  862. EXPECTED,
  863. <<<'INPUT'
  864. <?php
  865. namespace Test;
  866. use foo;
  867. use function bar;
  868. foo();
  869. bar();
  870. baz();
  871. INPUT,
  872. ];
  873. }
  874. /**
  875. * @dataProvider provideFixFullyQualifyClassesCases
  876. */
  877. public function testFixFullyQualifyClasses(string $expected, ?string $input = null): void
  878. {
  879. $this->fixer->configure(['import_classes' => false]);
  880. $this->doTest($expected, $input);
  881. }
  882. /**
  883. * @return iterable<string, array{0: string, 1?: string}>
  884. */
  885. public static function provideFixFullyQualifyClassesCases(): iterable
  886. {
  887. yield 'already fqn or sub namespace' => [
  888. <<<'EXPECTED'
  889. <?php
  890. use Foo;
  891. use Bar;
  892. new \Foo();
  893. Baz\Bar::baz();
  894. /**
  895. * @param \Foo $foo
  896. * @param Baz\Bar $bar
  897. */
  898. function abc(\Foo $foo, Baz\Bar $bar = null) {}
  899. EXPECTED,
  900. ];
  901. yield 'handle all occurrences' => [
  902. <<<'EXPECTED'
  903. <?php
  904. namespace X;
  905. use Foo;
  906. use Bar;
  907. new \Foo();
  908. new \Bar();
  909. \foo::baz();
  910. /**
  911. * @param \Foo|string $foo
  912. * @param null|\Bar[] $bar
  913. * @return array<string, ?\Bar<int, \foo>>|null
  914. */
  915. function abc($foo, \Bar $bar = null) {}
  916. EXPECTED,
  917. <<<'INPUT'
  918. <?php
  919. namespace X;
  920. use Foo;
  921. use Bar;
  922. new Foo();
  923. new Bar();
  924. foo::baz();
  925. /**
  926. * @param Foo|string $foo
  927. * @param null|Bar[] $bar
  928. * @return array<string, ?Bar<int, foo>>|null
  929. */
  930. function abc($foo, Bar $bar = null) {}
  931. INPUT,
  932. ];
  933. yield 'ignore other imports and non-imported names' => [
  934. <<<'EXPECTED'
  935. <?php
  936. namespace Test;
  937. use function Foo;
  938. use Bar;
  939. new Foo();
  940. new \Bar();
  941. new Baz();
  942. EXPECTED,
  943. <<<'INPUT'
  944. <?php
  945. namespace Test;
  946. use function Foo;
  947. use Bar;
  948. new Foo();
  949. new Bar();
  950. new Baz();
  951. INPUT,
  952. ];
  953. yield 'try catch' => [
  954. <<<'EXPECTED'
  955. <?php
  956. namespace Test;
  957. use Exception;
  958. try {
  959. } catch (\Exception $e) {
  960. }
  961. EXPECTED,
  962. <<<'INPUT'
  963. <?php
  964. namespace Test;
  965. use Exception;
  966. try {
  967. } catch (Exception $e) {
  968. }
  969. INPUT,
  970. ];
  971. yield 'try catch with comments' => [
  972. <<<'EXPECTED'
  973. <?php
  974. namespace Test;
  975. use Exception;
  976. try {
  977. } catch (/* ... */ \Exception $e /* ... */) {
  978. }
  979. EXPECTED,
  980. <<<'INPUT'
  981. <?php
  982. namespace Test;
  983. use Exception;
  984. try {
  985. } catch (/* ... */ Exception $e /* ... */) {
  986. }
  987. INPUT,
  988. ];
  989. yield 'key in PHPDoc\'s array shape matching class name' => [
  990. '<?php
  991. namespace Foo;
  992. use Exception;
  993. class Bar {
  994. /**
  995. * @return array{code: int, exception: \Exception}
  996. */
  997. public function f1(): array {}
  998. /**
  999. * @return array{exception: \Exception}
  1000. */
  1001. public function f2(): array {}
  1002. /**
  1003. * @return array{exceptions: array<\Exception>}
  1004. */
  1005. public function f3(): array {}
  1006. }',
  1007. '<?php
  1008. namespace Foo;
  1009. use Exception;
  1010. class Bar {
  1011. /**
  1012. * @return array{code: int, exception: Exception}
  1013. */
  1014. public function f1(): array {}
  1015. /**
  1016. * @return array{exception: Exception}
  1017. */
  1018. public function f2(): array {}
  1019. /**
  1020. * @return array{exceptions: array<Exception>}
  1021. */
  1022. public function f3(): array {}
  1023. }',
  1024. ];
  1025. }
  1026. /**
  1027. * @dataProvider provideFixFullyQualifyClasses80Cases
  1028. *
  1029. * @requires PHP 8.0
  1030. */
  1031. public function testFixFullyQualifyClasses80(string $expected, string $input): void
  1032. {
  1033. $this->fixer->configure(['import_classes' => false]);
  1034. $this->doTest($expected, $input);
  1035. }
  1036. /**
  1037. * @return iterable<string, array{string, string}>
  1038. */
  1039. public static function provideFixFullyQualifyClasses80Cases(): iterable
  1040. {
  1041. yield 'try catch without variable' => [
  1042. <<<'EXPECTED'
  1043. <?php
  1044. namespace Test;
  1045. use Exception;
  1046. try {
  1047. } catch (\Exception) {
  1048. }
  1049. EXPECTED,
  1050. <<<'INPUT'
  1051. <?php
  1052. namespace Test;
  1053. use Exception;
  1054. try {
  1055. } catch (Exception) {
  1056. }
  1057. INPUT,
  1058. ];
  1059. yield 'try catch without variable and comments' => [
  1060. <<<'EXPECTED'
  1061. <?php
  1062. namespace Test;
  1063. use Exception;
  1064. try {
  1065. } catch (/* non-capturing catch */ \Exception /* just because! */) {
  1066. }
  1067. EXPECTED,
  1068. <<<'INPUT'
  1069. <?php
  1070. namespace Test;
  1071. use Exception;
  1072. try {
  1073. } catch (/* non-capturing catch */ Exception /* just because! */) {
  1074. }
  1075. INPUT,
  1076. ];
  1077. }
  1078. /**
  1079. * @dataProvider provideMultipleNamespacesCases
  1080. */
  1081. public function testMultipleNamespaces(string $expected): void
  1082. {
  1083. $this->fixer->configure(['import_constants' => true]);
  1084. $this->doTest($expected);
  1085. }
  1086. /**
  1087. * @return iterable<array{string}>
  1088. */
  1089. public static function provideMultipleNamespacesCases(): iterable
  1090. {
  1091. yield [
  1092. <<<'INPUT'
  1093. <?php
  1094. namespace Test;
  1095. echo \FOO, \BAR;
  1096. namespace OtherTest;
  1097. echo \FOO, \BAR;
  1098. INPUT,
  1099. ];
  1100. yield [
  1101. <<<'INPUT'
  1102. <?php
  1103. namespace Test {
  1104. echo \FOO, \BAR;
  1105. }
  1106. namespace OtherTest {
  1107. echo \FOO, \BAR;
  1108. }
  1109. INPUT,
  1110. ];
  1111. yield [
  1112. <<<'INPUT'
  1113. <?php
  1114. namespace {
  1115. echo \FOO, \BAR;
  1116. }
  1117. namespace OtherTest {
  1118. echo \FOO, \BAR;
  1119. }
  1120. INPUT,
  1121. ];
  1122. yield [
  1123. <<<'INPUT'
  1124. <?php
  1125. namespace Test {
  1126. echo \FOO, \BAR;
  1127. }
  1128. namespace {
  1129. echo \FOO, \BAR;
  1130. }
  1131. INPUT,
  1132. ];
  1133. }
  1134. /**
  1135. * @requires PHP 8.0
  1136. */
  1137. public function testAttributes(): void
  1138. {
  1139. $this->fixer->configure([
  1140. 'import_classes' => true,
  1141. 'import_constants' => true,
  1142. 'import_functions' => true,
  1143. ]);
  1144. $this->doTest(
  1145. '<?php
  1146. namespace Foo;
  1147. use AnAttribute1;
  1148. use AnAttribute2;
  1149. use AnAttribute3;
  1150. class Bar
  1151. {
  1152. #[AnAttribute1]
  1153. public function f1() {}
  1154. #[AnAttribute2, AnAttribute3]
  1155. public function f2() {}
  1156. }',
  1157. '<?php
  1158. namespace Foo;
  1159. class Bar
  1160. {
  1161. #[\AnAttribute1]
  1162. public function f1() {}
  1163. #[\AnAttribute2, \AnAttribute3]
  1164. public function f2() {}
  1165. }'
  1166. );
  1167. }
  1168. /**
  1169. * @dataProvider provideFix81Cases
  1170. *
  1171. * @requires PHP 8.1
  1172. */
  1173. public function testFix81(string $expected, ?string $input = null): void
  1174. {
  1175. $this->fixer->configure([
  1176. 'import_constants' => true,
  1177. 'import_functions' => true,
  1178. ]);
  1179. $this->doTest($expected, $input);
  1180. }
  1181. /**
  1182. * @return iterable<string, array{string, string}>
  1183. */
  1184. public static function provideFix81Cases(): iterable
  1185. {
  1186. yield 'ignore enum methods' => [
  1187. <<<'EXPECTED'
  1188. <?php
  1189. namespace Test;
  1190. use function foo;
  1191. enum Bar {
  1192. function foo() {}
  1193. }
  1194. foo();
  1195. EXPECTED,
  1196. <<<'INPUT'
  1197. <?php
  1198. namespace Test;
  1199. enum Bar {
  1200. function foo() {}
  1201. }
  1202. \foo();
  1203. INPUT,
  1204. ];
  1205. yield 'ignore enum constants' => [
  1206. <<<'EXPECTED'
  1207. <?php
  1208. namespace Test;
  1209. use const FOO;
  1210. enum Bar {
  1211. const FOO = 1;
  1212. }
  1213. echo FOO;
  1214. EXPECTED,
  1215. <<<'INPUT'
  1216. <?php
  1217. namespace Test;
  1218. enum Bar {
  1219. const FOO = 1;
  1220. }
  1221. echo \FOO;
  1222. INPUT,
  1223. ];
  1224. }
  1225. }