Source code: com/puppycrawl/tools/checkstyle/checks/HiddenFieldCheck.java
1 ////////////////////////////////////////////////////////////////////////////////
2 // checkstyle: Checks Java source code for adherence to a set of rules.
3 // Copyright (C) 2001-2002 Oliver Burn
4 //
5 // This library is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU Lesser General Public
7 // License as published by the Free Software Foundation; either
8 // version 2.1 of the License, or (at your option) any later version.
9 //
10 // This library is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 // Lesser General Public License for more details.
14 //
15 // You should have received a copy of the GNU Lesser General Public
16 // License along with this library; if not, write to the Free Software
17 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 ////////////////////////////////////////////////////////////////////////////////
19 package com.puppycrawl.tools.checkstyle.checks;
20
21 import java.util.HashSet;
22 import java.util.Iterator;
23 import java.util.LinkedList;
24
25 import com.puppycrawl.tools.checkstyle.api.Check;
26 import com.puppycrawl.tools.checkstyle.api.DetailAST;
27 import com.puppycrawl.tools.checkstyle.api.ScopeUtils;
28 import com.puppycrawl.tools.checkstyle.api.TokenTypes;
29
30 /**
31 * <p>Checks that a local variable or a parameter does not shadow
32 * a field that is defined in the same class.
33 * </p>
34 * <p>
35 * An example of how to configure the check is:
36 * </p>
37 * <pre>
38 * <module name="HiddenField"/>
39 * </pre>
40 * <p>
41 * An example of how to configure the check so that it checks variables but not
42 * parameters is:
43 * </p>
44 * <pre>
45 * <module name="HiddenField">
46 * <property name="tokens" value="VARIABLE_DEF"/>
47 * </module>
48 * </pre>
49 * @author Rick Giles
50 * @version 1.0
51 */
52 public class HiddenFieldCheck
53 extends Check
54 {
55
56 /** stack of sets of field names,
57 * one for each class of a set of nested classes */
58 private LinkedList mFieldsStack = null;
59
60 /** @see com.puppycrawl.tools.checkstyle.api.Check */
61 public int[] getDefaultTokens()
62 {
63 return new int[] {
64 TokenTypes.VARIABLE_DEF,
65 TokenTypes.PARAMETER_DEF,
66 TokenTypes.CLASS_DEF,
67 };
68 }
69
70 /** @see com.puppycrawl.tools.checkstyle.api.Check */
71 public int[] getAcceptableTokens()
72 {
73 return new int[] {
74 TokenTypes.VARIABLE_DEF,
75 TokenTypes.PARAMETER_DEF,
76 };
77 }
78
79 /** @see com.puppycrawl.tools.checkstyle.api.Check */
80 public int[] getRequiredTokens()
81 {
82 return new int[] {
83 TokenTypes.CLASS_DEF,
84 };
85 }
86
87 /** @see com.puppycrawl.tools.checkstyle.api.Check */
88 public void beginTree()
89 {
90 mFieldsStack = new LinkedList();
91 }
92
93 /** @see com.puppycrawl.tools.checkstyle.api.Check */
94 public void visitToken(DetailAST aAST)
95 {
96 if (aAST.getType() == TokenTypes.CLASS_DEF) {
97 //find and push fields
98 final HashSet fieldSet = new HashSet(); //fields container
99 //add fields to container
100 final DetailAST objBlock =
101 aAST.findFirstToken(TokenTypes.OBJBLOCK);
102 DetailAST child = (DetailAST) objBlock.getFirstChild();
103 while (child != null) {
104 if (child.getType() == TokenTypes.VARIABLE_DEF) {
105 final String name =
106 child.findFirstToken(TokenTypes.IDENT).getText();
107 fieldSet.add(name);
108 }
109 child = (DetailAST) child.getNextSibling();
110 }
111 mFieldsStack.addLast(fieldSet); //push container
112 }
113 else {
114 //must be VARIABLE_DEF or PARAMETER_DEF
115 processVariable(aAST);
116 }
117 }
118
119 /** @see com.puppycrawl.tools.checkstyle.api.Check */
120 public void leaveToken(DetailAST aAST)
121 {
122 if (aAST.getType() == TokenTypes.CLASS_DEF) {
123 //pop
124 mFieldsStack.removeLast();
125 }
126 }
127
128 /**
129 * Process a variable token.
130 * Check whether a local variable or parameter shadows a field.
131 * Store a field for later comparison with local variables and parameters.
132 * @param aAST the variable token.
133 */
134 private void processVariable(DetailAST aAST)
135 {
136 if (!ScopeUtils.inInterfaceBlock(aAST)) {
137 if (ScopeUtils.inCodeBlock(aAST)) {
138 //local variable or parameter. Does it shadow a field?
139 final DetailAST nameAST = aAST.findFirstToken(TokenTypes.IDENT);
140 final String name = nameAST.getText();
141 final Iterator it = mFieldsStack.iterator();
142 while (it.hasNext()) {
143 final HashSet aFieldsSet = (HashSet) it.next();
144 if (aFieldsSet.contains(name)) {
145 log(nameAST.getLineNo(), nameAST.getColumnNo(),
146 "hidden.field", name);
147 break;
148 }
149 }
150 }
151 }
152 }
153 }