Source code: com/puppycrawl/tools/checkstyle/checks/InnerAssignmentCheck.java
1 ////////////////////////////////////////////////////////////////////////////////
2 // checkstyle: Checks Java source code for adherence to a set of rules.
3 // Copyright (C) 2001-2002 Oliver Burn
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;
21
22 import com.puppycrawl.tools.checkstyle.api.Check;
23 import com.puppycrawl.tools.checkstyle.api.TokenTypes;
24 import com.puppycrawl.tools.checkstyle.api.DetailAST;
25
26 /**
27 * <p>
28 * Checks for assignments in subexpressions, such as in
29 * <code>String s = Integer.toString(i = 2);</code>.
30 * </p>
31 * <p>
32 * Rationale: With the exception of <code>for</code> iterators, all assignments
33 * should occur in their own toplevel statement to increase readability.
34 * With inner assignments like the above it is difficult to see all places
35 * where a variable is set.
36 * </p>
37 * <p>
38 * By default the check will check the following assignment operators:
39 * {@link TokenTypes#ASSIGN ASSIGN},
40 * {@link TokenTypes#BAND_ASSIGN BAND_ASSIGN},
41 * {@link TokenTypes#BOR_ASSIGN BOR_ASSIGN},
42 * {@link TokenTypes#BSR_ASSIGN BSR_ASSIGN},
43 * {@link TokenTypes#BXOR_ASSIGN BXOR_ASSIGN},
44 * {@link TokenTypes#DIV_ASSIGN DIV_ASSIGN},
45 * {@link TokenTypes#MINUS_ASSIGN MINUS_ASSIGN},
46 * {@link TokenTypes#MOD_ASSIGN MOD_ASSIGN},
47 * {@link TokenTypes#PLUS_ASSIGN PLUS_ASSIGN},
48 * {@link TokenTypes#SL_ASSIGN SL_ASSIGN},
49 * {@link TokenTypes#SR_ASSIGN SR_ASSIGN},
50 * {@link TokenTypes#STAR_ASSIGN STAR_ASSIGN}.
51 * </p>
52 * <p> An example of how to configure the check is:
53 * <pre>
54 * <module name="InnerAssignment"/>
55 * </pre>
56 *
57 * <p> An example of how to configure the check for only <code>=</code>,
58 * <code>+=</code>, and <code>-=</code> operators is:
59 * </p>
60 * <pre>
61 * <module name="InnerAssignment">
62 * <tokens>ASSIGN, PLUS_ASSIGN, MINUS_ASSIGN</tokens>
63 * </module>
64 * </pre>
65
66 * @author lkuehne
67 */
68 public class InnerAssignmentCheck
69 extends Check
70 {
71 /** @see Check */
72 public int[] getDefaultTokens()
73 {
74 return new int[] {
75 TokenTypes.ASSIGN, // '='
76 TokenTypes.DIV_ASSIGN, // "/="
77 TokenTypes.PLUS_ASSIGN, // "+="
78 TokenTypes.MINUS_ASSIGN, //"-="
79 TokenTypes.STAR_ASSIGN, // "*="
80 TokenTypes.MOD_ASSIGN, // "%="
81 TokenTypes.SR_ASSIGN, // ">>="
82 TokenTypes.BSR_ASSIGN, // ">>>="
83 TokenTypes.SL_ASSIGN, // "<<="
84 TokenTypes.BXOR_ASSIGN, // "^="
85 TokenTypes.BOR_ASSIGN, // "|="
86 TokenTypes.BAND_ASSIGN, // "&="
87 };
88 }
89
90 /** @see Check */
91 public void visitToken(DetailAST aAST)
92 {
93 final DetailAST parent1 = aAST.getParent();
94 final DetailAST parent2 = parent1.getParent();
95 final DetailAST parent3 = parent2.getParent();
96
97 final boolean assigment = isAssignment(parent1);
98 final boolean expr = parent1.getType() == TokenTypes.EXPR;
99 final boolean exprList =
100 expr && parent2.getType() == TokenTypes.ELIST;
101 final boolean methodCall =
102 exprList && parent3.getType() == TokenTypes.METHOD_CALL;
103 final boolean ctorCall =
104 exprList && parent3.getType() == TokenTypes.LITERAL_NEW;
105
106 if (assigment || methodCall || ctorCall) {
107 log(aAST.getLineNo(), aAST.getColumnNo(), "assignment.inner.avoid");
108 }
109 }
110
111 /**
112 * Checks if an AST is an assignment operator.
113 * @param aAST the AST to check
114 * @return true iff aAST is an assignment operator.
115 */
116 private boolean isAssignment(DetailAST aAST)
117 {
118 // TODO: make actual tokens available to Check and loop over actual
119 // tokens here?
120 final int[] tokens = getDefaultTokens();
121
122 final int astType = aAST.getType();
123
124 for (int i = 0; i < tokens.length; i++) {
125 int tokenType = tokens[i];
126 if (astType == tokenType) {
127 return true;
128 }
129 }
130 return false;
131 }
132
133
134 }