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;
21
22 import java.util.Arrays;
23 import java.util.Collections;
24 import java.util.Set;
25 import java.util.stream.Collectors;
26
27 import com.puppycrawl.tools.checkstyle.StatelessCheck;
28 import com.puppycrawl.tools.checkstyle.api.AbstractCheck;
29 import com.puppycrawl.tools.checkstyle.api.DetailAST;
30 import com.puppycrawl.tools.checkstyle.api.TokenTypes;
31 import com.puppycrawl.tools.checkstyle.utils.CheckUtil;
32 import com.puppycrawl.tools.checkstyle.utils.CommonUtil;
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54 @StatelessCheck
55 public class FinalParametersCheck extends AbstractCheck {
56
57
58
59
60
61 public static final String MSG_KEY = "final.parameter";
62
63
64
65
66
67
68 private final Set<Integer> primitiveDataTypes = Collections.unmodifiableSet(
69 Arrays.stream(new Integer[] {
70 TokenTypes.LITERAL_BYTE,
71 TokenTypes.LITERAL_SHORT,
72 TokenTypes.LITERAL_INT,
73 TokenTypes.LITERAL_LONG,
74 TokenTypes.LITERAL_FLOAT,
75 TokenTypes.LITERAL_DOUBLE,
76 TokenTypes.LITERAL_BOOLEAN,
77 TokenTypes.LITERAL_CHAR, })
78 .collect(Collectors.toSet()));
79
80
81
82
83 private boolean ignorePrimitiveTypes;
84
85
86
87
88
89 public void setIgnorePrimitiveTypes(boolean ignorePrimitiveTypes) {
90 this.ignorePrimitiveTypes = ignorePrimitiveTypes;
91 }
92
93 @Override
94 public int[] getDefaultTokens() {
95 return new int[] {
96 TokenTypes.METHOD_DEF,
97 TokenTypes.CTOR_DEF,
98 };
99 }
100
101 @Override
102 public int[] getAcceptableTokens() {
103 return new int[] {
104 TokenTypes.METHOD_DEF,
105 TokenTypes.CTOR_DEF,
106 TokenTypes.LITERAL_CATCH,
107 TokenTypes.FOR_EACH_CLAUSE,
108 };
109 }
110
111 @Override
112 public int[] getRequiredTokens() {
113 return CommonUtil.EMPTY_INT_ARRAY;
114 }
115
116 @Override
117 public void visitToken(DetailAST ast) {
118
119 final DetailAST container = ast.getParent().getParent();
120 if (container.getType() != TokenTypes.INTERFACE_DEF) {
121 if (ast.getType() == TokenTypes.LITERAL_CATCH) {
122 visitCatch(ast);
123 }
124 else if (ast.getType() == TokenTypes.FOR_EACH_CLAUSE) {
125 visitForEachClause(ast);
126 }
127 else {
128 visitMethod(ast);
129 }
130 }
131 }
132
133
134
135
136
137 private void visitMethod(final DetailAST method) {
138 final DetailAST modifiers =
139 method.findFirstToken(TokenTypes.MODIFIERS);
140
141
142 if (modifiers.findFirstToken(TokenTypes.ABSTRACT) == null
143 && modifiers.findFirstToken(TokenTypes.LITERAL_NATIVE) == null) {
144 final DetailAST parameters =
145 method.findFirstToken(TokenTypes.PARAMETERS);
146 DetailAST child = parameters.getFirstChild();
147 while (child != null) {
148
149 if (child.getType() == TokenTypes.PARAMETER_DEF) {
150 checkParam(child);
151 }
152 child = child.getNextSibling();
153 }
154 }
155 }
156
157
158
159
160
161 private void visitCatch(final DetailAST catchClause) {
162 checkParam(catchClause.findFirstToken(TokenTypes.PARAMETER_DEF));
163 }
164
165
166
167
168
169 private void visitForEachClause(final DetailAST forEachClause) {
170 checkParam(forEachClause.findFirstToken(TokenTypes.VARIABLE_DEF));
171 }
172
173
174
175
176
177 private void checkParam(final DetailAST param) {
178 if (param.findFirstToken(TokenTypes.MODIFIERS).findFirstToken(TokenTypes.FINAL) == null
179 && !isIgnoredParam(param)
180 && !CheckUtil.isReceiverParameter(param)) {
181 final DetailAST paramName = param.findFirstToken(TokenTypes.IDENT);
182 final DetailAST firstNode = CheckUtil.getFirstNode(param);
183 log(firstNode,
184 MSG_KEY, paramName.getText());
185 }
186 }
187
188
189
190
191
192
193 private boolean isIgnoredParam(DetailAST paramDef) {
194 boolean result = false;
195 if (ignorePrimitiveTypes) {
196 final DetailAST parameterType = paramDef
197 .findFirstToken(TokenTypes.TYPE).getFirstChild();
198 if (primitiveDataTypes.contains(parameterType.getType())) {
199 result = true;
200 }
201 }
202 return result;
203 }
204
205 }