1111use PHP_CodeSniffer \Files \File ;
1212use PHP_CodeSniffer \Util \Tokens ;
1313use PHPCSUtils \Utils \Lists ;
14+ use PHPCSUtils \Utils \FunctionDeclarations ;
1415
1516class VariableAnalysisSniff implements Sniff {
1617 /**
@@ -117,6 +118,7 @@ public function register() {
117118 T_HEREDOC ,
118119 T_CLOSE_CURLY_BRACKET ,
119120 T_STRING ,
121+ T_FN , // TODO: we can't use this before php 7.4 so we need to replace it somehow
120122 ];
121123 }
122124
@@ -175,7 +177,11 @@ public function process(File $phpcsFile, $stackPtr) {
175177 $ this ->processScopeClose ($ phpcsFile , $ token ['scope_condition ' ]);
176178 return ;
177179 }
178- // TODO: process scope close for arrow functions (how do we know where the scope ends?)
180+ if (($ token ['type ' ] === 'T_FN ' ) && isset ($ token ['scope_closer ' ])) {
181+ Helpers::debug ('found arrow function ' , $ token );
182+ $ this ->processScopeClose ($ phpcsFile , $ token ['scope_closer ' ] - 1 );
183+ return ;
184+ }
179185 }
180186
181187 /**
@@ -248,9 +254,10 @@ protected function getVariableInfo($varName, $currScope) {
248254 * @return VariableInfo
249255 */
250256 protected function getOrCreateVariableInfo ($ varName , $ currScope ) {
257+ // TODO: this needs to find the scope of an arrow function if we are inside one, which must also include the scope of its parent!
251258 $ scopeInfo = $ this ->getOrCreateScopeInfo ($ currScope );
252259 if (!isset ($ scopeInfo ->variables [$ varName ])) {
253- Helpers::debug (' creating new variable for ' , $ varName, ' in scope ' , $ scopeInfo );
260+ Helpers::debug (" creating a new variable for ' { $ varName} ' in scope" , $ scopeInfo );
254261 $ scopeInfo ->variables [$ varName ] = new VariableInfo ($ varName );
255262 $ validUnusedVariableNames = (empty ($ this ->validUnusedVariableNames ))
256263 ? []
@@ -268,7 +275,7 @@ protected function getOrCreateVariableInfo($varName, $currScope) {
268275 $ scopeInfo ->variables [$ varName ]->ignoreUndefined = true ;
269276 }
270277 }
271- Helpers::debug (' scope for ' , $ varName, ' in scope ' , $ currScope , ' is ' , $ scopeInfo );
278+ Helpers::debug (" scope for ' { $ varName} ' is now " , $ scopeInfo );
272279 return $ scopeInfo ->variables [$ varName ];
273280 }
274281
@@ -334,7 +341,7 @@ protected function markVariableDeclaration(
334341 $ currScope ,
335342 $ permitMatchingRedeclaration = false
336343 ) {
337- Helpers::debug (' marking variable declared ' , $ varName , $ currScope );
344+ Helpers::debug (" marking variable ' { $ varName} ' declared in scope starting at token " , $ currScope );
338345 $ varInfo = $ this ->getOrCreateVariableInfo ($ varName , $ currScope );
339346 if (isset ($ varInfo ->scopeType )) {
340347 if (($ permitMatchingRedeclaration === false ) || ($ varInfo ->scopeType !== $ scopeType )) {
@@ -359,11 +366,11 @@ protected function markVariableDeclaration(
359366 $ varInfo ->typeHint = $ typeHint ;
360367 }
361368 if (isset ($ varInfo ->firstDeclared ) && ($ varInfo ->firstDeclared <= $ stackPtr )) {
362- Helpers::debug (' variable was already marked declared ' , $ varName , $ varInfo );
369+ Helpers::debug (" variable ' { $ varName } ' was already marked declared" , $ varInfo );
363370 return ;
364371 }
365372 $ varInfo ->firstDeclared = $ stackPtr ;
366- Helpers::debug (' variable marked declared ' , $ varName , $ varInfo );
373+ Helpers::debug (" variable ' { $ varName} ' marked declared " , $ varInfo );
367374 }
368375
369376 /**
@@ -433,7 +440,6 @@ protected function isVariableUndefined($varName, $stackPtr, $currScope) {
433440 */
434441 protected function markVariableReadAndWarnIfUndefined ($ phpcsFile , $ varName , $ stackPtr , $ currScope ) {
435442 $ this ->markVariableRead ($ varName , $ stackPtr , $ currScope );
436- // TODO: this is not finding variables defined in an arrow function scope
437443 if ($ this ->isVariableUndefined ($ varName , $ stackPtr , $ currScope ) === true ) {
438444 Helpers::debug ("variable $ varName looks undefined " );
439445 $ phpcsFile ->addWarning (
@@ -472,7 +478,7 @@ protected function markAllVariablesRead(File $phpcsFile, $stackPtr) {
472478 *
473479 * @return bool
474480 */
475- protected function checkForFunctionPrototype (File $ phpcsFile , $ stackPtr , $ varName , $ currScope ) {
481+ protected function checkForFunctionDefinition (File $ phpcsFile , $ stackPtr , $ varName , $ currScope ) {
476482 $ tokens = $ phpcsFile ->getTokens ();
477483
478484 // Are we a function or closure parameter?
@@ -489,7 +495,7 @@ protected function checkForFunctionPrototype(File $phpcsFile, $stackPtr, $varNam
489495 (is_int ($ functionPtr ))
490496 && (
491497 ($ tokens [$ functionPtr ]['code ' ] === T_FUNCTION )
492- || ($ tokens [ $ functionPtr][ ' code ' ] === T_FN ) // TODO: we can't use this because it's only in php7.4, use \PHPCSUtils\Utils\isArrowFunction instead
498+ || (FunctionDeclarations:: isArrowFunction ( $ phpcsFile , $ functionPtr))
493499 || ($ tokens [$ functionPtr ]['code ' ] === T_CLOSURE )
494500 )
495501 ) {
@@ -512,7 +518,7 @@ protected function checkForFunctionPrototype(File $phpcsFile, $stackPtr, $varNam
512518 $ this ->markVariableRead ($ varName , $ stackPtr , $ currScope );
513519 if ($ this ->isVariableUndefined ($ varName , $ stackPtr , $ currScope ) === true ) {
514520 // We haven't been defined by this point.
515- Helpers::debug ("variable $ varName in function prototype looks undefined " );
521+ Helpers::debug ("variable ' { $ varName} ' in function definition looks undefined " );
516522 $ phpcsFile ->addWarning ("Variable %s is undefined. " , $ stackPtr , 'UndefinedVariable ' , ["\${$ varName }" ]);
517523 return true ;
518524 }
@@ -1146,7 +1152,7 @@ protected function processVariable(File $phpcsFile, $stackPtr) {
11461152 $ token = $ tokens [$ stackPtr ];
11471153
11481154 $ varName = Helpers::normalizeVarName ($ token ['content ' ]);
1149- Helpers::debug (' examining token ' . $ varName );
1155+ Helpers::debug (" examining token for variable ' { $ varName} ' " , $ token );
11501156 $ currScope = Helpers::findVariableScope ($ phpcsFile , $ stackPtr );
11511157 if ($ currScope === null ) {
11521158 Helpers::debug ('no scope found ' );
@@ -1180,8 +1186,8 @@ protected function processVariable(File $phpcsFile, $stackPtr) {
11801186 }
11811187
11821188 // Are we a function or closure parameter?
1183- if ($ this ->checkForFunctionPrototype ($ phpcsFile , $ stackPtr , $ varName , $ currScope )) {
1184- Helpers::debug ('found function prototype ' );
1189+ if ($ this ->checkForFunctionDefinition ($ phpcsFile , $ stackPtr , $ varName , $ currScope )) {
1190+ Helpers::debug ('found function definition ' );
11851191 return ;
11861192 }
11871193
0 commit comments