Coverage Report - com.puppycrawl.tools.checkstyle.checks.whitespace.OperatorWrapCheck
 
Classes in this File Line Coverage Branch Coverage Complexity
OperatorWrapCheck
100%
26/26
100%
16/16
3
 
 1  
 ////////////////////////////////////////////////////////////////////////////////
 2  
 // checkstyle: Checks Java source code for adherence to a set of rules.
 3  
 // Copyright (C) 2001-2017 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 java.util.Locale;
 23  
 
 24  
 import com.puppycrawl.tools.checkstyle.StatelessCheck;
 25  
 import com.puppycrawl.tools.checkstyle.api.AbstractCheck;
 26  
 import com.puppycrawl.tools.checkstyle.api.DetailAST;
 27  
 import com.puppycrawl.tools.checkstyle.api.TokenTypes;
 28  
 import com.puppycrawl.tools.checkstyle.utils.CommonUtils;
 29  
 
 30  
 /**
 31  
  * <p>
 32  
  * Checks line wrapping for operators.
 33  
  * The policy to verify is specified using the {@link WrapOption} class
 34  
  * and defaults to {@link WrapOption#NL}.
 35  
  * </p>
 36  
  * <p> By default the check will check the following operators:
 37  
  *  {@link TokenTypes#BAND BAND},
 38  
  *  {@link TokenTypes#BOR BOR},
 39  
  *  {@link TokenTypes#BSR BSR},
 40  
  *  {@link TokenTypes#BXOR BXOR},
 41  
  *  {@link TokenTypes#COLON COLON},
 42  
  *  {@link TokenTypes#DIV DIV},
 43  
  *  {@link TokenTypes#EQUAL EQUAL},
 44  
  *  {@link TokenTypes#GE GE},
 45  
  *  {@link TokenTypes#GT GT},
 46  
  *  {@link TokenTypes#LAND LAND},
 47  
  *  {@link TokenTypes#LE LE},
 48  
  *  {@link TokenTypes#LITERAL_INSTANCEOF LITERAL_INSTANCEOF},
 49  
  *  {@link TokenTypes#LOR LOR},
 50  
  *  {@link TokenTypes#LT LT},
 51  
  *  {@link TokenTypes#MINUS MINUS},
 52  
  *  {@link TokenTypes#MOD MOD},
 53  
  *  {@link TokenTypes#NOT_EQUAL NOT_EQUAL},
 54  
  *  {@link TokenTypes#PLUS PLUS},
 55  
  *  {@link TokenTypes#QUESTION QUESTION},
 56  
  *  {@link TokenTypes#SL SL},
 57  
  *  {@link TokenTypes#SR SR},
 58  
  *  {@link TokenTypes#STAR STAR}.
 59  
  * Other acceptable tokens are
 60  
  *  {@link TokenTypes#ASSIGN ASSIGN},
 61  
  *  {@link TokenTypes#BAND_ASSIGN BAND_ASSIGN},
 62  
  *  {@link TokenTypes#BOR_ASSIGN BOR_ASSIGN},
 63  
  *  {@link TokenTypes#BSR_ASSIGN BSR_ASSIGN},
 64  
  *  {@link TokenTypes#BXOR_ASSIGN BXOR_ASSIGN},
 65  
  *  {@link TokenTypes#DIV_ASSIGN DIV_ASSIGN},
 66  
  *  {@link TokenTypes#MINUS_ASSIGN MINUS_ASSIGN},
 67  
  *  {@link TokenTypes#MOD_ASSIGN MOD_ASSIGN},
 68  
  *  {@link TokenTypes#PLUS_ASSIGN PLUS_ASSIGN},
 69  
  *  {@link TokenTypes#SL_ASSIGN SL_ASSIGN},
 70  
  *  {@link TokenTypes#SR_ASSIGN SR_ASSIGN},
 71  
  *  {@link TokenTypes#STAR_ASSIGN STAR_ASSIGN}.
 72  
  *  {@link TokenTypes#METHOD_REF METHOD_REF}.
 73  
  * </p>
 74  
  *  <p>
 75  
  * An example of how to configure the check is:
 76  
  * </p>
 77  
  * <pre>
 78  
  * &lt;module name="OperatorWrap"/&gt;
 79  
  * </pre>
 80  
  * <p> An example of how to configure the check for assignment operators at the
 81  
  * end of a line is:
 82  
  * </p>
 83  
  * <pre>
 84  
  * &lt;module name="OperatorWrap"&gt;
 85  
  *     &lt;property name="tokens"
 86  
  *               value="ASSIGN,DIV_ASSIGN,PLUS_ASSIGN,MINUS_ASSIGN,STAR_ASSIGN,MOD_ASSIGN
 87  
  *               ,SR_ASSIGN,BSR_ASSIGN,SL_ASSIGN,BXOR_ASSIGN,BOR_ASSIGN,BAND_ASSIGN"/&gt;
 88  
  *     &lt;property name="option" value="eol"/&gt;
 89  
  * &lt;/module&gt;
 90  
  * </pre>
 91  
  *
 92  
  * @author Rick Giles
 93  
  */
 94  
 @StatelessCheck
 95  17
 public class OperatorWrapCheck
 96  
     extends AbstractCheck {
 97  
 
 98  
     /**
 99  
      * A key is pointing to the warning message text in "messages.properties"
 100  
      * file.
 101  
      */
 102  
     public static final String MSG_LINE_NEW = "line.new";
 103  
 
 104  
     /**
 105  
      * A key is pointing to the warning message text in "messages.properties"
 106  
      * file.
 107  
      */
 108  
     public static final String MSG_LINE_PREVIOUS = "line.previous";
 109  
 
 110  
     /** The policy to enforce. */
 111  17
     private WrapOption option = WrapOption.NL;
 112  
 
 113  
     /**
 114  
      * Set the option to enforce.
 115  
      * @param optionStr string to decode option from
 116  
      * @throws IllegalArgumentException if unable to decode
 117  
      */
 118  
     public void setOption(String optionStr) {
 119  
         try {
 120  6
             option = WrapOption.valueOf(optionStr.trim().toUpperCase(Locale.ENGLISH));
 121  
         }
 122  1
         catch (IllegalArgumentException iae) {
 123  1
             throw new IllegalArgumentException("unable to parse " + optionStr, iae);
 124  5
         }
 125  5
     }
 126  
 
 127  
     @Override
 128  
     public int[] getDefaultTokens() {
 129  8
         return new int[] {
 130  
             TokenTypes.QUESTION,          // '?'
 131  
             TokenTypes.COLON,             // ':' (not reported for a case)
 132  
             TokenTypes.EQUAL,             // "=="
 133  
             TokenTypes.NOT_EQUAL,         // "!="
 134  
             TokenTypes.DIV,               // '/'
 135  
             TokenTypes.PLUS,              //' +' (unary plus is UNARY_PLUS)
 136  
             TokenTypes.MINUS,             // '-' (unary minus is UNARY_MINUS)
 137  
             TokenTypes.STAR,              // '*'
 138  
             TokenTypes.MOD,               // '%'
 139  
             TokenTypes.SR,                // ">>"
 140  
             TokenTypes.BSR,               // ">>>"
 141  
             TokenTypes.GE,                // ">="
 142  
             TokenTypes.GT,                // ">"
 143  
             TokenTypes.SL,                // "<<"
 144  
             TokenTypes.LE,                // "<="
 145  
             TokenTypes.LT,                // '<'
 146  
             TokenTypes.BXOR,              // '^'
 147  
             TokenTypes.BOR,               // '|'
 148  
             TokenTypes.LOR,               // "||"
 149  
             TokenTypes.BAND,              // '&'
 150  
             TokenTypes.LAND,              // "&&"
 151  
             TokenTypes.TYPE_EXTENSION_AND,
 152  
             TokenTypes.LITERAL_INSTANCEOF,
 153  
         };
 154  
     }
 155  
 
 156  
     @Override
 157  
     public int[] getAcceptableTokens() {
 158  11
         return new int[] {
 159  
             TokenTypes.QUESTION,          // '?'
 160  
             TokenTypes.COLON,             // ':' (not reported for a case)
 161  
             TokenTypes.EQUAL,             // "=="
 162  
             TokenTypes.NOT_EQUAL,         // "!="
 163  
             TokenTypes.DIV,               // '/'
 164  
             TokenTypes.PLUS,              //' +' (unary plus is UNARY_PLUS)
 165  
             TokenTypes.MINUS,             // '-' (unary minus is UNARY_MINUS)
 166  
             TokenTypes.STAR,              // '*'
 167  
             TokenTypes.MOD,               // '%'
 168  
             TokenTypes.SR,                // ">>"
 169  
             TokenTypes.BSR,               // ">>>"
 170  
             TokenTypes.GE,                // ">="
 171  
             TokenTypes.GT,                // ">"
 172  
             TokenTypes.SL,                // "<<"
 173  
             TokenTypes.LE,                // "<="
 174  
             TokenTypes.LT,                // '<'
 175  
             TokenTypes.BXOR,              // '^'
 176  
             TokenTypes.BOR,               // '|'
 177  
             TokenTypes.LOR,               // "||"
 178  
             TokenTypes.BAND,              // '&'
 179  
             TokenTypes.LAND,              // "&&"
 180  
             TokenTypes.LITERAL_INSTANCEOF,
 181  
             TokenTypes.TYPE_EXTENSION_AND,
 182  
             TokenTypes.ASSIGN,            // '='
 183  
             TokenTypes.DIV_ASSIGN,        // "/="
 184  
             TokenTypes.PLUS_ASSIGN,       // "+="
 185  
             TokenTypes.MINUS_ASSIGN,      //"-="
 186  
             TokenTypes.STAR_ASSIGN,       // "*="
 187  
             TokenTypes.MOD_ASSIGN,        // "%="
 188  
             TokenTypes.SR_ASSIGN,         // ">>="
 189  
             TokenTypes.BSR_ASSIGN,        // ">>>="
 190  
             TokenTypes.SL_ASSIGN,         // "<<="
 191  
             TokenTypes.BXOR_ASSIGN,       // "^="
 192  
             TokenTypes.BOR_ASSIGN,        // "|="
 193  
             TokenTypes.BAND_ASSIGN,       // "&="
 194  
             TokenTypes.METHOD_REF,        // "::"
 195  
 
 196  
         };
 197  
     }
 198  
 
 199  
     @Override
 200  
     public int[] getRequiredTokens() {
 201  21
         return CommonUtils.EMPTY_INT_ARRAY;
 202  
     }
 203  
 
 204  
     @Override
 205  
     public void visitToken(DetailAST ast) {
 206  42
         final DetailAST parent = ast.getParent();
 207  
         //we do not want to check colon for cases and defaults
 208  42
         if (ast.getType() != TokenTypes.COLON
 209  8
                 || parent.getType() != TokenTypes.LITERAL_DEFAULT
 210  6
                     && parent.getType() != TokenTypes.LITERAL_CASE) {
 211  36
             final String text = ast.getText();
 212  36
             final int colNo = ast.getColumnNo();
 213  36
             final int lineNo = ast.getLineNo();
 214  36
             final String currentLine = getLine(lineNo - 1);
 215  
 
 216  
             // Check if rest of line is whitespace, and not just the operator
 217  
             // by itself. This last bit is to handle the operator on a line by
 218  
             // itself.
 219  36
             if (option == WrapOption.NL
 220  14
                     && !text.equals(currentLine.trim())
 221  11
                     && CommonUtils.isBlank(currentLine.substring(colNo + text.length()))) {
 222  6
                 log(lineNo, colNo, MSG_LINE_NEW, text);
 223  
             }
 224  30
             else if (option == WrapOption.EOL
 225  22
                     && CommonUtils.hasWhitespaceBefore(colNo - 1, currentLine)) {
 226  6
                 log(lineNo, colNo, MSG_LINE_PREVIOUS, text);
 227  
             }
 228  
         }
 229  42
     }
 230  
 }