Completed
Pull Request — master (#126)
by Kévin
04:06
created

ArrayIllegalOffsetType   A

Complexity

Total Complexity 18

Size/Duplication

Total Lines 102
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 10

Test Coverage

Coverage 87.8%

Importance

Changes 2
Bugs 0 Features 0
Metric Value
c 2
b 0
f 0
dl 0
loc 102
ccs 36
cts 41
cp 0.878
rs 10
wmc 18
lcom 1
cbo 10

6 Methods

Rating   Name   Duplication   Size   Complexity  
A pass() 0 8 4
A analyzeDimensionFetch() 0 10 2
A analyzeArray() 0 15 4
B analyzeExpression() 0 22 6
A getRegister() 0 7 1
A getConfiguration() 0 9 1
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 ArrayIllegalOffsetType implements Pass\AnalyzerPassInterface, Pass\ConfigurablePassInterface
14
{
15
    /**
16
     * @param Expr\Array_|Expr\Assign $expr
17
     * @param Context $context
18
     * @return bool
19
     */
20 35
    public function pass(Expr $expr, Context $context)
21
    {
22 35
        if ($expr instanceof Expr\Array_) {
23 26
            return $this->analyzeArray($expr, $context);
24 12
        } elseif ($expr instanceof Expr\Assign && $expr->var instanceof Expr\ArrayDimFetch) {
25 1
            return $this->analyzeDimensionFetch($expr->var, $context);
26
        }
27 12
    }
28
29
    /**
30
     * @param Expr\ArrayDimFetch $expr
31
     * @param Context $context
32
     *
33
     * @return bool
34
     */
35 1
    private function analyzeDimensionFetch(Expr\ArrayDimFetch $expr, Context $context)
36
    {
37
        // $array[]
38 1
        if ($expr->dim === null) {
39 1
            return false;
40
        }
41
42
        // $array[…]
43 1
        return $this->analyzeExpression($expr->dim, $context);
44
    }
45
46
    /**
47
     * @param Expr\Array_ $expr
48
     * @param Context $context
49
     *
50
     * @return bool
51
     */
52 26
    private function analyzeArray(Expr\Array_ $expr, Context $context)
53
    {
54 26
        $result = false;
55
56
        /** @var Expr\ArrayItem $item */
57 26
        foreach ($expr->items as $item) {
58 10
            if ($item->key === null) {
59 7
                continue;
60
            }
61
62 3
            $result = $this->analyzeExpression($item->key, $context) || $result;
63 26
        }
64
65 26
        return $result;
66
    }
67
68 3
    private function analyzeExpression(Expr $expr, Context $context)
69
    {
70 3
        $compiledKey = $context->getExpressionCompiler()->compile($expr);
71 3
        if (!$compiledKey->isTypeKnown() || $compiledKey->isScalar()) {
72 3
            return false;
73
        }
74
75 1
        $keyType = $compiledKey->getTypeName();
76 1
        if ($compiledKey->isObject() && $compiledKey->getValue()) {
77 1
            $keyType = get_class($compiledKey->getValue());
78 1
        }
79
80 1
        if ($expr instanceof Expr\Variable) {
81 1
            $message = sprintf('Illegal array offset type %s for key %s.', $keyType, '$'.$expr->name);
82 1
        } else {
83 1
            $message = sprintf('Illegal array offset type %s.', $keyType);
84
        }
85
86 1
        $context->notice('array.illegal_offset_type', $message, $expr);
87
88 1
        return true;
89
    }
90
91
    /**
92
     * @return array
93
     */
94 1
    public function getRegister()
95
    {
96
        return [
97 1
            Expr\Array_::class,
98 1
            Expr\Assign::class,
99 1
        ];
100
    }
101
102
    /**
103
     * @return TreeBuilder
104
     */
105
    public function getConfiguration()
106
    {
107
        $treeBuilder = new TreeBuilder();
108
        $treeBuilder->root('array.illegal_offset_type')
109
            ->canBeDisabled()
110
        ;
111
112
        return $treeBuilder;
113
    }
114
}
115