NamespaceUsesAnalyzerTest.php 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615
  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\Tokenizer\Analyzer;
  13. use PhpCsFixer\Tests\TestCase;
  14. use PhpCsFixer\Tokenizer\Analyzer\Analysis\NamespaceAnalysis;
  15. use PhpCsFixer\Tokenizer\Analyzer\Analysis\NamespaceUseAnalysis;
  16. use PhpCsFixer\Tokenizer\Analyzer\NamespaceUsesAnalyzer;
  17. use PhpCsFixer\Tokenizer\Tokens;
  18. /**
  19. * @author VeeWee <toonverwerft@gmail.com>
  20. *
  21. * @internal
  22. *
  23. * @covers \PhpCsFixer\Tokenizer\Analyzer\NamespaceUsesAnalyzer
  24. */
  25. final class NamespaceUsesAnalyzerTest extends TestCase
  26. {
  27. /**
  28. * @param list<NamespaceUseAnalysis> $expected
  29. *
  30. * @dataProvider provideUsesFromTokensCases
  31. */
  32. public function testUsesFromTokens(string $code, array $expected, bool $allowMulti = false): void
  33. {
  34. $tokens = Tokens::fromCode($code);
  35. $analyzer = new NamespaceUsesAnalyzer();
  36. self::assertSame(
  37. serialize($expected),
  38. serialize($analyzer->getDeclarationsFromTokens($tokens, $allowMulti))
  39. );
  40. }
  41. /**
  42. * @return iterable<array{0: string, 1: list<NamespaceUseAnalysis>, 2?: bool}>
  43. */
  44. public static function provideUsesFromTokensCases(): iterable
  45. {
  46. yield ['<?php // no uses', []];
  47. yield ['<?php use Foo\Bar;', [
  48. new NamespaceUseAnalysis(
  49. NamespaceUseAnalysis::TYPE_CLASS,
  50. 'Foo\Bar',
  51. 'Bar',
  52. false,
  53. false,
  54. 1,
  55. 6
  56. ),
  57. ]];
  58. yield ['<?php use Foo\Bar; use Foo\Baz;', [
  59. new NamespaceUseAnalysis(
  60. NamespaceUseAnalysis::TYPE_CLASS,
  61. 'Foo\Bar',
  62. 'Bar',
  63. false,
  64. false,
  65. 1,
  66. 6
  67. ),
  68. new NamespaceUseAnalysis(
  69. NamespaceUseAnalysis::TYPE_CLASS,
  70. 'Foo\Baz',
  71. 'Baz',
  72. false,
  73. false,
  74. 8,
  75. 13,
  76. ),
  77. ]];
  78. yield ['<?php use \Foo\Bar;', [
  79. new NamespaceUseAnalysis(
  80. NamespaceUseAnalysis::TYPE_CLASS,
  81. '\Foo\Bar',
  82. 'Bar',
  83. false,
  84. false,
  85. 1,
  86. 7,
  87. ),
  88. ]];
  89. yield ['<?php use Foo\Bar as Baz;', [
  90. new NamespaceUseAnalysis(
  91. NamespaceUseAnalysis::TYPE_CLASS,
  92. 'Foo\Bar',
  93. 'Baz',
  94. true,
  95. false,
  96. 1,
  97. 10,
  98. ),
  99. ]];
  100. yield ['<?php use Foo\Bar as Baz; use Foo\Buz as Baz;', [
  101. new NamespaceUseAnalysis(
  102. NamespaceUseAnalysis::TYPE_CLASS,
  103. 'Foo\Bar',
  104. 'Baz',
  105. true,
  106. false,
  107. 1,
  108. 10,
  109. ),
  110. new NamespaceUseAnalysis(
  111. NamespaceUseAnalysis::TYPE_CLASS,
  112. 'Foo\Buz',
  113. 'Baz',
  114. true,
  115. false,
  116. 12,
  117. 21,
  118. ),
  119. ]];
  120. yield ['<?php use function My\count;', [
  121. new NamespaceUseAnalysis(
  122. NamespaceUseAnalysis::TYPE_FUNCTION,
  123. 'My\count',
  124. 'count',
  125. false,
  126. false,
  127. 1,
  128. 8,
  129. ),
  130. ]];
  131. yield ['<?php use function My\count as myCount;', [
  132. new NamespaceUseAnalysis(
  133. NamespaceUseAnalysis::TYPE_FUNCTION,
  134. 'My\count',
  135. 'myCount',
  136. true,
  137. false,
  138. 1,
  139. 12,
  140. ),
  141. ]];
  142. yield ['<?php use const My\Full\CONSTANT;', [
  143. new NamespaceUseAnalysis(
  144. NamespaceUseAnalysis::TYPE_CONSTANT,
  145. 'My\Full\CONSTANT',
  146. 'CONSTANT',
  147. false,
  148. false,
  149. 1,
  150. 10,
  151. ),
  152. ]];
  153. yield 'Comma-separated class import with multi-use parsing disabled' => ['<?php use Foo\Bar, Foo\Baz;', [], false];
  154. yield 'Group class import with multi-use parsing disabled' => ['<?php use Foo\{Bar, Baz};', [], false];
  155. yield 'Comma-separated class import' => ['<?php use Foo\Bar, Foo\Baz;', [
  156. new NamespaceUseAnalysis(
  157. NamespaceUseAnalysis::TYPE_CLASS,
  158. 'Foo\Bar',
  159. 'Bar',
  160. false,
  161. true,
  162. 1,
  163. 11,
  164. 3,
  165. 5
  166. ),
  167. new NamespaceUseAnalysis(
  168. NamespaceUseAnalysis::TYPE_CLASS,
  169. 'Foo\Baz',
  170. 'Baz',
  171. false,
  172. true,
  173. 1,
  174. 11,
  175. 8,
  176. 10
  177. ),
  178. ], true];
  179. yield 'group class import' => ['<?php use Foo\{Bar, Baz};', [
  180. new NamespaceUseAnalysis(
  181. NamespaceUseAnalysis::TYPE_CLASS,
  182. 'Foo\Bar',
  183. 'Bar',
  184. false,
  185. true,
  186. 1,
  187. 11,
  188. 6,
  189. 6
  190. ),
  191. new NamespaceUseAnalysis(
  192. NamespaceUseAnalysis::TYPE_CLASS,
  193. 'Foo\Baz',
  194. 'Baz',
  195. false,
  196. true,
  197. 1,
  198. 11,
  199. 9,
  200. 9
  201. ),
  202. ], true];
  203. yield 'Comma-separated function import' => ['<?php use function Foo\bar, Foo\baz;', [
  204. new NamespaceUseAnalysis(
  205. NamespaceUseAnalysis::TYPE_FUNCTION,
  206. 'Foo\bar',
  207. 'bar',
  208. false,
  209. true,
  210. 1,
  211. 13,
  212. 5,
  213. 7
  214. ),
  215. new NamespaceUseAnalysis(
  216. NamespaceUseAnalysis::TYPE_FUNCTION,
  217. 'Foo\baz',
  218. 'baz',
  219. false,
  220. true,
  221. 1,
  222. 13,
  223. 10,
  224. 12
  225. ),
  226. ], true];
  227. yield 'group function import' => ['<?php use function Foo\{bar, baz};', [
  228. new NamespaceUseAnalysis(
  229. NamespaceUseAnalysis::TYPE_FUNCTION,
  230. 'Foo\bar',
  231. 'bar',
  232. false,
  233. true,
  234. 1,
  235. 13,
  236. 8,
  237. 8
  238. ),
  239. new NamespaceUseAnalysis(
  240. NamespaceUseAnalysis::TYPE_FUNCTION,
  241. 'Foo\baz',
  242. 'baz',
  243. false,
  244. true,
  245. 1,
  246. 13,
  247. 11,
  248. 11
  249. ),
  250. ], true];
  251. yield 'Comma-separated constant import' => ['<?php use const Foo\BAR, Foo\BAZ;', [
  252. new NamespaceUseAnalysis(
  253. NamespaceUseAnalysis::TYPE_CONSTANT,
  254. 'Foo\BAR',
  255. 'BAR',
  256. false,
  257. true,
  258. 1,
  259. 13,
  260. 5,
  261. 7
  262. ),
  263. new NamespaceUseAnalysis(
  264. NamespaceUseAnalysis::TYPE_CONSTANT,
  265. 'Foo\BAZ',
  266. 'BAZ',
  267. false,
  268. true,
  269. 1,
  270. 13,
  271. 10,
  272. 12
  273. ),
  274. ], true];
  275. yield 'group constant import' => ['<?php use const Foo\{BAR, BAZ};', [
  276. new NamespaceUseAnalysis(
  277. NamespaceUseAnalysis::TYPE_CONSTANT,
  278. 'Foo\BAR',
  279. 'BAR',
  280. false,
  281. true,
  282. 1,
  283. 13,
  284. 8,
  285. 8
  286. ),
  287. new NamespaceUseAnalysis(
  288. NamespaceUseAnalysis::TYPE_CONSTANT,
  289. 'Foo\BAZ',
  290. 'BAZ',
  291. false,
  292. true,
  293. 1,
  294. 13,
  295. 11,
  296. 11
  297. ),
  298. ], true];
  299. yield 'multiple multi-imports with comments' => [
  300. <<<'PHP'
  301. <?php
  302. use Foo\Bar, /* Foo\Baz, */ Foo\Buzz, /** Foo\Bazzz, */ Foo\Bazzzz;
  303. use function Bar\f1, /* Bar\f2, */ Bar\f3, /** Bar\f4, */ Bar\f5;
  304. use const Buzz\C1, /* Buzz\C2, */ Buzz\C3, /** Buzz\C4, */ Buzz\C5;
  305. PHP,
  306. [
  307. new NamespaceUseAnalysis(
  308. NamespaceUseAnalysis::TYPE_CLASS,
  309. 'Foo\Bar',
  310. 'Bar',
  311. false,
  312. true,
  313. 1,
  314. 20,
  315. 3,
  316. 5
  317. ),
  318. new NamespaceUseAnalysis(
  319. NamespaceUseAnalysis::TYPE_CLASS,
  320. 'Foo\Buzz',
  321. 'Buzz',
  322. false,
  323. true,
  324. 1,
  325. 20,
  326. 10,
  327. 12
  328. ),
  329. new NamespaceUseAnalysis(
  330. NamespaceUseAnalysis::TYPE_CLASS,
  331. 'Foo\Bazzzz',
  332. 'Bazzzz',
  333. false,
  334. true,
  335. 1,
  336. 20,
  337. 17,
  338. 19
  339. ),
  340. new NamespaceUseAnalysis(
  341. NamespaceUseAnalysis::TYPE_FUNCTION,
  342. 'Bar\f1',
  343. 'f1',
  344. false,
  345. true,
  346. 22,
  347. 43,
  348. 26,
  349. 28
  350. ),
  351. new NamespaceUseAnalysis(
  352. NamespaceUseAnalysis::TYPE_FUNCTION,
  353. 'Bar\f3',
  354. 'f3',
  355. false,
  356. true,
  357. 22,
  358. 43,
  359. 33,
  360. 35
  361. ),
  362. new NamespaceUseAnalysis(
  363. NamespaceUseAnalysis::TYPE_FUNCTION,
  364. 'Bar\f5',
  365. 'f5',
  366. false,
  367. true,
  368. 22,
  369. 43,
  370. 40,
  371. 42
  372. ),
  373. new NamespaceUseAnalysis(
  374. NamespaceUseAnalysis::TYPE_CONSTANT,
  375. 'Buzz\C1',
  376. 'C1',
  377. false,
  378. true,
  379. 45,
  380. 66,
  381. 49,
  382. 51
  383. ),
  384. new NamespaceUseAnalysis(
  385. NamespaceUseAnalysis::TYPE_CONSTANT,
  386. 'Buzz\C3',
  387. 'C3',
  388. false,
  389. true,
  390. 45,
  391. 66,
  392. 56,
  393. 58
  394. ),
  395. new NamespaceUseAnalysis(
  396. NamespaceUseAnalysis::TYPE_CONSTANT,
  397. 'Buzz\C5',
  398. 'C5',
  399. false,
  400. true,
  401. 45,
  402. 66,
  403. 63,
  404. 65
  405. ),
  406. ],
  407. true,
  408. ];
  409. yield 'multiple multi-imports with aliases' => [
  410. <<<'PHP'
  411. <?php
  412. use Foo\Bar, Foo\Baz as Buzz;
  413. use function Bar\f1, Bar\f2 as func2;
  414. use const Buzz\C1, Buzz\C2 as CONST2;
  415. PHP,
  416. [
  417. new NamespaceUseAnalysis(
  418. NamespaceUseAnalysis::TYPE_CLASS,
  419. 'Foo\Bar',
  420. 'Bar',
  421. false,
  422. true,
  423. 1,
  424. 15,
  425. 3,
  426. 5
  427. ),
  428. new NamespaceUseAnalysis(
  429. NamespaceUseAnalysis::TYPE_CLASS,
  430. 'Foo\Baz',
  431. 'Buzz',
  432. true,
  433. true,
  434. 1,
  435. 15,
  436. 8,
  437. 14
  438. ),
  439. new NamespaceUseAnalysis(
  440. NamespaceUseAnalysis::TYPE_FUNCTION,
  441. 'Bar\f1',
  442. 'f1',
  443. false,
  444. true,
  445. 17,
  446. 33,
  447. 21,
  448. 23
  449. ),
  450. new NamespaceUseAnalysis(
  451. NamespaceUseAnalysis::TYPE_FUNCTION,
  452. 'Bar\f2',
  453. 'func2',
  454. true,
  455. true,
  456. 17,
  457. 33,
  458. 26,
  459. 32
  460. ),
  461. new NamespaceUseAnalysis(
  462. NamespaceUseAnalysis::TYPE_CONSTANT,
  463. 'Buzz\C1',
  464. 'C1',
  465. false,
  466. true,
  467. 35,
  468. 51,
  469. 39,
  470. 41
  471. ),
  472. new NamespaceUseAnalysis(
  473. NamespaceUseAnalysis::TYPE_CONSTANT,
  474. 'Buzz\C2',
  475. 'CONST2',
  476. true,
  477. true,
  478. 35,
  479. 51,
  480. 44,
  481. 50
  482. ),
  483. ],
  484. true,
  485. ];
  486. yield 'multiline grouped class import with trailing comma' => [
  487. <<<'PHP'
  488. <?php
  489. use Foo\{
  490. Bar,
  491. Baz,
  492. };
  493. PHP,
  494. [
  495. new NamespaceUseAnalysis(
  496. NamespaceUseAnalysis::TYPE_CLASS,
  497. 'Foo\Bar',
  498. 'Bar',
  499. false,
  500. true,
  501. 1,
  502. 14,
  503. 7,
  504. 7
  505. ),
  506. new NamespaceUseAnalysis(
  507. NamespaceUseAnalysis::TYPE_CLASS,
  508. 'Foo\Baz',
  509. 'Baz',
  510. false,
  511. true,
  512. 1,
  513. 14,
  514. 10,
  515. 10
  516. ),
  517. ],
  518. true,
  519. ];
  520. }
  521. /**
  522. * @param list<NamespaceUseAnalysis> $expected
  523. *
  524. * @dataProvider provideGetDeclarationsInNamespaceCases
  525. */
  526. public function testGetDeclarationsInNamespace(string $code, NamespaceAnalysis $namespace, array $expected): void
  527. {
  528. $tokens = Tokens::fromCode($code);
  529. $analyzer = new NamespaceUsesAnalyzer();
  530. self::assertSame(
  531. serialize($expected),
  532. serialize($analyzer->getDeclarationsInNamespace($tokens, $namespace))
  533. );
  534. }
  535. /**
  536. * @return iterable<array{0: string, 1: NamespaceAnalysis, 2: list<NamespaceUseAnalysis>}>
  537. */
  538. public static function provideGetDeclarationsInNamespaceCases(): iterable
  539. {
  540. yield [
  541. '<?php
  542. namespace Foo;
  543. use Bar;
  544. use Baz;',
  545. new NamespaceAnalysis('Foo', 'Foo', 2, 5, 2, 15),
  546. [
  547. new NamespaceUseAnalysis(NamespaceUseAnalysis::TYPE_CLASS, 'Bar', 'Bar', false, false, 7, 10),
  548. new NamespaceUseAnalysis(NamespaceUseAnalysis::TYPE_CLASS, 'Baz', 'Baz', false, false, 12, 15),
  549. ],
  550. ];
  551. yield [
  552. '<?php
  553. namespace Foo1 {
  554. use Bar1;
  555. use Baz1;
  556. }
  557. namespace Foo2 {
  558. use Bar2;
  559. use Baz2;
  560. }',
  561. new NamespaceAnalysis('Foo1', 'Foo1', 2, 4, 2, 18),
  562. [
  563. new NamespaceUseAnalysis(NamespaceUseAnalysis::TYPE_CLASS, 'Bar1', 'Bar1', false, false, 8, 11),
  564. new NamespaceUseAnalysis(NamespaceUseAnalysis::TYPE_CLASS, 'Baz1', 'Baz1', false, false, 13, 16),
  565. ],
  566. ];
  567. yield [
  568. '<?php
  569. namespace Foo1 {
  570. use Bar1;
  571. use Baz1;
  572. }
  573. namespace Foo2 {
  574. use Bar2;
  575. use Baz2;
  576. }',
  577. new NamespaceAnalysis('Foo2', 'Foo2', 20, 22, 20, 36),
  578. [
  579. new NamespaceUseAnalysis(NamespaceUseAnalysis::TYPE_CLASS, 'Bar2', 'Bar2', false, false, 26, 29),
  580. new NamespaceUseAnalysis(NamespaceUseAnalysis::TYPE_CLASS, 'Baz2', 'Baz2', false, false, 31, 34),
  581. ],
  582. ];
  583. }
  584. }