TokensAnalyzerTest.php 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985
  1. <?php
  2. /*
  3. * This file is part of PHP CS Fixer.
  4. *
  5. * (c) Fabien Potencier <fabien@symfony.com>
  6. * Dariusz Rumiński <dariusz.ruminski@gmail.com>
  7. *
  8. * This source file is subject to the MIT license that is bundled
  9. * with this source code in the file LICENSE.
  10. */
  11. namespace PhpCsFixer\Tests\Tokenizer;
  12. use PhpCsFixer\Tokenizer\Tokens;
  13. use PhpCsFixer\Tokenizer\TokensAnalyzer;
  14. /**
  15. * @author Dariusz Rumiński <dariusz.ruminski@gmail.com>
  16. * @author Max Voloshin <voloshin.dp@gmail.com>
  17. * @author Gregor Harlan <gharlan@web.de>
  18. *
  19. * @internal
  20. */
  21. final class TokensAnalyzerTest extends \PHPUnit_Framework_TestCase
  22. {
  23. public function testGetClassyElements()
  24. {
  25. $source = <<<'PHP'
  26. <?php
  27. class Foo
  28. {
  29. public $prop0;
  30. protected $prop1;
  31. private $prop2 = 1;
  32. var $prop3 = array(1,2,3);
  33. const CONSTANT = 'constant value';
  34. public function bar4()
  35. {
  36. $a = 5;
  37. return " ({$a})";
  38. }
  39. public function bar5($data)
  40. {
  41. $message = $data;
  42. $example = function ($arg) use ($message) {
  43. echo $arg . ' ' . $message;
  44. };
  45. $example('hello');
  46. }
  47. }
  48. function test(){}
  49. class Foo2
  50. {
  51. const CONSTANT = 'constant value';
  52. }
  53. PHP;
  54. $tokens = Tokens::fromCode($source);
  55. $tokensAnalyzer = new TokensAnalyzer($tokens);
  56. $elements = array_values($tokensAnalyzer->getClassyElements());
  57. $this->assertCount(8, $elements);
  58. $this->assertSame('property', $elements[0]['type']);
  59. $this->assertSame('property', $elements[1]['type']);
  60. $this->assertSame('property', $elements[2]['type']);
  61. $this->assertSame('property', $elements[3]['type']);
  62. $this->assertSame('const', $elements[4]['type']);
  63. $this->assertSame('method', $elements[5]['type']);
  64. $this->assertSame('method', $elements[6]['type']);
  65. $this->assertSame('const', $elements[7]['type']);
  66. }
  67. /**
  68. * @param string $source
  69. *
  70. * @dataProvider provideIsAnonymousClassCases
  71. */
  72. public function testIsAnonymousClass($source, array $expected)
  73. {
  74. $tokensAnalyzer = new TokensAnalyzer(Tokens::fromCode($source));
  75. foreach ($expected as $index => $expectedValue) {
  76. $this->assertSame($expectedValue, $tokensAnalyzer->isAnonymousClass($index));
  77. }
  78. }
  79. public function provideIsAnonymousClassCases()
  80. {
  81. return array(
  82. array(
  83. '<?php class foo {}',
  84. array(1 => false),
  85. ),
  86. array(
  87. '<?php $foo = new class() {};',
  88. array(7 => true),
  89. ),
  90. array(
  91. '<?php $foo = new class() extends Foo implements Bar, Baz {};',
  92. array(7 => true),
  93. ),
  94. array(
  95. '<?php class Foo { function bar() { return new class() {}; } }',
  96. array(1 => false, 19 => true),
  97. ),
  98. array(
  99. '<?php $a = new class(new class($d->a) implements B{}) extends C{};',
  100. array(7 => true, 11 => true),
  101. ),
  102. );
  103. }
  104. /**
  105. * @param string $source
  106. *
  107. * @dataProvider provideIsLambdaCases
  108. */
  109. public function testIsLambda($source, array $expected)
  110. {
  111. $tokensAnalyzer = new TokensAnalyzer(Tokens::fromCode($source));
  112. foreach ($expected as $index => $isLambda) {
  113. $this->assertSame($isLambda, $tokensAnalyzer->isLambda($index));
  114. }
  115. }
  116. public function provideIsLambdaCases()
  117. {
  118. return array(
  119. array(
  120. '<?php function foo () {};',
  121. array(1 => false),
  122. ),
  123. array(
  124. '<?php function /** foo */ foo () {};',
  125. array(1 => false),
  126. ),
  127. array(
  128. '<?php $foo = function () {};',
  129. array(5 => true),
  130. ),
  131. array(
  132. '<?php $foo = function /** foo */ () {};',
  133. array(5 => true),
  134. ),
  135. array(
  136. '<?php
  137. preg_replace_callback(
  138. "/(^|[a-z])/",
  139. function (array $matches) {
  140. return "a";
  141. },
  142. $string
  143. );',
  144. array(7 => true),
  145. ),
  146. array(
  147. '<?php $foo = function &() {};',
  148. array(5 => true),
  149. ),
  150. );
  151. }
  152. /**
  153. * @param string $source
  154. *
  155. * @dataProvider provideIsLambdaCases70
  156. * @requires PHP 7.0
  157. */
  158. public function testIsLambda70($source, array $expected)
  159. {
  160. $tokensAnalyzer = new TokensAnalyzer(Tokens::fromCode($source));
  161. foreach ($expected as $index => $expectedValue) {
  162. $this->assertSame($expectedValue, $tokensAnalyzer->isLambda($index));
  163. }
  164. }
  165. public function provideIsLambdaCases70()
  166. {
  167. return array(
  168. array(
  169. '<?php
  170. $a = function (): array {
  171. return [];
  172. };',
  173. array(6 => true),
  174. ),
  175. array(
  176. '<?php
  177. function foo (): array {
  178. return [];
  179. };',
  180. array(2 => false),
  181. ),
  182. );
  183. }
  184. /**
  185. * @param string $source
  186. *
  187. * @dataProvider provideIsLambdaCases71
  188. * @requires PHP 7.1
  189. */
  190. public function testIsLambda71($source, array $expected)
  191. {
  192. $tokensAnalyzer = new TokensAnalyzer(Tokens::fromCode($source));
  193. foreach ($expected as $index => $expectedValue) {
  194. $this->assertSame($expectedValue, $tokensAnalyzer->isLambda($index));
  195. }
  196. }
  197. public function provideIsLambdaCases71()
  198. {
  199. return array(
  200. array(
  201. '<?php
  202. $a = function (): void {
  203. return [];
  204. };',
  205. array(6 => true),
  206. ),
  207. array(
  208. '<?php
  209. function foo (): void {
  210. return [];
  211. };',
  212. array(2 => false),
  213. ),
  214. array(
  215. '<?php
  216. $a = function (): ?int {
  217. return [];
  218. };',
  219. array(6 => true),
  220. ),
  221. array(
  222. '<?php
  223. function foo (): ?int {
  224. return [];
  225. };',
  226. array(2 => false),
  227. ),
  228. );
  229. }
  230. /**
  231. * @param string $source
  232. *
  233. * @dataProvider provideIsUnarySuccessorOperator
  234. */
  235. public function testIsUnarySuccessorOperator($source, array $expected)
  236. {
  237. $tokensAnalyzer = new TokensAnalyzer(Tokens::fromCode($source));
  238. foreach ($expected as $index => $isUnary) {
  239. $this->assertSame($isUnary, $tokensAnalyzer->isUnarySuccessorOperator($index));
  240. if ($isUnary) {
  241. $this->assertFalse($tokensAnalyzer->isUnaryPredecessorOperator($index));
  242. $this->assertFalse($tokensAnalyzer->isBinaryOperator($index));
  243. }
  244. }
  245. }
  246. public function provideIsUnarySuccessorOperator()
  247. {
  248. return array(
  249. array(
  250. '<?php $a++;',
  251. array(2 => true),
  252. ),
  253. array(
  254. '<?php $a--;',
  255. array(2 => true),
  256. ),
  257. array(
  258. '<?php $a ++;',
  259. array(3 => true),
  260. ),
  261. array(
  262. '<?php $a++ + 1;',
  263. array(2 => true, 4 => false),
  264. ),
  265. array(
  266. '<?php ${"a"}++;',
  267. array(5 => true),
  268. ),
  269. array(
  270. '<?php $foo->bar++;',
  271. array(4 => true),
  272. ),
  273. array(
  274. '<?php $foo->{"bar"}++;',
  275. array(6 => true),
  276. ),
  277. array(
  278. '<?php $a["foo"]++;',
  279. array(5 => true),
  280. ),
  281. );
  282. }
  283. /**
  284. * @param string $source
  285. *
  286. * @dataProvider provideIsUnaryPredecessorOperator
  287. */
  288. public function testIsUnaryPredecessorOperator($source, array $expected)
  289. {
  290. $tokensAnalyzer = new TokensAnalyzer(Tokens::fromCode($source));
  291. foreach ($expected as $index => $isUnary) {
  292. $this->assertSame($isUnary, $tokensAnalyzer->isUnaryPredecessorOperator($index));
  293. if ($isUnary) {
  294. $this->assertFalse($tokensAnalyzer->isUnarySuccessorOperator($index));
  295. $this->assertFalse($tokensAnalyzer->isBinaryOperator($index));
  296. }
  297. }
  298. }
  299. public function provideIsUnaryPredecessorOperator()
  300. {
  301. return array(
  302. array(
  303. '<?php ++$a;',
  304. array(1 => true),
  305. ),
  306. array(
  307. '<?php --$a;',
  308. array(1 => true),
  309. ),
  310. array(
  311. '<?php -- $a;',
  312. array(1 => true),
  313. ),
  314. array(
  315. '<?php $a + ++$b;',
  316. array(3 => false, 5 => true),
  317. ),
  318. array(
  319. '<?php !!$a;',
  320. array(1 => true, 2 => true),
  321. ),
  322. array(
  323. '<?php $a = &$b;',
  324. array(5 => true),
  325. ),
  326. array(
  327. '<?php function &foo() {}',
  328. array(3 => true),
  329. ),
  330. array(
  331. '<?php @foo();',
  332. array(1 => true),
  333. ),
  334. array(
  335. '<?php foo(+ $a, -$b);',
  336. array(3 => true, 8 => true),
  337. ),
  338. array(
  339. '<?php function foo(&$a, array &$b, Bar &$c) {}',
  340. array(5 => true, 11 => true, 17 => true),
  341. ),
  342. );
  343. }
  344. /**
  345. * @param string $source
  346. *
  347. * @dataProvider provideIsUnaryPredecessorOperator56
  348. * @requires PHP 5.6
  349. */
  350. public function testIsUnaryPredecessorOperator56($source, array $expected)
  351. {
  352. $tokensAnalyzer = new TokensAnalyzer(Tokens::fromCode($source));
  353. foreach ($expected as $index => $isUnary) {
  354. $this->assertSame($isUnary, $tokensAnalyzer->isUnaryPredecessorOperator($index));
  355. if ($isUnary) {
  356. $this->assertFalse($tokensAnalyzer->isUnarySuccessorOperator($index));
  357. $this->assertFalse($tokensAnalyzer->isBinaryOperator($index));
  358. }
  359. }
  360. }
  361. public function provideIsUnaryPredecessorOperator56()
  362. {
  363. return array(
  364. array(
  365. '<?php function foo($a, ...$b) {}',
  366. array(8 => true),
  367. ),
  368. array(
  369. '<?php function foo(&...$b) {}',
  370. array(5 => true, 6 => true),
  371. ),
  372. array(
  373. '<?php function foo(array ...$b) {}',
  374. array(7 => true),
  375. ),
  376. array(
  377. '<?php $foo = function(...$a) {};',
  378. array(7 => true),
  379. ),
  380. array(
  381. '<?php $foo = function($a, ...$b) {};',
  382. array(10 => true),
  383. ),
  384. );
  385. }
  386. /**
  387. * @param string $source
  388. *
  389. * @dataProvider provideIsBinaryOperator
  390. */
  391. public function testIsBinaryOperator($source, array $expected)
  392. {
  393. $tokensAnalyzer = new TokensAnalyzer(Tokens::fromCode($source));
  394. foreach ($expected as $index => $isBinary) {
  395. $this->assertSame($isBinary, $tokensAnalyzer->isBinaryOperator($index));
  396. if ($isBinary) {
  397. $this->assertFalse($tokensAnalyzer->isUnarySuccessorOperator($index));
  398. $this->assertFalse($tokensAnalyzer->isUnaryPredecessorOperator($index));
  399. }
  400. }
  401. }
  402. public function provideIsBinaryOperator()
  403. {
  404. $cases = array(
  405. array(
  406. '<?php [] + [];',
  407. array(4 => true),
  408. ),
  409. array(
  410. '<?php $a + $b;',
  411. array(3 => true),
  412. ),
  413. array(
  414. '<?php 1 + $b;',
  415. array(3 => true),
  416. ),
  417. array(
  418. '<?php 0.2 + $b;',
  419. array(3 => true),
  420. ),
  421. array(
  422. '<?php $a[1] + $b;',
  423. array(6 => true),
  424. ),
  425. array(
  426. '<?php FOO + $b;',
  427. array(3 => true),
  428. ),
  429. array(
  430. '<?php foo() + $b;',
  431. array(5 => true),
  432. ),
  433. array(
  434. '<?php ${"foo"} + $b;',
  435. array(6 => true),
  436. ),
  437. array(
  438. '<?php $a+$b;',
  439. array(2 => true),
  440. ),
  441. array(
  442. '<?php $a /* foo */ + /* bar */ $b;',
  443. array(5 => true),
  444. ),
  445. array(
  446. '<?php $a =
  447. $b;',
  448. array(3 => true),
  449. ),
  450. array(
  451. '<?php $a
  452. = $b;',
  453. array(3 => true),
  454. ),
  455. array(
  456. '<?php $a = array("b" => "c", );',
  457. array(3 => true, 9 => true, 12 => false),
  458. ),
  459. array(
  460. '<?php $a * -$b;',
  461. array(3 => true, 5 => false),
  462. ),
  463. array(
  464. '<?php $a = -2 / +5;',
  465. array(3 => true, 5 => false, 8 => true, 10 => false),
  466. ),
  467. array(
  468. '<?php $a = &$b;',
  469. array(3 => true, 5 => false),
  470. ),
  471. array(
  472. '<?php $a++ + $b;',
  473. array(2 => false, 4 => true),
  474. ),
  475. array(
  476. '<?php $a = FOO & $bar;',
  477. array(7 => true),
  478. ),
  479. array(
  480. '<?php __LINE__ - 1;',
  481. array(3 => true),
  482. ),
  483. array(
  484. '<?php `echo 1` + 1;',
  485. array(5 => true),
  486. ),
  487. );
  488. $operators = array(
  489. '+', '-', '*', '/', '%', '<', '>', '|', '^', '&=', '&&', '||', '.=', '/=', '==', '>=', '===', '!=',
  490. '<>', '!==', '<=', 'and', 'or', 'xor', '-=', '%=', '*=', '|=', '+=', '<<', '<<=', '>>', '>>=', '^',
  491. );
  492. foreach ($operators as $operator) {
  493. $cases[] = array(
  494. '<?php $a '.$operator.' $b;',
  495. array(3 => true),
  496. );
  497. }
  498. return $cases;
  499. }
  500. /**
  501. * @param string $source
  502. *
  503. * @dataProvider provideIsBinaryOperator56
  504. * @requires PHP 5.6
  505. */
  506. public function testIsBinaryOperator56($source, array $expected)
  507. {
  508. $tokensAnalyzer = new TokensAnalyzer(Tokens::fromCode($source));
  509. foreach ($expected as $index => $isBinary) {
  510. $this->assertSame($isBinary, $tokensAnalyzer->isBinaryOperator($index));
  511. if ($isBinary) {
  512. $this->assertFalse($tokensAnalyzer->isUnarySuccessorOperator($index));
  513. $this->assertFalse($tokensAnalyzer->isUnaryPredecessorOperator($index));
  514. }
  515. }
  516. }
  517. public function provideIsBinaryOperator56()
  518. {
  519. return array(
  520. array(
  521. '<?php $a ** $b;',
  522. array(3 => true),
  523. ),
  524. array(
  525. '<?php $a **= $b;',
  526. array(3 => true),
  527. ),
  528. );
  529. }
  530. /**
  531. * @param string $source
  532. *
  533. * @dataProvider provideIsBinaryOperator70
  534. * @requires PHP 7.0
  535. */
  536. public function testIsBinaryOperator70($source, array $expected)
  537. {
  538. $tokensAnalyzer = new TokensAnalyzer(Tokens::fromCode($source));
  539. foreach ($expected as $index => $isBinary) {
  540. $this->assertSame($isBinary, $tokensAnalyzer->isBinaryOperator($index));
  541. if ($isBinary) {
  542. $this->assertFalse($tokensAnalyzer->isUnarySuccessorOperator($index));
  543. $this->assertFalse($tokensAnalyzer->isUnaryPredecessorOperator($index));
  544. }
  545. }
  546. }
  547. public function provideIsBinaryOperator70()
  548. {
  549. return array(
  550. array(
  551. '<?php $a <=> $b;',
  552. array(3 => true),
  553. ),
  554. array(
  555. '<?php $a ?? $b;',
  556. array(3 => true),
  557. ),
  558. );
  559. }
  560. /**
  561. * @param string $source
  562. * @param int $tokenIndex
  563. * @param bool $isMultilineArray
  564. *
  565. * @dataProvider provideIsArray
  566. * @requires PHP 5.4
  567. */
  568. public function testIsArray($source, $tokenIndex, $isMultilineArray = false)
  569. {
  570. $tokens = Tokens::fromCode($source);
  571. $tokensAnalyzer = new TokensAnalyzer($tokens);
  572. $this->assertTrue($tokensAnalyzer->isArray($tokenIndex), 'Expected to be an array.');
  573. $this->assertSame($isMultilineArray, $tokensAnalyzer->isArrayMultiLine($tokenIndex), sprintf('Expected %sto be a multiline array', $isMultilineArray ? '' : 'not '));
  574. }
  575. public function provideIsArray()
  576. {
  577. $cases = array(
  578. array(
  579. '<?php
  580. array("a" => 1);
  581. ',
  582. 2,
  583. ),
  584. array(
  585. // short array PHP 5.4 single line
  586. '<?php
  587. ["a" => 2];
  588. ',
  589. 2, false,
  590. ),
  591. array(
  592. '<?php
  593. array(
  594. "a" => 3
  595. );
  596. ',
  597. 2, true,
  598. ),
  599. array(
  600. // short array PHP 5.4 multi line
  601. '<?php
  602. [
  603. "a" => 4
  604. ];
  605. ',
  606. 2, true,
  607. ),
  608. array(
  609. '<?php
  610. array(
  611. "a" => array(5, 6, 7),
  612. 8 => new \Exception(\'Ellow\')
  613. );
  614. ',
  615. 2, true,
  616. ),
  617. array(
  618. // mix short array syntax
  619. '<?php
  620. array(
  621. "a" => [9, 10, 11],
  622. 12 => new \Exception(\'Ellow\')
  623. );
  624. ',
  625. 2, true,
  626. ),
  627. // Windows/Max EOL testing
  628. array(
  629. "<?php\r\narray('a' => 13);\r\n",
  630. 1,
  631. ),
  632. array(
  633. "<?php\r\n array(\r\n 'a' => 14,\r\n 'b' => 15\r\n );\r\n",
  634. 2, true,
  635. ),
  636. );
  637. return $cases;
  638. }
  639. /**
  640. * @param string $source
  641. * @param int $tokenIndex
  642. *
  643. * @dataProvider provideArrayExceptions
  644. */
  645. public function testIsNotArray($source, $tokenIndex)
  646. {
  647. $tokens = Tokens::fromCode($source);
  648. $tokensAnalyzer = new TokensAnalyzer($tokens);
  649. $this->assertFalse($tokensAnalyzer->isArray($tokenIndex));
  650. }
  651. /**
  652. * @param string $source
  653. * @param int $tokenIndex
  654. *
  655. * @expectedException \InvalidArgumentException
  656. * @dataProvider provideArrayExceptions
  657. */
  658. public function testIsMultiLineArrayException($source, $tokenIndex)
  659. {
  660. $tokens = Tokens::fromCode($source);
  661. $tokensAnalyzer = new TokensAnalyzer($tokens);
  662. $tokensAnalyzer->isArrayMultiLine($tokenIndex);
  663. }
  664. public function provideArrayExceptions()
  665. {
  666. $cases = array(
  667. array('<?php $a;', 1),
  668. array("<?php\n \$a = (0+1); // [0,1]", 4),
  669. array('<?php $text = "foo $bbb[0] bar";', 8),
  670. array('<?php $text = "foo ${aaa[123]} bar";', 9),
  671. );
  672. return $cases;
  673. }
  674. /**
  675. * @param string $source
  676. * @param int $index
  677. * @param array $expected
  678. *
  679. * @dataProvider provideGetFunctionProperties
  680. */
  681. public function testGetFunctionProperties($source, $index, array $expected)
  682. {
  683. $tokens = Tokens::fromCode($source);
  684. $tokensAnalyzer = new TokensAnalyzer($tokens);
  685. $attributes = $tokensAnalyzer->getMethodAttributes($index);
  686. $this->assertSame($expected, $attributes);
  687. }
  688. public function provideGetFunctionProperties()
  689. {
  690. $defaultAttributes = array(
  691. 'visibility' => null,
  692. 'static' => false,
  693. 'abstract' => false,
  694. 'final' => false,
  695. );
  696. $template = '
  697. <?php
  698. class TestClass {
  699. %s function a() {
  700. //
  701. }
  702. }
  703. ';
  704. $cases = array();
  705. $attributes = $defaultAttributes;
  706. $attributes['visibility'] = T_PRIVATE;
  707. $cases[] = array(sprintf($template, 'private'), 10, $attributes);
  708. $attributes = $defaultAttributes;
  709. $attributes['visibility'] = T_PUBLIC;
  710. $cases[] = array(sprintf($template, 'public'), 10, $attributes);
  711. $attributes = $defaultAttributes;
  712. $attributes['visibility'] = T_PROTECTED;
  713. $cases[] = array(sprintf($template, 'protected'), 10, $attributes);
  714. $attributes = $defaultAttributes;
  715. $attributes['visibility'] = null;
  716. $attributes['static'] = true;
  717. $cases[] = array(sprintf($template, 'static'), 10, $attributes);
  718. $attributes = $defaultAttributes;
  719. $attributes['visibility'] = T_PUBLIC;
  720. $attributes['static'] = true;
  721. $attributes['final'] = true;
  722. $cases[] = array(sprintf($template, 'final public static'), 14, $attributes);
  723. $attributes = $defaultAttributes;
  724. $attributes['visibility'] = null;
  725. $attributes['abstract'] = true;
  726. $cases[] = array(sprintf($template, 'abstract'), 10, $attributes);
  727. $attributes = $defaultAttributes;
  728. $attributes['visibility'] = T_PUBLIC;
  729. $attributes['abstract'] = true;
  730. $cases[] = array(sprintf($template, 'abstract public'), 12, $attributes);
  731. $attributes = $defaultAttributes;
  732. $cases[] = array(sprintf($template, ''), 8, $attributes);
  733. return $cases;
  734. }
  735. public function testIsWhilePartOfDoWhile()
  736. {
  737. $source =
  738. <<<'SRC'
  739. <?php
  740. // `not do`
  741. while(false) {
  742. }
  743. while (false);
  744. while (false)?>
  745. <?php
  746. if(false){
  747. }while(false);
  748. if(false){
  749. }while(false)?><?php
  750. while(false){}while(false){}
  751. while ($i <= 10):
  752. echo $i;
  753. $i++;
  754. endwhile;
  755. ?>
  756. <?php while(false): ?>
  757. <?php endwhile ?>
  758. <?php
  759. // `do`
  760. do{
  761. } while(false);
  762. do{
  763. } while(false)?>
  764. <?php
  765. if (false){}do{}while(false);
  766. // `not do`, `do`
  767. if(false){}while(false){}do{}while(false);
  768. SRC;
  769. $expected = array(
  770. 3 => false,
  771. 12 => false,
  772. 19 => false,
  773. 34 => false,
  774. 47 => false,
  775. 53 => false,
  776. 59 => false,
  777. 66 => false,
  778. 91 => false,
  779. 112 => true,
  780. 123 => true,
  781. 139 => true,
  782. 153 => false,
  783. 162 => true,
  784. );
  785. $tokens = Tokens::fromCode($source);
  786. $tokensAnalyzer = new TokensAnalyzer($tokens);
  787. foreach ($tokens as $index => $token) {
  788. if (!$token->isGivenKind(T_WHILE)) {
  789. continue;
  790. }
  791. $this->assertSame(
  792. $expected[$index],
  793. $tokensAnalyzer->isWhilePartOfDoWhile($index),
  794. sprintf('Expected token at index "%d" to be detected as %sa "do-while"-loop.', $index, true === $expected[$index] ? '' : 'not ')
  795. );
  796. }
  797. }
  798. /**
  799. * @param string $input
  800. * @param bool $perNamespace
  801. *
  802. * @dataProvider getImportUseIndexesCases
  803. */
  804. public function testGetImportUseIndexes(array $expected, $input, $perNamespace = false)
  805. {
  806. $tokens = Tokens::fromCode($input);
  807. $tokensAnalyzer = new TokensAnalyzer($tokens);
  808. $this->assertSame($expected, $tokensAnalyzer->getImportUseIndexes($perNamespace));
  809. }
  810. public function getImportUseIndexesCases()
  811. {
  812. return array(
  813. array(
  814. array(1, 8),
  815. '<?php use E\F?><?php use A\B;',
  816. ),
  817. array(
  818. array(array(1), array(14), array(29)),
  819. '<?php
  820. use T\A;
  821. namespace A { use D\C; }
  822. namespace b { use D\C; }
  823. ',
  824. true,
  825. ),
  826. array(
  827. array(array(1, 8)),
  828. '<?php use D\B; use A\C?>',
  829. true,
  830. ),
  831. array(
  832. array(1, 8),
  833. '<?php use D\B; use A\C?>',
  834. ),
  835. array(
  836. array(7, 22),
  837. '<?php
  838. namespace A { use D\C; }
  839. namespace b { use D\C; }
  840. ',
  841. ),
  842. array(
  843. array(3, 10, 34, 45, 54, 59, 77, 95),
  844. <<<'EOF'
  845. use Zoo\Bar;
  846. use Foo\Bar;
  847. use Foo\Zar\Baz;
  848. <?php
  849. use Foo\Bar;
  850. use Foo\Bar\Foo as Fooo, Foo\Bar\FooBar as FooBaz;
  851. use Foo\Bir as FBB;
  852. use Foo\Zar\Baz;
  853. use SomeClass;
  854. use Symfony\Annotation\Template, Symfony\Doctrine\Entities\Entity;
  855. use Zoo\Bar;
  856. $a = new someclass();
  857. use Zoo\Tar;
  858. class AnnotatedClass
  859. {
  860. }
  861. EOF
  862. ,
  863. ),
  864. );
  865. }
  866. /**
  867. * @param string $input
  868. * @param bool $perNamespace
  869. *
  870. * @dataProvider getImportUseIndexesCasesPHP70
  871. * @requires PHP 7.0
  872. */
  873. public function testGetImportUseIndexesPHP70(array $expected, $input, $perNamespace = false)
  874. {
  875. $tokens = Tokens::fromCode($input);
  876. $tokensAnalyzer = new TokensAnalyzer($tokens);
  877. $this->assertSame($expected, $tokensAnalyzer->getImportUseIndexes($perNamespace));
  878. }
  879. public function getImportUseIndexesCasesPHP70()
  880. {
  881. return array(
  882. array(
  883. array(1, 22, 41),
  884. '<?php
  885. use some\a\{ClassA, ClassB, ClassC as C};
  886. use function some\a\{fn_a, fn_b, fn_c};
  887. use const some\a\{ConstA, ConstB, ConstC};
  888. ',
  889. ),
  890. array(
  891. array(array(1, 22, 41)),
  892. '<?php
  893. use some\a\{ClassA, ClassB, ClassC as C};
  894. use function some\a\{fn_a, fn_b, fn_c};
  895. use const some\a\{ConstA, ConstB, ConstC};
  896. ',
  897. true,
  898. ),
  899. );
  900. }
  901. }