Completed
Pull Request — master (#293)
by Дмитрий
02:30
created

ControlFlowGraph::passReturn()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 2
dl 0
loc 4
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * @author Patsura Dmitry https://github.com/ovr <[email protected]>
4
 */
5
6
namespace PHPSA\ControlFlow\Graph;
7
8
9
use PhpParser\Node\Stmt\Function_;
10
use PHPSA\ControlFlow\Node\Assign;
11
use PHPSA\ControlFlow\Node\Exit_;
12
use PHPSA\ControlFlow\Node\JumpIf;
13
use PHPSA\ControlFlow\Node\Return_;
14
15
class ControlFlowGraph
16
{
17
    protected $root;
18
19
    protected $lastBlockId = 1;
20
21
    public function __construct($statement)
22
    {
23
        $block = new Block($this->lastBlockId++);
24
25
        if ($statement instanceof Function_) {
26
            if ($statement->stmts) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $statement->stmts of type PhpParser\Node[] is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
27
                $this->passNodes($statement->stmts, $block);
28
            }
29
        }
30
31
        $printer = new \PHPSA\ControlFlow\Printer\DebugText();
32
        $printer->printGraph($block);
33
    }
34
35
    protected function passNodes(array $nodes, Block $block) {
36
        foreach ($nodes as $stmt) {
37
            switch (get_class($stmt)) {
38
                case \PhpParser\Node\Expr\Assign::class:
39
                    $this->passAssign($stmt, $block);
40
                    break;
41
                case \PhpParser\Node\Stmt\Return_::class:
42
                    $this->passReturn($stmt, $block);
43
                    break;
44
                case \PhpParser\Node\Stmt\For_::class:
45
                    $block = $this->passFor($stmt, $block);
46
                    break;
47
                case \PhpParser\Node\Stmt\If_::class:
48
                    $block = $this->passIf($stmt, $block);
49
                    break;
50
                case \PhpParser\Node\Expr\Exit_::class:
51
                    $block->addChildren(new Exit_());
52
                    break;
53
                default:
54
                    echo 'Unimplemented ' . get_class($stmt) . PHP_EOL;
55
                    break;
56
            }
57
        }
58
    }
59
60
    protected function passIf(\PhpParser\Node\Stmt\If_ $if, Block $block)
0 ignored issues
show
Comprehensibility introduced by
Avoid variables with short names like $if. Configured minimum length is 3.

Short variable names may make your code harder to understand. Variable names should be self-descriptive. This check looks for variable names who are shorter than a configured minimum.

Loading history...
61
    {
62
        $jumpIf = new JumpIf($this->lastBlockId++);
0 ignored issues
show
Unused Code introduced by
The call to JumpIf::__construct() has too many arguments starting with $this->lastBlockId++.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
63
64
        $trueBlock = new Block($this->lastBlockId++);
65
        $this->passNodes($if->stmts, $trueBlock);
66
67
        $jumpIf->setIf($trueBlock);
68
69
        $elseBlock = null;
70
71
        if ($if->else) {
72
            if ($if->else->stmts) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $if->else->stmts of type PhpParser\Node[] is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
73
                $elseBlock = new Block($this->lastBlockId++);
74
                $this->passNodes($if->else->stmts, $elseBlock);
75
76
                $jumpIf->setElse($elseBlock);
77
            }
78
        }
79
80
        $block->addChildren(
81
            $jumpIf
82
        );
83
84
        $exitBlock = new Block($this->lastBlockId++);
85
        $trueBlock->setExit($exitBlock);
86
87
        if ($elseBlock) {
88
            $elseBlock->setExit($exitBlock);
89
        }
90
91
        return $exitBlock;
92
    }
93
94
95
    protected function passFor(\PhpParser\Node\Stmt\For_ $for, Block $block)
96
    {
97
        $this->passNodes($for->init, $block);
98
99
        $block->setExit(
100
            $loop = new Block($this->lastBlockId++)
101
        );
102
        $this->passNodes($for->stmts, $loop);
103
104
        $loop->setExit(
105
            $after = new Block($this->lastBlockId++)
106
        );
107
        return $after;
108
    }
109
110
    protected function passAssign(\PhpParser\Node\Expr\Assign $assign, Block $block)
0 ignored issues
show
Unused Code introduced by
The parameter $assign is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
111
    {
112
        $block->addChildren(new Assign());
113
    }
114
115
    protected function passReturn(\PhpParser\Node\Stmt\Return_ $return_, Block $block)
0 ignored issues
show
Unused Code introduced by
The parameter $return_ is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
116
    {
117
        $block->addChildren(new Return_());
118
    }
119
}
120