Skip to content

Commit

Permalink
Fix complex constant return expression (#1)
Browse files Browse the repository at this point in the history
* Preserve meaningful test cases

* Fix BinaryOp, Scalar and ArrayDimFetch return cases

* Prefer spl_object_id over spl_object_hash

* Test multiline heredoc as well

* Adapt array types to spl_object_id return type
  • Loading branch information
Slamdunk authored Oct 28, 2022
1 parent 5409243 commit 548bcae
Show file tree
Hide file tree
Showing 3 changed files with 88 additions and 236 deletions.
44 changes: 36 additions & 8 deletions src/StaticAnalysis/ExecutableLinesFindingVisitor.php
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
use PhpParser\Node\Stmt\TryCatch;
use PhpParser\Node\Stmt\Unset_;
use PhpParser\Node\Stmt\While_;
use PhpParser\NodeAbstract;
use PhpParser\NodeVisitorAbstract;

/**
Expand All @@ -71,6 +72,11 @@ final class ExecutableLinesFindingVisitor extends NodeVisitorAbstract
*/
private $returns = [];

/**
* @psalm-var array<int, bool>
*/
private $arrayDimFetchVars = [];

public function enterNode(Node $node): void
{
$this->savePropertyLines($node);
Expand Down Expand Up @@ -123,7 +129,7 @@ private function computeReturns(): void
$line = $return->getEndLine();

if ($return->expr !== null) {
$line = $return->expr->getStartLine();
$line = $this->getNodeStartLine($return->expr);
}

$this->executableLines[$line] = $line;
Expand All @@ -136,13 +142,6 @@ private function computeReturns(): void
private function getLines(Node $node): array
{
if ($node instanceof BinaryOp) {
if (($node->left instanceof Node\Scalar ||
$node->left instanceof Node\Expr\ConstFetch) &&
($node->right instanceof Node\Scalar ||
$node->right instanceof Node\Expr\ConstFetch)) {
return [$node->right->getStartLine()];
}

return [];
}

Expand All @@ -154,6 +153,8 @@ private function getLines(Node $node): array
}

if ($node instanceof ArrayDimFetch) {
$this->arrayDimFetchVars[spl_object_id($node->var)] = true;

if (null === $node->dim) {
return [];
}
Expand All @@ -162,6 +163,10 @@ private function getLines(Node $node): array
}

if ($node instanceof Array_) {
if (isset($this->arrayDimFetchVars[spl_object_id($node)])) {
return [];
}

$startLine = $node->getStartLine();

if (isset($this->executableLines[$startLine])) {
Expand Down Expand Up @@ -242,6 +247,29 @@ private function getLines(Node $node): array
return [$node->getStartLine()];
}

private function getNodeStartLine(NodeAbstract $node): int
{
if ($node instanceof Node\Expr\BooleanNot ||
$node instanceof Node\Expr\AssignOp\ShiftLeft ||
$node instanceof Node\Expr\AssignOp\ShiftRight
) {
return $node->getEndLine();
}

if ($node instanceof BinaryOp) {
return $this->getNodeStartLine($node->right);
}

if ($node instanceof Node\Scalar\String_ && (
$node->getAttribute('kind') === Node\Scalar\String_::KIND_HEREDOC ||
$node->getAttribute('kind') === Node\Scalar\String_::KIND_NOWDOC
)) {
return $node->getStartLine() + 1;
}

return $node->getStartLine();
}

private function isExecutable(Node $node): bool
{
return $node instanceof Assign ||
Expand Down
221 changes: 36 additions & 185 deletions tests/_files/source_with_multiline_constant_return.php
Original file line number Diff line number Diff line change
Expand Up @@ -245,22 +245,7 @@ public function Spaceship(): int
;
}

public function nowdocSimpleA(): string
{
return <<<'EOF'
foo
EOF;
}

public function nowdocSimpleB(): string
{
return
<<<'EOF'
foo
EOF;
}

public function nowdocSimpleC(): string
public function nowdoc(): string
{
return
<<<'EOF'
Expand Down Expand Up @@ -316,17 +301,8 @@ public function complexAssociativityRight(): int
**
2
**
3;
}

public function complexAssociativityLeft(): int
{
return
1
>>
2
>>
3;
3
;
}

public function complexAssociativityNa(): bool
Expand All @@ -335,7 +311,8 @@ public function complexAssociativityNa(): bool
!
!
!
false;
false
;
}

public function complexTernary(): int
Expand All @@ -347,17 +324,8 @@ public function complexTernary(): int
? 3
: 4
)
: 5;
}

public function complexNullCoalescing(): int
{
return
null
??
1
??
null;
: 5
;
}

public function constFromArray(): string
Expand All @@ -368,165 +336,48 @@ public function constFromArray(): string
'ro',
'fi',
'omega',
][2];
]
[2]
;
}

public function withNotConstInTheMiddle(): string
{
return
''
. ''
. phpversion()
. ''
. '';
}

public function andA(): bool
{
return
true
&& false;
}

public function andB(): bool
{
return
true
&& true;
}

public function andC(): bool
{
return
false
&& true;
}

public function andD(): bool
{
return
false
&& false;
}

public function andE(): bool
{
return
__TRAIT__ // compile time constant evaluated to false
&& 1
&& 0;
}

public function andF(): bool
{
return
PHP_VERSION_ID // compile time constant evaluated to true
&& 1
&& 0;
}

public function orA(): bool
{
return
true
|| false;
}

public function orB(): bool
{
return
true
|| true;
}

public function orC(): bool
{
return
false
|| true;
}

public function orD(): bool
{
return
false
|| false;
}

public function orE(): bool
{
return
__TRAIT__
|| true
|| false;
}

public function orF(): bool
{
return
PHP_VERSION_ID
|| true
|| false;
}

public function orG(): bool
{
return
PHP_VERSION_ID === PHP_VERSION_ID
|| true
|| false;
.
''
.
phpversion()
.
''
.
''
;
}

public function orH(): bool
public function multipleConcats(): string
{
return
PHP_VERSION_ID !== PHP_VERSION_ID
|| true
|| false;
}

public function constIfFalseA(): bool
{
if (false) {
return true;
}

return false;
}

public function constIfFalseB(): bool
{
if (__TRAIT__) {
return true;
}

return false;
}

public function constIfTrueA(): bool
{
if (true) {
return true;
}

return false;
}

public function constIfTrueB(): bool
{
if (PHP_VERSION_ID) {
return true;
}

return false;
'a'
.
'b'
.
'c'
.
'd'
.
'e'
;
}

public function constIfUnknown(): bool
public function multilineHeredoc(): string
{
if (__NOT_EXPECTED_TO_BE_KNOWN_CONSTANT__) {
return true;
}
return <<<EOF
a
b
c
EOF;

return false;
}
}
Loading

0 comments on commit 548bcae

Please sign in to comment.