77use VariableAnalysis \Lib \VariableInfo ;
88use VariableAnalysis \Lib \Constants ;
99use VariableAnalysis \Lib \Helpers ;
10+ use VariableAnalysis \Lib \ScopeManager ;
1011use PHP_CodeSniffer \Sniffs \Sniff ;
1112use PHP_CodeSniffer \Files \File ;
1213use PHP_CodeSniffer \Util \Tokens ;
@@ -21,36 +22,9 @@ class VariableAnalysisSniff implements Sniff
2122 protected $ currentFile = null ;
2223
2324 /**
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
4526 */
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 ;
5428
5529 /**
5630 * A list of custom functions which pass in variables to be initialized by
@@ -165,6 +139,11 @@ class VariableAnalysisSniff implements Sniff
165139 */
166140 public $ allowUnusedVariablesBeforeRequire = false ;
167141
142+ public function __construct ()
143+ {
144+ $ this ->scopeManager = new ScopeManager ();
145+ }
146+
168147 /**
169148 * Decide which tokens to scan.
170149 *
@@ -237,13 +216,12 @@ public function process(File $phpcsFile, $stackPtr)
237216 // easily accessed in other places which aren't passed the object.
238217 if ($ this ->currentFile !== $ phpcsFile ) {
239218 $ this ->currentFile = $ phpcsFile ;
240- // Reset the scope end cache when the File changes since it is per-file.
241- $ this ->scopeEndIndexCache = [];
242219 }
243220
244221 // 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 );
247225 }
248226
249227 // Report variables defined but not used in the current scope as unused
@@ -282,69 +260,11 @@ public function process(File $phpcsFile, $stackPtr)
282260 Helpers::isArrowFunction ($ phpcsFile , $ stackPtr )
283261 ) {
284262 Helpers::debug ('found scope condition ' , $ token );
285- $ this ->recordScopeStartAndEnd ($ phpcsFile , $ stackPtr );
263+ $ this ->scopeManager -> recordScopeStartAndEnd ($ phpcsFile , $ stackPtr );
286264 return ;
287265 }
288266 }
289267
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-
348268 /**
349269 * Find scopes closed by a token and process their variables.
350270 *
@@ -357,7 +277,7 @@ function ($found, $scope) use ($stackPtr) {
357277 */
358278 private function searchForAndProcessClosingScopesAt ($ phpcsFile , $ stackPtr )
359279 {
360- $ scopeIndicesThisCloses = $ this ->getScopesClosedBy ($ phpcsFile , $ stackPtr );
280+ $ scopeIndicesThisCloses = $ this ->scopeManager -> getScopesForScopeEnd ($ phpcsFile-> getFilename () , $ stackPtr );
361281
362282 foreach ($ scopeIndicesThisCloses as $ scopeIndexThisCloses ) {
363283 Helpers::debug ('found closing scope at index ' , $ stackPtr , 'for scopes starting at: ' , $ scopeIndexThisCloses );
@@ -388,16 +308,6 @@ protected function isGetDefinedVars(File $phpcsFile, $stackPtr)
388308 return true ;
389309 }
390310
391- /**
392- * @param int $currScope
393- *
394- * @return string
395- */
396- protected function getScopeKey ($ currScope )
397- {
398- return $ this ->getFilename () . ': ' . $ currScope ;
399- }
400-
401311 /**
402312 * @return string
403313 */
@@ -406,29 +316,21 @@ protected function getFilename()
406316 return $ this ->currentFile ? $ this ->currentFile ->getFilename () : 'unknown file ' ;
407317 }
408318
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-
420319 /**
421320 * @param int $currScope
422321 *
423322 * @return ScopeInfo
424323 */
425324 protected function getOrCreateScopeInfo ($ currScope )
426325 {
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 );
430332 }
431- return $ this -> scopes [ $ scopeKey ] ;
333+ return $ scope ;
432334 }
433335
434336 /**
@@ -439,7 +341,7 @@ protected function getOrCreateScopeInfo($currScope)
439341 */
440342 protected function getVariableInfo ($ varName , $ currScope )
441343 {
442- $ scopeInfo = $ this ->getScopeInfo ( $ currScope );
344+ $ scopeInfo = $ this ->scopeManager -> getScopeForScopeStart ( $ this -> getFilename (), $ currScope );
443345 return ($ scopeInfo && isset ($ scopeInfo ->variables [$ varName ])) ? $ scopeInfo ->variables [$ varName ] : null ;
444346 }
445347
@@ -1873,7 +1775,7 @@ protected function processCompact(File $phpcsFile, $stackPtr)
18731775 */
18741776 protected function processScopeClose (File $ phpcsFile , $ stackPtr )
18751777 {
1876- $ scopeInfo = $ this ->getScopeInfo ( $ stackPtr );
1778+ $ scopeInfo = $ this ->scopeManager -> getScopeForScopeStart ( $ phpcsFile -> getFilename (), $ stackPtr );
18771779 if (is_null ($ scopeInfo )) {
18781780 return ;
18791781 }
0 commit comments