Completed
Pull Request — master (#129)
by Kévin
03:41
created

VariableVariableUsage::analyzeAssign()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2

Importance

Changes 0
Metric Value
cc 2
eloc 4
c 0
b 0
f 0
nc 2
nop 2
dl 0
loc 9
ccs 4
cts 4
cp 1
crap 2
rs 9.6666
1
<?php
2
/**
3
 * @author Kévin Gomez https://github.com/K-Phoen <[email protected]>
4
 */
5
6
namespace PHPSA\Analyzer\Pass\Expression;
7
8
use PhpParser\Node\Expr;
9
use PHPSA\Analyzer\Pass;
10
use PHPSA\Context;
11
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
12
13
class VariableVariableUsage implements Pass\AnalyzerPassInterface, Pass\ConfigurablePassInterface
14
{
15
    /**
16
     * @param Expr\Assign $expr
17
     * @param Context $context
18
     * @return bool
19
     */
20 13
    public function pass(Expr\Assign $expr, Context $context)
21
    {
22
        // $(this->)something[] = …
23 13
        if ($expr->var instanceof Expr\ArrayDimFetch) {
24 2
            return $this->analyzeArrayDimFetch($expr->var, $context);
25
        }
26
27
        // $this->something = …
28 13
        if ($expr->var instanceof Expr\PropertyFetch) {
29 2
            return $this->analyzePropertyFetch($expr->var, $context);
30
        }
31
32
        // $something = …
33 13
        return $this->analyzeAssign($expr, $context);
34
    }
35
36 13
    private function analyzeAssign(Expr\Assign $expr, Context $context)
37
    {
38
        // list($a, $b) = …
39 13
        if ($expr->var instanceof Expr\List_) {
40 1
            return $this->analyzeList($expr->var, $context);
41
        }
42
43 13
        return $this->analyzeVar($expr->var, $context);
0 ignored issues
show
Compatibility introduced by
$expr->var of type object<PhpParser\Node\Expr> is not a sub-type of object<PhpParser\Node\Expr\Variable>. It seems like you assume a child class of the class PhpParser\Node\Expr to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
44
    }
45
46 1
    private function analyzeList(Expr\List_ $expr, Context $context)
47
    {
48 1
        $result = false;
49
50 1
        foreach ($expr->vars as $var) {
51
            // list($a, ) = …
52 1
            if (!$var) {
53 1
                continue;
54
            }
55
56 1
            $result = $this->analyzeVar($var, $context) || $result;
0 ignored issues
show
Compatibility introduced by
$var of type object<PhpParser\Node\Expr> is not a sub-type of object<PhpParser\Node\Expr\Variable>. It seems like you assume a child class of the class PhpParser\Node\Expr to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
57 1
        }
58
59 1
        return $result;
60
    }
61
62 2
    private function analyzeArrayDimFetch(Expr\ArrayDimFetch $expr, Context $context)
63
    {
64 2
        $result = false;
65
66
        // $array[] = …
67 2
        if ($expr->var instanceof Expr\Variable) {
68 2
            $result = $this->analyzeVar($expr->var, $context);
69 2
        } else if ($expr->var instanceof Expr\PropertyFetch) {
70
            // $this->array[] = …
71 2
            $result = $this->analyzePropertyFetch($expr->var, $context);
72 2
        }
73
74 2
        if ($expr->dim instanceof Expr\Variable) {
75 1
            $result = $this->analyzeVar($expr->dim, $context) || $result;
76 1
        }
77
78 2
        return $result;
79
    }
80
81 2
    private function analyzePropertyFetch(Expr\PropertyFetch $expr, Context $context)
82
    {
83 2
        if ($expr->name instanceof Expr\Variable) {
84 1
            $this->notice($context, $expr->name);
85 1
            return true;
86
        }
87
88 2
        return false;
89
    }
90
91 13
    private function analyzeVar(Expr\Variable $var, Context $context)
92
    {
93 13
        if (!$var->name instanceof Expr\Variable) {
94 13
            return false;
95
        }
96
97 1
        $this->notice($context, $var);
98
99 1
        return true;
100
    }
101
102 1
    private function notice(Context $context, Expr $expr)
103
    {
104 1
        $context->notice('variable.dynamic_assignment', 'Dynamic assignment is greatly discouraged.', $expr);
105 1
    }
106
107
    /**
108
     * @return array
109
     */
110 1
    public function getRegister()
111
    {
112
        return [
113
            Expr\Assign::class
114 1
        ];
115
    }
116
117
    /**
118
     * @return TreeBuilder
119
     */
120
    public function getConfiguration()
121
    {
122
        $treeBuilder = new TreeBuilder();
123
        $treeBuilder->root('variable.dynamic_assignment')
124
            ->canBeDisabled()
125
        ;
126
127
        return $treeBuilder;
128
    }
129
}
130