Skip to content

Commit 83e12cb

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

File tree

2 files changed

+64
-2
lines changed

2 files changed

+64
-2
lines changed

Diff for: 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
*

Diff for: VariableAnalysis/Sniffs/CodeAnalysis/VariableAnalysisSniff.php

+29-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,20 @@ 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+
* @param string $functionName
211+
*
212+
* @return array<array<int|string>>
213+
*/
214+
private function getPassByReferenceFunctions()
215+
{
216+
if ($this->passByRefFunctionsCache) {
217+
return $this->passByRefFunctionsCache;
218+
}
198219
$passByRefFunctions = Constants::getPassByReferenceFunctions();
199220
if (!empty($this->sitePassByRefFunctions)) {
200221
$lines = Helpers::splitStringToArray('/\s+/', trim($this->sitePassByRefFunctions));
@@ -206,7 +227,8 @@ private function getPassByReferenceFunction($functionName)
206227
if ($this->allowWordPressPassByRefFunctions) {
207228
$passByRefFunctions = array_merge($passByRefFunctions, Constants::getWordPressPassByReferenceFunctions());
208229
}
209-
return isset($passByRefFunctions[$functionName]) ? $passByRefFunctions[$functionName] : [];
230+
$this->passByRefFunctionsCache = $passByRefFunctions;
231+
return $passByRefFunctions;
210232
}
211233

212234
/**
@@ -1485,7 +1507,12 @@ protected function processVariableAsPassByReferenceFunctionCall(File $phpcsFile,
14851507
$functionName = $tokens[$functionPtr]['content'];
14861508
$refArgs = $this->getPassByReferenceFunction($functionName);
14871509
if (! $refArgs) {
1488-
return false;
1510+
// Check again with the fully namespaced function name.
1511+
$functionName = Helpers::getFunctionNameWithNamespace($phpcsFile, $functionPtr);
1512+
$refArgs = $this->getPassByReferenceFunction($functionName);
1513+
if (! $refArgs) {
1514+
return false;
1515+
}
14891516
}
14901517

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

0 commit comments

Comments
 (0)