Skip to content

Commit 2e0ecf2

Browse files
committed
Add namespace to function names when looking for pass-by-reference
1 parent 0deed7b commit 2e0ecf2

File tree

2 files changed

+62
-2
lines changed

2 files changed

+62
-2
lines changed

VariableAnalysis/Lib/Helpers.php

+35
Original file line numberDiff line numberDiff line change
@@ -1658,6 +1658,41 @@ public static function isConstructorPromotion(File $phpcsFile, $stackPtr)
16581658
return false;
16591659
}
16601660

1661+
/**
1662+
* If looking at a function call token, return a string for the full function
1663+
* name including any inline namespace.
1664+
*
1665+
* So for example, if the call looks like `\My\Namespace\doSomething($bar)`
1666+
* and `$stackPtr` refers to `doSomething`, this will return
1667+
* `\My\Namespace\doSomething`.
1668+
*
1669+
* @param File $phpcsFile
1670+
* @param int $stackPtr
1671+
*
1672+
* @return string|null
1673+
*/
1674+
public static function getFunctionNameWithNamespace(File $phpcsFile, $stackPtr)
1675+
{
1676+
$tokens = $phpcsFile->getTokens();
1677+
1678+
if (! isset($tokens[$stackPtr])) {
1679+
return null;
1680+
}
1681+
$startOfScope = self::findVariableScope($phpcsFile, $stackPtr);
1682+
$functionName = $tokens[$stackPtr]['content'];
1683+
1684+
// Move backwards from the token, collecting namespace separators and
1685+
// strings, until we encounter whitespace or something else.
1686+
$partOfNamespace = [T_NS_SEPARATOR, T_STRING];
1687+
for ($i = $stackPtr - 1; $i > $startOfScope; $i--) {
1688+
if (! in_array($tokens[$i]['code'], $partOfNamespace, true)) {
1689+
break;
1690+
}
1691+
$functionName = "{$tokens[$i]['content']}{$functionName}";
1692+
}
1693+
return $functionName;
1694+
}
1695+
16611696
/**
16621697
* Return false if the token is definitely not part of a typehint
16631698
*

VariableAnalysis/Sniffs/CodeAnalysis/VariableAnalysisSniff.php

+27-2
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,13 @@ class VariableAnalysisSniff implements Sniff
153153
*/
154154
public $allowUnusedVariablesBeforeRequire = false;
155155

156+
/**
157+
* A cache for getPassByReferenceFunctions
158+
*
159+
* @var array<array<int|string>>
160+
*/
161+
private $passByRefFunctionsCache = [];
162+
156163
public function __construct()
157164
{
158165
$this->scopeManager = new ScopeManager();
@@ -195,6 +202,18 @@ public function register()
195202
*/
196203
private function getPassByReferenceFunction($functionName)
197204
{
205+
$passByRefFunctions = $this->getPassByReferenceFunctions();
206+
return isset($passByRefFunctions[$functionName]) ? $passByRefFunctions[$functionName] : [];
207+
}
208+
209+
/**
210+
* @return array<array<int|string>>
211+
*/
212+
private function getPassByReferenceFunctions()
213+
{
214+
if ($this->passByRefFunctionsCache) {
215+
return $this->passByRefFunctionsCache;
216+
}
198217
$passByRefFunctions = Constants::getPassByReferenceFunctions();
199218
if (!empty($this->sitePassByRefFunctions)) {
200219
$lines = Helpers::splitStringToArray('/\s+/', trim($this->sitePassByRefFunctions));
@@ -206,7 +225,8 @@ private function getPassByReferenceFunction($functionName)
206225
if ($this->allowWordPressPassByRefFunctions) {
207226
$passByRefFunctions = array_merge($passByRefFunctions, Constants::getWordPressPassByReferenceFunctions());
208227
}
209-
return isset($passByRefFunctions[$functionName]) ? $passByRefFunctions[$functionName] : [];
228+
$this->passByRefFunctionsCache = $passByRefFunctions;
229+
return $passByRefFunctions;
210230
}
211231

212232
/**
@@ -1485,7 +1505,12 @@ protected function processVariableAsPassByReferenceFunctionCall(File $phpcsFile,
14851505
$functionName = $tokens[$functionPtr]['content'];
14861506
$refArgs = $this->getPassByReferenceFunction($functionName);
14871507
if (! $refArgs) {
1488-
return false;
1508+
// Check again with the fully namespaced function name.
1509+
$functionName = Helpers::getFunctionNameWithNamespace($phpcsFile, $functionPtr);
1510+
$refArgs = $this->getPassByReferenceFunction($functionName);
1511+
if (! $refArgs) {
1512+
return false;
1513+
}
14891514
}
14901515

14911516
$argPtrs = Helpers::findFunctionCallArguments($phpcsFile, $stackPtr);

0 commit comments

Comments
 (0)