NoUnusedImportsFixerTest.php 36 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682
  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. * @internal
  16. *
  17. * @covers \PhpCsFixer\Fixer\Import\NoUnusedImportsFixer
  18. *
  19. * @extends AbstractFixerTestCase<\PhpCsFixer\Fixer\Import\NoUnusedImportsFixer>
  20. */
  21. final class NoUnusedImportsFixerTest extends AbstractFixerTestCase
  22. {
  23. /**
  24. * @dataProvider provideFixCases
  25. */
  26. public function testFix(string $expected, ?string $input = null): void
  27. {
  28. $this->doTest($expected, $input);
  29. }
  30. /**
  31. * @return iterable<int|string, array{0: string, 1?: string}>
  32. */
  33. public static function provideFixCases(): iterable
  34. {
  35. yield 'simple' => [
  36. <<<'EOF'
  37. <?php
  38. use Foo\Bar;
  39. use Foo\Bar\FooBar as FooBaz;
  40. use SomeClass;
  41. $a = new Bar();
  42. $a = new FooBaz();
  43. $a = new SomeClass();
  44. use Symfony\Annotation\Template;
  45. use Symfony\Doctrine\Entities\Entity;
  46. use Symfony\Array123\ArrayInterface;
  47. class AnnotatedClass
  48. {
  49. /**
  50. * @Template(foobar=21)
  51. * @param Entity $foo
  52. */
  53. public function doSomething($foo)
  54. {
  55. $bar = $foo->toArray();
  56. /** @var ArrayInterface $bar */
  57. }
  58. }
  59. EOF,
  60. <<<'EOF'
  61. <?php
  62. use Foo\Bar;
  63. use Foo\Bar\Baz;
  64. use Foo\Bar\FooBar as FooBaz;
  65. use Foo\Bar\Foo as Fooo;
  66. use Foo\Bar\Baar\Baar;
  67. use SomeClass;
  68. $a = new Bar();
  69. $a = new FooBaz();
  70. $a = new SomeClass();
  71. use Symfony\Annotation\Template;
  72. use Symfony\Doctrine\Entities\Entity;
  73. use Symfony\Array123\ArrayInterface;
  74. class AnnotatedClass
  75. {
  76. /**
  77. * @Template(foobar=21)
  78. * @param Entity $foo
  79. */
  80. public function doSomething($foo)
  81. {
  82. $bar = $foo->toArray();
  83. /** @var ArrayInterface $bar */
  84. }
  85. }
  86. EOF,
  87. ];
  88. yield 'with_indents' => [
  89. <<<'EOF'
  90. <?php
  91. use Foo\Bar;
  92. $foo = 1;
  93. use Foo\Bar\FooBar as FooBaz;
  94. use SomeClassIndented;
  95. $a = new Bar();
  96. $a = new FooBaz();
  97. $a = new SomeClassIndented();
  98. EOF,
  99. <<<'EOF'
  100. <?php
  101. use Foo\Bar;
  102. use Foo\Bar\Baz;
  103. $foo = 1;
  104. use Foo\Bar\FooBar as FooBaz;
  105. use Foo\Bar\Foo as Fooo;
  106. use Foo\Bar\Baar\Baar;
  107. use SomeClassIndented;
  108. $a = new Bar();
  109. $a = new FooBaz();
  110. $a = new SomeClassIndented();
  111. EOF,
  112. ];
  113. yield 'in_same_namespace_1' => [
  114. <<<'EOF'
  115. <?php
  116. namespace Foo\Bar\FooBar;
  117. use Foo\Bar\FooBar\Foo as Fooz;
  118. use Foo\Bar\FooBar\Aaa\Bbb;
  119. use XYZ\FQCN_XYZ;
  120. $a = new Baz();
  121. $b = new Fooz();
  122. $c = new Bar\Fooz();
  123. $d = new Bbb();
  124. $e = new FQCN_Babo();
  125. $f = new FQCN_XYZ();
  126. EOF,
  127. <<<'EOF'
  128. <?php
  129. namespace Foo\Bar\FooBar;
  130. use Foo\Bar\FooBar\Baz;
  131. use Foo\Bar\FooBar\Foo as Fooz;
  132. use Foo\Bar\FooBar\Bar;
  133. use Foo\Bar\FooBar\Aaa\Bbb;
  134. use \Foo\Bar\FooBar\FQCN_Babo;
  135. use XYZ\FQCN_XYZ;
  136. $a = new Baz();
  137. $b = new Fooz();
  138. $c = new Bar\Fooz();
  139. $d = new Bbb();
  140. $e = new FQCN_Babo();
  141. $f = new FQCN_XYZ();
  142. EOF,
  143. ];
  144. yield 'in_same_namespace_2' => [
  145. <<<'EOF'
  146. <?php namespace App\Http\Controllers;
  147. EOF,
  148. <<<'EOF'
  149. <?php namespace App\Http\Controllers;
  150. use Illuminate\Http\Request;
  151. use App\Http\Controllers\Controller;
  152. EOF,
  153. ];
  154. yield 'in_same_namespace_multiple_1' => [
  155. <<<'EOF'
  156. <?php
  157. namespace Foooooooo;
  158. namespace Foo;
  159. use Foooooooo\Baaaaz;
  160. $a = new Bar();
  161. $b = new Baz();
  162. $c = new Baaaaz();
  163. EOF,
  164. <<<'EOF'
  165. <?php
  166. namespace Foooooooo;
  167. namespace Foo;
  168. use Foo\Bar;
  169. use Foo\Baz;
  170. use Foooooooo\Baaaar;
  171. use Foooooooo\Baaaaz;
  172. $a = new Bar();
  173. $b = new Baz();
  174. $c = new Baaaaz();
  175. EOF,
  176. ];
  177. yield 'in_same_namespace_multiple_2' => [
  178. <<<'EOF'
  179. <?php
  180. namespace Foooooooo;
  181. use Foo\Bar;
  182. $a = new Baaaar();
  183. $b = new Baaaaz();
  184. $c = new Bar();
  185. namespace Foo;
  186. use Foooooooo\Baaaaz;
  187. $a = new Bar();
  188. $b = new Baz();
  189. $c = new Baaaaz();
  190. EOF,
  191. <<<'EOF'
  192. <?php
  193. namespace Foooooooo;
  194. use Foo\Bar;
  195. use Foo\Baz;
  196. use Foooooooo\Baaaar;
  197. use Foooooooo\Baaaaz;
  198. $a = new Baaaar();
  199. $b = new Baaaaz();
  200. $c = new Bar();
  201. namespace Foo;
  202. use Foo\Bar;
  203. use Foo\Baz;
  204. use Foooooooo\Baaaar;
  205. use Foooooooo\Baaaaz;
  206. $a = new Bar();
  207. $b = new Baz();
  208. $c = new Baaaaz();
  209. EOF,
  210. ];
  211. yield 'in_same_namespace_multiple_braces' => [
  212. <<<'EOF'
  213. <?php
  214. namespace Foooooooo
  215. {
  216. use Foo\Bar;
  217. $a = new Baaaar();
  218. $b = new Baaaaz();
  219. $c = new Bar();
  220. }
  221. namespace Foo
  222. {
  223. use Foooooooo\Baaaaz;
  224. $a = new Bar();
  225. $b = new Baz();
  226. $c = new Baaaaz();
  227. }
  228. EOF,
  229. <<<'EOF'
  230. <?php
  231. namespace Foooooooo
  232. {
  233. use Foo\Bar;
  234. use Foo\Baz;
  235. use Foooooooo\Baaaar;
  236. use Foooooooo\Baaaaz;
  237. $a = new Baaaar();
  238. $b = new Baaaaz();
  239. $c = new Bar();
  240. }
  241. namespace Foo
  242. {
  243. use Foo\Bar;
  244. use Foo\Baz;
  245. use Foooooooo\Baaaar;
  246. use Foooooooo\Baaaaz;
  247. $a = new Bar();
  248. $b = new Baz();
  249. $c = new Baaaaz();
  250. }
  251. EOF,
  252. ];
  253. yield 'multiple_use' => [
  254. <<<'EOF'
  255. <?php
  256. namespace Foo;
  257. use BarE;
  258. $c = new D();
  259. $e = new BarE();
  260. EOF,
  261. <<<'EOF'
  262. <?php
  263. namespace Foo;
  264. use Bar;
  265. use BarA;
  266. use BarB, BarC as C, BarD;
  267. use BarB2;
  268. use BarB\B2;
  269. use BarE;
  270. use function fun_a, fun_b, fun_c;
  271. use const CONST_A, CONST_B, CONST_C;
  272. $c = new D();
  273. $e = new BarE();
  274. EOF,
  275. ];
  276. yield 'with_braces' => [
  277. <<<'EOF'
  278. <?php
  279. namespace Foo\Bar\FooBar {
  280. use Foo\Bar\FooBar\Foo as Fooz;
  281. use Foo\Bar\FooBar\Aaa\Bbb;
  282. $a = new Baz();
  283. $b = new Fooz();
  284. $c = new Bar\Fooz();
  285. $d = new Bbb();
  286. }
  287. EOF,
  288. <<<'EOF'
  289. <?php
  290. namespace Foo\Bar\FooBar {
  291. use Foo\Bar\FooBar\Baz;
  292. use Foo\Bar\FooBar\Foo as Fooz;
  293. use Foo\Bar\FooBar\Bar;
  294. use Foo\Bar\FooBar\Aaa\Bbb;
  295. $a = new Baz();
  296. $b = new Fooz();
  297. $c = new Bar\Fooz();
  298. $d = new Bbb();
  299. }
  300. EOF,
  301. ];
  302. yield 'trailing_spaces' => [
  303. <<<'EOF'
  304. <?php
  305. use Foo\Bar ;
  306. use Foo\Bar\FooBar as FooBaz ;
  307. $a = new Bar();
  308. $a = new FooBaz();
  309. EOF,
  310. <<<'EOF'
  311. <?php
  312. use Foo\Bar ;
  313. use Foo\Bar\FooBar as FooBaz ;
  314. use Foo\Bar\Foo as Fooo ;
  315. use SomeClass ;
  316. $a = new Bar();
  317. $a = new FooBaz();
  318. EOF,
  319. ];
  320. yield 'traits' => [
  321. <<<'EOF'
  322. <?php
  323. use Foo as Bar;
  324. use A\MyTrait1;
  325. class MyParent
  326. {
  327. use MyTrait1;
  328. use MyTrait2;
  329. use Bar;
  330. }
  331. EOF,
  332. <<<'EOF'
  333. <?php
  334. use Foo;
  335. use Foo as Bar;
  336. use A\MyTrait1;
  337. class MyParent
  338. {
  339. use MyTrait1;
  340. use MyTrait2;
  341. use Bar;
  342. }
  343. EOF,
  344. ];
  345. yield 'function_use' => [
  346. <<<'EOF'
  347. <?php
  348. use Foo;
  349. $f = new Foo();
  350. $a = function ($item) use ($f) {
  351. return !in_array($item, $f);
  352. };
  353. EOF,
  354. <<<'EOF'
  355. <?php
  356. use Foo;
  357. use Bar;
  358. $f = new Foo();
  359. $a = function ($item) use ($f) {
  360. return !in_array($item, $f);
  361. };
  362. EOF,
  363. ];
  364. yield 'similar_names' => [
  365. <<<'EOF'
  366. <?php
  367. use SomeEntityRepository;
  368. class SomeService
  369. {
  370. public function __construct(SomeEntityRepository $repo)
  371. {
  372. $this->repo = $repo;
  373. }
  374. }
  375. EOF,
  376. <<<'EOF'
  377. <?php
  378. use SomeEntityRepository;
  379. use SomeEntity;
  380. class SomeService
  381. {
  382. public function __construct(SomeEntityRepository $repo)
  383. {
  384. $this->repo = $repo;
  385. }
  386. }
  387. EOF,
  388. ];
  389. yield 'variable_name' => [
  390. <<<'EOF'
  391. <?php
  392. $bar = null;
  393. EOF,
  394. <<<'EOF'
  395. <?php
  396. use Foo\Bar;
  397. $bar = null;
  398. EOF,
  399. ];
  400. yield 'property name, method name, static method call, static property' => [
  401. <<<'EOF'
  402. <?php
  403. $foo->bar = null;
  404. $foo->bar();
  405. $foo::bar();
  406. $foo::bar;
  407. EOF,
  408. <<<'EOF'
  409. <?php
  410. use Foo\Bar;
  411. $foo->bar = null;
  412. $foo->bar();
  413. $foo::bar();
  414. $foo::bar;
  415. EOF,
  416. ];
  417. yield 'constant_name' => [
  418. <<<'EOF'
  419. <?php
  420. class Baz
  421. {
  422. const BAR = 0;
  423. }
  424. EOF,
  425. <<<'EOF'
  426. <?php
  427. use Foo\Bar;
  428. class Baz
  429. {
  430. const BAR = 0;
  431. }
  432. EOF,
  433. ];
  434. yield 'namespace_part' => [
  435. <<<'EOF'
  436. <?php
  437. new \Baz\Bar();
  438. EOF,
  439. <<<'EOF'
  440. <?php
  441. use Foo\Bar;
  442. new \Baz\Bar();
  443. EOF,
  444. ];
  445. yield 'use_in_string_1' => [
  446. <<<'EOF'
  447. <?php
  448. $x=<<<'EOA'
  449. use a;
  450. use b;
  451. EOA;
  452. EOF,
  453. ];
  454. yield 'use_in_string_2' => [
  455. <<<'EOF'
  456. <?php
  457. $x='
  458. use a;
  459. use b;
  460. ';
  461. EOF,
  462. ];
  463. yield 'use_in_string_3' => [
  464. <<<'EOF'
  465. <?php
  466. $x="
  467. use a;
  468. use b;
  469. ";
  470. EOF,
  471. ];
  472. yield 'import_in_global_namespace' => [
  473. <<<'EOF'
  474. <?php
  475. namespace A;
  476. use \SplFileInfo;
  477. new SplFileInfo(__FILE__);
  478. EOF,
  479. ];
  480. yield 'no_import_in_global_namespace' => [
  481. <<<'EOF'
  482. <?php
  483. namespace A;
  484. new \SplFileInfo(__FILE__);
  485. EOF,
  486. <<<'EOF'
  487. <?php
  488. namespace A;
  489. use SplFileInfo;
  490. new \SplFileInfo(__FILE__);
  491. EOF,
  492. ];
  493. yield 'no_import_attribute_in_global_namespace' => [
  494. <<<'EOF'
  495. <?php
  496. namespace A;
  497. #[\Attribute(\Attribute::TARGET_PROPERTY)]
  498. final class B {}
  499. EOF,
  500. <<<'EOF'
  501. <?php
  502. namespace A;
  503. use Attribute;
  504. #[\Attribute(\Attribute::TARGET_PROPERTY)]
  505. final class B {}
  506. EOF,
  507. ];
  508. yield 'use_as_last_statement' => [
  509. <<<'EOF'
  510. <?php
  511. EOF,
  512. <<<'EOF'
  513. <?php
  514. use Bar\Finder;
  515. EOF,
  516. ];
  517. yield 'use_with_same_last_part_that_is_in_namespace' => [
  518. <<<'EOF'
  519. <?php
  520. namespace Foo\Finder;
  521. EOF,
  522. <<<'EOF'
  523. <?php
  524. namespace Foo\Finder;
  525. use Bar\Finder;
  526. EOF,
  527. ];
  528. yield 'used_use_with_same_last_part_that_is_in_namespace' => [
  529. <<<'EOF'
  530. <?php
  531. namespace Foo\Finder;
  532. use Bar\Finder;
  533. class Baz extends Finder
  534. {
  535. }
  536. EOF,
  537. ];
  538. yield 'foo' => [
  539. <<<'EOF'
  540. <?php
  541. namespace Aaa;
  542. class Ddd
  543. {
  544. }
  545. EOF,
  546. <<<'EOF'
  547. <?php
  548. namespace Aaa;
  549. use Aaa\Bbb;
  550. use Ccc;
  551. class Ddd
  552. {
  553. }
  554. EOF,
  555. ];
  556. yield 'close_tag_1' => [
  557. '<?php
  558. ?>inline content<?php ?>',
  559. '<?php
  560. use A\AA;
  561. use B\C?>inline content<?php use A\D; use E\F ?>',
  562. ];
  563. yield 'close_tag_2' => [
  564. '<?php ?>',
  565. '<?php use A\B;?>',
  566. ];
  567. yield 'close_tag_3' => [
  568. '<?php ?>',
  569. '<?php use A\B?>',
  570. ];
  571. yield 'case_mismatch_typo' => [
  572. '<?php
  573. use Foo\exception; // must be kept by non-risky fixer
  574. try {
  575. x();
  576. } catch (Exception $e) {
  577. echo \'Foo\Exception caught\';
  578. } catch (\Exception $e) {
  579. echo \'Exception caught\';
  580. }
  581. ',
  582. ];
  583. yield 'with_matches_in_comments' => [
  584. '<?php
  585. use Foo;
  586. use Bar;
  587. use Baz;
  588. //Foo
  589. #Bar
  590. /*Baz*/',
  591. ];
  592. yield 'with_case_insensitive_matches_in_comments' => [
  593. '<?php
  594. use Foo;
  595. use Bar;
  596. use Baz;
  597. //foo
  598. #bar
  599. /*baz*/',
  600. ];
  601. yield 'with_same_namespace_import_and_unused_import' => [
  602. <<<'EOF'
  603. <?php
  604. namespace Foo;
  605. use Bar\C;
  606. /* test */
  607. abstract class D extends A implements C
  608. {
  609. }
  610. EOF,
  611. <<<'EOF'
  612. <?php
  613. namespace Foo;
  614. use Bar\C;
  615. use Foo\A;
  616. use Foo\Bar\B /* test */ ;
  617. abstract class D extends A implements C
  618. {
  619. }
  620. EOF,
  621. ];
  622. yield 'with_same_namespace_import_and_unused_import_after_namespace_statement' => [
  623. <<<'EOF'
  624. <?php
  625. namespace Foo;
  626. use Foo\Bar\C;
  627. abstract class D extends A implements C
  628. {
  629. }
  630. EOF,
  631. <<<'EOF'
  632. <?php
  633. namespace Foo;
  634. use Foo\A;
  635. use Foo\Bar\B;
  636. use Foo\Bar\C;
  637. abstract class D extends A implements C
  638. {
  639. }
  640. EOF,
  641. ];
  642. yield 'wrong_casing' => [
  643. <<<'EOF'
  644. <?php
  645. use Foo\Foo;
  646. use Bar\Bar;
  647. $a = new FOO();
  648. $b = new bar();
  649. EOF,
  650. ];
  651. yield 'phpdoc_unused' => [
  652. <<<'EOF'
  653. <?php
  654. class Foo extends \PHPUnit_Framework_TestCase
  655. {
  656. /**
  657. * @expectedException \Exception
  658. */
  659. public function testBar()
  660. { }
  661. }
  662. EOF,
  663. <<<'EOF'
  664. <?php
  665. use Some\Exception;
  666. class Foo extends \PHPUnit_Framework_TestCase
  667. {
  668. /**
  669. * @expectedException \Exception
  670. */
  671. public function testBar()
  672. { }
  673. }
  674. EOF,
  675. ];
  676. yield 'imported_class_is_used_for_constants_1' => [
  677. '<?php
  678. use A\ABC;
  679. $a = 5-ABC::Test;
  680. $a = 5-ABC::Test-5;
  681. $a = ABC::Test-5;
  682. ',
  683. ];
  684. yield 'imported_class_is_used_for_constants_2' => [
  685. '<?php
  686. use A\ABC;
  687. $a = 5-ABC::Test;
  688. $a = 5-ABC::Test-5;
  689. ',
  690. ];
  691. yield 'imported_class_is_used_for_constants_3' => [
  692. '<?php
  693. use A\ABC;
  694. $a = 5-ABC::Test;
  695. ',
  696. ];
  697. yield 'imported_class_is_used_for_constants_4' => ['<?php
  698. use A\ABC;
  699. $a = ABC::Test-5;
  700. ',
  701. ];
  702. yield 'imported_class_is_used_for_constants_5' => ['<?php
  703. use A\ABC;
  704. $a = 5-ABC::Test-5;
  705. ',
  706. ];
  707. yield 'imported_class_is_used_for_constants_6' => ['<?php
  708. use A\ABC;
  709. $b = $a-->ABC::Test;
  710. ',
  711. ];
  712. yield 'imported_class_name_is_prefix_with_dash_of_constant' => [
  713. <<<'EOF'
  714. <?php
  715. class Dummy
  716. {
  717. const C = 'bar-bados';
  718. }
  719. EOF,
  720. <<<'EOF'
  721. <?php
  722. use Foo\Bar;
  723. class Dummy
  724. {
  725. const C = 'bar-bados';
  726. }
  727. EOF,
  728. ];
  729. yield 'imported_class_name_is_suffix_with_dash_of_constant' => [
  730. <<<'EOF'
  731. <?php
  732. class Dummy
  733. {
  734. const C = 'tool-bar';
  735. }
  736. EOF,
  737. <<<'EOF'
  738. <?php
  739. use Foo\Bar;
  740. class Dummy
  741. {
  742. const C = 'tool-bar';
  743. }
  744. EOF,
  745. ];
  746. yield 'imported_class_name_is_inside_with_dash_of_constant' => [
  747. <<<'EOF'
  748. <?php
  749. class Dummy
  750. {
  751. const C = 'tool-bar-bados';
  752. }
  753. EOF,
  754. <<<'EOF'
  755. <?php
  756. use Foo\Bar;
  757. class Dummy
  758. {
  759. const C = 'tool-bar-bados';
  760. }
  761. EOF,
  762. ];
  763. yield 'functions_in_the_global_namespace_should_not_be_removed_even_when_declaration_has_new_lines_and_is_uppercase' => [
  764. <<<'EOF'
  765. <?php
  766. namespace Foo;
  767. use function is_int;
  768. is_int(1);
  769. EOF,
  770. <<<'EOF'
  771. <?php
  772. namespace Foo;
  773. use function is_int;
  774. use function is_float;
  775. is_int(1);
  776. EOF,
  777. ];
  778. yield 'constants_in_the_global_namespace_should_not_be_removed' => [
  779. $expected = <<<'EOF'
  780. <?php
  781. namespace Foo;
  782. use const PHP_INT_MAX;
  783. echo PHP_INT_MAX;
  784. EOF,
  785. <<<'EOF'
  786. <?php
  787. namespace Foo;
  788. use const PHP_INT_MAX;
  789. use const PHP_INT_MIN;
  790. echo PHP_INT_MAX;
  791. EOF,
  792. ];
  793. yield 'functions_in_the_global_namespace_should_not_be_removed_even_when_declaration_has_ne_lines_and_is_uppercase' => [
  794. <<<'EOF'
  795. <?php
  796. namespace Foo;use/**/FUNCTION#1
  797. is_int;#2
  798. is_int(1);
  799. EOF,
  800. <<<'EOF'
  801. <?php
  802. namespace Foo;use/**/FUNCTION#1
  803. is_int;#2
  804. use function
  805. is_float;
  806. use
  807. const
  808. PHP_INT_MIN;
  809. is_int(1);
  810. EOF,
  811. ];
  812. yield 'use_trait should never be removed' => [
  813. <<<'EOF'
  814. <?php
  815. class UsesTraits
  816. {
  817. /**
  818. * @see #4086
  819. */
  820. private function withComplexStringVariable()
  821. {
  822. $name = 'World';
  823. return "Hello, {$name}!";
  824. }
  825. use MyTrait;
  826. }
  827. EOF,
  828. ];
  829. yield 'imported_name_is_part_of_namespace' => [
  830. <<<'EOF'
  831. <?php
  832. namespace App\Foo;
  833. class Baz
  834. {
  835. }
  836. EOF,
  837. <<<'EOF'
  838. <?php
  839. namespace App\Foo;
  840. use Foo\Bar\App;
  841. class Baz
  842. {
  843. }
  844. EOF,
  845. ];
  846. yield 'imported_name_is_part_of_namespace with closing tag' => [
  847. <<<'EOF'
  848. <?php
  849. namespace A\B {?>
  850. <?php
  851. require_once __DIR__.'/test2.php' ?>
  852. <?php
  853. use X\Z\Y
  854. ?>
  855. <?php
  856. $y = new Y() ?>
  857. <?php
  858. var_dump($y);}
  859. EOF,
  860. ];
  861. yield [
  862. '<?php
  863. use App\Http\Requests\StoreRequest;
  864. class StoreController
  865. {
  866. /**
  867. * @param \App\Http\Requests\StoreRequest $request
  868. */
  869. public function __invoke(StoreRequest $request)
  870. {}
  871. }',
  872. '<?php
  873. use App\Http\Requests\StoreRequest;
  874. use Illuminate\Http\Request;
  875. class StoreController
  876. {
  877. /**
  878. * @param \App\Http\Requests\StoreRequest $request
  879. */
  880. public function __invoke(StoreRequest $request)
  881. {}
  882. }',
  883. ];
  884. yield 'unused import matching function call' => [
  885. '<?php
  886. namespace Foo;
  887. bar();',
  888. '<?php
  889. namespace Foo;
  890. use Bar;
  891. bar();',
  892. ];
  893. yield 'unused import matching function declaration' => [
  894. '<?php
  895. namespace Foo;
  896. function bar () {}',
  897. '<?php
  898. namespace Foo;
  899. use Bar;
  900. function bar () {}',
  901. ];
  902. yield 'unused import matching method declaration' => [
  903. '<?php
  904. namespace Foo;
  905. class Foo {
  906. public function bar () {}
  907. }',
  908. '<?php
  909. namespace Foo;
  910. use Bar;
  911. class Foo {
  912. public function bar () {}
  913. }',
  914. ];
  915. yield 'unused import matching constant usage' => [
  916. '<?php
  917. namespace Foo;
  918. echo BAR;',
  919. '<?php
  920. namespace Foo;
  921. use Bar;
  922. echo BAR;',
  923. ];
  924. yield 'unused import matching class constant' => [
  925. '<?php
  926. namespace Foo;
  927. class Foo {
  928. const BAR = 1;
  929. }',
  930. '<?php
  931. namespace Foo;
  932. use Bar;
  933. class Foo {
  934. const BAR = 1;
  935. }',
  936. ];
  937. yield 'unused function import matching class usage' => [
  938. '<?php
  939. namespace Foo;
  940. new Bar();
  941. Baz::method();',
  942. '<?php
  943. namespace Foo;
  944. use function bar;
  945. use function baz;
  946. new Bar();
  947. Baz::method();',
  948. ];
  949. yield 'unused function import matching method call' => [
  950. '<?php
  951. namespace Foo;
  952. Foo::bar();',
  953. '<?php
  954. namespace Foo;
  955. use function bar;
  956. Foo::bar();',
  957. ];
  958. yield 'unused function import matching method declaration' => [
  959. '<?php
  960. namespace Foo;
  961. class Foo {
  962. public function bar () {}
  963. }',
  964. '<?php
  965. namespace Foo;
  966. use function bar;
  967. class Foo {
  968. public function bar () {}
  969. }',
  970. ];
  971. yield 'unused function import matching constant usage' => [
  972. '<?php
  973. namespace Foo;
  974. echo BAR;',
  975. '<?php
  976. namespace Foo;
  977. use function bar;
  978. echo BAR;',
  979. ];
  980. yield 'unused function import matching class constant' => [
  981. '<?php
  982. namespace Foo;
  983. class Foo {
  984. const BAR = 1;
  985. }',
  986. '<?php
  987. namespace Foo;
  988. use function bar;
  989. class Foo {
  990. const BAR = 1;
  991. }',
  992. ];
  993. yield 'unused constant import matching function call' => [
  994. '<?php
  995. namespace Foo;
  996. bar();',
  997. '<?php
  998. namespace Foo;
  999. use const BAR;
  1000. bar();',
  1001. ];
  1002. yield 'unused constant import matching function declaration' => [
  1003. '<?php
  1004. namespace Foo;
  1005. function bar () {}',
  1006. '<?php
  1007. namespace Foo;
  1008. use const BAR;
  1009. function bar () {}',
  1010. ];
  1011. yield 'unused constant import matching method declaration' => [
  1012. '<?php
  1013. namespace Foo;
  1014. class Foo {
  1015. public function bar () {}
  1016. }',
  1017. '<?php
  1018. namespace Foo;
  1019. use const BAR;
  1020. class Foo {
  1021. public function bar () {}
  1022. }',
  1023. ];
  1024. yield 'unused constant import matching class constant' => [
  1025. '<?php
  1026. namespace Foo;
  1027. class Foo {
  1028. const BAR = 1;
  1029. }',
  1030. '<?php
  1031. namespace Foo;
  1032. use const BAR;
  1033. class Foo {
  1034. const BAR = 1;
  1035. }',
  1036. ];
  1037. yield 'attribute without braces' => [
  1038. '<?php
  1039. use Foo;
  1040. class Controller
  1041. {
  1042. #[Foo]
  1043. public function foo() {}
  1044. }',
  1045. ];
  1046. yield 'attribute with braces' => [
  1047. '<?php
  1048. use Foo;
  1049. class Controller
  1050. {
  1051. #[Foo()]
  1052. public function foo() {}
  1053. }',
  1054. ];
  1055. yield 'go to' => [
  1056. '<?php
  1057. Bar1:
  1058. Bar2:
  1059. Bar3:
  1060. ',
  1061. '<?php
  1062. use Bar1;
  1063. use const Bar2;
  1064. use function Bar3;
  1065. Bar1:
  1066. Bar2:
  1067. Bar3:
  1068. ',
  1069. ];
  1070. yield [
  1071. <<<'EOF'
  1072. <?php
  1073. use some\a\{ClassD};
  1074. use function some\c\{fn_a};
  1075. use const some\d\{ConstB};
  1076. new CLassD();
  1077. echo fn_a(ConstB);
  1078. EOF,
  1079. <<<'EOF'
  1080. <?php
  1081. use some\a\{ClassD};
  1082. use some\b\{ClassA, ClassB, ClassC as C};
  1083. use function some\c\{fn_a, fn_b, fn_c};
  1084. use const some\d\{ConstA, ConstB, ConstC};
  1085. new CLassD();
  1086. echo fn_a(ConstB);
  1087. EOF,
  1088. ];
  1089. yield 'grouped imports' => [
  1090. <<<'EOF'
  1091. <?php
  1092. use some\y\{ClassA, ClassC as C,};
  1093. use function some\a\{
  1094. fn_b,
  1095. };
  1096. use const some\Z\{ConstA,ConstC,};
  1097. echo ConstA.ConstC;
  1098. fn_b(ClassA::test, new C());
  1099. EOF,
  1100. <<<'EOF'
  1101. <?php
  1102. use A\{B,};
  1103. use some\y\{ClassA, ClassB, ClassC as C,};
  1104. use function some\a\{
  1105. fn_a,
  1106. fn_b,
  1107. fn_c,
  1108. };
  1109. use function some\b\{fn_x, fn_y, fn_z,};
  1110. use const some\Z\{ConstA,ConstB,ConstC,};
  1111. use const some\X\{ConstX,ConstY,ConstZ};
  1112. use C\{D,E,};
  1113. use Z;
  1114. echo ConstA.ConstC;
  1115. fn_b(ClassA::test, new C());
  1116. EOF,
  1117. ];
  1118. yield 'multiline grouped imports with comments' => [
  1119. <<<'EOF'
  1120. <?php
  1121. use function some\a\{
  1122. // Foo
  1123. fn_b,
  1124. /* Bar *//** Baz */
  1125. # Buzz
  1126. };
  1127. fn_b();
  1128. EOF,
  1129. <<<'EOF'
  1130. <?php
  1131. use function some\a\{
  1132. fn_a, // Foo
  1133. fn_b,
  1134. /* Bar */ fn_c, /** Baz */
  1135. fn_d, # Buzz
  1136. };
  1137. fn_b();
  1138. EOF,
  1139. ];
  1140. yield 'comma-separated imports' => [
  1141. <<<'EOF'
  1142. <?php
  1143. use A;
  1144. use function fn_b;
  1145. use const ConstC;
  1146. fn_b(new A(), ConstC);
  1147. EOF,
  1148. <<<'EOF'
  1149. <?php
  1150. use A, B, C;
  1151. use function fn_a, fn_b, fn_c;
  1152. use const ConstA, ConstB, ConstC;
  1153. fn_b(new A(), ConstC);
  1154. EOF,
  1155. ];
  1156. yield 'only unused comma-separated imports in single line' => [
  1157. '<?php ',
  1158. '<?php use A, B, C;',
  1159. ];
  1160. yield 'only unused grouped imports in single line' => [
  1161. '<?php ',
  1162. '<?php use A\{B, C};',
  1163. ];
  1164. yield 'unused comma-separated imports right after open tag, with consecutive lines' => [
  1165. "<?php \n# Comment",
  1166. "<?php use A, B, C;\n\n# Comment",
  1167. ];
  1168. yield 'unused grouped imports right after open tag, with consecutive lines' => [
  1169. "<?php \n# Comment",
  1170. "<?php use A\\{B, C};\n\n# Comment",
  1171. ];
  1172. yield 'unused comma-separated imports right after open tag with a non-empty token after it, and with consecutive lines' => [
  1173. "<?php # Comment\n\n# Another comment",
  1174. "<?php use A, B, C; # Comment\n\n# Another comment",
  1175. ];
  1176. yield 'unused grouped imports right after open tag with a non-empty token after it, and with consecutive lines' => [
  1177. "<?php # Comment\n\n# Another comment",
  1178. "<?php use A\\{B, C}; # Comment\n\n# Another comment",
  1179. ];
  1180. yield 'only unused comma-separated imports in the last line, with whitespace after' => [
  1181. "<?php \n",
  1182. "<?php \nuse A, B, C; \t\t",
  1183. ];
  1184. yield 'only unused grouped imports in the last line, with whitespace after' => [
  1185. "<?php \n",
  1186. "<?php \nuse A\\{B, C}; \t\t",
  1187. ];
  1188. }
  1189. /**
  1190. * @requires PHP <8.0
  1191. */
  1192. public function testFixPre80(): void
  1193. {
  1194. $this->doTest(
  1195. '<?php
  1196. # 1
  1197. # 2
  1198. # 3
  1199. # 4
  1200. use /**/A\B/**/;
  1201. echo 1;
  1202. new B();
  1203. ',
  1204. '<?php
  1205. use# 1
  1206. \# 2
  1207. Exception# 3
  1208. # 4
  1209. ;
  1210. use /**/A\B/**/;
  1211. echo 1;
  1212. new B();
  1213. '
  1214. );
  1215. }
  1216. /**
  1217. * @requires PHP 8.0
  1218. *
  1219. * @dataProvider provideFix80Cases
  1220. */
  1221. public function testFix80(string $expected, ?string $input = null): void
  1222. {
  1223. $this->doTest($expected, $input);
  1224. }
  1225. /**
  1226. * @return iterable<int|string, array{0: string, 1?: string}>
  1227. */
  1228. public static function provideFix80Cases(): iterable
  1229. {
  1230. yield [
  1231. '<?php
  1232. $x = $foo?->bar;
  1233. $y = foo?->bar();
  1234. ',
  1235. '<?php
  1236. use Foo\Bar;
  1237. $x = $foo?->bar;
  1238. $y = foo?->bar();
  1239. ',
  1240. ];
  1241. yield 'with union type in non-capturing catch' => [
  1242. '<?php
  1243. use Foo;
  1244. use Bar;
  1245. try {} catch (Foo | Bar) {}',
  1246. ];
  1247. yield 'union return' => [
  1248. '<?php
  1249. use Foo;
  1250. use Bar;
  1251. abstract class Baz
  1252. {
  1253. abstract public function test(): Foo|Bar;
  1254. }
  1255. ',
  1256. ];
  1257. yield 'attribute' => [
  1258. "<?php
  1259. use Acme\\JsonSchemaValidationBundle\\Annotation\\JsonSchema;
  1260. use Sensio\\Bundle\\FrameworkExtraBundle\\Configuration\\IsGranted;
  1261. use Symfony\\Component\\Routing\\Annotation\\Route;
  1262. #[
  1263. Route('/basket/{uuid}/item', name: 'addBasketItem', requirements: ['uuid' => '%regex.uuid%'], methods: ['POST']),
  1264. IsGranted('ROLE_USER'),
  1265. JsonSchema('Public/Basket/addItem.json'),
  1266. ]
  1267. class Foo {}
  1268. ",
  1269. ];
  1270. yield 'attribute 2' => [
  1271. '<?php
  1272. use Psr\Log\LoggerInterface;
  1273. function f( #[Target(\'xxx\')] LoggerInterface|null $logger) {}
  1274. ',
  1275. ];
  1276. }
  1277. /**
  1278. * @requires PHP 8.1
  1279. *
  1280. * @dataProvider provideFix81Cases
  1281. */
  1282. public function testFix81(string $expected, ?string $input = null): void
  1283. {
  1284. $this->doTest($expected, $input);
  1285. }
  1286. /**
  1287. * @return iterable<int|string, array{0: string, 1?: string}>
  1288. */
  1289. public static function provideFix81Cases(): iterable
  1290. {
  1291. yield 'final const' => [
  1292. '<?php
  1293. class Foo
  1294. {
  1295. final public const B1 = "2";
  1296. }
  1297. ',
  1298. '<?php
  1299. use A\B1;
  1300. class Foo
  1301. {
  1302. final public const B1 = "2";
  1303. }
  1304. ',
  1305. ];
  1306. yield 'first callable class' => [
  1307. '<?php
  1308. use Foo;
  1309. Foo::method(...);',
  1310. '<?php
  1311. use Foo;
  1312. use Bar;
  1313. Foo::method(...);',
  1314. ];
  1315. yield 'New in initializers' => [
  1316. '<?php
  1317. namespace A\B\C;
  1318. use Foo1;
  1319. use Foo2;
  1320. use Foo3;
  1321. use Foo4;
  1322. use Foo5;
  1323. use Foo6;
  1324. use Foo7;
  1325. class Test {
  1326. public function __construct(
  1327. public $prop = (new Foo1),
  1328. ) {}
  1329. }
  1330. function test(
  1331. $foo = (new Foo2),
  1332. $baz = (new Foo3(x: 2)),
  1333. ) {
  1334. }
  1335. static $x = new Foo4();
  1336. const C = (new Foo5);
  1337. function test2($param = (new Foo6)) {}
  1338. const D = new Foo7(1,2);
  1339. ',
  1340. ];
  1341. yield [
  1342. '<?php
  1343. enum Foo: string
  1344. {
  1345. use Bar;
  1346. case Test1 = "a";
  1347. }
  1348. ',
  1349. ];
  1350. yield [
  1351. '<?php
  1352. use Foo\Class1;
  1353. use Foo\Class2;
  1354. class C
  1355. {
  1356. public function t(Class1 | Class2 $fields) {}
  1357. }
  1358. ',
  1359. ];
  1360. yield [
  1361. '<?php
  1362. use Foo\Class1;
  1363. use Foo\Class2;
  1364. class C
  1365. {
  1366. public function t(Class1 | Class2 ...$fields) {}
  1367. }
  1368. ',
  1369. ];
  1370. }
  1371. }