1
2
3
4
5 package com.qulice.checkstyle;
6
7 import com.puppycrawl.tools.checkstyle.api.AbstractCheck;
8 import com.puppycrawl.tools.checkstyle.api.DetailAST;
9 import com.puppycrawl.tools.checkstyle.api.TokenTypes;
10
11
12
13
14
15
16
17 public final class ConstantUsageCheck extends AbstractCheck {
18
19 @Override
20 public int[] getDefaultTokens() {
21 return new int[]{
22 TokenTypes.VARIABLE_DEF,
23 };
24 }
25
26 @Override
27 public int[] getAcceptableTokens() {
28 return this.getDefaultTokens();
29 }
30
31 @Override
32 public int[] getRequiredTokens() {
33 return this.getDefaultTokens();
34 }
35
36 @Override
37 public void visitToken(final DetailAST ast) {
38 if (ConstantUsageCheck.isField(ast)
39 && ConstantUsageCheck.isFinal(ast)) {
40 final DetailAST namenode = ast.findFirstToken(TokenTypes.IDENT);
41 if (!"serialVersionUID".equals(this.getText(namenode))) {
42 this.checkField(ast, namenode);
43 }
44 }
45 }
46
47
48
49
50
51
52
53 private void checkField(final DetailAST ast, final DetailAST namenode) {
54 final String name = namenode.getText();
55 final int line = namenode.getLineNo();
56 DetailAST variable = ast.getNextSibling();
57 int counter = 0;
58 while (null != variable) {
59 switch (variable.getType()) {
60 case TokenTypes.VARIABLE_DEF:
61 counter += this.parseVarDef(variable, name);
62 break;
63 case TokenTypes.CLASS_DEF:
64 counter += this.parseDef(
65 variable, name, TokenTypes.OBJBLOCK
66 );
67 break;
68 default:
69 counter += this.parseDef(variable, name, TokenTypes.SLIST);
70 break;
71 }
72 variable = variable.getNextSibling();
73 }
74 if (counter == 0 && ConstantUsageCheck.isPrivate(ast)) {
75 this.log(
76 line,
77 String.format("Private constant \"%s\" is not used", name)
78 );
79 }
80 }
81
82
83
84
85
86
87
88
89 private int parseVarDef(final DetailAST variable, final String name) {
90 int counter = 0;
91 final DetailAST assign =
92 variable.findFirstToken(TokenTypes.ASSIGN);
93 if (assign != null) {
94 DetailAST expression =
95 assign.findFirstToken(TokenTypes.EXPR);
96 if (expression == null) {
97 expression = assign.findFirstToken(
98 TokenTypes.ARRAY_INIT
99 );
100 }
101 final String text = this.getText(expression);
102 if (text.contains(name)) {
103 ++counter;
104 }
105 }
106 return counter;
107 }
108
109
110
111
112
113
114
115 private String getText(final DetailAST node) {
116 final String ret;
117 if (node == null) {
118 ret = "";
119 } else if (0 == node.getChildCount()) {
120 ret = node.getText();
121 } else {
122 final StringBuilder result = new StringBuilder();
123 DetailAST child = node.getFirstChild();
124 while (null != child) {
125 final String text = this.getText(child);
126 result.append(text);
127 if (".".equals(node.getText())
128 && child.getNextSibling() != null) {
129 result.append(node.getText());
130 }
131 child = child.getNextSibling();
132 }
133 ret = result.toString();
134 }
135 return ret;
136 }
137
138
139
140
141
142
143
144
145 private static boolean isField(final DetailAST node) {
146 final DetailAST parent = node.getParent();
147 return TokenTypes.OBJBLOCK == parent.getType();
148 }
149
150
151
152
153
154
155
156 private static boolean isFinal(final DetailAST node) {
157 final DetailAST modifiers = node.findFirstToken(TokenTypes.MODIFIERS);
158 return modifiers.getChildCount(TokenTypes.FINAL) > 0;
159 }
160
161
162
163
164
165
166
167
168 private static boolean isPrivate(final DetailAST node) {
169 final DetailAST modifiers = node.findFirstToken(TokenTypes.MODIFIERS);
170 return modifiers.getChildCount(TokenTypes.LITERAL_PRIVATE) > 0;
171 }
172
173
174
175
176
177
178
179
180
181 private int parseDef(final DetailAST definition, final String name,
182 final int type) {
183 int counter = 0;
184 final DetailAST modifiers =
185 definition.findFirstToken(TokenTypes.MODIFIERS);
186 if (modifiers != null) {
187 counter += this.parseAnnotation(modifiers, name);
188 }
189 final DetailAST opening = definition.findFirstToken(type);
190 if (null != opening) {
191 final DetailAST closing = opening.findFirstToken(TokenTypes.RCURLY);
192 final int start = opening.getLineNo();
193 final int end = closing.getLineNo() - 1;
194 final String[] lines = this.getLines();
195 for (int pos = start; pos < end; pos += 1) {
196 if (lines[pos].contains(name)) {
197 counter += 1;
198 }
199 }
200 }
201 return counter;
202 }
203
204
205
206
207
208
209
210
211 private int parseAnnotation(final DetailAST modifiers, final String name) {
212 int counter = 0;
213 final DetailAST variable =
214 modifiers.findFirstToken(TokenTypes.ANNOTATION);
215 if (variable != null) {
216 final String txt = this.getText(variable);
217 if (txt.contains(name)) {
218 ++counter;
219 }
220 }
221 return counter;
222 }
223 }