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

VariableVariableUsage::notice()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 2
c 0
b 0
f 0
nc 1
nop 2
dl 0
loc 4
ccs 3
cts 3
cp 1
crap 1
rs 10
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 11
    public function pass(Expr\Assign $expr, Context $context)
21
    {
22
        // $(this->)something[] = …
23 11
        if ($expr->var instanceof Expr\ArrayDimFetch) {
24 1
            return $this->analyzeArrayDimFetch($expr->var, $context);
25
        }
26
27
        // $this->something = …
28 11
        if ($expr->var instanceof Expr\PropertyFetch) {
29 1
            return $this->analyzePropertyFetch($expr->var, $context);
30
        }
31
32
        // $something = …
33 11
        return $this->analyzeAssign($expr, $context);
34
    }
35
36 11
    private function analyzeAssign(Expr\Assign $expr, Context $context)
37
    {
38
        // list($a, $b) = …
39 11
        if ($expr->var instanceof Expr\List_) {
40 1
            return $this->analyzeList($expr->var, $context);
41
        }
42
43 11
        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 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...
52 1
        }
53
54 1
        return $result;
55
    }
56
57 1
    private function analyzeArrayDimFetch(Expr\ArrayDimFetch $expr, Context $context)
58
    {
59 1
        $result = false;
60
61
        // $array[] = …
62 1
        if ($expr->var instanceof Expr\Variable) {
63 1
            $result = $this->analyzeVar($expr->var, $context);
64 1
        } else if ($expr->var instanceof Expr\PropertyFetch) {
65
            // $this->array[] = …
66 1
            $result = $this->analyzePropertyFetch($expr->var, $context);
67 1
        }
68
69 1
        if ($expr->dim instanceof Expr\Variable) {
70
            $result = $this->analyzeVar($expr->dim, $context) || $result;
71
        }
72
73 1
        return $result;
74
    }
75
76 1
    private function analyzePropertyFetch(Expr\PropertyFetch $expr, Context $context)
77
    {
78 1
        if ($expr->name instanceof Expr\Variable) {
79 1
            $this->notice($context, $expr->name);
80 1
            return true;
81
        }
82
83
        return false;
84
    }
85
86 11
    private function analyzeVar(Expr\Variable $var, Context $context)
87
    {
88 11
        if (!$var->name instanceof Expr\Variable) {
89 11
            return false;
90
        }
91
92 1
        $this->notice($context, $var);
93
94 1
        return true;
95
    }
96
97 1
    private function notice(Context $context, Expr $expr)
98
    {
99 1
        $context->notice('variable.dynamic_assignment', 'Dynamic assignment is greatly discouraged.', $expr);
100 1
    }
101
102
    /**
103
     * @return array
104
     */
105 1
    public function getRegister()
106
    {
107
        return [
108
            Expr\Assign::class
109 1
        ];
110
    }
111
112
    /**
113
     * @return TreeBuilder
114
     */
115
    public function getConfiguration()
116
    {
117
        $treeBuilder = new TreeBuilder();
118
        $treeBuilder->root('variable.dynamic_assignment')
119
            ->canBeDisabled()
120
        ;
121
122
        return $treeBuilder;
123
    }
124
}
125