PageRenderTime 24ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/vendor/fabpot/php-cs-fixer/Symfony/CS/Fixer/Symfony/UnusedUseFixer.php

https://gitlab.com/yousafsyed/easternglamor
PHP | 240 lines | 165 code | 47 blank | 28 comment | 19 complexity | f38b725af9f29efa5e377c202dd58346 MD5 | raw file
  1. <?php
  2. /*
  3. * This file is part of the PHP CS utility.
  4. *
  5. * (c) Fabien Potencier <fabien@symfony.com>
  6. *
  7. * This source file is subject to the MIT license that is bundled
  8. * with this source code in the file LICENSE.
  9. */
  10. namespace Symfony\CS\Fixer\Symfony;
  11. use Symfony\CS\AbstractFixer;
  12. use Symfony\CS\Tokenizer\Tokens;
  13. /**
  14. * @author Dariusz RumiƄski <dariusz.ruminski@gmail.com>
  15. */
  16. class UnusedUseFixer extends AbstractFixer
  17. {
  18. /**
  19. * {@inheritdoc}
  20. */
  21. public function fix(\SplFileInfo $file, $content)
  22. {
  23. $tokens = Tokens::fromCode($content);
  24. $namespaceDeclarations = $this->getNamespaceDeclarations($tokens);
  25. $useDeclarationsIndexes = $tokens->getImportUseIndexes();
  26. $useDeclarations = $this->getNamespaceUseDeclarations($tokens, $useDeclarationsIndexes);
  27. $contentWithoutUseDeclarations = $this->generateCodeWithoutPartials($tokens, array_merge($namespaceDeclarations, $useDeclarations));
  28. $useUsages = $this->detectUseUsages($contentWithoutUseDeclarations, $useDeclarations);
  29. $this->removeUnusedUseDeclarations($tokens, $useDeclarations, $useUsages);
  30. $this->removeUsesInSameNamespace($tokens, $useDeclarations, $namespaceDeclarations);
  31. return $tokens->generateCode();
  32. }
  33. /**
  34. * {@inheritdoc}
  35. */
  36. public function getPriority()
  37. {
  38. // should be run after the MultipleUseFixer
  39. return -10;
  40. }
  41. /**
  42. * {@inheritdoc}
  43. */
  44. public function supports(\SplFileInfo $file)
  45. {
  46. // some fixtures are auto-generated by Symfony and may contain unused use statements
  47. if (false !== strpos($file, DIRECTORY_SEPARATOR.'Fixtures'.DIRECTORY_SEPARATOR)) {
  48. return false;
  49. }
  50. return true;
  51. }
  52. /**
  53. * {@inheritdoc}
  54. */
  55. public function getDescription()
  56. {
  57. return 'Unused use statements must be removed.';
  58. }
  59. private function detectUseUsages($content, array $useDeclarations)
  60. {
  61. $usages = array();
  62. foreach ($useDeclarations as $shortName => $useDeclaration) {
  63. $usages[$shortName] = (bool) preg_match('/(?<![\$\\\\])\b'.preg_quote($shortName).'\b/i', $content);
  64. }
  65. return $usages;
  66. }
  67. private function generateCodeWithoutPartials(Tokens $tokens, array $partials)
  68. {
  69. $content = '';
  70. foreach ($tokens as $index => $token) {
  71. $allowToAppend = true;
  72. foreach ($partials as $partial) {
  73. if ($partial['start'] <= $index && $index <= $partial['end']) {
  74. $allowToAppend = false;
  75. break;
  76. }
  77. }
  78. if ($allowToAppend) {
  79. $content .= $token->getContent();
  80. }
  81. }
  82. return $content;
  83. }
  84. private function getNamespaceDeclarations(Tokens $tokens)
  85. {
  86. $namespaces = array();
  87. foreach ($tokens as $index => $token) {
  88. if (!$token->isGivenKind(T_NAMESPACE)) {
  89. continue;
  90. }
  91. $declarationEndIndex = $tokens->getNextTokenOfKind($index, array(';', '{'));
  92. $namespaces[] = array(
  93. 'end' => $declarationEndIndex,
  94. 'name' => trim($tokens->generatePartialCode($index + 1, $declarationEndIndex - 1)),
  95. 'start' => $index,
  96. );
  97. }
  98. return $namespaces;
  99. }
  100. private function getNamespaceUseDeclarations(Tokens $tokens, array $useIndexes)
  101. {
  102. $uses = array();
  103. foreach ($useIndexes as $index) {
  104. $declarationEndIndex = $tokens->getNextTokenOfKind($index, array(';'));
  105. $declarationContent = $tokens->generatePartialCode($index + 1, $declarationEndIndex - 1);
  106. // ignore multiple use statements like: `use BarB, BarC as C, BarD;`
  107. // that should be split into few separate statements
  108. if (false !== strpos($declarationContent, ',')) {
  109. continue;
  110. }
  111. $declarationParts = preg_split('/\s+as\s+/i', $declarationContent);
  112. if (1 === count($declarationParts)) {
  113. $fullName = $declarationContent;
  114. $declarationParts = explode('\\', $fullName);
  115. $shortName = end($declarationParts);
  116. $aliased = false;
  117. } else {
  118. $fullName = $declarationParts[0];
  119. $shortName = $declarationParts[1];
  120. $declarationParts = explode('\\', $fullName);
  121. $aliased = $shortName !== end($declarationParts);
  122. }
  123. $shortName = trim($shortName);
  124. $uses[$shortName] = array(
  125. 'aliased' => $aliased,
  126. 'end' => $declarationEndIndex,
  127. 'fullName' => trim($fullName),
  128. 'shortName' => $shortName,
  129. 'start' => $index,
  130. );
  131. }
  132. return $uses;
  133. }
  134. private function removeUnusedUseDeclarations(Tokens $tokens, array $useDeclarations, array $useUsages)
  135. {
  136. foreach ($useDeclarations as $shortName => $useDeclaration) {
  137. if (!$useUsages[$shortName]) {
  138. $this->removeUseDeclaration($tokens, $useDeclaration);
  139. }
  140. }
  141. }
  142. private function removeUseDeclaration(Tokens $tokens, array $useDeclaration)
  143. {
  144. for ($index = $useDeclaration['start']; $index <= $useDeclaration['end']; ++$index) {
  145. $tokens[$index]->clear();
  146. }
  147. $prevToken = $tokens[$useDeclaration['start'] - 1];
  148. if ($prevToken->isWhitespace()) {
  149. $prevToken->setContent(rtrim($prevToken->getContent(), " \t"));
  150. }
  151. if (!isset($tokens[$useDeclaration['end'] + 1])) {
  152. return;
  153. }
  154. $nextToken = $tokens[$useDeclaration['end'] + 1];
  155. if ($nextToken->isWhitespace()) {
  156. $content = ltrim($nextToken->getContent(), " \t");
  157. if ($content && "\n" === $content[0]) {
  158. $content = substr($content, 1);
  159. }
  160. $nextToken->setContent($content);
  161. }
  162. if ($prevToken->isWhitespace() && $nextToken->isWhitespace()) {
  163. $nextToken->override(array(T_WHITESPACE, $prevToken->getContent().$nextToken->getContent(), $prevToken->getLine()));
  164. $prevToken->clear();
  165. }
  166. }
  167. private function removeUsesInSameNamespace(Tokens $tokens, array $useDeclarations, array $namespaceDeclarations)
  168. {
  169. if (empty($namespaceDeclarations)) {
  170. return;
  171. }
  172. // safeguard for files with multiple namespaces to avoid breaking them until we support this case
  173. if (count($namespaceDeclarations) > 1) {
  174. return;
  175. }
  176. $namespace = $namespaceDeclarations[0]['name'];
  177. $nsLength = strlen($namespace.'\\');
  178. foreach ($useDeclarations as $useDeclaration) {
  179. if ($useDeclaration['aliased']) {
  180. continue;
  181. }
  182. if (0 !== strpos($useDeclaration['fullName'], $namespace.'\\')) {
  183. continue;
  184. }
  185. $partName = substr($useDeclaration['fullName'], $nsLength);
  186. if (false === strpos($partName, '\\')) {
  187. $this->removeUseDeclaration($tokens, $useDeclaration);
  188. }
  189. }
  190. }
  191. }