1 //////////////////////////////////////////////////////////////////////////////// 2 // checkstyle: Checks Java source code for adherence to a set of rules. 3 // Copyright (C) 2001-2014 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.whitespace; 21 22 import com.puppycrawl.tools.checkstyle.api.DetailAST; 23 import com.puppycrawl.tools.checkstyle.api.TokenTypes; 24 import com.puppycrawl.tools.checkstyle.api.Utils; 25 import com.puppycrawl.tools.checkstyle.checks.AbstractOptionCheck; 26 27 /** 28 * <p> 29 * Checks line wrapping for operators. 30 * The policy to verify is specified using the {@link WrapOption} class 31 * and defaults to {@link WrapOption#NL}. 32 * </p> 33 * <p> By default the check will check the following operators: 34 * {@link TokenTypes#BAND BAND}, 35 * {@link TokenTypes#BOR BOR}, 36 * {@link TokenTypes#BSR BSR}, 37 * {@link TokenTypes#BXOR BXOR}, 38 * {@link TokenTypes#COLON COLON}, 39 * {@link TokenTypes#DIV DIV}, 40 * {@link TokenTypes#EQUAL EQUAL}, 41 * {@link TokenTypes#GE GE}, 42 * {@link TokenTypes#GT GT}, 43 * {@link TokenTypes#LAND LAND}, 44 * {@link TokenTypes#LE LE}, 45 * {@link TokenTypes#LITERAL_INSTANCEOF LITERAL_INSTANCEOF}, 46 * {@link TokenTypes#LOR LOR}, 47 * {@link TokenTypes#LT LT}, 48 * {@link TokenTypes#MINUS MINUS}, 49 * {@link TokenTypes#MOD MOD}, 50 * {@link TokenTypes#NOT_EQUAL NOT_EQUAL}, 51 * {@link TokenTypes#PLUS PLUS}, 52 * {@link TokenTypes#QUESTION QUESTION}, 53 * {@link TokenTypes#SL SL}, 54 * {@link TokenTypes#SR SR}, 55 * {@link TokenTypes#STAR STAR}. 56 * Other acceptable tokens are 57 * {@link TokenTypes#ASSIGN ASSIGN}, 58 * {@link TokenTypes#BAND_ASSIGN BAND_ASSIGN}, 59 * {@link TokenTypes#BOR_ASSIGN BOR_ASSIGN}, 60 * {@link TokenTypes#BSR_ASSIGN BSR_ASSIGN}, 61 * {@link TokenTypes#BXOR_ASSIGN BXOR_ASSIGN}, 62 * {@link TokenTypes#DIV_ASSIGN DIV_ASSIGN}, 63 * {@link TokenTypes#MINUS_ASSIGN MINUS_ASSIGN}, 64 * {@link TokenTypes#MOD_ASSIGN MOD_ASSIGN}, 65 * {@link TokenTypes#PLUS_ASSIGN PLUS_ASSIGN}, 66 * {@link TokenTypes#SL_ASSIGN SL_ASSIGN}, 67 * {@link TokenTypes#SR_ASSIGN SR_ASSIGN}, 68 * {@link TokenTypes#STAR_ASSIGN STAR_ASSIGN}. 69 * </p> 70 * <p> 71 * An example of how to configure the check is: 72 * </p> 73 * <pre> 74 * <module name="OperatorWrap"/> 75 * </pre> 76 * <p> An example of how to configure the check for assignment operators at the 77 * end of a line is: 78 * </p> 79 * <pre> 80 * <module name="OperatorWrap"> 81 * <property name="tokens" 82 * value="ASSIGN,DIV_ASSIGN,PLUS_ASSIGN,MINUS_ASSIGN,STAR_ASSIGN,MOD_ASSIGN,SR_ASSIGN,BSR_ASSIGN,SL_ASSIGN,BXOR_ASSIGN,BOR_ASSIGN,BAND_ASSIGN"/> 83 * <property name="option" value="eol"/> 84 * </module> 85 * </pre> 86 * 87 * @author Rick Giles 88 * @version 1.0 89 */ 90 public class OperatorWrapCheck 91 extends AbstractOptionCheck<WrapOption> 92 { 93 /** 94 * Sets the operator wrap option to new line. 95 */ 96 public OperatorWrapCheck() 97 { 98 super(WrapOption.NL, WrapOption.class); 99 } 100 101 @Override 102 public int[] getDefaultTokens() 103 { 104 return new int[] { 105 TokenTypes.QUESTION, // '?' 106 TokenTypes.COLON, // ':' (not reported for a case) 107 TokenTypes.EQUAL, // "==" 108 TokenTypes.NOT_EQUAL, // "!=" 109 TokenTypes.DIV, // '/' 110 TokenTypes.PLUS, //' +' (unary plus is UNARY_PLUS) 111 TokenTypes.MINUS, // '-' (unary minus is UNARY_MINUS) 112 TokenTypes.STAR, // '*' 113 TokenTypes.MOD, // '%' 114 TokenTypes.SR, // ">>" 115 TokenTypes.BSR, // ">>>" 116 TokenTypes.GE, // ">=" 117 TokenTypes.GT, // ">" 118 TokenTypes.SL, // "<<" 119 TokenTypes.LE, // "<=" 120 TokenTypes.LT, // '<' 121 TokenTypes.BXOR, // '^' 122 TokenTypes.BOR, // '|' 123 TokenTypes.LOR, // "||" 124 TokenTypes.BAND, // '&' 125 TokenTypes.LAND, // "&&" 126 TokenTypes.TYPE_EXTENSION_AND, 127 TokenTypes.LITERAL_INSTANCEOF, 128 }; 129 } 130 131 @Override 132 public int[] getAcceptableTokens() 133 { 134 return new int[] { 135 TokenTypes.QUESTION, // '?' 136 TokenTypes.COLON, // ':' (not reported for a case) 137 TokenTypes.EQUAL, // "==" 138 TokenTypes.NOT_EQUAL, // "!=" 139 TokenTypes.DIV, // '/' 140 TokenTypes.PLUS, //' +' (unary plus is UNARY_PLUS) 141 TokenTypes.MINUS, // '-' (unary minus is UNARY_MINUS) 142 TokenTypes.STAR, // '*' 143 TokenTypes.MOD, // '%' 144 TokenTypes.SR, // ">>" 145 TokenTypes.BSR, // ">>>" 146 TokenTypes.GE, // ">=" 147 TokenTypes.GT, // ">" 148 TokenTypes.SL, // "<<" 149 TokenTypes.LE, // "<=" 150 TokenTypes.LT, // '<' 151 TokenTypes.BXOR, // '^' 152 TokenTypes.BOR, // '|' 153 TokenTypes.LOR, // "||" 154 TokenTypes.BAND, // '&' 155 TokenTypes.LAND, // "&&" 156 TokenTypes.LITERAL_INSTANCEOF, 157 TokenTypes.TYPE_EXTENSION_AND, 158 TokenTypes.ASSIGN, // '=' 159 TokenTypes.DIV_ASSIGN, // "/=" 160 TokenTypes.PLUS_ASSIGN, // "+=" 161 TokenTypes.MINUS_ASSIGN, //"-=" 162 TokenTypes.STAR_ASSIGN, // "*=" 163 TokenTypes.MOD_ASSIGN, // "%=" 164 TokenTypes.SR_ASSIGN, // ">>=" 165 TokenTypes.BSR_ASSIGN, // ">>>=" 166 TokenTypes.SL_ASSIGN, // "<<=" 167 TokenTypes.BXOR_ASSIGN, // "^=" 168 TokenTypes.BOR_ASSIGN, // "|=" 169 TokenTypes.BAND_ASSIGN, // "&=" 170 171 }; 172 } 173 174 @Override 175 public void visitToken(DetailAST ast) 176 { 177 if (ast.getType() == TokenTypes.COLON) { 178 final DetailAST parent = ast.getParent(); 179 if ((parent.getType() == TokenTypes.LITERAL_DEFAULT) 180 || (parent.getType() == TokenTypes.LITERAL_CASE)) 181 { 182 //we do not want to check colon for cases and defaults 183 return; 184 } 185 } 186 final WrapOption wOp = getAbstractOption(); 187 188 final String text = ast.getText(); 189 final int colNo = ast.getColumnNo(); 190 final int lineNo = ast.getLineNo(); 191 final String currentLine = getLine(lineNo - 1); 192 193 // TODO: Handle comments before and after operator 194 // Check if rest of line is whitespace, and not just the operator 195 // by itself. This last bit is to handle the operator on a line by 196 // itself. 197 if ((wOp == WrapOption.NL) 198 && !text.equals(currentLine.trim()) 199 && (currentLine.substring(colNo + text.length()) 200 .trim().length() == 0)) 201 { 202 log(lineNo, colNo, "line.new", text); 203 } 204 else if ((wOp == WrapOption.EOL) 205 && Utils.whitespaceBefore(colNo - 1, currentLine)) 206 { 207 log(lineNo, colNo, "line.previous", text); 208 } 209 } 210 }