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.coding;
21
22 import java.util.HashMap;
23 import java.util.Map;
24
25 import com.puppycrawl.tools.checkstyle.StatelessCheck;
26 import com.puppycrawl.tools.checkstyle.api.AbstractCheck;
27 import com.puppycrawl.tools.checkstyle.api.DetailAST;
28 import com.puppycrawl.tools.checkstyle.api.TokenTypes;
29 import com.puppycrawl.tools.checkstyle.utils.TokenUtil;
30
31
32
33
34
35
36
37
38
39
40 @StatelessCheck
41 public class OverloadMethodsDeclarationOrderCheck extends AbstractCheck {
42
43
44
45
46
47 public static final String MSG_KEY = "overload.methods.declaration";
48
49
50
51
52
53 public static final String MSG_ORDER = "overload.methods.declaration.order";
54
55
56
57
58 private boolean orderByIncreasingParameterCount;
59
60
61
62
63
64
65
66
67 public void setOrderByIncreasingParameterCount(boolean orderByIncreasingParameterCount) {
68 this.orderByIncreasingParameterCount = orderByIncreasingParameterCount;
69 }
70
71 @Override
72 public int[] getDefaultTokens() {
73 return getRequiredTokens();
74 }
75
76 @Override
77 public int[] getAcceptableTokens() {
78 return getRequiredTokens();
79 }
80
81 @Override
82 public int[] getRequiredTokens() {
83 return new int[] {
84 TokenTypes.OBJBLOCK,
85 };
86 }
87
88 @Override
89 public void visitToken(DetailAST ast) {
90 final int parentType = ast.getParent().getType();
91
92 final int[] tokenTypes = {
93 TokenTypes.CLASS_DEF,
94 TokenTypes.ENUM_DEF,
95 TokenTypes.INTERFACE_DEF,
96 TokenTypes.LITERAL_NEW,
97 TokenTypes.RECORD_DEF,
98 };
99
100 if (TokenUtil.isOfType(parentType, tokenTypes)) {
101 checkOverloadMethodsGrouping(ast);
102 }
103 }
104
105
106
107
108
109
110
111
112 private void checkOverloadMethodsGrouping(DetailAST objectBlock) {
113 final int allowedDistance = 1;
114 DetailAST currentToken = objectBlock.getFirstChild();
115 final Map<String, Integer> methodIndexMap = new HashMap<>();
116 final Map<String, Integer> methodLineNumberMap = new HashMap<>();
117
118 final Map<String, Integer> methodParameterCountMap = new HashMap<>();
119 final Map<String, Boolean> methodIsOrderedMap = new HashMap<>();
120
121 int currentIndex = 0;
122 while (currentToken != null) {
123 if (currentToken.getType() == TokenTypes.METHOD_DEF) {
124 currentIndex++;
125 final String methodName =
126 currentToken.findFirstToken(TokenTypes.IDENT).getText();
127 final Integer previousIndex = methodIndexMap.get(methodName);
128
129 if (previousIndex != null) {
130 final DetailAST previousSibling = currentToken.getPreviousSibling();
131 final boolean isMethod = previousSibling.getType() == TokenTypes.METHOD_DEF;
132
133 if (!isMethod || currentIndex - previousIndex > allowedDistance) {
134 final int previousLineWithOverloadMethod =
135 methodLineNumberMap.get(methodName);
136 log(currentToken, MSG_KEY,
137 previousLineWithOverloadMethod);
138 }
139
140 if (orderByIncreasingParameterCount) {
141 checkMethodOrdering(currentToken, methodName,
142 methodIsOrderedMap, methodParameterCountMap);
143 }
144 }
145 methodIsOrderedMap.putIfAbsent(methodName, Boolean.TRUE);
146 methodIndexMap.put(methodName, currentIndex);
147 methodLineNumberMap.put(methodName, currentToken.getLineNo());
148 methodParameterCountMap.put(methodName, getParameterCount(currentToken));
149 }
150 currentToken = currentToken.getNextSibling();
151 }
152 }
153
154
155
156
157
158
159
160
161
162
163
164
165
166 private void checkMethodOrdering(DetailAST currentMethod, String methodName,
167 Map<String, Boolean> methodIsOrderedMap, Map<String, Integer> methodParameterCountMap) {
168
169 final int currentParamCount = getParameterCount(currentMethod);
170 final boolean isOrdered = methodIsOrderedMap.get(methodName)
171 && currentParamCount >= methodParameterCountMap.get(methodName);
172 if (!isOrdered) {
173 methodIsOrderedMap.put(methodName, Boolean.FALSE);
174 log(currentMethod, MSG_ORDER);
175 }
176 }
177
178
179
180
181
182
183
184 private static int getParameterCount(DetailAST method) {
185 final DetailAST params = method.findFirstToken(TokenTypes.PARAMETERS);
186 return params.getChildCount(TokenTypes.PARAMETER_DEF);
187 }
188 }