Completed
Push — master ( e82a73...132a7c )
by Povilas
02:27
created

DetectorVisitor::isNumber()   A

Complexity

Conditions 4
Paths 6

Size

Total Lines 10
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 10
rs 9.2
c 0
b 0
f 0
cc 4
eloc 6
nc 6
nop 1
1
<?php
2
3
namespace Povils\PHPMND\Visitor;
4
5
use PhpParser\Node;
6
use PhpParser\Node\Const_;
7
use PhpParser\Node\Expr\UnaryMinus;
8
use PhpParser\Node\Expr\UnaryPlus;
9
use PhpParser\Node\Scalar;
10
use PhpParser\Node\Scalar\DNumber;
11
use PhpParser\Node\Scalar\LNumber;
12
use PhpParser\Node\Scalar\String_;
13
use PhpParser\NodeTraverser;
14
use PhpParser\NodeVisitorAbstract;
15
use Povils\PHPMND\Console\Option;
16
use Povils\PHPMND\Extension\Extension;
17
use Povils\PHPMND\Extension\FunctionAwareExtension;
18
use Povils\PHPMND\FileReport;
19
20
/**
21
 * Class DetectorVisitor
22
 *
23
 * @package Povils\PHPMND
24
 */
25
class DetectorVisitor extends NodeVisitorAbstract
26
{
27
    /**
28
     * @var FileReport
29
     */
30
    private $fileReport;
31
32
    /**
33
     * @var Option
34
     */
35
    private $option;
36
37
    /**
38
     * @param FileReport $fileReport
39
     * @param Option $option
40
     */
41
    public function __construct(FileReport $fileReport, Option $option)
42
    {
43
        $this->fileReport = $fileReport;
44
        $this->option = $option;
45
    }
46
47
    /**
48
     * @inheritdoc
49
     */
50
    public function enterNode(Node $node)
51
    {
52
        if ($node instanceof Const_) {
53
            return NodeTraverser::DONT_TRAVERSE_CHILDREN;
54
        }
55
56
        if ($this->isNumber($node) || $this->isString($node)) {
57
            /** @var LNumber|DNumber|String_ $scalar */
58
            $scalar = $node;
59
            if ($this->hasSign($node)) {
60
                $node = $node->getAttribute('parent');
61
                if ($this->isMinus($node)) {
62
                    $scalar->value = -$scalar->value;
63
                }
64
            }
65
            foreach ($this->option->getExtensions() as $extension) {
66
                if ($extension->extend($node) && false === $this->ignoreFunc($node, $extension)) {
67
                    $this->fileReport->addEntry($scalar->getLine(), $scalar->value);
68
69
                    return null;
70
                }
71
            }
72
        }
73
74
        return null;
75
    }
76
77
    /**
78
     * @param Node $node
79
     *
80
     * @return bool
81
     */
82
    private function isNumber(Node $node)
83
    {
84
        $isNumber = (
85
            $node instanceof LNumber ||
86
            $node instanceof DNumber ||
87
            $this->isValidNumeric($node)
88
        );
89
90
        return $isNumber && false === $this->ignoreNumber($node);
91
    }
92
93
    /**
94
     * @param Node $node
95
     *
96
     * @return bool
97
     */
98
    private function isString(Node $node)
99
    {
100
        return $this->option->includeStrings() && $node instanceof String_ && false === $this->ignoreString($node);
101
    }
102
103
    /**
104
     * @param LNumber|DNumber|Node $node
105
     *
106
     * @return bool
107
     */
108
    private function ignoreNumber(Node $node)
109
    {
110
        return in_array($node->value, $this->option->getIgnoreNumbers(), true);
111
    }
112
113
    /**
114
     * @param String_|Node $node
115
     *
116
     * @return bool
117
     */
118
    private function ignoreString(Node $node)
119
    {
120
        return in_array($node->value, $this->option->getIgnoreStrings(), true);
121
    }
122
123
    /**
124
     * @param Node $node
125
     *
126
     * @return bool
127
     */
128
    private function hasSign(Node $node)
129
    {
130
        return $node->getAttribute('parent') instanceof UnaryMinus || $node->getAttribute('parent') instanceof UnaryPlus;
131
    }
132
133
    /**
134
     * @param Node $node
135
     *
136
     * @return bool
137
     */
138
    private function isMinus(Node $node)
139
    {
140
        return $node instanceof UnaryMinus;
141
    }
142
143
    /**
144
     * @param Node $node
145
     * @param Extension $extension
146
     *
147
     * @return bool
148
     */
149
    private function ignoreFunc(Node $node, Extension $extension)
150
    {
151
        if ($extension instanceof FunctionAwareExtension) {
152
            return $extension->ignoreFunc($node, $this->option->getIgnoreFuncs());
153
        }
154
155
        return false;
156
    }
157
158
    /**
159
     * @param Node $node
160
     * @return bool
161
     */
162
    private function isValidNumeric(Node $node)
163
    {
164
        return $this->option->includeNumericStrings() &&
165
        isset($node->value) &&
0 ignored issues
show
Bug introduced by
Accessing value on the interface PhpParser\Node suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
166
        is_numeric($node->value) &&
0 ignored issues
show
Bug introduced by
Accessing value on the interface PhpParser\Node suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
167
        false === $this->ignoreString($node);
168
    }
169
}
170