1 //////////////////////////////////////////////////////////////////////////////// 2 // checkstyle: Checks Java source code for adherence to a set of rules. 3 // Copyright (C) 2001-2015 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.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 */ 89 public class OperatorWrapCheck 90 extends AbstractOptionCheck<WrapOption> 91 { 92 93 /** 94 * A key is pointing to the warning message text in "messages.properties" 95 * file. 96 */ 97 public static final String LINE_NEW = "line.new"; 98 99 /** 100 * A key is pointing to the warning message text in "messages.properties" 101 * file. 102 */ 103 public static final String LINE_PREVIOUS = "line.previous"; 104 105 /** 106 * Sets the operator wrap option to new line. 107 */ 108 public OperatorWrapCheck() 109 { 110 super(WrapOption.NL, WrapOption.class); 111 } 112 113 @Override 114 public int[] getDefaultTokens() 115 { 116 return new int[] { 117 TokenTypes.QUESTION, // '?' 118 TokenTypes.COLON, // ':' (not reported for a case) 119 TokenTypes.EQUAL, // "==" 120 TokenTypes.NOT_EQUAL, // "!=" 121 TokenTypes.DIV, // '/' 122 TokenTypes.PLUS, //' +' (unary plus is UNARY_PLUS) 123 TokenTypes.MINUS, // '-' (unary minus is UNARY_MINUS) 124 TokenTypes.STAR, // '*' 125 TokenTypes.MOD, // '%' 126 TokenTypes.SR, // ">>" 127 TokenTypes.BSR, // ">>>" 128 TokenTypes.GE, // ">=" 129 TokenTypes.GT, // ">" 130 TokenTypes.SL, // "<<" 131 TokenTypes.LE, // "<=" 132 TokenTypes.LT, // '<' 133 TokenTypes.BXOR, // '^' 134 TokenTypes.BOR, // '|' 135 TokenTypes.LOR, // "||" 136 TokenTypes.BAND, // '&' 137 TokenTypes.LAND, // "&&" 138 TokenTypes.TYPE_EXTENSION_AND, 139 TokenTypes.LITERAL_INSTANCEOF, 140 }; 141 } 142 143 @Override 144 public int[] getAcceptableTokens() 145 { 146 return new int[] { 147 TokenTypes.QUESTION, // '?' 148 TokenTypes.COLON, // ':' (not reported for a case) 149 TokenTypes.EQUAL, // "==" 150 TokenTypes.NOT_EQUAL, // "!=" 151 TokenTypes.DIV, // '/' 152 TokenTypes.PLUS, //' +' (unary plus is UNARY_PLUS) 153 TokenTypes.MINUS, // '-' (unary minus is UNARY_MINUS) 154 TokenTypes.STAR, // '*' 155 TokenTypes.MOD, // '%' 156 TokenTypes.SR, // ">>" 157 TokenTypes.BSR, // ">>>" 158 TokenTypes.GE, // ">=" 159 TokenTypes.GT, // ">" 160 TokenTypes.SL, // "<<" 161 TokenTypes.LE, // "<=" 162 TokenTypes.LT, // '<' 163 TokenTypes.BXOR, // '^' 164 TokenTypes.BOR, // '|' 165 TokenTypes.LOR, // "||" 166 TokenTypes.BAND, // '&' 167 TokenTypes.LAND, // "&&" 168 TokenTypes.LITERAL_INSTANCEOF, 169 TokenTypes.TYPE_EXTENSION_AND, 170 TokenTypes.ASSIGN, // '=' 171 TokenTypes.DIV_ASSIGN, // "/=" 172 TokenTypes.PLUS_ASSIGN, // "+=" 173 TokenTypes.MINUS_ASSIGN, //"-=" 174 TokenTypes.STAR_ASSIGN, // "*=" 175 TokenTypes.MOD_ASSIGN, // "%=" 176 TokenTypes.SR_ASSIGN, // ">>=" 177 TokenTypes.BSR_ASSIGN, // ">>>=" 178 TokenTypes.SL_ASSIGN, // "<<=" 179 TokenTypes.BXOR_ASSIGN, // "^=" 180 TokenTypes.BOR_ASSIGN, // "|=" 181 TokenTypes.BAND_ASSIGN, // "&=" 182 183 }; 184 } 185 186 @Override 187 public void visitToken(DetailAST ast) 188 { 189 if (ast.getType() == TokenTypes.COLON) { 190 final DetailAST parent = ast.getParent(); 191 if (parent.getType() == TokenTypes.LITERAL_DEFAULT 192 || parent.getType() == TokenTypes.LITERAL_CASE) 193 { 194 //we do not want to check colon for cases and defaults 195 return; 196 } 197 } 198 final WrapOption wOp = getAbstractOption(); 199 200 final String text = ast.getText(); 201 final int colNo = ast.getColumnNo(); 202 final int lineNo = ast.getLineNo(); 203 final String currentLine = getLine(lineNo - 1); 204 205 // TODO: Handle comments before and after operator 206 // Check if rest of line is whitespace, and not just the operator 207 // by itself. This last bit is to handle the operator on a line by 208 // itself. 209 if (wOp == WrapOption.NL 210 && !text.equals(currentLine.trim()) 211 && currentLine.substring(colNo + text.length()) 212 .trim().length() == 0) 213 { 214 log(lineNo, colNo, LINE_NEW, text); 215 } 216 else if (wOp == WrapOption.EOL 217 && Utils.whitespaceBefore(colNo - 1, currentLine)) 218 { 219 log(lineNo, colNo, LINE_PREVIOUS, text); 220 } 221 } 222 }