7
7
use VariableAnalysis \Lib \VariableInfo ;
8
8
use VariableAnalysis \Lib \Constants ;
9
9
use VariableAnalysis \Lib \Helpers ;
10
+ use VariableAnalysis \Lib \ScopeManager ;
10
11
use PHP_CodeSniffer \Sniffs \Sniff ;
11
12
use PHP_CodeSniffer \Files \File ;
12
13
use PHP_CodeSniffer \Util \Tokens ;
@@ -21,36 +22,9 @@ class VariableAnalysisSniff implements Sniff
21
22
protected $ currentFile = null ;
22
23
23
24
/**
24
- * An associative array of scopes for variables encountered so far and the
25
- * variables within them.
26
- *
27
- * Each scope is keyed by a string of the form `filename:scopeStartIndex`
28
- * (see `getScopeKey`).
29
- *
30
- * @var array<string, ScopeInfo>
31
- */
32
- private $ scopes = [];
33
-
34
- /**
35
- * An associative array of a list of token index pairs which start and end
36
- * scopes and will be used to check for unused variables.
37
- *
38
- * Each array of scopes is keyed by a string containing the filename (see
39
- * `getFilename`).
40
- *
41
- * Unlike the `ScopeInfo` objects stored in `$this->scopes`, these objects do
42
- * not track variables themselves, only the position of the scope boundaries.
43
- *
44
- * @var array<string, ScopeInfo[]>
25
+ * @var ScopeManager
45
26
*/
46
- private $ scopeStartEndPairs = [];
47
-
48
- /**
49
- * A cache of scope end indices in the current file to improve performance.
50
- *
51
- * @var int[]
52
- */
53
- private $ scopeEndIndexCache = [];
27
+ private $ scopeManager ;
54
28
55
29
/**
56
30
* A list of custom functions which pass in variables to be initialized by
@@ -165,6 +139,11 @@ class VariableAnalysisSniff implements Sniff
165
139
*/
166
140
public $ allowUnusedVariablesBeforeRequire = false ;
167
141
142
+ public function __construct ()
143
+ {
144
+ $ this ->scopeManager = new ScopeManager ();
145
+ }
146
+
168
147
/**
169
148
* Decide which tokens to scan.
170
149
*
@@ -237,13 +216,12 @@ public function process(File $phpcsFile, $stackPtr)
237
216
// easily accessed in other places which aren't passed the object.
238
217
if ($ this ->currentFile !== $ phpcsFile ) {
239
218
$ this ->currentFile = $ phpcsFile ;
240
- // Reset the scope end cache when the File changes since it is per-file.
241
- $ this ->scopeEndIndexCache = [];
242
219
}
243
220
244
221
// Add the global scope for the current file to our scope indexes.
245
- if (empty ($ this ->scopeStartEndPairs [$ this ->getFilename ()])) {
246
- $ this ->recordScopeStartAndEnd ($ phpcsFile , 0 );
222
+ $ scopesForFilename = $ this ->scopeManager ->getScopesForFilename ($ phpcsFile ->getFilename ());
223
+ if (empty ($ scopesForFilename )) {
224
+ $ this ->scopeManager ->recordScopeStartAndEnd ($ phpcsFile , 0 );
247
225
}
248
226
249
227
// Report variables defined but not used in the current scope as unused
@@ -282,69 +260,11 @@ public function process(File $phpcsFile, $stackPtr)
282
260
Helpers::isArrowFunction ($ phpcsFile , $ stackPtr )
283
261
) {
284
262
Helpers::debug ('found scope condition ' , $ token );
285
- $ this ->recordScopeStartAndEnd ($ phpcsFile , $ stackPtr );
263
+ $ this ->scopeManager -> recordScopeStartAndEnd ($ phpcsFile , $ stackPtr );
286
264
return ;
287
265
}
288
266
}
289
267
290
- /**
291
- * Add a scope's start and end index to our record for the file.
292
- *
293
- * @param File $phpcsFile
294
- * @param int $scopeStartIndex
295
- *
296
- * @return void
297
- */
298
- private function recordScopeStartAndEnd ($ phpcsFile , $ scopeStartIndex )
299
- {
300
- $ scopeEndIndex = Helpers::getScopeCloseForScopeOpen ($ phpcsFile , $ scopeStartIndex );
301
- $ filename = $ this ->getFilename ();
302
- if (! isset ($ this ->scopeStartEndPairs [$ filename ])) {
303
- $ this ->scopeStartEndPairs [$ filename ] = [];
304
- }
305
- Helpers::debug ('recording scope for file ' , $ filename , 'start/end ' , $ scopeStartIndex , $ scopeEndIndex );
306
- $ this ->scopeStartEndPairs [$ filename ][] = new ScopeInfo ($ scopeStartIndex , $ scopeEndIndex );
307
- $ this ->scopeEndIndexCache [] = $ scopeEndIndex ;
308
- }
309
-
310
- /**
311
- * Find scopes closed by a token.
312
- *
313
- * @param File $phpcsFile
314
- * @param int $stackPtr
315
- *
316
- * @return ScopeInfo[]
317
- */
318
- private function getScopesClosedBy ($ phpcsFile , $ stackPtr )
319
- {
320
- if (! in_array ($ stackPtr , $ this ->scopeEndIndexCache , true )) {
321
- return [];
322
- }
323
- $ scopePairsForFile = isset ($ this ->scopeStartEndPairs [$ this ->getFilename ()]) ? $ this ->scopeStartEndPairs [$ this ->getFilename ()] : [];
324
- $ scopeIndicesThisCloses = array_reduce (
325
- $ scopePairsForFile ,
326
- /**
327
- * @param ScopeInfo[] $found
328
- * @param ScopeInfo $scope
329
- *
330
- * @return ScopeInfo[]
331
- */
332
- function ($ found , $ scope ) use ($ stackPtr ) {
333
- if (! is_int ($ scope ->scopeEndIndex )) {
334
- Helpers::debug ('No scope closer found for scope start ' , $ scope ->scopeStartIndex );
335
- return $ found ;
336
- }
337
-
338
- if ($ stackPtr === $ scope ->scopeEndIndex ) {
339
- $ found [] = $ scope ;
340
- }
341
- return $ found ;
342
- },
343
- []
344
- );
345
- return $ scopeIndicesThisCloses ;
346
- }
347
-
348
268
/**
349
269
* Find scopes closed by a token and process their variables.
350
270
*
@@ -357,7 +277,7 @@ function ($found, $scope) use ($stackPtr) {
357
277
*/
358
278
private function searchForAndProcessClosingScopesAt ($ phpcsFile , $ stackPtr )
359
279
{
360
- $ scopeIndicesThisCloses = $ this ->getScopesClosedBy ($ phpcsFile , $ stackPtr );
280
+ $ scopeIndicesThisCloses = $ this ->scopeManager -> getScopesForScopeEnd ($ phpcsFile-> getFilename () , $ stackPtr );
361
281
362
282
foreach ($ scopeIndicesThisCloses as $ scopeIndexThisCloses ) {
363
283
Helpers::debug ('found closing scope at index ' , $ stackPtr , 'for scopes starting at: ' , $ scopeIndexThisCloses );
@@ -388,16 +308,6 @@ protected function isGetDefinedVars(File $phpcsFile, $stackPtr)
388
308
return true ;
389
309
}
390
310
391
- /**
392
- * @param int $currScope
393
- *
394
- * @return string
395
- */
396
- protected function getScopeKey ($ currScope )
397
- {
398
- return $ this ->getFilename () . ': ' . $ currScope ;
399
- }
400
-
401
311
/**
402
312
* @return string
403
313
*/
@@ -406,29 +316,21 @@ protected function getFilename()
406
316
return $ this ->currentFile ? $ this ->currentFile ->getFilename () : 'unknown file ' ;
407
317
}
408
318
409
- /**
410
- * @param int $currScope
411
- *
412
- * @return ScopeInfo|null
413
- */
414
- protected function getScopeInfo ($ currScope )
415
- {
416
- $ scopeKey = $ this ->getScopeKey ($ currScope );
417
- return isset ($ this ->scopes [$ scopeKey ]) ? $ this ->scopes [$ scopeKey ] : null ;
418
- }
419
-
420
319
/**
421
320
* @param int $currScope
422
321
*
423
322
* @return ScopeInfo
424
323
*/
425
324
protected function getOrCreateScopeInfo ($ currScope )
426
325
{
427
- $ scopeKey = $ this ->getScopeKey ($ currScope );
428
- if (!isset ($ this ->scopes [$ scopeKey ])) {
429
- $ this ->scopes [$ scopeKey ] = new ScopeInfo ($ currScope );
326
+ $ scope = $ this ->scopeManager ->getScopeForScopeStart ($ this ->getFilename (), $ currScope );
327
+ if (! $ scope ) {
328
+ if (! $ this ->currentFile ) {
329
+ throw new \Exception ('Cannot create scope info; current file is not set. ' );
330
+ }
331
+ $ scope = $ this ->scopeManager ->recordScopeStartAndEnd ($ this ->currentFile , $ currScope );
430
332
}
431
- return $ this -> scopes [ $ scopeKey ] ;
333
+ return $ scope ;
432
334
}
433
335
434
336
/**
@@ -439,7 +341,7 @@ protected function getOrCreateScopeInfo($currScope)
439
341
*/
440
342
protected function getVariableInfo ($ varName , $ currScope )
441
343
{
442
- $ scopeInfo = $ this ->getScopeInfo ( $ currScope );
344
+ $ scopeInfo = $ this ->scopeManager -> getScopeForScopeStart ( $ this -> getFilename (), $ currScope );
443
345
return ($ scopeInfo && isset ($ scopeInfo ->variables [$ varName ])) ? $ scopeInfo ->variables [$ varName ] : null ;
444
346
}
445
347
@@ -1873,7 +1775,7 @@ protected function processCompact(File $phpcsFile, $stackPtr)
1873
1775
*/
1874
1776
protected function processScopeClose (File $ phpcsFile , $ stackPtr )
1875
1777
{
1876
- $ scopeInfo = $ this ->getScopeInfo ( $ stackPtr );
1778
+ $ scopeInfo = $ this ->scopeManager -> getScopeForScopeStart ( $ phpcsFile -> getFilename (), $ stackPtr );
1877
1779
if (is_null ($ scopeInfo )) {
1878
1780
return ;
1879
1781
}
0 commit comments