|
15 | 15 | use PhpCsFixer\AbstractFixer; |
16 | 16 | use PhpCsFixer\FixerDefinition\CodeSample; |
17 | 17 | use PhpCsFixer\FixerDefinition\FixerDefinition; |
| 18 | +use PhpCsFixer\Tokenizer\Analyzer\NamespacesAnalyzer; |
18 | 19 | use PhpCsFixer\Tokenizer\CT; |
19 | 20 | use PhpCsFixer\Tokenizer\Token; |
20 | 21 | use PhpCsFixer\Tokenizer\Tokens; |
@@ -63,40 +64,16 @@ public function isCandidate(Tokens $tokens) |
63 | 64 | */ |
64 | 65 | protected function applyFix(\SplFileInfo $file, Tokens $tokens) |
65 | 66 | { |
66 | | - $this->replaceClassKeywords($tokens); |
67 | | - } |
| 67 | + $namespacesAnalyzer = new NamespacesAnalyzer(); |
68 | 68 |
|
69 | | - /** |
70 | | - * Replaces ::class keyword, namespace by namespace. |
71 | | - * |
72 | | - * It uses recursive method to get rid of token index changes. |
73 | | - * |
74 | | - * @param int $namespaceNumber |
75 | | - */ |
76 | | - private function replaceClassKeywords(Tokens $tokens, $namespaceNumber = -1) |
77 | | - { |
78 | | - $namespaceIndexes = array_keys($tokens->findGivenKind(T_NAMESPACE)); |
79 | | - |
80 | | - // Namespace blocks |
81 | | - if (\count($namespaceIndexes) && isset($namespaceIndexes[$namespaceNumber])) { |
82 | | - $startIndex = $namespaceIndexes[$namespaceNumber]; |
83 | | - |
84 | | - $namespaceBlockStartIndex = $tokens->getNextTokenOfKind($startIndex, [';', '{']); |
85 | | - $endIndex = $tokens[$namespaceBlockStartIndex]->equals('{') |
86 | | - ? $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $namespaceBlockStartIndex) |
87 | | - : $tokens->getNextTokenOfKind($namespaceBlockStartIndex, [T_NAMESPACE]); |
88 | | - $endIndex = $endIndex ?: $tokens->count() - 1; |
89 | | - } elseif (-1 === $namespaceNumber) { // Out of any namespace block |
90 | | - $startIndex = 0; |
91 | | - $endIndex = \count($namespaceIndexes) ? $namespaceIndexes[0] : $tokens->count() - 1; |
92 | | - } else { |
93 | | - return; |
| 69 | + $previousNamespaceScopeEndIndex = 0; |
| 70 | + foreach ($namespacesAnalyzer->getDeclarations($tokens) as $declaration) { |
| 71 | + $this->replaceClassKeywordsSection($tokens, '', $previousNamespaceScopeEndIndex, $declaration->getStartIndex()); |
| 72 | + $this->replaceClassKeywordsSection($tokens, $declaration->getFullName(), $declaration->getStartIndex(), $declaration->getScopeEndIndex()); |
| 73 | + $previousNamespaceScopeEndIndex = $declaration->getScopeEndIndex(); |
94 | 74 | } |
95 | 75 |
|
96 | | - $this->storeImports($tokens, $startIndex, $endIndex); |
97 | | - $tokens->rewind(); |
98 | | - $this->replaceClassKeywordsSection($tokens, $startIndex, $endIndex); |
99 | | - $this->replaceClassKeywords($tokens, $namespaceNumber + 1); |
| 76 | + $this->replaceClassKeywordsSection($tokens, '', $previousNamespaceScopeEndIndex, $tokens->count() - 1); |
100 | 77 | } |
101 | 78 |
|
102 | 79 | /** |
@@ -152,21 +129,29 @@ static function ($import) { |
152 | 129 | } |
153 | 130 |
|
154 | 131 | /** |
155 | | - * @param int $startIndex |
156 | | - * @param int $endIndex |
| 132 | + * @param string $namespace |
| 133 | + * @param int $startIndex |
| 134 | + * @param int $endIndex |
157 | 135 | */ |
158 | | - private function replaceClassKeywordsSection(Tokens $tokens, $startIndex, $endIndex) |
| 136 | + private function replaceClassKeywordsSection(Tokens $tokens, $namespace, $startIndex, $endIndex) |
159 | 137 | { |
| 138 | + if ($endIndex - $startIndex < 3) { |
| 139 | + return; |
| 140 | + } |
| 141 | + |
| 142 | + $this->storeImports($tokens, $startIndex, $endIndex); |
| 143 | + |
160 | 144 | $ctClassTokens = $tokens->findGivenKind(CT::T_CLASS_CONSTANT, $startIndex, $endIndex); |
161 | 145 | foreach (array_reverse(array_keys($ctClassTokens)) as $classIndex) { |
162 | | - $this->replaceClassKeyword($tokens, $classIndex); |
| 146 | + $this->replaceClassKeyword($tokens, $namespace, $classIndex); |
163 | 147 | } |
164 | 148 | } |
165 | 149 |
|
166 | 150 | /** |
167 | | - * @param int $classIndex |
| 151 | + * @param string $namespace |
| 152 | + * @param int $classIndex |
168 | 153 | */ |
169 | | - private function replaceClassKeyword(Tokens $tokens, $classIndex) |
| 154 | + private function replaceClassKeyword(Tokens $tokens, $namespace, $classIndex) |
170 | 155 | { |
171 | 156 | $classEndIndex = $tokens->getPrevMeaningfulToken($classIndex); |
172 | 157 | $classEndIndex = $tokens->getPrevMeaningfulToken($classEndIndex); |
@@ -218,20 +203,21 @@ private function replaceClassKeyword(Tokens $tokens, $classIndex) |
218 | 203 |
|
219 | 204 | $tokens->insertAt($classBeginIndex, new Token([ |
220 | 205 | T_CONSTANT_ENCAPSED_STRING, |
221 | | - "'".$this->makeClassFQN($classImport, $classString)."'", |
| 206 | + "'".$this->makeClassFQN($namespace, $classImport, $classString)."'", |
222 | 207 | ])); |
223 | 208 | } |
224 | 209 |
|
225 | 210 | /** |
| 211 | + * @param string $namespace |
226 | 212 | * @param false|string $classImport |
227 | 213 | * @param string $classString |
228 | 214 | * |
229 | 215 | * @return string |
230 | 216 | */ |
231 | | - private function makeClassFQN($classImport, $classString) |
| 217 | + private function makeClassFQN($namespace, $classImport, $classString) |
232 | 218 | { |
233 | 219 | if (false === $classImport) { |
234 | | - return $classString; |
| 220 | + return ('' !== $namespace ? ($namespace.'\\') : '').$classString; |
235 | 221 | } |
236 | 222 |
|
237 | 223 | $classStringArray = explode('\\', $classString); |
|
0 commit comments