1 ////////////////////////////////////////////////////////////////////////////////
2 // checkstyle: Checks Java source code for adherence to a set of rules.
3 // Copyright (C) 2001-2019 the original author or authors.
4 //
5 // This library is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU Lesser General Public
7 // License as published by the Free Software Foundation; either
8 // version 2.1 of the License, or (at your option) any later version.
9 //
10 // This library is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 // Lesser General Public License for more details.
14 //
15 // You should have received a copy of the GNU Lesser General Public
16 // License along with this library; if not, write to the Free Software
17 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
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
30 /**
31 * <p>
32 * Checks that overload methods are grouped together. Example:
33 * </p>
34 * <pre>
35 * {@code
36 * public void foo(int i) {}
37 * public void foo(String s) {}
38 * public void notFoo() {} // Have to be after foo(int i, String s)
39 * public void foo(int i, String s) {}
40 * }
41 * </pre>
42 * <p>
43 * An example of how to configure the check is:
44 * </p>
45 *
46 * <pre>
47 * <module name="OverloadMethodsDeclarationOrder"/>
48 * </pre>
49 */
50 @StatelessCheck
51 public class OverloadMethodsDeclarationOrderCheck extends AbstractCheck {
52
53 /**
54 * A key is pointing to the warning message text in "messages.properties"
55 * file.
56 */
57 public static final String MSG_KEY = "overload.methods.declaration";
58
59 @Override
60 public int[] getDefaultTokens() {
61 return getRequiredTokens();
62 }
63
64 @Override
65 public int[] getAcceptableTokens() {
66 return getRequiredTokens();
67 }
68
69 @Override
70 public int[] getRequiredTokens() {
71 return new int[] {
72 TokenTypes.OBJBLOCK,
73 };
74 }
75
76 @Override
77 public void visitToken(DetailAST ast) {
78 final int parentType = ast.getParent().getType();
79 if (parentType == TokenTypes.CLASS_DEF
80 || parentType == TokenTypes.ENUM_DEF
81 || parentType == TokenTypes.INTERFACE_DEF
82 || parentType == TokenTypes.LITERAL_NEW) {
83 checkOverloadMethodsGrouping(ast);
84 }
85 }
86
87 /**
88 * Checks that if overload methods are grouped together they should not be
89 * separated from each other.
90 * @param objectBlock
91 * is a class, interface or enum object block.
92 */
93 private void checkOverloadMethodsGrouping(DetailAST objectBlock) {
94 final int allowedDistance = 1;
95 DetailAST currentToken = objectBlock.getFirstChild();
96 final Map<String, Integer> methodIndexMap = new HashMap<>();
97 final Map<String, Integer> methodLineNumberMap = new HashMap<>();
98 int currentIndex = 0;
99 while (currentToken != null) {
100 if (currentToken.getType() == TokenTypes.METHOD_DEF) {
101 currentIndex++;
102 final String methodName =
103 currentToken.findFirstToken(TokenTypes.IDENT).getText();
104 if (methodIndexMap.containsKey(methodName)) {
105 final int previousIndex = methodIndexMap.get(methodName);
106 if (currentIndex - previousIndex > allowedDistance) {
107 final int previousLineWithOverloadMethod =
108 methodLineNumberMap.get(methodName);
109 log(currentToken.getLineNo(), MSG_KEY,
110 previousLineWithOverloadMethod);
111 }
112 }
113 methodIndexMap.put(methodName, currentIndex);
114 methodLineNumberMap.put(methodName, currentToken.getLineNo());
115 }
116 currentToken = currentToken.getNextSibling();
117 }
118 }
119
120 }