Skip to content

Commit

Permalink
Fix File::isReference() method
Browse files Browse the repository at this point in the history
The `File:isReference()` method misidentified a number of situations where the `T_BITWISE_AND` token was encountered, most notably:
* An array assignment of a calculated value with a bitwise and operator in it ,was being misidentified as a reference.
* A calculated default value for a function parameter with a bitwise and operator in it, was being misidentified as a reference.
* New by reference was not recognized as a reference.
* References to class properties with `self::`, `parent::`, `static::`, `namespace\Class::`, `classname::` were not recognized as references.

This commit fixes these cases.

Fixes 1604
  • Loading branch information
jrfnl committed Aug 15, 2017
1 parent 611d868 commit badc598
Showing 1 changed file with 60 additions and 22 deletions.
82 changes: 60 additions & 22 deletions src/Files/File.php
Original file line number Diff line number Diff line change
Expand Up @@ -1612,7 +1612,7 @@ public function isReference($stackPtr)
}

if ($this->tokens[$tokenBefore]['code'] === T_DOUBLE_ARROW) {
// Inside a foreach loop, this is a reference.
// Inside a foreach loop or array assignment, this is a reference.
return true;
}

Expand All @@ -1621,29 +1621,51 @@ public function isReference($stackPtr)
return true;
}

if ($this->tokens[$tokenBefore]['code'] === T_OPEN_SHORT_ARRAY) {
// Inside an array declaration, this is a reference.
return true;
}

if (isset(Util\Tokens::$assignmentTokens[$this->tokens[$tokenBefore]['code']]) === true) {
// This is directly after an assignment. It's a reference. Even if
// it is part of an operation, the other tests will handle it.
return true;
}

$tokenAfter = $this->findNext(
Util\Tokens::$emptyTokens,
($stackPtr + 1),
null,
true
);

if ($this->tokens[$tokenAfter]['code'] === T_NEW) {
return true;
}

if (isset($this->tokens[$stackPtr]['nested_parenthesis']) === true) {
$brackets = $this->tokens[$stackPtr]['nested_parenthesis'];
$lastBracket = array_pop($brackets);
if (isset($this->tokens[$lastBracket]['parenthesis_owner']) === true) {
$owner = $this->tokens[$this->tokens[$lastBracket]['parenthesis_owner']];
if ($owner['code'] === T_FUNCTION
|| $owner['code'] === T_CLOSURE
|| $owner['code'] === T_ARRAY
) {
// Inside a function or array declaration, this is a reference.
return true;
}
$params = $this->getMethodParameters($this->tokens[$lastBracket]['parenthesis_owner']);
foreach ($params as $param) {
$varToken = $tokenAfter;
if ($param['variable_length'] === true) {
$varToken = $this->findNext(
(Util\Tokens::$emptyTokens + array(T_ELLIPSIS)),
($stackPtr + 1),
null,
true
);
}

if ($param['token'] === $varToken
&& $param['pass_by_reference'] === true
) {
// Function parameter declared to be passed by reference.
return true;
}
}
}//end if
} else {
$prev = false;
for ($t = ($this->tokens[$lastBracket]['parenthesis_opener'] - 1); $t >= 0; $t--) {
Expand All @@ -1654,24 +1676,40 @@ public function isReference($stackPtr)
}

if ($prev !== false && $this->tokens[$prev]['code'] === T_USE) {
// Closure use by reference.
return true;
}
}//end if
}//end if

$tokenAfter = $this->findNext(
Util\Tokens::$emptyTokens,
($stackPtr + 1),
null,
true
);

if ($this->tokens[$tokenAfter]['code'] === T_VARIABLE
&& ($this->tokens[$tokenBefore]['code'] === T_OPEN_PARENTHESIS
|| $this->tokens[$tokenBefore]['code'] === T_COMMA)
// Pass by reference in function calls and assign by reference in arrays.
if ($this->tokens[$tokenBefore]['code'] === T_OPEN_PARENTHESIS
|| $this->tokens[$tokenBefore]['code'] === T_COMMA
|| $this->tokens[$tokenBefore]['code'] === T_OPEN_SHORT_ARRAY
) {
return true;
}
if ($this->tokens[$tokenAfter]['code'] === T_VARIABLE) {
return true;
} else {
$skip = Util\Tokens::$emptyTokens;
$skip[] = T_NS_SEPARATOR;
$skip[] = T_SELF;
$skip[] = T_PARENT;
$skip[] = T_STATIC;
$skip[] = T_STRING;
$skip[] = T_NAMESPACE;
$skip[] = T_DOUBLE_COLON;

$nextSignificantAfter = $this->findNext(
$skip,
($stackPtr + 1),
null,
true
);
if ($this->tokens[$nextSignificantAfter]['code'] === T_VARIABLE) {
return true;
}
}//end if
}//end if

return false;

Expand Down

0 comments on commit badc598

Please sign in to comment.