1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31 package com.qulice.checkstyle;
32
33 import com.puppycrawl.tools.checkstyle.api.AbstractCheck;
34 import com.puppycrawl.tools.checkstyle.api.DetailAST;
35 import com.puppycrawl.tools.checkstyle.api.FileContents;
36 import com.puppycrawl.tools.checkstyle.api.TokenTypes;
37 import com.puppycrawl.tools.checkstyle.utils.AnnotationUtil;
38 import java.util.regex.Pattern;
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57 public final class NonStaticMethodCheck extends AbstractCheck {
58
59
60
61
62
63 private Pattern exclude = Pattern.compile("^$");
64
65
66
67
68
69 public void setExcludeFileNamePattern(final String excl) {
70 this.exclude = Pattern.compile(excl);
71 }
72
73 @Override
74 public int[] getDefaultTokens() {
75 return new int[] {
76 TokenTypes.METHOD_DEF,
77 };
78 }
79
80 @Override
81 public int[] getAcceptableTokens() {
82 return this.getDefaultTokens();
83 }
84
85 @Override
86 public int[] getRequiredTokens() {
87 return this.getDefaultTokens();
88 }
89
90 @Override
91 @SuppressWarnings("deprecation")
92 public void visitToken(final DetailAST ast) {
93 if (this.exclude.matcher(this.getFileContents().getFileName())
94 .find()) {
95 return;
96 }
97 if (TokenTypes.CLASS_DEF == ast.getParent().getParent().getType()) {
98 this.checkClassMethod(ast);
99 }
100 }
101
102
103
104
105
106
107
108
109 private void checkClassMethod(final DetailAST method) {
110 final DetailAST modifiers = method
111 .findFirstToken(TokenTypes.MODIFIERS);
112 if (modifiers.findFirstToken(TokenTypes.LITERAL_STATIC) != null) {
113 return;
114 }
115 final BranchContains checker = new BranchContains(method);
116 final boolean onlythrow =
117 checker.check(TokenTypes.LITERAL_THROW)
118 && !checker.check(TokenTypes.LCURLY)
119 && this.countSemiColons(method) == 1;
120 if (!AnnotationUtil.containsAnnotation(method, "Override")
121 && !isInAbstractOrNativeMethod(method)
122 && !checker.check(TokenTypes.LITERAL_THIS)
123 && !onlythrow) {
124 final int line = method.getLineNo();
125 this.log(
126 line,
127 "This method must be static, because it does not refer to \"this\""
128 );
129 }
130 }
131
132
133
134
135
136
137 private static boolean isInAbstractOrNativeMethod(final DetailAST method) {
138 final DetailAST modifiers = method.findFirstToken(TokenTypes.MODIFIERS);
139 final BranchContains checker = new BranchContains(modifiers);
140 return checker.check(TokenTypes.ABSTRACT)
141 || checker.check(TokenTypes.LITERAL_NATIVE);
142 }
143
144
145
146
147
148
149
150 @SuppressWarnings("deprecation")
151 private int countSemiColons(final DetailAST method) {
152 final DetailAST openingbrace = method.findFirstToken(TokenTypes.SLIST);
153 int count = 0;
154 if (openingbrace != null) {
155 final DetailAST closingbrace =
156 openingbrace.findFirstToken(TokenTypes.RCURLY);
157 final int lastline = closingbrace.getLineNo();
158 final int firstline = openingbrace.getLineNo();
159 final FileContents contents = this.getFileContents();
160 for (int line = firstline - 1; line < lastline; line += 1) {
161 if (!contents.lineIsBlank(line)
162 && !contents.lineIsComment(line)
163 && contents.getLine(line).contains(";")) {
164 count += 1;
165 }
166 }
167 }
168 return count;
169 }
170 }