1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package com.puppycrawl.tools.checkstyle.checks.coding;
20
21 import com.puppycrawl.tools.checkstyle.api.DetailAST;
22 import com.puppycrawl.tools.checkstyle.api.FastStack;
23 import com.puppycrawl.tools.checkstyle.api.TokenTypes;
24 import com.puppycrawl.tools.checkstyle.checks.AbstractFormatCheck;
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39 public final class ReturnCountCheck extends AbstractFormatCheck
40 {
41
42 private static final int DEFAULT_MAX = 2;
43
44
45 private final FastStack<Context> contextStack = FastStack.newInstance();
46
47 private int max;
48
49 private Context context;
50
51
52 public ReturnCountCheck()
53 {
54 super("^equals$");
55 setMax(DEFAULT_MAX);
56 }
57
58 @Override
59 public int[] getDefaultTokens()
60 {
61 return new int[] {
62 TokenTypes.CTOR_DEF,
63 TokenTypes.METHOD_DEF,
64 TokenTypes.LITERAL_RETURN,
65 };
66 }
67
68 @Override
69 public int[] getRequiredTokens()
70 {
71 return new int[]{
72 TokenTypes.CTOR_DEF,
73 TokenTypes.METHOD_DEF,
74 };
75 }
76
77
78
79
80
81 public int getMax()
82 {
83 return max;
84 }
85
86
87
88
89
90 public void setMax(int max)
91 {
92 this.max = max;
93 }
94
95 @Override
96 public void beginTree(DetailAST rootAST)
97 {
98 context = null;
99 contextStack.clear();
100 }
101
102 @Override
103 public void visitToken(DetailAST ast)
104 {
105 switch (ast.getType()) {
106 case TokenTypes.CTOR_DEF:
107 case TokenTypes.METHOD_DEF:
108 visitMethodDef(ast);
109 break;
110 case TokenTypes.LITERAL_RETURN:
111 context.visitLiteralReturn();
112 break;
113 default:
114 throw new IllegalStateException(ast.toString());
115 }
116 }
117
118 @Override
119 public void leaveToken(DetailAST ast)
120 {
121 switch (ast.getType()) {
122 case TokenTypes.CTOR_DEF:
123 case TokenTypes.METHOD_DEF:
124 leaveMethodDef(ast);
125 break;
126 case TokenTypes.LITERAL_RETURN:
127
128 break;
129 default:
130 throw new IllegalStateException(ast.toString());
131 }
132 }
133
134
135
136
137
138 private void visitMethodDef(DetailAST ast)
139 {
140 contextStack.push(context);
141 final DetailAST methodNameAST = ast.findFirstToken(TokenTypes.IDENT);
142 context =
143 new Context(!getRegexp().matcher(methodNameAST.getText()).find());
144 }
145
146
147
148
149
150
151 private void leaveMethodDef(DetailAST ast)
152 {
153 context.checkCount(ast);
154 context = contextStack.pop();
155 }
156
157
158
159
160
161 private class Context
162 {
163
164 private final boolean checking;
165
166 private int count;
167
168
169
170
171
172 public Context(boolean checking)
173 {
174 this.checking = checking;
175 count = 0;
176 }
177
178
179 public void visitLiteralReturn()
180 {
181 ++count;
182 }
183
184
185
186
187
188
189 public void checkCount(DetailAST ast)
190 {
191 if (checking && (count > getMax())) {
192 log(ast.getLineNo(), ast.getColumnNo(), "return.count",
193 count, getMax());
194 }
195 }
196 }
197 }