Passed
Push — master ( f7e716...766349 )
by Marc
02:34 queued 11s
created

ShortVariable::applyClass()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 11

Duplication

Lines 11
Ratio 100 %

Code Coverage

Tests 8
CRAP Score 3

Importance

Changes 0
Metric Value
cc 3
nc 3
nop 1
dl 11
loc 11
ccs 8
cts 8
cp 1
crap 3
rs 9.9
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
     * and checks the variable name length against the configured minimum
43
     * length.
44
     *
45
     * @param \PHPMD\AbstractNode $node
46
     * @return void
47
     */
48 21
    public function apply(AbstractNode $node)
49
    {
50 21
        $this->resetProcessed();
51
52 21
        if ($node->getType() === 'class') {
53 11
            $this->applyClass($node);
54 11
            return;
55
        }
56
57 14
        $this->applyNoClass($node);
58 14
    }
59
60
    /**
61
     * Extracts all variable and variable declarator nodes from the given class node
62
     * and checks the variable name length against the configured minimum
63
     * length.
64
     *
65
     * @param AbstractNode $node
66
     * @return void
67
     */
68 11 View Code Duplication
    private function applyClass(AbstractNode $node)
69
    {
70 11
        $fields = $node->findChildrenOfType('FieldDeclaration');
71 11
        foreach ($fields as $field) {
72 5
            $declarators = $field->findChildrenOfType('VariableDeclarator');
73 5
            foreach ($declarators as $declarator) {
74 5
                $this->checkNodeImage($declarator);
75
            }
76
        }
77 11
        $this->resetProcessed();
78 11
    }
79
80
    /**
81
     * Extracts all variable and variable declarator nodes from the given no class node
82
     * and checks the variable name length against the configured minimum
83
     * length.
84
     *
85
     * @param AbstractNode $node
86
     * @return void
87
     */
88 14 View Code Duplication
    private function applyNoClass(AbstractNode $node)
89
    {
90 14
        $declarators = $node->findChildrenOfType('VariableDeclarator');
91 14
        foreach ($declarators as $declarator) {
92 4
            $this->checkNodeImage($declarator);
93
        }
94
95 14
        $variables = $node->findChildrenOfType('Variable');
96 14
        foreach ($variables as $variable) {
97 10
            $this->checkNodeImage($variable);
98
        }
99 14
        $this->resetProcessed();
100 14
    }
101
102
    /**
103
     * Checks if the variable name of the given node is greater/equal to the
104
     * configured threshold or if the given node is an allowed context.
105
     *
106
     * @param \PHPMD\AbstractNode $node
107
     * @return void
108
     */
109 18
    protected function checkNodeImage(AbstractNode $node)
110
    {
111 18
        if ($this->isNotProcessed($node)) {
112 18
            $this->addProcessed($node);
113 18
            $this->checkMinimumLength($node);
114
        }
115 18
    }
116
117
    /**
118
     * Template method that performs the real node image check.
119
     *
120
     * @param \PHPMD\AbstractNode $node
121
     * @return void
122
     */
123 18
    protected function checkMinimumLength(AbstractNode $node)
124
    {
125 18
        $threshold = $this->getIntProperty('minimum');
126
127 18
        if ($threshold <= strlen($node->getImage()) - 1) {
128 6
            return;
129
        }
130
131 13
        if ($this->isNameAllowedInContext($node)) {
132 4
            return;
133
        }
134
135 9
        $exceptions = $this->getExceptionsList();
136
137 9
        if (in_array(substr($node->getImage(), 1), $exceptions)) {
138 1
            return;
139
        }
140
141 8
        $this->addViolation($node, array($node->getImage(), $threshold));
142 8
    }
143
144
    /**
145
     * Gets array of exceptions from property
146
     *
147
     * @return array
148
     */
149 9 View Code Duplication
    private function getExceptionsList()
150
    {
151
        try {
152 9
            $exceptions = $this->getStringProperty('exceptions');
153
        } catch (\OutOfBoundsException $e) {
154
            $exceptions = '';
155
        }
156
157 9
        return explode(',', $exceptions);
158
    }
159
160
    /**
161
     * Checks if a short name is acceptable in the current context. For the
162
     * moment these contexts are the init section of a for-loop and short
163
     * variable names in catch-statements.
164
     *
165
     * @param \PHPMD\AbstractNode $node
166
     * @return boolean
167
     */
168 13
    private function isNameAllowedInContext(AbstractNode $node)
169
    {
170 13
        return $this->isChildOf($node, 'CatchStatement')
171 12
                || $this->isChildOf($node, 'ForInit')
172 11
                || $this->isChildOf($node, 'ForeachStatement')
173 13
                || $this->isChildOf($node, 'MemberPrimaryPrefix');
174
    }
175
176
    /**
177
     * Checks if the given node is a direct or indirect child of a node with
178
     * the given type.
179
     *
180
     * @param \PHPMD\AbstractNode $node
181
     * @param string $type
182
     * @return boolean
183
     */
184 13 View Code Duplication
    private function isChildOf(AbstractNode $node, $type)
185
    {
186 13
        $parent = $node->getParent();
187 13
        while (is_object($parent)) {
188 13
            if ($parent->isInstanceOf($type)) {
189 4
                return true;
190
            }
191 12
            $parent = $parent->getParent();
192
        }
193 12
        return false;
194
    }
195
196
    /**
197
     * Resets the already processed nodes.
198
     *
199
     * @return void
200
     */
201 21
    protected function resetProcessed()
202
    {
203 21
        $this->processedVariables = array();
204 21
    }
205
206
    /**
207
     * Flags the given node as already processed.
208
     *
209
     * @param \PHPMD\AbstractNode $node
210
     * @return void
211
     */
212 18
    protected function addProcessed(AbstractNode $node)
213
    {
214 18
        $this->processedVariables[$node->getImage()] = true;
215 18
    }
216
217
    /**
218
     * Checks if the given node was already processed.
219
     *
220
     * @param \PHPMD\AbstractNode $node
221
     * @return boolean
222
     */
223 18
    protected function isNotProcessed(AbstractNode $node)
224
    {
225 18
        return !isset($this->processedVariables[$node->getImage()]);
226
    }
227
}
228