PhpdocToPropertyTypeFixerTest.php 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454
  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\FunctionNotation;
  13. use PhpCsFixer\Tests\Test\AbstractFixerTestCase;
  14. /**
  15. * @internal
  16. *
  17. * @covers \PhpCsFixer\Fixer\FunctionNotation\PhpdocToPropertyTypeFixer
  18. */
  19. final class PhpdocToPropertyTypeFixerTest extends AbstractFixerTestCase
  20. {
  21. /**
  22. * @dataProvider provideFixCases
  23. */
  24. public function testFix(string $expected, ?string $input = null, array $config = []): void
  25. {
  26. if (null !== $input && \PHP_VERSION_ID < 70400) {
  27. $expected = $input;
  28. $input = null;
  29. }
  30. $this->fixer->configure($config);
  31. $this->doTest($expected, $input);
  32. }
  33. public function provideFixCases(): array
  34. {
  35. return [
  36. 'no phpdoc return' => [
  37. '<?php class Foo { private $foo; }',
  38. ],
  39. 'invalid return' => [
  40. '<?php class Foo { /** @var */ private $foo; }',
  41. ],
  42. 'invalid class 1' => [
  43. '<?php class Foo { /** @var \9 */ private $foo; }',
  44. ],
  45. 'invalid class 2' => [
  46. '<?php class Foo { /** @var \\Foo\\\\Bar */ private $foo; }',
  47. ],
  48. 'multiple returns' => [
  49. '<?php
  50. class Foo {
  51. /**
  52. * @var Bar
  53. * @var Baz
  54. */
  55. private $foo;
  56. }
  57. ',
  58. ],
  59. 'non-root class' => [
  60. '<?php class Foo { /** @var Bar */ private Bar $foo; }',
  61. '<?php class Foo { /** @var Bar */ private $foo; }',
  62. ],
  63. 'non-root namespaced class' => [
  64. '<?php class Foo { /** @var My\Bar */ private My\Bar $foo; }',
  65. '<?php class Foo { /** @var My\Bar */ private $foo; }',
  66. ],
  67. 'root class' => [
  68. '<?php class Foo { /** @var \My\Bar */ private \My\Bar $foo; }',
  69. '<?php class Foo { /** @var \My\Bar */ private $foo; }',
  70. ],
  71. 'void' => [
  72. '<?php class Foo { /** @var void */ private $foo; }',
  73. ],
  74. 'never' => [
  75. '<?php class Foo { /** @var never */ private $foo; }',
  76. ],
  77. 'iterable' => [
  78. '<?php class Foo { /** @var iterable */ private iterable $foo; }',
  79. '<?php class Foo { /** @var iterable */ private $foo; }',
  80. ],
  81. 'object' => [
  82. '<?php class Foo { /** @var object */ private object $foo; }',
  83. '<?php class Foo { /** @var object */ private $foo; }',
  84. ],
  85. 'fix scalar types by default, int' => [
  86. '<?php class Foo { /** @var int */ private int $foo; }',
  87. '<?php class Foo { /** @var int */ private $foo; }',
  88. ],
  89. 'fix scalar types by default, float' => [
  90. '<?php class Foo { /** @var float */ private float $foo; }',
  91. '<?php class Foo { /** @var float */ private $foo; }',
  92. ],
  93. 'fix scalar types by default, string' => [
  94. '<?php class Foo { /** @var string */ private string $foo; }',
  95. '<?php class Foo { /** @var string */ private $foo; }',
  96. ],
  97. 'fix scalar types by default, bool' => [
  98. '<?php class Foo { /** @var bool */ private bool $foo; }',
  99. '<?php class Foo { /** @var bool */ private $foo; }',
  100. ],
  101. 'fix scalar types by default, false' => [
  102. '<?php class Foo { /** @var false */ private bool $foo; }',
  103. '<?php class Foo { /** @var false */ private $foo; }',
  104. ],
  105. 'fix scalar types by default, true' => [
  106. '<?php class Foo { /** @var true */ private bool $foo; }',
  107. '<?php class Foo { /** @var true */ private $foo; }',
  108. ],
  109. 'do not fix scalar types when configured as such' => [
  110. '<?php class Foo { /** @var int */ private $foo; }',
  111. null,
  112. ['scalar_types' => false],
  113. ],
  114. 'array native type' => [
  115. '<?php class Foo { /** @var array */ private array $foo; }',
  116. '<?php class Foo { /** @var array */ private $foo; }',
  117. ],
  118. 'callable type' => [
  119. '<?php class Foo { /** @var callable */ private $foo; }',
  120. ],
  121. 'self accessor' => [
  122. '<?php class Foo { /** @var self */ private self $foo; }',
  123. '<?php class Foo { /** @var self */ private $foo; }',
  124. ],
  125. 'report static as self' => [
  126. '<?php class Foo { /** @var static */ private self $foo; }',
  127. '<?php class Foo { /** @var static */ private $foo; }',
  128. ],
  129. 'skip resource special type' => [
  130. '<?php class Foo { /** @var resource */ private $foo; }',
  131. ],
  132. 'skip mixed special type' => [
  133. '<?php class Foo { /** @var mixed */ private $foo; }',
  134. ],
  135. 'null alone cannot be a property type' => [
  136. '<?php class Foo { /** @var null */ private $foo; }',
  137. ],
  138. 'skip mixed types' => [
  139. '<?php class Foo { /** @var Foo|Bar */ private $foo; }',
  140. ],
  141. 'nullable type' => [
  142. '<?php class Foo { /** @var null|Bar */ private ?Bar $foo; }',
  143. '<?php class Foo { /** @var null|Bar */ private $foo; }',
  144. ],
  145. 'nullable type reverse order' => [
  146. '<?php class Foo { /** @var Bar|null */ private ?Bar $foo; }',
  147. '<?php class Foo { /** @var Bar|null */ private $foo; }',
  148. ],
  149. 'nullable native type' => [
  150. '<?php class Foo { /** @var null|array */ private ?array $foo; }',
  151. '<?php class Foo { /** @var null|array */ private $foo; }',
  152. ],
  153. 'skip mixed nullable types' => [
  154. '<?php class Foo { /** @var null|Foo|Bar */ private $foo; }',
  155. ],
  156. 'generics' => [
  157. '<?php class Foo { /** @var array<int, bool> */ private array $foo; }',
  158. '<?php class Foo { /** @var array<int, bool> */ private $foo; }',
  159. ],
  160. 'array of types' => [
  161. '<?php class Foo { /** @var Foo[] */ private array $foo; }',
  162. '<?php class Foo { /** @var Foo[] */ private $foo; }',
  163. ],
  164. 'array of array of types' => [
  165. '<?php class Foo { /** @var Foo[][] */ private array $foo; }',
  166. '<?php class Foo { /** @var Foo[][] */ private $foo; }',
  167. ],
  168. 'nullable array of types' => [
  169. '<?php class Foo { /** @var null|Foo[] */ private ?array $foo; }',
  170. '<?php class Foo { /** @var null|Foo[] */ private $foo; }',
  171. ],
  172. 'comments' => [
  173. '<?php
  174. class Foo
  175. {
  176. // comment 0
  177. /** @var Foo */ # comment 1
  178. public/**/Foo $foo/**/;# comment 2
  179. }
  180. ',
  181. '<?php
  182. class Foo
  183. {
  184. // comment 0
  185. /** @var Foo */ # comment 1
  186. public/**/$foo/**/;# comment 2
  187. }
  188. ',
  189. ],
  190. 'array and traversable' => [
  191. '<?php class Foo { /** @var array|Traversable */ private iterable $foo; }',
  192. '<?php class Foo { /** @var array|Traversable */ private $foo; }',
  193. ],
  194. 'array and traversable with leading slash' => [
  195. '<?php class Foo { /** @var array|\Traversable */ private iterable $foo; }',
  196. '<?php class Foo { /** @var array|\Traversable */ private $foo; }',
  197. ],
  198. 'array and traversable in a namespace' => [
  199. '<?php
  200. namespace App;
  201. class Foo {
  202. /** @var array|Traversable */
  203. private $foo;
  204. }
  205. ',
  206. ],
  207. 'array and traversable with leading slash in a namespace' => [
  208. '<?php
  209. namespace App;
  210. class Foo {
  211. /** @var array|\Traversable */
  212. private iterable $foo;
  213. }
  214. ',
  215. '<?php
  216. namespace App;
  217. class Foo {
  218. /** @var array|\Traversable */
  219. private $foo;
  220. }
  221. ',
  222. ],
  223. 'array and imported traversable in a namespace' => [
  224. '<?php
  225. namespace App;
  226. use Traversable;
  227. class Foo {
  228. /** @var array|Traversable */
  229. private iterable $foo;
  230. }
  231. ',
  232. '<?php
  233. namespace App;
  234. use Traversable;
  235. class Foo {
  236. /** @var array|Traversable */
  237. private $foo;
  238. }
  239. ',
  240. ],
  241. 'array and object aliased as traversable in a namespace' => [
  242. '<?php
  243. namespace App;
  244. use Bar as Traversable;
  245. class Foo {
  246. /** @var array|Traversable */
  247. private $foo;
  248. }
  249. ',
  250. null,
  251. ],
  252. 'array of object and traversable' => [
  253. '<?php class Foo { /** @var Foo[]|Traversable */ private iterable $foo; }',
  254. '<?php class Foo { /** @var Foo[]|Traversable */ private $foo; }',
  255. ],
  256. 'array of object and iterable' => [
  257. '<?php class Foo { /** @var Foo[]|iterable */ private iterable $foo; }',
  258. '<?php class Foo { /** @var Foo[]|iterable */ private $foo; }',
  259. ],
  260. 'array of string and array of int' => [
  261. '<?php class Foo { /** @var string[]|int[] */ private array $foo; }',
  262. '<?php class Foo { /** @var string[]|int[] */ private $foo; }',
  263. ],
  264. 'trait' => [
  265. '<?php trait Foo { /** @var int */ private int $foo; }',
  266. '<?php trait Foo { /** @var int */ private $foo; }',
  267. ],
  268. 'static property' => [
  269. '<?php class Foo { /** @var int */ private static int $foo; }',
  270. '<?php class Foo { /** @var int */ private static $foo; }',
  271. ],
  272. 'static property reverse order' => [
  273. '<?php class Foo { /** @var int */ static private int $foo; }',
  274. '<?php class Foo { /** @var int */ static private $foo; }',
  275. ],
  276. 'var' => [
  277. '<?php class Foo { /** @var int */ var int $foo; }',
  278. '<?php class Foo { /** @var int */ var $foo; }',
  279. ],
  280. 'with default value' => [
  281. '<?php class Foo { /** @var int */ public int $foo = 1; }',
  282. '<?php class Foo { /** @var int */ public $foo = 1; }',
  283. ],
  284. 'multiple properties of the same type' => [
  285. '<?php class Foo {
  286. /**
  287. * @var int $foo
  288. * @var int $bar
  289. */
  290. public int $foo, $bar;
  291. }',
  292. '<?php class Foo {
  293. /**
  294. * @var int $foo
  295. * @var int $bar
  296. */
  297. public $foo, $bar;
  298. }',
  299. ],
  300. 'multiple properties of different types' => [
  301. '<?php class Foo {
  302. /**
  303. * @var int $foo
  304. * @var string $bar
  305. */
  306. public $foo, $bar;
  307. }',
  308. ],
  309. 'single property with different annotations' => [
  310. '<?php class Foo {
  311. /**
  312. * @var int $foo
  313. * @var string $foo
  314. */
  315. public $foo;
  316. }',
  317. ],
  318. 'multiple properties with missing annotation' => [
  319. '<?php class Foo {
  320. /**
  321. * @var int $foo
  322. */
  323. public $foo, $bar;
  324. }',
  325. ],
  326. 'multiple properties with annotation without name' => [
  327. '<?php class Foo {
  328. /**
  329. * @var int
  330. * @var int $bar
  331. */
  332. public $foo, $bar;
  333. }',
  334. ],
  335. 'multiple properties with annotation without name reverse order' => [
  336. '<?php class Foo {
  337. /**
  338. * @var int $foo
  339. * @var int
  340. */
  341. public $foo, $bar;
  342. }',
  343. ],
  344. 'multiple properties with extra annotations' => [
  345. '<?php class Foo {
  346. /**
  347. * @var string
  348. * @var int $foo
  349. * @var int $bar
  350. * @var int
  351. */
  352. public int $foo, $bar;
  353. }',
  354. '<?php class Foo {
  355. /**
  356. * @var string
  357. * @var int $foo
  358. * @var int $bar
  359. * @var int
  360. */
  361. public $foo, $bar;
  362. }',
  363. ],
  364. 'abstract method' => [
  365. '<?php abstract class Foo {
  366. /** @var Bar */ private Bar $foo;
  367. public abstract function getFoo();
  368. }',
  369. '<?php abstract class Foo {
  370. /** @var Bar */ private $foo;
  371. public abstract function getFoo();
  372. }',
  373. ],
  374. 'great number of properties' => [
  375. '<?php class Foo {
  376. /** @var string */
  377. private string $foo1;
  378. /** @var string */
  379. private string $foo2;
  380. /** @var int */
  381. private int $foo3;
  382. /** @var string */
  383. private string $foo4;
  384. /** @var string */
  385. private string $foo5;
  386. /** @var string */
  387. private string $foo6;
  388. /** @var string */
  389. private string $foo7;
  390. /** @var int */
  391. private int $foo8;
  392. /** @var string */
  393. private string $foo9;
  394. /** @var int|null */
  395. private ?int $foo10;
  396. }',
  397. '<?php class Foo {
  398. /** @var string */
  399. private $foo1;
  400. /** @var string */
  401. private $foo2;
  402. /** @var int */
  403. private $foo3;
  404. /** @var string */
  405. private $foo4;
  406. /** @var string */
  407. private $foo5;
  408. /** @var string */
  409. private $foo6;
  410. /** @var string */
  411. private $foo7;
  412. /** @var int */
  413. private $foo8;
  414. /** @var string */
  415. private $foo9;
  416. /** @var int|null */
  417. private $foo10;
  418. }',
  419. ],
  420. 'anonymous class' => [
  421. '<?php new class { /** @var int */ private int $foo; };',
  422. '<?php new class { /** @var int */ private $foo; };',
  423. ],
  424. ];
  425. }
  426. }