VoidReturnFixerTest.php 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380
  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. * @author Mark Nielsen
  16. *
  17. * @internal
  18. *
  19. * @covers \PhpCsFixer\Fixer\FunctionNotation\VoidReturnFixer
  20. *
  21. * @extends AbstractFixerTestCase<\PhpCsFixer\Fixer\FunctionNotation\VoidReturnFixer>
  22. */
  23. final class VoidReturnFixerTest extends AbstractFixerTestCase
  24. {
  25. /**
  26. * @dataProvider provideFixCases
  27. */
  28. public function testFix(string $expected, ?string $input = null): void
  29. {
  30. $this->doTest($expected, $input);
  31. }
  32. /**
  33. * @return iterable<array{string, 1?: ?string}>
  34. */
  35. public static function provideFixCases(): iterable
  36. {
  37. yield ['<?php class Test { public function __construct() {} }'];
  38. yield ['<?php class Test { public function __destruct() {} }'];
  39. yield ['<?php class Test { public function __clone() {} }'];
  40. yield ['<?php function foo($param) { return $param; }'];
  41. yield ['<?php function foo($param) { return null; }'];
  42. yield ['<?php function foo($param) { yield; }'];
  43. yield ['<?php function foo($param) { yield $param; }'];
  44. yield ['<?php function foo($param) { yield from test(); }'];
  45. yield ['<?php function foo($param): Void {}'];
  46. yield ['<?php interface Test { public function foo($param); }'];
  47. yield ['<?php function foo($param) { return function($a) use ($param): string {}; }'];
  48. yield ['<?php abstract class Test { abstract public function foo($param); }'];
  49. yield ['<?php use Foo\ { function Bar }; function test() { return Bar(); }'];
  50. yield ['<?php
  51. /**
  52. * @return array
  53. */
  54. function foo($param) {}
  55. '];
  56. yield ['<?php
  57. interface Test {
  58. /**
  59. * @return array
  60. */
  61. public function foo($param);
  62. }
  63. '];
  64. yield [
  65. '<?php function foo($param): void { return; }',
  66. '<?php function foo($param) { return; }',
  67. ];
  68. yield [
  69. '<?php function foo($param): void {}',
  70. '<?php function foo($param) {}',
  71. ];
  72. yield [
  73. '<?php class Test { public function foo($param): void { return; } }',
  74. '<?php class Test { public function foo($param) { return; } }',
  75. ];
  76. yield [
  77. '<?php class Test { public function foo($param): void {} }',
  78. '<?php class Test { public function foo($param) {} }',
  79. ];
  80. yield [
  81. '<?php trait Test { public function foo($param): void { return; } }',
  82. '<?php trait Test { public function foo($param) { return; } }',
  83. ];
  84. yield [
  85. '<?php trait Test { public function foo($param): void {} }',
  86. '<?php trait Test { public function foo($param) {} }',
  87. ];
  88. yield [
  89. '<?php $arr = []; usort($arr, function ($a, $b): void {});',
  90. '<?php $arr = []; usort($arr, function ($a, $b) {});',
  91. ];
  92. yield [
  93. '<?php $arr = []; $param = 1; usort($arr, function ($a, $b) use ($param): void {});',
  94. '<?php $arr = []; $param = 1; usort($arr, function ($a, $b) use ($param) {});',
  95. ];
  96. yield [
  97. '<?php function foo($param) { return function($a) use ($param): void {}; }',
  98. '<?php function foo($param) { return function($a) use ($param) {}; }',
  99. ];
  100. yield [
  101. '<?php function foo($param): void { $arr = []; usort($arr, function ($a, $b) use ($param): void {}); }',
  102. '<?php function foo($param) { $arr = []; usort($arr, function ($a, $b) use ($param) {}); }',
  103. ];
  104. yield [
  105. '<?php function foo() { $arr = []; return usort($arr, new class { public function __invoke($a, $b): void {} }); }',
  106. '<?php function foo() { $arr = []; return usort($arr, new class { public function __invoke($a, $b) {} }); }',
  107. ];
  108. yield [
  109. '<?php function foo(): void { $arr = []; usort($arr, new class { public function __invoke($a, $b): void {} }); }',
  110. '<?php function foo() { $arr = []; usort($arr, new class { public function __invoke($a, $b) {} }); }',
  111. ];
  112. yield [
  113. '<?php
  114. function foo(): void {
  115. $a = function (): void {};
  116. }',
  117. '<?php
  118. function foo() {
  119. $a = function () {};
  120. }',
  121. ];
  122. yield [
  123. '<?php
  124. function foo(): void {
  125. (function (): void {
  126. return;
  127. })();
  128. }',
  129. '<?php
  130. function foo() {
  131. (function () {
  132. return;
  133. })();
  134. }',
  135. ];
  136. yield [
  137. '<?php
  138. function foo(): void {
  139. (function () {
  140. return 1;
  141. })();
  142. }',
  143. '<?php
  144. function foo() {
  145. (function () {
  146. return 1;
  147. })();
  148. }',
  149. ];
  150. yield [
  151. '<?php
  152. function foo(): void {
  153. $b = new class {
  154. public function b1(): void {}
  155. public function b2() { return 2; }
  156. };
  157. }',
  158. '<?php
  159. function foo() {
  160. $b = new class {
  161. public function b1() {}
  162. public function b2() { return 2; }
  163. };
  164. }',
  165. ];
  166. yield [
  167. '<?php
  168. /**
  169. * @return void
  170. */
  171. function foo($param): void {}',
  172. '<?php
  173. /**
  174. * @return void
  175. */
  176. function foo($param) {}',
  177. ];
  178. yield [
  179. '<?php
  180. interface Test {
  181. /**
  182. * @return void
  183. */
  184. public function foo($param): void;
  185. }',
  186. '<?php
  187. interface Test {
  188. /**
  189. * @return void
  190. */
  191. public function foo($param);
  192. }',
  193. ];
  194. yield [
  195. '<?php
  196. abstract class Test {
  197. /**
  198. * @return void
  199. */
  200. abstract protected function foo($param): void;
  201. }',
  202. '<?php
  203. abstract class Test {
  204. /**
  205. * @return void
  206. */
  207. abstract protected function foo($param);
  208. }',
  209. ];
  210. yield [
  211. '<?php fn($a) => null;',
  212. ];
  213. yield [
  214. '<?php fn($a) => 1;',
  215. ];
  216. yield [
  217. '<?php fn($a) => var_dump($a);',
  218. ];
  219. $excluded = ['__clone', '__construct', '__debugInfo', '__destruct', '__isset', '__serialize', '__set_state', '__sleep', '__toString'];
  220. foreach (self::provideMagicMethodsDefinitions() as $magicMethodsDefinition) {
  221. $name = $magicMethodsDefinition[0];
  222. $arguments = $magicMethodsDefinition[1] ?? 0;
  223. $isStatic = $magicMethodsDefinition[2] ?? false;
  224. $code = \sprintf(
  225. '<?php class Test { public%s function %s(%s)%%s {} }',
  226. $isStatic ? ' static' : '',
  227. $name,
  228. implode(',', array_map(
  229. static fn (int $n): string => \sprintf('$x%d', $n),
  230. array_keys(array_fill(0, $arguments, true)),
  231. ))
  232. );
  233. $input = \sprintf($code, '');
  234. $expected = \sprintf($code, \in_array($name, $excluded, true) ? '' : ': void');
  235. yield \sprintf('Test if magic method %s is handled without causing syntax error', $name) => [
  236. $expected,
  237. $expected === $input ? null : $input,
  238. ];
  239. }
  240. }
  241. /**
  242. * @dataProvider provideFix80Cases
  243. *
  244. * @requires PHP 8.0
  245. */
  246. public function testFix80(string $expected, ?string $input = null): void
  247. {
  248. $this->doTest($expected, $input);
  249. }
  250. /**
  251. * @return iterable<array{string, 1?: ?string}>
  252. */
  253. public static function provideFix80Cases(): iterable
  254. {
  255. yield [
  256. '<?php
  257. class Foo
  258. {
  259. /**
  260. * @return int|false
  261. */
  262. #[\ReturnTypeWillChange]
  263. public function test() {}
  264. }
  265. ',
  266. ];
  267. yield [
  268. '<?php
  269. /**
  270. * @return void
  271. */
  272. #[\Deprecated]
  273. function test(): void {};
  274. ',
  275. '<?php
  276. /**
  277. * @return void
  278. */
  279. #[\Deprecated]
  280. function test() {};
  281. ',
  282. ];
  283. }
  284. /**
  285. * @return iterable<array{string, 1?: int, 2?: bool}>
  286. */
  287. private static function provideMagicMethodsDefinitions(): iterable
  288. {
  289. // List: https://www.php.net/manual/en/language.oop5.magic.php
  290. yield ['__construct'];
  291. yield ['__destruct'];
  292. yield ['__call', 2];
  293. yield ['__callStatic', 2, true];
  294. yield ['__get', 1];
  295. yield ['__set', 2];
  296. yield ['__isset', 1];
  297. yield ['__unset', 1];
  298. yield ['__sleep'];
  299. yield ['__wakeup'];
  300. yield ['__serialize'];
  301. yield ['__unserialize', 1];
  302. yield ['__toString'];
  303. yield ['__invoke'];
  304. yield ['__set_state', 1, true];
  305. yield ['__clone'];
  306. yield ['__debugInfo'];
  307. }
  308. }