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;
21
22 import java.util.Optional;
23 import java.util.regex.Pattern;
24
25 import com.puppycrawl.tools.checkstyle.FileStatefulCheck;
26 import com.puppycrawl.tools.checkstyle.api.AbstractCheck;
27 import com.puppycrawl.tools.checkstyle.api.DetailAST;
28 import com.puppycrawl.tools.checkstyle.api.FullIdent;
29 import com.puppycrawl.tools.checkstyle.api.TokenTypes;
30
31
32
33
34
35
36
37
38
39
40
41 @FileStatefulCheck
42 public class UncommentedMainCheck
43 extends AbstractCheck {
44
45
46
47
48
49 public static final String MSG_KEY = "uncommented.main";
50
51
52 private Pattern excludedClasses = Pattern.compile("^$");
53
54 private String currentClass;
55
56 private FullIdent packageName;
57
58 private int classDepth;
59
60
61
62
63
64 public void setExcludedClasses(Pattern excludedClasses) {
65 this.excludedClasses = excludedClasses;
66 }
67
68 @Override
69 public int[] getAcceptableTokens() {
70 return getRequiredTokens();
71 }
72
73 @Override
74 public int[] getDefaultTokens() {
75 return getRequiredTokens();
76 }
77
78 @Override
79 public int[] getRequiredTokens() {
80 return new int[] {
81 TokenTypes.METHOD_DEF,
82 TokenTypes.CLASS_DEF,
83 TokenTypes.PACKAGE_DEF,
84 };
85 }
86
87 @Override
88 public void beginTree(DetailAST rootAST) {
89 packageName = FullIdent.createFullIdent(null);
90 currentClass = null;
91 classDepth = 0;
92 }
93
94 @Override
95 public void leaveToken(DetailAST ast) {
96 if (ast.getType() == TokenTypes.CLASS_DEF) {
97 classDepth--;
98 }
99 }
100
101 @Override
102 public void visitToken(DetailAST ast) {
103 switch (ast.getType()) {
104 case TokenTypes.PACKAGE_DEF:
105 visitPackageDef(ast);
106 break;
107 case TokenTypes.CLASS_DEF:
108 visitClassDef(ast);
109 break;
110 case TokenTypes.METHOD_DEF:
111 visitMethodDef(ast);
112 break;
113 default:
114 throw new IllegalStateException(ast.toString());
115 }
116 }
117
118
119
120
121
122 private void visitPackageDef(DetailAST packageDef) {
123 packageName = FullIdent.createFullIdent(packageDef.getLastChild()
124 .getPreviousSibling());
125 }
126
127
128
129
130
131 private void visitClassDef(DetailAST classDef) {
132
133
134 if (classDepth == 0) {
135 final DetailAST ident = classDef.findFirstToken(TokenTypes.IDENT);
136 currentClass = packageName.getText() + "." + ident.getText();
137 classDepth++;
138 }
139 }
140
141
142
143
144
145
146 private void visitMethodDef(DetailAST method) {
147 if (classDepth == 1
148
149 && checkClassName()
150 && checkName(method)
151 && checkModifiers(method)
152 && checkType(method)
153 && checkParams(method)) {
154 log(method.getLineNo(), MSG_KEY);
155 }
156 }
157
158
159
160
161
162 private boolean checkClassName() {
163 return !excludedClasses.matcher(currentClass).find();
164 }
165
166
167
168
169
170
171 private static boolean checkName(DetailAST method) {
172 final DetailAST ident = method.findFirstToken(TokenTypes.IDENT);
173 return "main".equals(ident.getText());
174 }
175
176
177
178
179
180
181 private static boolean checkModifiers(DetailAST method) {
182 final DetailAST modifiers =
183 method.findFirstToken(TokenTypes.MODIFIERS);
184
185 return modifiers.findFirstToken(TokenTypes.LITERAL_PUBLIC) != null
186 && modifiers.findFirstToken(TokenTypes.LITERAL_STATIC) != null;
187 }
188
189
190
191
192
193
194 private static boolean checkType(DetailAST method) {
195 final DetailAST type =
196 method.findFirstToken(TokenTypes.TYPE).getFirstChild();
197 return type.getType() == TokenTypes.LITERAL_VOID;
198 }
199
200
201
202
203
204
205 private static boolean checkParams(DetailAST method) {
206 boolean checkPassed = false;
207 final DetailAST params = method.findFirstToken(TokenTypes.PARAMETERS);
208
209 if (params.getChildCount() == 1) {
210 final DetailAST parameterType = params.getFirstChild().findFirstToken(TokenTypes.TYPE);
211 final Optional<DetailAST> arrayDecl = Optional.ofNullable(
212 parameterType.findFirstToken(TokenTypes.ARRAY_DECLARATOR));
213 final Optional<DetailAST> varargs = Optional.ofNullable(
214 params.getFirstChild().findFirstToken(TokenTypes.ELLIPSIS));
215
216 if (arrayDecl.isPresent()) {
217 checkPassed = isStringType(arrayDecl.get().getFirstChild());
218 }
219 else if (varargs.isPresent()) {
220 checkPassed = isStringType(parameterType.getFirstChild());
221 }
222 }
223 return checkPassed;
224 }
225
226
227
228
229
230
231 private static boolean isStringType(DetailAST typeAst) {
232 final FullIdent type = FullIdent.createFullIdent(typeAst);
233 return "String".equals(type.getText())
234 || "java.lang.String".equals(type.getText());
235 }
236
237 }