Completed
Pull Request — master (#86)
by Scott
01:49
created

DetectorVisitor::checkNameContainsLanguage()   A

Complexity

Conditions 4
Paths 5

Size

Total Lines 21

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 21
rs 9.584
c 0
b 0
f 0
cc 4
nc 5
nop 2
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\ArrayAwareExtension;
17
use Povils\PHPMND\Extension\Extension;
18
use Povils\PHPMND\Extension\FunctionAwareExtension;
19
use Povils\PHPMND\FileReport;
20
21
/**
22
 * Class DetectorVisitor
23
 *
24
 * @package Povils\PHPMND
25
 */
26
class DetectorVisitor extends NodeVisitorAbstract
27
{
28
    /**
29
     * @var FileReport
30
     */
31
    private $fileReport;
32
33
    /**
34
     * @var Option
35
     */
36
    private $option;
37
38
    public function __construct(FileReport $fileReport, Option $option)
39
    {
40
        $this->fileReport = $fileReport;
41
        $this->option = $option;
42
    }
43
44
    public function enterNode(Node $node): ?int
45
    {
46
        if ($this->isIgnoreableConst($node)) {
47
            if ($this->checkNameContainsLanguage(
48
                $node->name->name,
0 ignored issues
show
Bug introduced by
Accessing name 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...
49
                $node->value->value ?? 0
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...
50
            )) {
51
                $this->fileReport->addEntry($node->getLine(), $node->value->value);
52
            }
53
54
            return NodeTraverser::DONT_TRAVERSE_CHILDREN;
55
        }
56
57
        /** @var LNumber|DNumber|String_ $scalar */
58
        $scalar = $node;
59
        if ($this->hasSign($scalar)) {
60
            $node = $scalar->getAttribute('parent');
61
            if ($this->isMinus($node) && isset($scalar->value)) {
62
                $scalar->value = -$scalar->value;
63
            }
64
        }
65
66
        if ($this->isNumber($scalar) || $this->isString($scalar)) {
67
            if ($this->checkNameContainsLanguage(
68
                $scalar->getAttribute('parent')->var->name ?? '',
69
                $scalar->value
70
            )) {
71
                $this->fileReport->addEntry($node->getLine(), $scalar->value);
72
            }
73
74
            foreach ($this->option->getExtensions() as $extension) {
75
                $extension->setOption($this->option);
76
                if ($extension->extend($node)) {
77
                    $this->fileReport->addEntry($scalar->getLine(), $scalar->value);
78
79
                    return null;
80
                }
81
            }
82
        }
83
84
        return null;
85
    }
86
87
    private function isIgnoreableConst(Node $node): bool
88
    {
89
        return $node instanceof Const_ &&
90
            ($this->isNumber($node->value) || $this->isString($node->value));
91
    }
92
93
    private function isNumber(Node $node): bool
94
    {
95
        $isNumber = (
96
            $node instanceof LNumber ||
97
            $node instanceof DNumber ||
98
            $this->isValidNumeric($node)
99
        );
100
101
        return $isNumber && false === $this->ignoreNumber($node);
102
    }
103
104
    private function isString(Node $node): bool
105
    {
106
        return $this->option->includeStrings() && $node instanceof String_ && false === $this->ignoreString($node);
107
    }
108
109
    private function ignoreNumber(Node $node): bool
110
    {
111
        return in_array($node->value, $this->option->getIgnoreNumbers(), true);
112
    }
113
114
    private function ignoreString(Node $node): bool
115
    {
116
        return in_array($node->value, $this->option->getIgnoreStrings(), true);
117
    }
118
119
    private function hasSign(Node $node): bool
120
    {
121
        return $node->getAttribute('parent') instanceof UnaryMinus
122
            || $node->getAttribute('parent') instanceof UnaryPlus;
123
    }
124
125
    private function isMinus(Node $node): bool
126
    {
127
        return $node instanceof UnaryMinus;
128
    }
129
130
    private function isValidNumeric(Node $node): bool
131
    {
132
        return $this->option->includeNumericStrings() &&
133
        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...
134
        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...
135
        false === $this->ignoreString($node);
136
    }
137
138
    private function checkNameContainsLanguage(string $name, $value): bool
139
    {
140
        $value = (int) $value;
141
        foreach ($this->option->checkNaming() as $language) {
142
            $generatedNumbers = $language->parse($value);
143
144
            $regex = '/(?<name>';
145
            foreach ($generatedNumbers as $word) {
146
                $regex .= "(?:{$word}[\s_-]*)?";
147
            }
148
149
            $regex .= ')/i';
150
            preg_match($regex, $name, $matches);
151
152
            if (strlen($matches['name']) > 0) {
153
                return true;
154
            }
155
        }
156
157
        return false;
158
    }
159
}
160