Passed
Push — master ( db3beb...1edc4a )
by
unknown
02:51 queued 11s
created

ShortVariable::applyNonClass()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 13

Duplication

Lines 13
Ratio 100 %

Code Coverage

Tests 9
CRAP Score 3

Importance

Changes 0
Metric Value
cc 3
nc 4
nop 1
dl 13
loc 13
ccs 9
cts 9
cp 1
crap 3
rs 9.8333
c 0
b 0
f 0
1
<?php
2
/**
3
 * This file is part of PHP Mess Detector.
4
 *
5
 * Copyright (c) Manuel Pichler <[email protected]>.
6
 * All rights reserved.
7
 *
8
 * Licensed under BSD License
9
 * For full copyright and license information, please see the LICENSE file.
10
 * Redistributions of files must retain the above copyright notice.
11
 *
12
 * @author Manuel Pichler <[email protected]>
13
 * @copyright Manuel Pichler. All rights reserved.
14
 * @license https://opensource.org/licenses/bsd-license.php BSD License
15
 * @link http://phpmd.org/
16
 */
17
18
namespace PHPMD\Rule\Naming;
19
20
use PHPMD\AbstractNode;
21
use PHPMD\AbstractRule;
22
use PHPMD\Rule\ClassAware;
23
use PHPMD\Rule\FunctionAware;
24
use PHPMD\Rule\MethodAware;
25
26
/**
27
 * This rule class will detect variables, parameters and properties with short
28
 * names.
29
 */
30
class ShortVariable extends AbstractRule implements ClassAware, MethodAware, FunctionAware
31
{
32
    /**
33
     * Temporary map holding variables that were already processed in the
34
     * current context.
35
     *
36
     * @var array(string=>boolean)
37
     */
38
    private $processedVariables = array();
39
40
    /**
41
     * Extracts all variable and variable declarator nodes from the given node
42
     *
43
     * Checks the variable name length against the configured minimum
44
     * length.
45
     *
46
     * @param \PHPMD\AbstractNode $node
47
     * @return void
48
     */
49 21
    public function apply(AbstractNode $node)
50
    {
51 21
        $this->resetProcessed();
52
53 21
        if ($node->getType() === 'class') {
54 11
            $this->applyClass($node);
55 11
            return;
56
        }
57
58 14
        $this->applyNonClass($node);
59 14
    }
60
61
    /**
62
     * Extracts all variable and variable declarator nodes from the given class node
63
     *
64
     * Checks the variable name length against the configured minimum
65
     * length.
66
     *
67
     * @param AbstractNode $node
68
     * @return void
69
     */
70 11 View Code Duplication
    private function applyClass(AbstractNode $node)
71
    {
72 11
        $fields = $node->findChildrenOfType('FieldDeclaration');
73 11
        foreach ($fields as $field) {
74 5
            $declarators = $field->findChildrenOfType('VariableDeclarator');
75 5
            foreach ($declarators as $declarator) {
76 5
                $this->checkNodeImage($declarator);
77
            }
78
        }
79 11
        $this->resetProcessed();
80 11
    }
81
82
    /**
83
     * Extracts all variable and variable declarator nodes from the given non-class node
84
     *
85
     * Checks the variable name length against the configured minimum
86
     * length.
87
     *
88
     * @param AbstractNode $node
89
     * @return void
90
     */
91 14 View Code Duplication
    private function applyNonClass(AbstractNode $node)
92
    {
93 14
        $declarators = $node->findChildrenOfType('VariableDeclarator');
94 14
        foreach ($declarators as $declarator) {
95 4
            $this->checkNodeImage($declarator);
96
        }
97
98 14
        $variables = $node->findChildrenOfType('Variable');
99 14
        foreach ($variables as $variable) {
100 10
            $this->checkNodeImage($variable);
101
        }
102 14
        $this->resetProcessed();
103 14
    }
104
105
    /**
106
     * Checks if the variable name of the given node is greater/equal to the
107
     * configured threshold or if the given node is an allowed context.
108
     *
109
     * @param \PHPMD\AbstractNode $node
110
     * @return void
111
     */
112 18
    protected function checkNodeImage(AbstractNode $node)
113
    {
114 18
        if ($this->isNotProcessed($node)) {
115 18
            $this->addProcessed($node);
116 18
            $this->checkMinimumLength($node);
117
        }
118 18
    }
119
120
    /**
121
     * Template method that performs the real node image check.
122
     *
123
     * @param \PHPMD\AbstractNode $node
124
     * @return void
125
     */
126 18
    protected function checkMinimumLength(AbstractNode $node)
127
    {
128 18
        $threshold = $this->getIntProperty('minimum');
129
130 18
        if ($threshold <= strlen($node->getImage()) - 1) {
131 6
            return;
132
        }
133
134 13
        if ($this->isNameAllowedInContext($node)) {
135 4
            return;
136
        }
137
138 9
        $exceptions = $this->getExceptionsList();
139
140 9
        if (in_array(substr($node->getImage(), 1), $exceptions)) {
141 1
            return;
142
        }
143
144 8
        $this->addViolation($node, array($node->getImage(), $threshold));
145 8
    }
146
147
    /**
148
     * Gets array of exceptions from property
149
     *
150
     * @return array
151
     */
152 9 View Code Duplication
    private function getExceptionsList()
153
    {
154
        try {
155 9
            $exceptions = $this->getStringProperty('exceptions');
156
        } catch (\OutOfBoundsException $e) {
157
            $exceptions = '';
158
        }
159
160 9
        return explode(',', $exceptions);
161
    }
162
163
    /**
164
     * Checks if a short name is acceptable in the current context. For the
165
     * moment these contexts are the init section of a for-loop and short
166
     * variable names in catch-statements.
167
     *
168
     * @param \PHPMD\AbstractNode $node
169
     * @return boolean
170
     */
171 13
    private function isNameAllowedInContext(AbstractNode $node)
172
    {
173 13
        return $this->isChildOf($node, 'CatchStatement')
174 12
                || $this->isChildOf($node, 'ForInit')
175 11
                || $this->isChildOf($node, 'ForeachStatement')
176 13
                || $this->isChildOf($node, 'MemberPrimaryPrefix');
177
    }
178
179
    /**
180
     * Checks if the given node is a direct or indirect child of a node with
181
     * the given type.
182
     *
183
     * @param \PHPMD\AbstractNode $node
184
     * @param string $type
185
     * @return boolean
186
     */
187 13 View Code Duplication
    private function isChildOf(AbstractNode $node, $type)
188
    {
189 13
        $parent = $node->getParent();
190 13
        while (is_object($parent)) {
191 13
            if ($parent->isInstanceOf($type)) {
192 4
                return true;
193
            }
194 12
            $parent = $parent->getParent();
195
        }
196 12
        return false;
197
    }
198
199
    /**
200
     * Resets the already processed nodes.
201
     *
202
     * @return void
203
     */
204 21
    protected function resetProcessed()
205
    {
206 21
        $this->processedVariables = array();
207 21
    }
208
209
    /**
210
     * Flags the given node as already processed.
211
     *
212
     * @param \PHPMD\AbstractNode $node
213
     * @return void
214
     */
215 18
    protected function addProcessed(AbstractNode $node)
216
    {
217 18
        $this->processedVariables[$node->getImage()] = true;
218 18
    }
219
220
    /**
221
     * Checks if the given node was already processed.
222
     *
223
     * @param \PHPMD\AbstractNode $node
224
     * @return boolean
225
     */
226 18
    protected function isNotProcessed(AbstractNode $node)
227
    {
228 18
        return !isset($this->processedVariables[$node->getImage()]);
229
    }
230
}
231