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 final boolean skip = AnnotationUtil.containsAnnotation(method, "Override")
95 || isInAbstractOrNativeMethod(method)
96 || onlythrow;
97 if (!skip
98 && !checker.check(TokenTypes.LITERAL_THIS)
99 && !checker.check(TokenTypes.LITERAL_SUPER)) {
100 this.log(
101 method.getLineNo(),
102 "This method must be static, because it does not refer to \"this\""
103 );
104 }
105 }
106
107
108
109
110
111
112 private static boolean isInAbstractOrNativeMethod(final DetailAST method) {
113 final BranchContains checker = new BranchContains(
114 method.findFirstToken(TokenTypes.MODIFIERS)
115 );
116 return checker.check(TokenTypes.ABSTRACT)
117 || checker.check(TokenTypes.LITERAL_NATIVE);
118 }
119
120
121
122
123
124
125
126 @SuppressWarnings("deprecation")
127 private int countSemiColons(final DetailAST method) {
128 final DetailAST openingbrace = method.findFirstToken(TokenTypes.SLIST);
129 int count = 0;
130 if (openingbrace != null) {
131 final DetailAST closingbrace =
132 openingbrace.findFirstToken(TokenTypes.RCURLY);
133 final int lastline = closingbrace.getLineNo();
134 final int firstline = openingbrace.getLineNo();
135 final FileContents contents = this.getFileContents();
136 for (int line = firstline - 1; line < lastline; line += 1) {
137 if (!contents.lineIsBlank(line)
138 && !contents.lineIsComment(line)
139 && contents.getLine(line).contains(";")) {
140 count += 1;
141 }
142 }
143 }
144 return count;
145 }
146 }