ClassAttributesSeparationFixerTest.php 46 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400
  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\ClassNotation;
  13. use PhpCsFixer\ConfigurationException\InvalidFixerConfigurationException;
  14. use PhpCsFixer\Tests\Test\AbstractFixerTestCase;
  15. use PhpCsFixer\Tokenizer\Tokens;
  16. use PhpCsFixer\WhitespacesFixerConfig;
  17. /**
  18. * @internal
  19. *
  20. * @covers \PhpCsFixer\Fixer\ClassNotation\ClassAttributesSeparationFixer
  21. */
  22. final class ClassAttributesSeparationFixerTest extends AbstractFixerTestCase
  23. {
  24. /**
  25. * @dataProvider provideFixCases
  26. */
  27. public function testFix(string $expected, ?string $input = null): void
  28. {
  29. $this->doTest($expected, $input);
  30. }
  31. public static function provideFixCases(): iterable
  32. {
  33. yield [
  34. '<?php
  35. class Sample
  36. {
  37. private $a; // foo
  38. /** second in a hour */
  39. private $b;
  40. }
  41. ',
  42. '<?php
  43. class Sample
  44. {private $a; // foo
  45. /** second in a hour */
  46. private $b;
  47. }
  48. ',
  49. ];
  50. yield 'empty class' => [
  51. '<?php class Foo {}',
  52. ];
  53. yield 'simple top class' => [
  54. '<?php class A {
  55. public function Foo(){}
  56. }',
  57. '<?php class A {public function Foo(){}}',
  58. ];
  59. yield 'comment' => [
  60. '<?php class A {
  61. /* function comment */
  62. public function Bar(){}
  63. }',
  64. '<?php class A {/* function comment */public function Bar(){}
  65. }',
  66. ];
  67. yield 'comment, multiple lines' => [
  68. '<?php class A {
  69. /* some comment */
  70. public function Bar(){}
  71. }',
  72. '<?php class A {
  73. /* some comment */
  74. public function Bar(){}
  75. }',
  76. ];
  77. yield 'simple PHPDoc case' => [
  78. '<?php class Foo
  79. {
  80. /** Doc 1 */
  81. public function A(){}
  82. /** Doc 2 */
  83. public function B(){}
  84. }',
  85. '<?php class Foo
  86. {/** Doc 1 */public function A(){}
  87. /** Doc 2 */
  88. public function B(){}
  89. }',
  90. ];
  91. yield 'add a newline at the end of a class with trait group' => [
  92. '<?php class A
  93. {
  94. use Bar {
  95. __construct as barConstruct;
  96. baz as barBaz;
  97. }
  98. }',
  99. '<?php class A
  100. {
  101. use Bar {
  102. __construct as barConstruct;
  103. baz as barBaz;
  104. }}',
  105. ];
  106. yield 'add a newline at the end of a class with trait' => [
  107. '<?php class A
  108. {
  109. use A\B\C;
  110. }',
  111. '<?php class A
  112. {
  113. use A\B\C;}',
  114. ];
  115. yield 'removes extra lines at the end of an interface' => [
  116. '<?php interface F
  117. {
  118. public function A();
  119. }',
  120. '<?php interface F
  121. {
  122. public function A();
  123. }',
  124. ];
  125. yield 'removes extra lines at the end of an abstract class' => [
  126. '<?php abstract class F
  127. {
  128. public abstract function A();
  129. }',
  130. '<?php abstract class F
  131. {
  132. public abstract function A();
  133. }',
  134. ];
  135. yield 'add a newline at the end of a class' => [
  136. '<?php class A
  137. {
  138. public function A(){}
  139. }',
  140. '<?php class A
  141. {
  142. public function A(){}}',
  143. ];
  144. yield 'add a newline at the end of a class: with comments' => [
  145. '<?php class A
  146. {
  147. public const A = 1; /* foo */ /* bar */
  148. }',
  149. '<?php class A
  150. {
  151. public const A = 1; /* foo */ /* bar */}',
  152. ];
  153. yield 'add a newline at the end of a class: with comments with trailing space' => [
  154. '<?php class A
  155. {
  156. public const A = 1; /* foo */ /* bar */
  157. }',
  158. '<?php class A
  159. {
  160. public const A = 1; /* foo */ /* bar */ }',
  161. ];
  162. $to = $from = '<?php ';
  163. for ($i = 0; $i < 15; ++$i) {
  164. $from .= sprintf('class A%d{public function GA%d(){return new class {public function B6B%d(){}};}public function otherFunction%d(){}}', $i, $i, $i, $i);
  165. $to .= sprintf("class A%d{\npublic function GA%d(){return new class {\npublic function B6B%d(){}\n};}\n\npublic function otherFunction%d(){}\n}", $i, $i, $i, $i);
  166. }
  167. yield [$to, $from];
  168. yield [
  169. '<?php $a = new class {
  170. public function H(){}
  171. public function B7(){}
  172. private function C(){}
  173. };',
  174. '<?php $a = new class {
  175. public function H(){}
  176. public function B7(){}
  177. private function C(){}
  178. };',
  179. ];
  180. yield [
  181. '<?php
  182. class A
  183. {
  184. public function getFilter()
  185. {
  186. return new class () implements FilterInterface {
  187. private $d = 123;
  188. public function pass($a, $b) {
  189. echo $a;
  190. }
  191. public $e = 5;
  192. };}
  193. }
  194. ',
  195. '<?php
  196. class A
  197. {public function getFilter()
  198. {
  199. return new class () implements FilterInterface {private $d = 123;
  200. public function pass($a, $b) {
  201. echo $a;
  202. }
  203. public $e = 5;};}
  204. }
  205. ',
  206. ];
  207. }
  208. /**
  209. * @param array<mixed> $elements
  210. *
  211. * @dataProvider provideInvalidElementsCases
  212. */
  213. public function testInvalidElements(array $elements): void
  214. {
  215. $this->expectException(InvalidFixerConfigurationException::class);
  216. $this->fixer->configure(['elements' => $elements]);
  217. }
  218. public static function provideInvalidElementsCases(): iterable
  219. {
  220. yield 'numeric keys' => [['method', 'property']];
  221. yield 'wrong key name' => [['methods' => 'one']];
  222. yield 'wrong key value' => [['method' => 'two']];
  223. }
  224. /**
  225. * @dataProvider provideCommentBlockStartDetectionCases
  226. */
  227. public function testCommentBlockStartDetection(int $expected, string $code, int $index): void
  228. {
  229. Tokens::clearCache();
  230. $tokens = Tokens::fromCode($code);
  231. $method = new \ReflectionMethod($this->fixer, 'findCommentBlockStart');
  232. $method->setAccessible(true);
  233. $result = $method->invoke($this->fixer, $tokens, $index, 0);
  234. self::assertSame(
  235. $expected,
  236. $result,
  237. sprintf('Expected index %d (%s) got index %d (%s).', $expected, $tokens[$expected]->toJson(), $result, $tokens[$result]->toJson())
  238. );
  239. }
  240. public static function provideCommentBlockStartDetectionCases(): iterable
  241. {
  242. yield [
  243. 4,
  244. '<?php
  245. //ui
  246. //j1
  247. //k2
  248. ',
  249. 6,
  250. ];
  251. yield [
  252. 4,
  253. '<?php
  254. //ui
  255. //j1
  256. //k2
  257. ',
  258. 5,
  259. ];
  260. yield [
  261. 4,
  262. '<?php
  263. /**/
  264. //j1
  265. //k2
  266. ',
  267. 6,
  268. ];
  269. yield [
  270. 4,
  271. '<?php
  272. $a;//j
  273. //k
  274. ',
  275. 6,
  276. ];
  277. yield [
  278. 2,
  279. '<?php
  280. //a
  281. ',
  282. 2,
  283. ];
  284. yield [
  285. 2,
  286. '<?php
  287. //b
  288. //c
  289. ',
  290. 2,
  291. ];
  292. yield [
  293. 2,
  294. '<?php
  295. //d
  296. //e
  297. ',
  298. 4,
  299. ];
  300. yield [
  301. 2,
  302. '<?php
  303. /**/
  304. //f
  305. //g
  306. //h
  307. ',
  308. 8,
  309. ];
  310. }
  311. /**
  312. * @dataProvider provideFixClassesCases
  313. */
  314. public function testFixClasses(string $expected, ?string $input = null): void
  315. {
  316. $this->doTest($expected, $input);
  317. }
  318. public static function provideFixClassesCases(): iterable
  319. {
  320. yield ['<?php
  321. class SomeClass1
  322. {
  323. // This comment
  324. // is multiline.
  325. public function echoA()
  326. {
  327. echo "a";
  328. }
  329. }
  330. '];
  331. yield [
  332. '<?php
  333. class SomeClass2
  334. {
  335. // This comment
  336. /* is multiline. */
  337. public function echoA()
  338. {
  339. echo "a";
  340. }
  341. }
  342. ',
  343. '<?php
  344. class SomeClass2
  345. {
  346. // This comment
  347. /* is multiline. */public function echoA()
  348. {
  349. echo "a";
  350. }
  351. }
  352. ',
  353. ];
  354. yield [
  355. '<?php
  356. class SomeClass3
  357. {
  358. // This comment
  359. // is multiline.
  360. public function echoA()
  361. {
  362. echo "a";
  363. }
  364. }
  365. ', ];
  366. yield [
  367. '<?php
  368. class SomeClass1
  369. {
  370. private $a; //
  371. public function methodA()
  372. {
  373. }
  374. private $b;
  375. //
  376. public function methodB()
  377. {
  378. }
  379. // C
  380. public function methodC()
  381. {
  382. }
  383. // D
  384. public function methodD()
  385. {
  386. }
  387. /* E */
  388. public function methodE()
  389. {
  390. }
  391. /* F */
  392. public function methodF()
  393. {
  394. }
  395. }
  396. ',
  397. '<?php
  398. class SomeClass1
  399. {
  400. private $a; //
  401. public function methodA()
  402. {
  403. }
  404. private $b;
  405. //
  406. public function methodB()
  407. {
  408. }
  409. // C
  410. public function methodC()
  411. {
  412. }
  413. // D
  414. public function methodD()
  415. {
  416. }
  417. /* E */
  418. public function methodE()
  419. {
  420. }
  421. /* F */
  422. public function methodF()
  423. {
  424. }
  425. }
  426. ', ];
  427. yield ['<?php
  428. class SomeClass
  429. {
  430. // comment
  431. public function echoA()
  432. {
  433. echo "a";
  434. }
  435. }
  436. '];
  437. yield ['<?php
  438. class SomeClass
  439. {
  440. // This comment
  441. // is multiline.
  442. public function echoA()
  443. {
  444. echo "a";
  445. }
  446. }
  447. '];
  448. yield [
  449. '<?php
  450. class SomeClass
  451. {
  452. // comment
  453. public function echoA()
  454. {
  455. echo "a";
  456. }
  457. }
  458. ',
  459. '<?php
  460. class SomeClass
  461. {
  462. // comment
  463. public function echoA()
  464. {
  465. echo "a";
  466. }
  467. }
  468. ',
  469. ];
  470. yield [
  471. '<?php
  472. class SomeClass
  473. {
  474. /* comment */
  475. public function echoB()
  476. {
  477. echo "a";
  478. }
  479. }
  480. ',
  481. '<?php
  482. class SomeClass
  483. {
  484. /* comment */public function echoB()
  485. {
  486. echo "a";
  487. }
  488. }
  489. ',
  490. ];
  491. yield [
  492. '<?php
  493. class SomeClass
  494. {
  495. /* comment */
  496. public function echoC()
  497. {
  498. echo "a";
  499. }
  500. }
  501. ',
  502. '<?php
  503. class SomeClass
  504. {
  505. /* comment */ public function echoC()
  506. {
  507. echo "a";
  508. }
  509. }
  510. ',
  511. ];
  512. yield [
  513. '<?php
  514. abstract class MethodTest2
  515. {
  516. public function method045()
  517. {
  518. $files = null;
  519. if (!empty($files)) {
  520. $this->filter(
  521. function (\SplFileInfo $file) use ($files) {
  522. return !in_array($file->getRelativePathname(), $files, true);
  523. }
  524. );
  525. }
  526. }
  527. private $a;
  528. public static function method145()
  529. {
  530. }
  531. abstract protected function method245();
  532. // comment
  533. final private function method345()
  534. {
  535. }
  536. }
  537. function some1(){ echo 1;}
  538. function some2(){ echo 2;}',
  539. '<?php
  540. abstract class MethodTest2
  541. {
  542. public function method045()
  543. {
  544. $files = null;
  545. if (!empty($files)) {
  546. $this->filter(
  547. function (\SplFileInfo $file) use ($files) {
  548. return !in_array($file->getRelativePathname(), $files, true);
  549. }
  550. );
  551. }
  552. }
  553. private $a;
  554. public static function method145()
  555. {
  556. }
  557. abstract protected function method245();
  558. // comment
  559. final private function method345()
  560. {
  561. }
  562. }
  563. function some1(){ echo 1;}
  564. function some2(){ echo 2;}',
  565. ];
  566. yield [
  567. '<?php
  568. /*
  569. * This file is part of the PHP CS utility.
  570. *
  571. * (c) Fabien Potencier <fabien@symfony.com>
  572. *
  573. * This source file is subject to the MIT license that is bundled
  574. * with this source code in the file LICENSE.
  575. */
  576. namespace PhpCsFixer\Linter;
  577. /**
  578. * Dummy linter. No linting is performed. No error is raised.
  579. *
  580. * @author Dariusz Rumiński <dariusz.ruminski@gmail.com>
  581. *
  582. * @internal
  583. */
  584. final class NullLinter implements LinterInterface
  585. {
  586. /**
  587. * {@inheritdoc}
  588. */
  589. public function lintFile($path)
  590. {
  591. unset($path);
  592. }
  593. /**
  594. * {@inheritdoc}
  595. */
  596. public function lintSource($source)
  597. {
  598. unset($source);
  599. }
  600. }
  601. ',
  602. ];
  603. // do not touch anonymous functions (since PHP doesn't allow
  604. // for class attributes being functions :(, we only have to test
  605. // those used within methods)
  606. yield [
  607. '<?php
  608. class MethodTestAnonymous
  609. {
  610. public function method444a()
  611. {
  612. $text = "hello";
  613. $example = function ($arg) use ($message) {
  614. var_dump($arg . " " . $message);
  615. };
  616. $example($text);
  617. $example = function($arg) use ($message) {
  618. var_dump($arg . " " . $message);
  619. };
  620. $example = function /*test*/ ($arg) use ($message) {
  621. var_dump($arg . " " . $message);
  622. };
  623. }
  624. }',
  625. ];
  626. yield [
  627. '<?php
  628. class MethodTest1
  629. {
  630. private $c; //
  631. public function method444a()
  632. {
  633. }
  634. /**
  635. *
  636. */
  637. public function method444b()
  638. {
  639. }
  640. //
  641. public function method444c()
  642. {
  643. }
  644. private $a;
  645. public function method444d()
  646. {
  647. }
  648. private $b;
  649. //
  650. public function method444e()
  651. {
  652. }
  653. public function method444f()
  654. {
  655. }
  656. private $d; //
  657. public function method444f1()
  658. {
  659. }
  660. /**/
  661. public function method444g()
  662. {
  663. }
  664. }',
  665. '<?php
  666. class MethodTest1
  667. {
  668. private $c; //
  669. public function method444a()
  670. {
  671. }
  672. /**
  673. *
  674. */
  675. public function method444b()
  676. {
  677. }
  678. //
  679. public function method444c()
  680. {
  681. }
  682. private $a;
  683. public function method444d()
  684. {
  685. }
  686. private $b;
  687. //
  688. public function method444e()
  689. {
  690. }
  691. public function method444f()
  692. {
  693. }
  694. private $d; //
  695. public function method444f1()
  696. {
  697. }
  698. /**/
  699. public function method444g()
  700. {
  701. }
  702. }',
  703. ];
  704. // spaces between methods
  705. yield [
  706. '<?php
  707. abstract class MethodTest3
  708. {
  709. public function method021()
  710. {
  711. }
  712. public static function method121()
  713. {
  714. }
  715. abstract protected function method221(); '.'
  716. final private function method321a()
  717. {
  718. }
  719. }',
  720. '<?php
  721. abstract class MethodTest3
  722. {
  723. public function method021()
  724. {
  725. }
  726. public static function method121()
  727. {
  728. }
  729. abstract protected function method221();
  730. '.'
  731. final private function method321a()
  732. {
  733. }
  734. }', ];
  735. // don't change correct code
  736. yield [
  737. '<?php
  738. class SmallHelperException extends \Exception
  739. {
  740. public function getId111()
  741. {
  742. return 1;
  743. }
  744. public function getMessage111()
  745. {
  746. return \'message\';
  747. }
  748. }
  749. class MethodTest123124124
  750. {
  751. public function method111a(){}
  752. public function method211a(){}
  753. }',
  754. ];
  755. // do not touch function out of class scope
  756. yield [
  757. '<?php
  758. function some0() {
  759. }
  760. class MethodTest4
  761. {
  762. public function method122b()
  763. {
  764. }
  765. public function method222b()
  766. {
  767. }
  768. }
  769. function some() {
  770. }
  771. function some2() {
  772. }
  773. ',
  774. ];
  775. yield [
  776. '<?php interface A {
  777. public function B1(); // allowed comment
  778. public function C(); // allowed comment
  779. }',
  780. '<?php interface A {public function B1(); // allowed comment
  781. public function C(); // allowed comment
  782. }',
  783. ];
  784. yield [
  785. '<?php class Foo {
  786. var $a;
  787. var $b;
  788. }',
  789. '<?php class Foo {
  790. var $a;
  791. var $b;
  792. }',
  793. ];
  794. yield [
  795. '<?php
  796. class A
  797. {
  798. /** 1 */
  799. function A2() {}
  800. /** 2 */
  801. function B2() {}
  802. }
  803. ',
  804. '<?php
  805. class A
  806. {
  807. /** 1 */
  808. function A2() {}
  809. /** 2 */
  810. function B2() {}
  811. }
  812. ',
  813. ];
  814. }
  815. /**
  816. * @dataProvider provideFixTraitsCases
  817. */
  818. public function testFixTraits(string $expected, ?string $input = null): void
  819. {
  820. $this->doTest($expected, $input);
  821. }
  822. public static function provideFixTraitsCases(): iterable
  823. {
  824. // do not touch well formatted traits
  825. yield [
  826. '<?php
  827. trait OkTrait
  828. {
  829. function getReturnTypeOk()
  830. {
  831. }
  832. /**
  833. *
  834. */
  835. function getReturnDescriptionOk()
  836. {
  837. }
  838. }',
  839. ];
  840. yield [
  841. '<?php
  842. trait ezcReflectionReturnInfo {
  843. public $x = 1;
  844. protected function getA(){echo 1;}
  845. function getB(){echo 2;}
  846. protected function getC(){echo 3;}
  847. /** Description */
  848. function getD(){echo 4;}
  849. protected function getE(){echo 3;}
  850. private $a;
  851. function getF(){echo 4;}
  852. }',
  853. '<?php
  854. trait ezcReflectionReturnInfo {
  855. public $x = 1;
  856. protected function getA(){echo 1;}function getB(){echo 2;}
  857. protected function getC(){echo 3;}/** Description */function getD(){echo 4;}
  858. protected function getE(){echo 3;}private $a;function getF(){echo 4;}
  859. }',
  860. ];
  861. yield [
  862. '<?php
  863. trait SomeReturnInfo {
  864. function getReturnType()
  865. {
  866. }
  867. function getReturnDescription()
  868. {
  869. }
  870. function getReturnDescription2()
  871. {
  872. }
  873. abstract public function getWorld();
  874. }',
  875. '<?php
  876. trait SomeReturnInfo {
  877. function getReturnType()
  878. {
  879. }
  880. function getReturnDescription()
  881. {
  882. } function getReturnDescription2()
  883. {
  884. }
  885. abstract public function getWorld();
  886. }',
  887. ];
  888. }
  889. /**
  890. * @dataProvider provideFixInterfaceCases
  891. */
  892. public function testFixInterface(string $expected, ?string $input = null): void
  893. {
  894. $this->doTest($expected, $input);
  895. }
  896. public static function provideFixInterfaceCases(): iterable
  897. {
  898. yield [
  899. '<?php
  900. interface TestInterface
  901. {
  902. public function someInterfaceMethod4();
  903. public function someInterfaceMethod5();
  904. /**
  905. * {@link}
  906. */ '.'
  907. public function someInterfaceMethod6();
  908. public function someInterfaceMethod7();
  909. public function someInterfaceMethod8();
  910. }',
  911. '<?php
  912. interface TestInterface
  913. { public function someInterfaceMethod4();
  914. public function someInterfaceMethod5();
  915. /**
  916. * {@link}
  917. */ '.'
  918. public function someInterfaceMethod6();
  919. public function someInterfaceMethod7(); public function someInterfaceMethod8();
  920. }',
  921. ];
  922. // do not touch well formatted interfaces
  923. yield [
  924. '<?php
  925. interface TestInterfaceOK
  926. {
  927. public function someMethod1();
  928. public function someMethod2();
  929. }',
  930. ];
  931. // method after trait use
  932. yield [
  933. '<?php
  934. trait ezcReflectionReturnInfo {
  935. function getReturnDescription() {}
  936. }
  937. class ezcReflectionMethod extends ReflectionMethod {
  938. use ezcReflectionReturnInfo;
  939. function afterUseTrait(){}
  940. function afterUseTrait2(){}
  941. }',
  942. '<?php
  943. trait ezcReflectionReturnInfo {
  944. function getReturnDescription() {}
  945. }
  946. class ezcReflectionMethod extends ReflectionMethod {
  947. use ezcReflectionReturnInfo;function afterUseTrait(){}function afterUseTrait2(){}
  948. }',
  949. ];
  950. }
  951. /**
  952. * @dataProvider provideMessyWhitespacesCases
  953. */
  954. public function testMessyWhitespaces(string $expected, ?string $input = null): void
  955. {
  956. $this->fixer->setWhitespacesConfig(new WhitespacesFixerConfig("\t", "\r\n"));
  957. $this->doTest($expected, $input);
  958. }
  959. public static function provideMessyWhitespacesCases(): iterable
  960. {
  961. yield [
  962. "<?php\r\nclass SomeClass\r\n{\r\n // comment\n\n public function echoA()\r\n {\r\n echo 'a';\r\n }\r\n}\r\n",
  963. "<?php\r\nclass SomeClass\r\n{\r\n // comment\n\n\n public function echoA()\r\n {\r\n echo 'a';\r\n }\r\n}\r\n",
  964. ];
  965. yield [
  966. "<?php\r\nclass SomeClass\r\n{\r\n // comment\r\n\r\n public function echoA()\r\n {\r\n echo 'a';\r\n }\r\n}\r\n",
  967. "<?php\r\nclass SomeClass\r\n{\r\n // comment\r\n\r\n\r\n public function echoA()\r\n {\r\n echo 'a';\r\n }\r\n}\r\n",
  968. ];
  969. }
  970. /**
  971. * @param array<string, mixed> $config
  972. *
  973. * @dataProvider provideWithConfigCases
  974. */
  975. public function testWithConfig(string $expected, ?string $input, array $config): void
  976. {
  977. $this->fixer->configure($config);
  978. $this->doTest($expected, $input);
  979. }
  980. public static function provideWithConfigCases(): iterable
  981. {
  982. yield 'multi line property' => [
  983. '<?php class Foo
  984. {
  985. private $prop = [
  986. 1 => true,
  987. 2 => false,
  988. ];
  989. // comment2
  990. private $bar = 1;
  991. }',
  992. '<?php class Foo
  993. {
  994. private $prop = [
  995. 1 => true,
  996. 2 => false,
  997. ]; // comment2
  998. private $bar = 1;
  999. }',
  1000. ['elements' => ['property' => 'one']],
  1001. ];
  1002. yield 'trait group import none' => [
  1003. '<?php class Foo
  1004. {
  1005. use Ao;
  1006. use B0 { X0 as Y0;} // test
  1007. use A;
  1008. use B { X as Y;} // test
  1009. use Char;
  1010. use Bar {
  1011. __construct as barConstruct;
  1012. baz as barBaz;
  1013. }
  1014. use Dua;
  1015. }',
  1016. '<?php class Foo
  1017. {
  1018. use Ao;
  1019. use B0 { X0 as Y0;} // test
  1020. use A;
  1021. use B { X as Y;} // test
  1022. use Char;
  1023. use Bar {
  1024. __construct as barConstruct;
  1025. baz as barBaz;
  1026. }
  1027. use Dua;
  1028. }',
  1029. ['elements' => ['trait_import' => 'none']],
  1030. ];
  1031. yield [
  1032. '<?php
  1033. class Foo
  1034. {
  1035. /** A */
  1036. private $email;
  1037. private $foo0; #0 /* test */
  1038. private $foo1; #1
  1039. private $foo2; /* @2 */
  1040. }',
  1041. '<?php
  1042. class Foo
  1043. {
  1044. /** A */
  1045. private $email;
  1046. private $foo0; #0 /* test */
  1047. private $foo1; #1
  1048. private $foo2; /* @2 */
  1049. }',
  1050. ['elements' => ['property' => 'none']],
  1051. ];
  1052. yield [
  1053. '<?php
  1054. class Sample
  1055. {
  1056. /** @var int */
  1057. const FOO = 1;
  1058. /** @var int */
  1059. const BAR = 2;
  1060. const BAZ = 3;
  1061. const OTHER = 4;
  1062. const OTHER2 = 5;
  1063. }',
  1064. '<?php
  1065. class Sample
  1066. {
  1067. /** @var int */
  1068. const FOO = 1;
  1069. /** @var int */
  1070. const BAR = 2;
  1071. const BAZ = 3;
  1072. const OTHER = 4;
  1073. const OTHER2 = 5;
  1074. }',
  1075. ['elements' => ['const' => 'none']],
  1076. ];
  1077. yield 'multiple trait import 5954' => [
  1078. '<?php
  1079. class Foo
  1080. {
  1081. use Bar, Baz;
  1082. }',
  1083. null,
  1084. ['elements' => ['method' => 'one']],
  1085. ];
  1086. yield 'multiple trait import with method 5954' => [
  1087. '<?php
  1088. class Foo
  1089. {
  1090. use Bar, Baz;
  1091. public function f() {}
  1092. }',
  1093. '<?php
  1094. class Foo
  1095. {
  1096. use Bar, Baz;
  1097. public function f() {}
  1098. }',
  1099. ['elements' => ['method' => 'one']],
  1100. ];
  1101. yield 'trait group import 5843' => [
  1102. '<?php
  1103. class Foo
  1104. {
  1105. use Ao;
  1106. use B0 { X0 as Y0;} // test
  1107. use A;
  1108. use B { X as Y;} // test
  1109. use Char;
  1110. use Bar {
  1111. __construct as barConstruct;
  1112. baz as barBaz;
  1113. }
  1114. use Dua;
  1115. public function aaa()
  1116. {
  1117. }
  1118. }',
  1119. '<?php
  1120. class Foo
  1121. {
  1122. use Ao;
  1123. use B0 { X0 as Y0;} // test
  1124. use A;
  1125. use B { X as Y;} // test
  1126. use Char;
  1127. use Bar {
  1128. __construct as barConstruct;
  1129. baz as barBaz;
  1130. }
  1131. use Dua;
  1132. public function aaa()
  1133. {
  1134. }
  1135. }',
  1136. ['elements' => ['method' => 'one', 'trait_import' => 'one']],
  1137. ];
  1138. yield [
  1139. '<?php
  1140. class Foo
  1141. {
  1142. use SomeTrait1;
  1143. use SomeTrait2;
  1144. public function Bar(){}
  1145. }
  1146. ',
  1147. '<?php
  1148. class Foo
  1149. {
  1150. use SomeTrait1;
  1151. use SomeTrait2;
  1152. public function Bar(){}
  1153. }
  1154. ',
  1155. ['elements' => ['method' => 'one', 'trait_import' => 'one']],
  1156. ];
  1157. yield 'trait group import 5852' => [
  1158. '<?php
  1159. class Foo
  1160. {
  1161. use A;
  1162. use B;
  1163. /**
  1164. *
  1165. */
  1166. public function A(){}
  1167. }',
  1168. '<?php
  1169. class Foo
  1170. {
  1171. use A;
  1172. use B;
  1173. /**
  1174. *
  1175. */
  1176. public function A(){}
  1177. }',
  1178. ['elements' => ['const' => 'one', 'method' => 'one', 'property' => 'one', 'trait_import' => 'none']],
  1179. ];
  1180. yield [
  1181. '<?php
  1182. abstract class Example
  1183. {
  1184. use SomeTrait;
  1185. use AnotherTrait;
  1186. public $property;
  1187. abstract public function method(): void;
  1188. }',
  1189. '<?php
  1190. abstract class Example
  1191. {
  1192. use SomeTrait;
  1193. use AnotherTrait;
  1194. public $property;
  1195. abstract public function method(): void;
  1196. }',
  1197. ['elements' => ['const' => 'one', 'method' => 'one', 'property' => 'one']],
  1198. ];
  1199. yield [
  1200. '<?php
  1201. class A
  1202. {
  1203. private $a = null;
  1204. public $b = 1;
  1205. function A() {}
  1206. }
  1207. ',
  1208. '<?php
  1209. class A
  1210. {
  1211. private $a = null;
  1212. public $b = 1;
  1213. function A() {}
  1214. }
  1215. ',
  1216. ['elements' => ['property' => 'one']],
  1217. ];
  1218. yield [
  1219. '<?php
  1220. class A
  1221. {
  1222. private $a = null;
  1223. public $b = 1;
  1224. function A() {}
  1225. }
  1226. ',
  1227. '<?php
  1228. class A
  1229. {
  1230. private $a = null;
  1231. public $b = 1;
  1232. function A() {}
  1233. }
  1234. ',
  1235. ['elements' => ['property' => 'none']],
  1236. ];
  1237. yield [
  1238. '<?php
  1239. class A
  1240. {
  1241. const A = 1;
  1242. const THREE = ONE + self::TWO; /* test */ # test
  1243. const B = 2;
  1244. }
  1245. ',
  1246. '<?php
  1247. class A
  1248. {
  1249. const A = 1;
  1250. const THREE = ONE + self::TWO; /* test */ # test
  1251. const B = 2;
  1252. }
  1253. ',
  1254. ['elements' => ['const' => 'one']],
  1255. ];
  1256. yield [
  1257. '<?php
  1258. class A
  1259. {
  1260. const A = 1;
  1261. const THREE = ONE + self::TWO;
  1262. const B = 2;
  1263. }
  1264. ',
  1265. '<?php
  1266. class A
  1267. {
  1268. const A = 1;
  1269. const THREE = ONE + self::TWO;
  1270. const B = 2;
  1271. }
  1272. ',
  1273. ['elements' => ['const' => 'none']],
  1274. ];
  1275. yield [
  1276. '<?php
  1277. class A
  1278. {
  1279. function D() {}
  1280. function B4() {}
  1281. }
  1282. ',
  1283. '<?php
  1284. class A
  1285. {
  1286. function D() {}
  1287. function B4() {}
  1288. }
  1289. ',
  1290. ['elements' => ['method' => 'one']],
  1291. ];
  1292. yield [
  1293. '<?php
  1294. class A
  1295. {
  1296. function A() {}
  1297. function B() {}
  1298. }
  1299. ',
  1300. '<?php
  1301. class A
  1302. {
  1303. function A() {}
  1304. function B() {}
  1305. }
  1306. ',
  1307. ['elements' => ['method' => 'none']],
  1308. ];
  1309. yield [
  1310. '<?php
  1311. class A
  1312. {
  1313. private $x;
  1314. private $y;
  1315. final function f1() {}
  1316. final function f2() {}
  1317. }
  1318. ',
  1319. '<?php
  1320. class A
  1321. {
  1322. private $x;
  1323. private $y;
  1324. final function f1() {}
  1325. final function f2() {}
  1326. }
  1327. ',
  1328. ['elements' => ['property' => 'none', 'method' => 'one']],
  1329. ];
  1330. yield [
  1331. '<?php
  1332. class A
  1333. {
  1334. const FOO = 1;
  1335. const BAR = 2;
  1336. function f1() {}
  1337. function f2() {}
  1338. }
  1339. ',
  1340. '<?php
  1341. class A
  1342. {
  1343. const FOO = 1;
  1344. const BAR = 2;
  1345. function f1() {}
  1346. function f2() {}
  1347. }
  1348. ',
  1349. ['elements' => ['const' => 'none', 'method' => 'one']],
  1350. ];
  1351. yield [
  1352. '<?php
  1353. class A
  1354. {
  1355. const FOO = 1;
  1356. const BAR = 2;
  1357. public function f1() {}
  1358. public function f2() {}
  1359. }
  1360. ',
  1361. '<?php
  1362. class A
  1363. {
  1364. const FOO = 1;
  1365. const BAR = 2;
  1366. public function f1() {}
  1367. public function f2() {}
  1368. }
  1369. ',
  1370. ['elements' => ['const' => 'none', 'method' => 'one']],
  1371. ];
  1372. yield [
  1373. '<?php
  1374. class A
  1375. {
  1376. const B = 2;
  1377. const FOO = 1;
  1378. const BAR = 2;
  1379. /** @var int */
  1380. const BAZ = 3;
  1381. /** @var int */
  1382. const NEW = 4;
  1383. /** @var int */
  1384. const A = 5;
  1385. }
  1386. ',
  1387. '<?php
  1388. class A
  1389. {
  1390. const B = 2;
  1391. const FOO = 1;
  1392. const BAR = 2;
  1393. /** @var int */
  1394. const BAZ = 3;
  1395. /** @var int */
  1396. const NEW = 4;
  1397. /** @var int */
  1398. const A = 5;
  1399. }
  1400. ',
  1401. ['elements' => ['const' => 'only_if_meta']],
  1402. ];
  1403. yield [
  1404. '<?php
  1405. class B
  1406. {
  1407. public $foo;
  1408. /** @var string */
  1409. public $bar;
  1410. public $baz;
  1411. }
  1412. ',
  1413. '<?php
  1414. class B
  1415. {
  1416. public $foo;
  1417. /** @var string */
  1418. public $bar;
  1419. public $baz;
  1420. }
  1421. ',
  1422. ['elements' => ['property' => 'only_if_meta']],
  1423. ];
  1424. yield [
  1425. '<?php
  1426. class C
  1427. {
  1428. public function f1() {}
  1429. public function f2() {}
  1430. public function f3() {}
  1431. /** @return string */
  1432. public function f4() {}
  1433. }
  1434. ',
  1435. '<?php
  1436. class C
  1437. {
  1438. public function f1() {}
  1439. public function f2() {}
  1440. public function f3() {}
  1441. /** @return string */
  1442. public function f4() {}
  1443. }
  1444. ',
  1445. ['elements' => ['method' => 'only_if_meta']],
  1446. ];
  1447. yield [
  1448. '<?php
  1449. class Sample
  1450. {
  1451. /** @var int */
  1452. const ART = 1;
  1453. const SCIENCE = 2;
  1454. /** @var string */
  1455. public $a;
  1456. /** @var int */
  1457. public $b;
  1458. public $c;
  1459. /**
  1460. * @param string $a
  1461. * @param int $b
  1462. * @param int $c
  1463. */
  1464. public function __construct($a, $b, $c) {}
  1465. public function __destruct() {}
  1466. }
  1467. ',
  1468. '<?php
  1469. class Sample
  1470. {
  1471. /** @var int */
  1472. const ART = 1;
  1473. const SCIENCE = 2;
  1474. /** @var string */
  1475. public $a;
  1476. /** @var int */
  1477. public $b;
  1478. public $c;
  1479. /**
  1480. * @param string $a
  1481. * @param int $b
  1482. * @param int $c
  1483. */
  1484. public function __construct($a, $b, $c) {}
  1485. public function __destruct() {}
  1486. }
  1487. ',
  1488. ['elements' => ['const' => 'only_if_meta', 'property' => 'only_if_meta', 'method' => 'only_if_meta']],
  1489. ];
  1490. yield [
  1491. '<?php
  1492. class A
  1493. {
  1494. use A;
  1495. use B;
  1496. private $a = null;
  1497. public $b = 1;
  1498. }
  1499. ',
  1500. '<?php
  1501. class A
  1502. {
  1503. use A;
  1504. use B;
  1505. private $a = null;
  1506. public $b = 1;
  1507. }
  1508. ',
  1509. ['elements' => ['property' => 'none', 'trait_import' => 'none']],
  1510. ];
  1511. }
  1512. /**
  1513. * @dataProvider provideFix71Cases
  1514. */
  1515. public function testFix71(string $expected, string $input): void
  1516. {
  1517. $this->fixer->configure([
  1518. 'elements' => ['method' => 'one', 'const' => 'one'],
  1519. ]);
  1520. $this->doTest($expected, $input);
  1521. }
  1522. public static function provideFix71Cases(): iterable
  1523. {
  1524. yield [
  1525. '<?php
  1526. class Foo {
  1527. public function H1(){}
  1528. /** */
  1529. public const BAR = 123;
  1530. /** */
  1531. private const BAZ = "a";
  1532. }',
  1533. '<?php
  1534. class Foo {
  1535. public function H1(){}
  1536. /** */
  1537. public const BAR = 123;
  1538. /** */
  1539. private const BAZ = "a";
  1540. }',
  1541. ];
  1542. }
  1543. /**
  1544. * @param array<string, mixed> $config
  1545. *
  1546. * @dataProvider provideFix74Cases
  1547. */
  1548. public function testFix74(string $expected, ?string $input = null, array $config = []): void
  1549. {
  1550. $this->fixer->configure($config);
  1551. $this->doTest($expected, $input);
  1552. }
  1553. public static function provideFix74Cases(): iterable
  1554. {
  1555. yield [
  1556. '<?php
  1557. class Foo {
  1558. private ?int $foo;
  1559. protected string $bar;
  1560. public iterable $baz;
  1561. var ? Foo\Bar $qux;
  1562. }',
  1563. '<?php
  1564. class Foo {
  1565. private ?int $foo;
  1566. protected string $bar;
  1567. public iterable $baz;
  1568. var ? Foo\Bar $qux;
  1569. }',
  1570. ];
  1571. yield [
  1572. '<?php
  1573. class Foo {
  1574. private array $foo;
  1575. private array $bar;
  1576. }',
  1577. '<?php
  1578. class Foo {
  1579. private array $foo;
  1580. private array $bar;
  1581. }',
  1582. ];
  1583. yield [
  1584. '<?php
  1585. class Entity
  1586. {
  1587. /**
  1588. * @ORM\Column(name="one", type="text")
  1589. */
  1590. private string $one;
  1591. /**
  1592. * @ORM\Column(name="two", type="text")
  1593. */
  1594. private string $two;
  1595. private string $three;
  1596. private string $four;
  1597. private string $five;
  1598. }',
  1599. '<?php
  1600. class Entity
  1601. {
  1602. /**
  1603. * @ORM\Column(name="one", type="text")
  1604. */
  1605. private string $one;
  1606. /**
  1607. * @ORM\Column(name="two", type="text")
  1608. */
  1609. private string $two;
  1610. private string $three;
  1611. private string $four;
  1612. private string $five;
  1613. }',
  1614. ['elements' => ['property' => 'only_if_meta']],
  1615. ];
  1616. }
  1617. /**
  1618. * @param array<string, mixed> $config
  1619. *
  1620. * @dataProvider provideFixPhp80Cases
  1621. *
  1622. * @requires PHP 8.0
  1623. */
  1624. public function testFixPhp80(string $expected, ?string $input, array $config = []): void
  1625. {
  1626. $this->fixer->configure($config);
  1627. $this->doTest($expected, $input);
  1628. }
  1629. public static function provideFixPhp80Cases(): iterable
  1630. {
  1631. yield 'attributes' => [
  1632. '<?php
  1633. class User1
  1634. {
  1635. #[ORM\Id, ORM\Column("integer"), ORM\GeneratedValue]
  1636. private $id;
  1637. #[ORM\Column("string", ORM\Column::UNIQUE)]
  1638. #[Assert\String()]
  1639. #[Assert\Email(["message" => "The email {{ value }} is not a valid email."])]
  1640. private $email;
  1641. #[Assert\String()]
  1642. private $name;
  1643. }',
  1644. '<?php
  1645. class User1
  1646. {
  1647. #[ORM\Id, ORM\Column("integer"), ORM\GeneratedValue]
  1648. private $id;
  1649. #[ORM\Column("string", ORM\Column::UNIQUE)]
  1650. #[Assert\String()]
  1651. #[Assert\Email(["message" => "The email {{ value }} is not a valid email."])]
  1652. private $email;
  1653. #[Assert\String()]
  1654. private $name;
  1655. }',
  1656. ];
  1657. yield 'attributes minimal' => [
  1658. '<?php
  1659. class User2{
  1660. #[ORM\Id, ORM\Column("integer"), ORM\GeneratedValue]
  1661. private $id;
  1662. }',
  1663. '<?php
  1664. class User2{#[ORM\Id, ORM\Column("integer"), ORM\GeneratedValue] private $id;}',
  1665. ];
  1666. yield 'attribute block' => [
  1667. '<?php
  1668. class User3
  1669. {
  1670. private $id;
  1671. #[ORM\Column("string")]
  1672. #[Assert\Email(["message" => "Foo"])]
  1673. private $email;
  1674. }',
  1675. '<?php
  1676. class User3
  1677. {
  1678. private $id;
  1679. #[ORM\Column("string")]
  1680. #[Assert\Email(["message" => "Foo"])] private $email;
  1681. }',
  1682. ];
  1683. yield 'constructor property promotion' => [
  1684. '<?php
  1685. class Foo {
  1686. private array $foo;
  1687. private array $bar;
  1688. public function __construct(
  1689. public float $x = 0.0,
  1690. protected float $y = 0.0,
  1691. private float $z = 0.0,
  1692. ) {}
  1693. }',
  1694. '<?php
  1695. class Foo {
  1696. private array $foo;
  1697. private array $bar;
  1698. public function __construct(
  1699. public float $x = 0.0,
  1700. protected float $y = 0.0,
  1701. private float $z = 0.0,
  1702. ) {}
  1703. }',
  1704. ];
  1705. yield 'typed properties' => [
  1706. '<?php
  1707. class Foo {
  1708. private static int | float | null $a;
  1709. private static int | float | null $b;
  1710. private int | float | null $c;
  1711. private int | float | null $d;
  1712. }',
  1713. '<?php
  1714. class Foo {
  1715. private static int | float | null $a;
  1716. private static int | float | null $b;
  1717. private int | float | null $c;
  1718. private int | float | null $d;
  1719. }',
  1720. ];
  1721. yield 'attributes with conditional spacing' => [
  1722. '<?php
  1723. class User
  1724. {
  1725. private $id;
  1726. #[Assert\String()]
  1727. private $name;
  1728. private $email;
  1729. }
  1730. ',
  1731. '<?php
  1732. class User
  1733. {
  1734. private $id;
  1735. #[Assert\String()]
  1736. private $name;
  1737. private $email;
  1738. }
  1739. ',
  1740. ['elements' => ['property' => 'only_if_meta']],
  1741. ];
  1742. yield 'mixed attributes and phpdoc with conditional spacing' => [
  1743. '<?php
  1744. class User
  1745. {
  1746. private $id;
  1747. /** @var string */
  1748. #[Assert\Email(["message" => "Foo"])]
  1749. private $email;
  1750. #[Assert\String()]
  1751. #[ORM\Column()]
  1752. private $place;
  1753. #[ORM\Column()]
  1754. /** @var string */
  1755. private $hash;
  1756. /** @var string **/
  1757. #[ORM\Column()]
  1758. /** @internal */
  1759. private $updatedAt;
  1760. }
  1761. ',
  1762. '<?php
  1763. class User
  1764. {
  1765. private $id;
  1766. /** @var string */
  1767. #[Assert\Email(["message" => "Foo"])]
  1768. private $email;
  1769. #[Assert\String()]
  1770. #[ORM\Column()]
  1771. private $place;
  1772. #[ORM\Column()]
  1773. /** @var string */
  1774. private $hash;
  1775. /** @var string **/
  1776. #[ORM\Column()]
  1777. /** @internal */
  1778. private $updatedAt;
  1779. }
  1780. ',
  1781. ['elements' => ['property' => 'only_if_meta']],
  1782. ];
  1783. yield [
  1784. '<?php
  1785. class Foo
  1786. {
  1787. #[Assert\Email(["message" => "Foo"])]
  1788. private $email;
  1789. private $foo1; #1
  1790. private $foo2; /* @2 */
  1791. }',
  1792. '<?php
  1793. class Foo
  1794. {
  1795. #[Assert\Email(["message" => "Foo"])]
  1796. private $email;
  1797. private $foo1; #1
  1798. private $foo2; /* @2 */
  1799. }',
  1800. ['elements' => ['property' => 'none']],
  1801. ];
  1802. }
  1803. /**
  1804. * @dataProvider provideFixClassesWithTraitsCases
  1805. */
  1806. public function testFixClassesWithTraits(string $expected, ?string $input = null): void
  1807. {
  1808. $this->doTest($expected, $input);
  1809. }
  1810. public static function provideFixClassesWithTraitsCases(): iterable
  1811. {
  1812. yield [
  1813. '<?php
  1814. class Foo
  1815. {
  1816. use SomeTrait1;
  1817. use SomeTrait2;
  1818. public function Bar(){}
  1819. }
  1820. ',
  1821. '<?php
  1822. class Foo
  1823. {
  1824. use SomeTrait1;
  1825. use SomeTrait2;
  1826. public function Bar(){}
  1827. }
  1828. ',
  1829. ];
  1830. }
  1831. /**
  1832. * @param array<string, mixed> $config
  1833. *
  1834. * @dataProvider provideFix81Cases
  1835. *
  1836. * @requires PHP 8.1
  1837. */
  1838. public function testFix81(string $expected, ?string $input, array $config = []): void
  1839. {
  1840. $this->fixer->configure($config);
  1841. $this->doTest($expected, $input);
  1842. }
  1843. public static function provideFix81Cases(): iterable
  1844. {
  1845. yield [
  1846. '<?php class A {
  1847. public int $a0;
  1848. public readonly int $a1;
  1849. readonly public int $a2;
  1850. readonly int $a3;
  1851. public int $a4;
  1852. }',
  1853. '<?php class A {
  1854. public int $a0;
  1855. public readonly int $a1;
  1856. readonly public int $a2;
  1857. readonly int $a3;
  1858. public int $a4;
  1859. }',
  1860. ];
  1861. yield [
  1862. '<?php
  1863. class Foo
  1864. {
  1865. final public const B1 = "1";
  1866. public final const B2 = "2";
  1867. final const B3 = "3";
  1868. }
  1869. ',
  1870. '<?php
  1871. class Foo
  1872. {
  1873. final public const B1 = "1";
  1874. public final const B2 = "2";
  1875. final const B3 = "3";
  1876. }
  1877. ',
  1878. ];
  1879. yield 'intersection properties' => [
  1880. '<?php
  1881. class Foo {
  1882. private static Bar & Something & Baz $a;
  1883. private static Bar & Something & Baz $b;
  1884. private Bar & Something & Baz $c;
  1885. private Bar & Something & Baz $d;
  1886. }',
  1887. '<?php
  1888. class Foo {
  1889. private static Bar & Something & Baz $a;
  1890. private static Bar & Something & Baz $b;
  1891. private Bar & Something & Baz $c;
  1892. private Bar & Something & Baz $d;
  1893. }',
  1894. ];
  1895. $input = '<?php
  1896. enum Cards: string
  1897. {
  1898. protected const Deck = "d.d";
  1899. protected const Pack = "p.p";
  1900. case Hearts = "H";
  1901. case Spades = "S";
  1902. case Diamonds = "D";
  1903. case Clubs = "C";
  1904. protected function test() {
  1905. echo 1;
  1906. }
  1907. protected function test2() {
  1908. echo 2;
  1909. }
  1910. }
  1911. ';
  1912. yield [
  1913. '<?php
  1914. enum Cards: string
  1915. {
  1916. protected const Deck = "d.d";
  1917. protected const Pack = "p.p";
  1918. case Hearts = "H";
  1919. case Spades = "S";
  1920. case Diamonds = "D";
  1921. case Clubs = "C";
  1922. protected function test() {
  1923. echo 1;
  1924. }
  1925. protected function test2() {
  1926. echo 2;
  1927. }
  1928. }
  1929. ',
  1930. $input,
  1931. ['elements' => [
  1932. 'const' => 'one',
  1933. 'method' => 'one',
  1934. 'case' => 'one',
  1935. ]],
  1936. ];
  1937. yield [
  1938. '<?php
  1939. enum Cards: string
  1940. {
  1941. protected const Deck = "d.d";
  1942. protected const Pack = "p.p";
  1943. case Hearts = "H";
  1944. case Spades = "S";
  1945. case Diamonds = "D";
  1946. case Clubs = "C";
  1947. protected function test() {
  1948. echo 1;
  1949. }
  1950. protected function test2() {
  1951. echo 2;
  1952. }
  1953. }
  1954. ',
  1955. $input,
  1956. ['elements' => [
  1957. 'const' => 'none',
  1958. 'method' => 'one',
  1959. 'case' => 'none',
  1960. ]],
  1961. ];
  1962. }
  1963. /**
  1964. * @dataProvider provideFix82Cases
  1965. *
  1966. * @requires PHP 8.2
  1967. */
  1968. public function testFix82(string $expected, ?string $input = null): void
  1969. {
  1970. $this->doTest($expected, $input);
  1971. }
  1972. public static function provideFix82Cases(): iterable
  1973. {
  1974. yield [
  1975. '<?php
  1976. trait Foo {
  1977. const Bar = 1;
  1978. const Baz = 2;
  1979. }',
  1980. '<?php
  1981. trait Foo {
  1982. const Bar = 1;
  1983. const Baz = 2;
  1984. }',
  1985. ];
  1986. }
  1987. }