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