Skip to content

Commit 3ea2c00

Browse files
committed
Try to process scope close for arrow functions
1 parent b3eca86 commit 3ea2c00

File tree

1 file changed

+19
-13
lines changed

1 file changed

+19
-13
lines changed

VariableAnalysis/Sniffs/CodeAnalysis/VariableAnalysisSniff.php

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
use PHP_CodeSniffer\Files\File;
1212
use PHP_CodeSniffer\Util\Tokens;
1313
use PHPCSUtils\Utils\Lists;
14+
use PHPCSUtils\Utils\FunctionDeclarations;
1415

1516
class 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

Comments
 (0)