1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package com.puppycrawl.tools.checkstyle.checks.coding;
21
22 import com.puppycrawl.tools.checkstyle.StatelessCheck;
23 import com.puppycrawl.tools.checkstyle.api.AbstractCheck;
24 import com.puppycrawl.tools.checkstyle.api.DetailAST;
25 import com.puppycrawl.tools.checkstyle.api.TokenTypes;
26 import com.puppycrawl.tools.checkstyle.utils.CheckUtil;
27 import com.puppycrawl.tools.checkstyle.utils.ScopeUtil;
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66 @StatelessCheck
67 public class ExplicitInitializationCheck extends AbstractCheck {
68
69
70
71
72
73 public static final String MSG_KEY = "explicit.init";
74
75
76
77
78 private boolean onlyObjectReferences;
79
80 @Override
81 public final int[] getDefaultTokens() {
82 return getRequiredTokens();
83 }
84
85 @Override
86 public final int[] getRequiredTokens() {
87 return new int[] {TokenTypes.VARIABLE_DEF};
88 }
89
90 @Override
91 public final int[] getAcceptableTokens() {
92 return getRequiredTokens();
93 }
94
95
96
97
98
99
100
101
102
103 public void setOnlyObjectReferences(boolean onlyObjectReferences) {
104 this.onlyObjectReferences = onlyObjectReferences;
105 }
106
107 @Override
108 public void visitToken(DetailAST ast) {
109 if (!isSkipCase(ast)) {
110 final DetailAST assign = ast.findFirstToken(TokenTypes.ASSIGN);
111 final DetailAST exprStart =
112 assign.getFirstChild().getFirstChild();
113 if (exprStart.getType() == TokenTypes.LITERAL_NULL) {
114 final DetailAST ident = ast.findFirstToken(TokenTypes.IDENT);
115 log(ident, MSG_KEY, ident.getText(), "null");
116 }
117 if (!onlyObjectReferences) {
118 validateNonObjects(ast);
119 }
120 }
121 }
122
123
124
125
126
127
128 private void validateNonObjects(DetailAST ast) {
129 final DetailAST ident = ast.findFirstToken(TokenTypes.IDENT);
130 final DetailAST assign = ast.findFirstToken(TokenTypes.ASSIGN);
131 final DetailAST exprStart =
132 assign.getFirstChild().getFirstChild();
133 final DetailAST type = ast.findFirstToken(TokenTypes.TYPE);
134 final int primitiveType = type.getFirstChild().getType();
135 if (primitiveType == TokenTypes.LITERAL_BOOLEAN
136 && exprStart.getType() == TokenTypes.LITERAL_FALSE) {
137 log(ident, MSG_KEY, ident.getText(), "false");
138 }
139 if (isNumericType(primitiveType) && isZero(exprStart)) {
140 log(ident, MSG_KEY, ident.getText(), "0");
141 }
142 if (primitiveType == TokenTypes.LITERAL_CHAR
143 && isZeroChar(exprStart)) {
144 log(ident, MSG_KEY, ident.getText(), "\\0");
145 }
146 }
147
148
149
150
151
152
153
154 private static boolean isZeroChar(DetailAST exprStart) {
155 return isZero(exprStart)
156 || "'\\0'".equals(exprStart.getText());
157 }
158
159
160
161
162
163
164
165 private static boolean isSkipCase(DetailAST ast) {
166 boolean skipCase = true;
167
168
169
170 if (!ScopeUtil.isLocalVariableDef(ast)
171 && !ScopeUtil.isInInterfaceOrAnnotationBlock(ast)) {
172 final DetailAST assign = ast.findFirstToken(TokenTypes.ASSIGN);
173
174 if (assign != null) {
175 final DetailAST modifiers = ast.findFirstToken(TokenTypes.MODIFIERS);
176 skipCase = modifiers.findFirstToken(TokenTypes.FINAL) != null;
177 }
178 }
179 return skipCase;
180 }
181
182
183
184
185
186
187
188
189 private static boolean isNumericType(int type) {
190 return type == TokenTypes.LITERAL_BYTE
191 || type == TokenTypes.LITERAL_SHORT
192 || type == TokenTypes.LITERAL_INT
193 || type == TokenTypes.LITERAL_FLOAT
194 || type == TokenTypes.LITERAL_LONG
195 || type == TokenTypes.LITERAL_DOUBLE;
196 }
197
198
199
200
201
202
203
204 private static boolean isZero(DetailAST expr) {
205 final int type = expr.getType();
206 final boolean isZero;
207 switch (type) {
208 case TokenTypes.NUM_FLOAT:
209 case TokenTypes.NUM_DOUBLE:
210 case TokenTypes.NUM_INT:
211 case TokenTypes.NUM_LONG:
212 final String text = expr.getText();
213 isZero = Double.compare(CheckUtil.parseDouble(text, type), 0.0) == 0;
214 break;
215 default:
216 isZero = false;
217 }
218 return isZero;
219 }
220
221 }