001//////////////////////////////////////////////////////////////////////////////// 002// checkstyle: Checks Java source code for adherence to a set of rules. 003// Copyright (C) 2001-2014 Oliver Burn 004// 005// This library is free software; you can redistribute it and/or 006// modify it under the terms of the GNU Lesser General Public 007// License as published by the Free Software Foundation; either 008// version 2.1 of the License, or (at your option) any later version. 009// 010// This library is distributed in the hope that it will be useful, 011// but WITHOUT ANY WARRANTY; without even the implied warranty of 012// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 013// Lesser General Public License for more details. 014// 015// You should have received a copy of the GNU Lesser General Public 016// License along with this library; if not, write to the Free Software 017// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 018//////////////////////////////////////////////////////////////////////////////// 019 020package com.puppycrawl.tools.checkstyle.checks.whitespace; 021 022import com.puppycrawl.tools.checkstyle.api.DetailAST; 023import com.puppycrawl.tools.checkstyle.api.TokenTypes; 024import com.puppycrawl.tools.checkstyle.api.Utils; 025import com.puppycrawl.tools.checkstyle.checks.AbstractOptionCheck; 026 027/** 028 * <p> 029 * Checks line wrapping for operators. 030 * The policy to verify is specified using the {@link WrapOption} class 031 * and defaults to {@link WrapOption#NL}. 032 * </p> 033 * <p> By default the check will check the following operators: 034 * {@link TokenTypes#BAND BAND}, 035 * {@link TokenTypes#BOR BOR}, 036 * {@link TokenTypes#BSR BSR}, 037 * {@link TokenTypes#BXOR BXOR}, 038 * {@link TokenTypes#COLON COLON}, 039 * {@link TokenTypes#DIV DIV}, 040 * {@link TokenTypes#EQUAL EQUAL}, 041 * {@link TokenTypes#GE GE}, 042 * {@link TokenTypes#GT GT}, 043 * {@link TokenTypes#LAND LAND}, 044 * {@link TokenTypes#LE LE}, 045 * {@link TokenTypes#LITERAL_INSTANCEOF LITERAL_INSTANCEOF}, 046 * {@link TokenTypes#LOR LOR}, 047 * {@link TokenTypes#LT LT}, 048 * {@link TokenTypes#MINUS MINUS}, 049 * {@link TokenTypes#MOD MOD}, 050 * {@link TokenTypes#NOT_EQUAL NOT_EQUAL}, 051 * {@link TokenTypes#PLUS PLUS}, 052 * {@link TokenTypes#QUESTION QUESTION}, 053 * {@link TokenTypes#SL SL}, 054 * {@link TokenTypes#SR SR}, 055 * {@link TokenTypes#STAR STAR}. 056 * Other acceptable tokens are 057 * {@link TokenTypes#ASSIGN ASSIGN}, 058 * {@link TokenTypes#BAND_ASSIGN BAND_ASSIGN}, 059 * {@link TokenTypes#BOR_ASSIGN BOR_ASSIGN}, 060 * {@link TokenTypes#BSR_ASSIGN BSR_ASSIGN}, 061 * {@link TokenTypes#BXOR_ASSIGN BXOR_ASSIGN}, 062 * {@link TokenTypes#DIV_ASSIGN DIV_ASSIGN}, 063 * {@link TokenTypes#MINUS_ASSIGN MINUS_ASSIGN}, 064 * {@link TokenTypes#MOD_ASSIGN MOD_ASSIGN}, 065 * {@link TokenTypes#PLUS_ASSIGN PLUS_ASSIGN}, 066 * {@link TokenTypes#SL_ASSIGN SL_ASSIGN}, 067 * {@link TokenTypes#SR_ASSIGN SR_ASSIGN}, 068 * {@link TokenTypes#STAR_ASSIGN STAR_ASSIGN}. 069 * </p> 070 * <p> 071 * An example of how to configure the check is: 072 * </p> 073 * <pre> 074 * <module name="OperatorWrap"/> 075 * </pre> 076 * <p> An example of how to configure the check for assignment operators at the 077 * end of a line is: 078 * </p> 079 * <pre> 080 * <module name="OperatorWrap"> 081 * <property name="tokens" 082 * value="ASSIGN,DIV_ASSIGN,PLUS_ASSIGN,MINUS_ASSIGN,STAR_ASSIGN,MOD_ASSIGN,SR_ASSIGN,BSR_ASSIGN,SL_ASSIGN,BXOR_ASSIGN,BOR_ASSIGN,BAND_ASSIGN"/> 083 * <property name="option" value="eol"/> 084 * </module> 085 * </pre> 086 * 087 * @author Rick Giles 088 * @version 1.0 089 */ 090public class OperatorWrapCheck 091 extends AbstractOptionCheck<WrapOption> 092{ 093 /** 094 * Sets the operator wrap option to new line. 095 */ 096 public OperatorWrapCheck() 097 { 098 super(WrapOption.NL, WrapOption.class); 099 } 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}