Arbit - project tracking

PHPMD

Browse source code

File: / source/ PHP/ PMD/ Rule/ UnusedPrivateField.php

Type
text/plain text/plain
Last Author
mapi
Version
235
Line Rev. Author Source
1 129 mapi <?php
2 mapi /**
3 mapi * This file is part of PHP_PMD.
4 mapi *
5 mapi * PHP Version 5
6 mapi *
7 174 mapi * Copyright (c) 2009-2010, Manuel Pichler <mapi@phpmd.org>.
8 129 mapi * All rights reserved.
9 mapi *
10 mapi * Redistribution and use in source and binary forms, with or without
11 mapi * modification, are permitted provided that the following conditions
12 mapi * are met:
13 mapi *
14 mapi * * Redistributions of source code must retain the above copyright
15 mapi * notice, this list of conditions and the following disclaimer.
16 mapi *
17 mapi * * Redistributions in binary form must reproduce the above copyright
18 mapi * notice, this list of conditions and the following disclaimer in
19 mapi * the documentation and/or other materials provided with the
20 mapi * distribution.
21 mapi *
22 mapi * * Neither the name of Manuel Pichler nor the names of his
23 mapi * contributors may be used to endorse or promote products derived
24 mapi * from this software without specific prior written permission.
25 mapi *
26 mapi * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
27 mapi * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
28 mapi * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
29 mapi * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
30 mapi * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
31 mapi * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
32 mapi * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
33 mapi * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
34 mapi * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35 mapi * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
36 mapi * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37 mapi * POSSIBILITY OF SUCH DAMAGE.
38 mapi *
39 mapi * @category PHP
40 mapi * @package PHP_PMD
41 mapi * @subpackage Rule
42 174 mapi * @author Manuel Pichler <mapi@phpmd.org>
43 150 mapi * @copyright 2009-2010 Manuel Pichler. All rights reserved.
44 129 mapi * @license http://www.opensource.org/licenses/bsd-license.php BSD License
45 mapi * @version SVN: $Id$
46 174 mapi * @link http://phpmd.org
47 129 mapi */
48 mapi
49 mapi require_once 'PHP/PMD/AbstractRule.php';
50 mapi require_once 'PHP/PMD/Rule/IClassAware.php';
51 mapi
52 mapi /**
53 mapi * This rule collects all private fields in a class that aren't used in any
54 mapi * method of the analyzed class.
55 mapi *
56 mapi * @category PHP
57 mapi * @package PHP_PMD
58 mapi * @subpackage Rule
59 174 mapi * @author Manuel Pichler <mapi@phpmd.org>
60 150 mapi * @copyright 2009-2010 Manuel Pichler. All rights reserved.
61 129 mapi * @license http://www.opensource.org/licenses/bsd-license.php BSD License
62 mapi * @version Release: @package_version@
63 174 mapi * @link http://phpmd.org
64 129 mapi */
65 mapi class PHP_PMD_Rule_UnusedPrivateField
66 mapi extends PHP_PMD_AbstractRule
67 mapi implements PHP_PMD_Rule_IClassAware
68 mapi {
69 mapi /**
70 133 mapi * Collected private fields/variable declarators in the currently processed
71 mapi * class.
72 129 mapi *
73 mapi * @var array(string=>PHP_PMD_Node_ASTNode)
74 mapi */
75 mapi private $_fields = array();
76 mapi
77 mapi /**
78 mapi * This method checks that all private class properties are at least accessed
79 mapi * by one method.
80 mapi *
81 mapi * @param PHP_PMD_AbstractNode $node The context source code node.
82 mapi *
83 mapi * @return void
84 mapi */
85 mapi public function apply(PHP_PMD_AbstractNode $node)
86 mapi {
87 134 mapi foreach ($this->_collectUnusedPrivateFields($node) as $field) {
88 129 mapi $this->addViolation($field, array($field->getImage()));
89 mapi }
90 mapi }
91 mapi
92 mapi /**
93 134 mapi * This method collects all private fields that aren't used by any class
94 mapi * method.
95 mapi *
96 200 mapi * @param PHP_PMD_Node_Class $class The context class node.
97 134 mapi *
98 mapi * @return array(PHP_PMD_AbstractNode)
99 mapi */
100 200 mapi private function _collectUnusedPrivateFields(PHP_PMD_Node_Class $class)
101 134 mapi {
102 mapi $this->_fields = array();
103 mapi
104 mapi $this->_collectPrivateFields($class);
105 mapi $this->_removeUsedFields($class);
106 mapi
107 mapi return $this->_fields;
108 mapi }
109 mapi
110 mapi /**
111 129 mapi * This method collects all private fields in the given class and stores
112 mapi * them in the <b>$_fields</b> property.
113 mapi *
114 200 mapi * @param PHP_PMD_Node_Class $class The context class instance.
115 129 mapi *
116 mapi * @return void
117 mapi */
118 200 mapi private function _collectPrivateFields(PHP_PMD_Node_Class $class)
119 129 mapi {
120 mapi foreach ($class->findChildrenOfType('FieldDeclaration') as $declaration) {
121 mapi if ($declaration->isPrivate()) {
122 mapi $this->_collectPrivateField($declaration);
123 mapi }
124 mapi }
125 mapi }
126 mapi
127 mapi /**
128 mapi * This method extracts all variable declarators from the given field
129 mapi * declaration and stores them in the <b>$_fields</b> property.
130 mapi *
131 mapi * @param PHP_PMD_Node_ASTNode $declaration The context field declaration.
132 mapi *
133 mapi * @return void
134 mapi */
135 mapi private function _collectPrivateField(PHP_PMD_Node_ASTNode $declaration)
136 mapi {
137 mapi $fields = $declaration->findChildrenOfType('VariableDeclarator');
138 mapi foreach ($fields as $field) {
139 mapi $this->_fields[$field->getImage()] = $field;
140 mapi }
141 mapi }
142 mapi
143 mapi /**
144 mapi * This method extracts all property postfix nodes from the given class and
145 mapi * removes all fields from the <b>$_fields</b> property that are accessed by
146 mapi * one of the postfix nodes.
147 mapi *
148 200 mapi * @param PHP_PMD_Node_Class $class The context class instance.
149 129 mapi *
150 mapi * @return void
151 mapi */
152 200 mapi private function _removeUsedFields(PHP_PMD_Node_Class $class)
153 129 mapi {
154 mapi foreach ($class->findChildrenOfType('PropertyPostfix') as $postfix) {
155 235 mapi if ($this->isInScopeOfClass($class, $postfix)) {
156 129 mapi $this->_removeUsedField($postfix);
157 mapi }
158 mapi }
159 mapi }
160 mapi
161 mapi /**
162 mapi * This method removes the field from the <b>$_fields</b> property that is
163 mapi * accessed through the given property postfix node.
164 mapi *
165 mapi * @param PHP_PMD_Node_ASTNode $postfix The context postfix node.
166 mapi *
167 mapi * @return void
168 mapi */
169 mapi private function _removeUsedField(PHP_PMD_Node_ASTNode $postfix)
170 mapi {
171 235 mapi if ($postfix->getParent()->isStatic()) {
172 mapi $image = '';
173 mapi $child = $postfix->getFirstChildOfType('Variable');
174 129 mapi } else {
175 235 mapi $image = '$';
176 mapi $child = $postfix->getFirstChildOfType('Identifier');
177 129 mapi }
178 mapi
179 235 mapi
180 mapi if ($this->isValidPropertyNode($child)) {
181 mapi unset($this->_fields[$image . $child->getImage()]);
182 mapi }
183 129 mapi }
184 mapi
185 mapi /**
186 235 mapi * Checks if the given node is a valid property node.
187 mapi *
188 mapi * @param PHP_PMD_Node_ASTNode $node The context property node.
189 mapi *
190 mapi * @return boolean
191 mapi * @since 0.2.6
192 mapi */
193 mapi protected function isValidPropertyNode(PHP_PMD_Node_ASTNode $node = null)
194 mapi {
195 mapi if ($node === null) {
196 mapi return false;
197 mapi }
198 mapi
199 mapi $parent = $node->getParent();
200 mapi while (!$parent->isInstanceOf('PropertyPostfix')) {
201 mapi if ($parent->isInstanceOf('CompoundVariable')) {
202 mapi return false;
203 mapi }
204 mapi $parent = $parent->getParent();
205 mapi }
206 mapi return true;
207 mapi }
208 mapi
209 mapi /**
210 129 mapi * This method checks that the given property postfix is accessed on an
211 mapi * instance or static reference to the given class.
212 mapi *
213 200 mapi * @param PHP_PMD_Node_Class $class The context class node instance.
214 mapi * @param PHP_PMD_Node_ASTNode $postfix The context property postfix node.
215 129 mapi *
216 mapi * @return boolean
217 mapi */
218 235 mapi protected function isInScopeOfClass(
219 200 mapi PHP_PMD_Node_Class $class,
220 129 mapi PHP_PMD_Node_ASTNode $postfix
221 mapi ) {
222 235 mapi $owner = $postfix->getParent()->getChild(0);
223 mapi if ($owner->isInstanceOf('PropertyPostfix')) {
224 mapi $owner = $owner->getParent()->getParent()->getChild(0);
225 mapi }
226 129 mapi return (
227 235 mapi $owner->isInstanceOf('SelfReference') ||
228 mapi $owner->isInstanceOf('StaticReference') ||
229 129 mapi // TODO: Replace this with ThisVariable check when this AST node is
230 mapi // ported back from the design disharmony branch
231 235 mapi strcasecmp($owner->getImage(), '$this') === 0 ||
232 mapi strcasecmp($owner->getImage(), $class->getImage()) === 0
233 129 mapi );
234 mapi }
235 197 mapi }