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.design;
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
27
28
29
30
31
32
33
34
35
36 @StatelessCheck
37 public class HideUtilityClassConstructorCheck extends AbstractCheck {
38
39
40
41
42
43 public static final String MSG_KEY = "hide.utility.class";
44
45 @Override
46 public int[] getDefaultTokens() {
47 return getRequiredTokens();
48 }
49
50 @Override
51 public int[] getAcceptableTokens() {
52 return getRequiredTokens();
53 }
54
55 @Override
56 public int[] getRequiredTokens() {
57 return new int[] {TokenTypes.CLASS_DEF};
58 }
59
60 @Override
61 public void visitToken(DetailAST ast) {
62
63 if (!isAbstract(ast)) {
64 final boolean hasStaticModifier = isStatic(ast);
65
66 final Details details = new Details(ast);
67 details.invoke();
68
69 final boolean hasDefaultCtor = details.isHasDefaultCtor();
70 final boolean hasPublicCtor = details.isHasPublicCtor();
71 final boolean hasNonStaticMethodOrField = details.isHasNonStaticMethodOrField();
72 final boolean hasNonPrivateStaticMethodOrField =
73 details.isHasNonPrivateStaticMethodOrField();
74
75 final boolean hasAccessibleCtor = hasDefaultCtor || hasPublicCtor;
76
77
78
79 final boolean extendsJlo =
80 ast.findFirstToken(TokenTypes.EXTENDS_CLAUSE) == null;
81
82 final boolean isUtilClass = extendsJlo
83 && !hasNonStaticMethodOrField && hasNonPrivateStaticMethodOrField;
84
85 if (isUtilClass && hasAccessibleCtor && !hasStaticModifier) {
86 log(ast, MSG_KEY);
87 }
88 }
89 }
90
91
92
93
94
95
96 private static boolean isAbstract(DetailAST ast) {
97 return ast.findFirstToken(TokenTypes.MODIFIERS)
98 .findFirstToken(TokenTypes.ABSTRACT) != null;
99 }
100
101
102
103
104
105
106 private static boolean isStatic(DetailAST ast) {
107 return ast.findFirstToken(TokenTypes.MODIFIERS)
108 .findFirstToken(TokenTypes.LITERAL_STATIC) != null;
109 }
110
111
112
113
114 private static class Details {
115
116
117 private final DetailAST ast;
118
119 private boolean hasNonStaticMethodOrField;
120
121 private boolean hasNonPrivateStaticMethodOrField;
122
123 private boolean hasDefaultCtor;
124
125 private boolean hasPublicCtor;
126
127
128
129
130
131 Details(DetailAST ast) {
132 this.ast = ast;
133 }
134
135
136
137
138
139 public boolean isHasNonStaticMethodOrField() {
140 return hasNonStaticMethodOrField;
141 }
142
143
144
145
146
147 public boolean isHasNonPrivateStaticMethodOrField() {
148 return hasNonPrivateStaticMethodOrField;
149 }
150
151
152
153
154
155 public boolean isHasDefaultCtor() {
156 return hasDefaultCtor;
157 }
158
159
160
161
162
163 public boolean isHasPublicCtor() {
164 return hasPublicCtor;
165 }
166
167
168
169
170 public void invoke() {
171 final DetailAST objBlock = ast.findFirstToken(TokenTypes.OBJBLOCK);
172 hasNonStaticMethodOrField = false;
173 hasNonPrivateStaticMethodOrField = false;
174 hasDefaultCtor = true;
175 hasPublicCtor = false;
176 DetailAST child = objBlock.getFirstChild();
177
178 while (child != null) {
179 final int type = child.getType();
180 if (type == TokenTypes.METHOD_DEF
181 || type == TokenTypes.VARIABLE_DEF) {
182 final DetailAST modifiers =
183 child.findFirstToken(TokenTypes.MODIFIERS);
184 final boolean isStatic =
185 modifiers.findFirstToken(TokenTypes.LITERAL_STATIC) != null;
186
187 if (isStatic) {
188 final boolean isPrivate =
189 modifiers.findFirstToken(TokenTypes.LITERAL_PRIVATE) != null;
190
191 if (!isPrivate) {
192 hasNonPrivateStaticMethodOrField = true;
193 }
194 }
195 else {
196 hasNonStaticMethodOrField = true;
197 }
198 }
199 if (type == TokenTypes.CTOR_DEF) {
200 hasDefaultCtor = false;
201 final DetailAST modifiers =
202 child.findFirstToken(TokenTypes.MODIFIERS);
203 if (modifiers.findFirstToken(TokenTypes.LITERAL_PRIVATE) == null
204 && modifiers.findFirstToken(TokenTypes.LITERAL_PROTECTED) == null) {
205
206
207 hasPublicCtor = true;
208 }
209 }
210 child = child.getNextSibling();
211 }
212 }
213
214 }
215
216 }