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 @StatelessCheck
47 public class ExplicitInitializationCheck extends AbstractCheck {
48
49
50
51
52
53 public static final String MSG_KEY = "explicit.init";
54
55
56 private boolean onlyObjectReferences;
57
58 @Override
59 public final int[] getDefaultTokens() {
60 return getRequiredTokens();
61 }
62
63 @Override
64 public final int[] getRequiredTokens() {
65 return new int[] {TokenTypes.VARIABLE_DEF};
66 }
67
68 @Override
69 public final int[] getAcceptableTokens() {
70 return getRequiredTokens();
71 }
72
73
74
75
76
77
78 public void setOnlyObjectReferences(boolean onlyObjectReferences) {
79 this.onlyObjectReferences = onlyObjectReferences;
80 }
81
82 @Override
83 public void visitToken(DetailAST ast) {
84 if (!isSkipCase(ast)) {
85 final DetailAST assign = ast.findFirstToken(TokenTypes.ASSIGN);
86 final DetailAST exprStart =
87 assign.getFirstChild().getFirstChild();
88 if (exprStart.getType() == TokenTypes.LITERAL_NULL) {
89 final DetailAST ident = ast.findFirstToken(TokenTypes.IDENT);
90 log(ident, MSG_KEY, ident.getText(), "null");
91 }
92 if (!onlyObjectReferences) {
93 validateNonObjects(ast);
94 }
95 }
96 }
97
98
99
100
101
102 private void validateNonObjects(DetailAST ast) {
103 final DetailAST ident = ast.findFirstToken(TokenTypes.IDENT);
104 final DetailAST assign = ast.findFirstToken(TokenTypes.ASSIGN);
105 final DetailAST exprStart =
106 assign.getFirstChild().getFirstChild();
107 final DetailAST type = ast.findFirstToken(TokenTypes.TYPE);
108 final int primitiveType = type.getFirstChild().getType();
109 if (primitiveType == TokenTypes.LITERAL_BOOLEAN
110 && exprStart.getType() == TokenTypes.LITERAL_FALSE) {
111 log(ident, MSG_KEY, ident.getText(), "false");
112 }
113 if (isNumericType(primitiveType) && isZero(exprStart)) {
114 log(ident, MSG_KEY, ident.getText(), "0");
115 }
116 if (primitiveType == TokenTypes.LITERAL_CHAR
117 && isZeroChar(exprStart)) {
118 log(ident, MSG_KEY, ident.getText(), "\\0");
119 }
120 }
121
122
123
124
125
126
127 private static boolean isZeroChar(DetailAST exprStart) {
128 return isZero(exprStart)
129 || exprStart.getType() == TokenTypes.CHAR_LITERAL
130 && "'\\0'".equals(exprStart.getText());
131 }
132
133
134
135
136
137
138 private static boolean isSkipCase(DetailAST ast) {
139 boolean skipCase = true;
140
141
142
143 if (!ScopeUtil.isLocalVariableDef(ast)
144 && !ScopeUtil.isInInterfaceOrAnnotationBlock(ast)) {
145 final DetailAST assign = ast.findFirstToken(TokenTypes.ASSIGN);
146
147 if (assign != null) {
148 final DetailAST modifiers = ast.findFirstToken(TokenTypes.MODIFIERS);
149 skipCase = modifiers.findFirstToken(TokenTypes.FINAL) != null;
150 }
151 }
152 return skipCase;
153 }
154
155
156
157
158
159
160
161 private static boolean isNumericType(int type) {
162 return type == TokenTypes.LITERAL_BYTE
163 || type == TokenTypes.LITERAL_SHORT
164 || type == TokenTypes.LITERAL_INT
165 || type == TokenTypes.LITERAL_FLOAT
166 || type == TokenTypes.LITERAL_LONG
167 || type == TokenTypes.LITERAL_DOUBLE;
168 }
169
170
171
172
173
174
175
176 private static boolean isZero(DetailAST expr) {
177 final int type = expr.getType();
178 final boolean isZero;
179 switch (type) {
180 case TokenTypes.NUM_FLOAT:
181 case TokenTypes.NUM_DOUBLE:
182 case TokenTypes.NUM_INT:
183 case TokenTypes.NUM_LONG:
184 final String text = expr.getText();
185 isZero = Double.compare(CheckUtil.parseDouble(text, type), 0.0) == 0;
186 break;
187 default:
188 isZero = false;
189 }
190 return isZero;
191 }
192
193 }