Coverage Report - com.puppycrawl.tools.checkstyle.checks.whitespace.NoWhitespaceBeforeCheck
 
Classes in this File Line Coverage Branch Coverage Complexity
NoWhitespaceBeforeCheck
100%
27/27
100%
26/26
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 com.puppycrawl.tools.checkstyle.StatelessCheck;
 23  
 import com.puppycrawl.tools.checkstyle.api.AbstractCheck;
 24  
 import com.puppycrawl.tools.checkstyle.api.DetailAST;
 25  
 import com.puppycrawl.tools.checkstyle.api.TokenTypes;
 26  
 import com.puppycrawl.tools.checkstyle.utils.CommonUtils;
 27  
 
 28  
 /**
 29  
  * <p>
 30  
  * Checks that there is no whitespace before a token.
 31  
  * More specifically, it checks that it is not preceded with whitespace,
 32  
  * or (if line breaks are allowed) all characters on the line before are
 33  
  * whitespace. To allow line breaks before a token, set property
 34  
  * allowLineBreaks to true. No check occurs before semi-colons in empty
 35  
  * for loop initializers or conditions.
 36  
  * </p>
 37  
  * <p> By default the check will check the following operators:
 38  
  *  {@link TokenTypes#COMMA COMMA},
 39  
  *  {@link TokenTypes#SEMI SEMI},
 40  
  *  {@link TokenTypes#POST_DEC POST_DEC},
 41  
  *  {@link TokenTypes#POST_INC POST_INC},
 42  
  *  {@link TokenTypes#ELLIPSIS ELLIPSIS}.
 43  
  * {@link TokenTypes#DOT DOT} is also an acceptable token in a configuration
 44  
  * of this check.
 45  
  * </p>
 46  
  *
 47  
  * <p>
 48  
  * An example of how to configure the check is:
 49  
  * </p>
 50  
  * <pre>
 51  
  * &lt;module name="NoWhitespaceBefore"/&gt;
 52  
  * </pre>
 53  
  * <p> An example of how to configure the check to allow line breaks before
 54  
  * a {@link TokenTypes#DOT DOT} token is:
 55  
  * </p>
 56  
  * <pre>
 57  
  * &lt;module name="NoWhitespaceBefore"&gt;
 58  
  *     &lt;property name="tokens" value="DOT"/&gt;
 59  
  *     &lt;property name="allowLineBreaks" value="true"/&gt;
 60  
  * &lt;/module&gt;
 61  
  * </pre>
 62  
  * @author Rick Giles
 63  
  * @author lkuehne
 64  
  */
 65  
 @StatelessCheck
 66  18
 public class NoWhitespaceBeforeCheck
 67  
     extends AbstractCheck {
 68  
 
 69  
     /**
 70  
      * A key is pointing to the warning message text in "messages.properties"
 71  
      * file.
 72  
      */
 73  
     public static final String MSG_KEY = "ws.preceded";
 74  
 
 75  
     /** Whether whitespace is allowed if the AST is at a linebreak. */
 76  
     private boolean allowLineBreaks;
 77  
 
 78  
     @Override
 79  
     public int[] getDefaultTokens() {
 80  8
         return new int[] {
 81  
             TokenTypes.COMMA,
 82  
             TokenTypes.SEMI,
 83  
             TokenTypes.POST_INC,
 84  
             TokenTypes.POST_DEC,
 85  
             TokenTypes.ELLIPSIS,
 86  
         };
 87  
     }
 88  
 
 89  
     @Override
 90  
     public int[] getAcceptableTokens() {
 91  14
         return new int[] {
 92  
             TokenTypes.COMMA,
 93  
             TokenTypes.SEMI,
 94  
             TokenTypes.POST_INC,
 95  
             TokenTypes.POST_DEC,
 96  
             TokenTypes.DOT,
 97  
             TokenTypes.GENERIC_START,
 98  
             TokenTypes.GENERIC_END,
 99  
             TokenTypes.ELLIPSIS,
 100  
             TokenTypes.METHOD_REF,
 101  
         };
 102  
     }
 103  
 
 104  
     @Override
 105  
     public int[] getRequiredTokens() {
 106  26
         return CommonUtils.EMPTY_INT_ARRAY;
 107  
     }
 108  
 
 109  
     @Override
 110  
     public void visitToken(DetailAST ast) {
 111  156
         final String line = getLine(ast.getLineNo() - 1);
 112  156
         final int before = ast.getColumnNo() - 1;
 113  
 
 114  156
         if ((before == -1 || Character.isWhitespace(line.charAt(before)))
 115  34
                 && !isInEmptyForInitializerOrCondition(ast)) {
 116  
 
 117  30
             boolean flag = !allowLineBreaks;
 118  
             // verify all characters before '.' are whitespace
 119  72
             for (int i = 0; !flag && i <= before - 1; i++) {
 120  48
                 if (!Character.isWhitespace(line.charAt(i))) {
 121  6
                     flag = true;
 122  6
                     break;
 123  
                 }
 124  
             }
 125  30
             if (flag) {
 126  27
                 log(ast.getLineNo(), before, MSG_KEY, ast.getText());
 127  
             }
 128  
         }
 129  156
     }
 130  
 
 131  
     /**
 132  
      * Checks that semicolon is in empty for initializer or condition.
 133  
      * @param semicolonAst DetailAST of semicolon.
 134  
      * @return true if semicolon is in empty for initializer or condition.
 135  
      */
 136  
     private static boolean isInEmptyForInitializerOrCondition(DetailAST semicolonAst) {
 137  34
         boolean result = false;
 138  34
         if (semicolonAst.getType() == TokenTypes.SEMI) {
 139  15
             final DetailAST sibling = semicolonAst.getPreviousSibling();
 140  15
             if (sibling != null
 141  14
                     && (sibling.getType() == TokenTypes.FOR_INIT
 142  11
                             || sibling.getType() == TokenTypes.FOR_CONDITION)
 143  7
                     && sibling.getChildCount() == 0) {
 144  4
                 result = true;
 145  
             }
 146  
         }
 147  34
         return result;
 148  
     }
 149  
 
 150  
     /**
 151  
      * Control whether whitespace is flagged at line breaks.
 152  
      * @param allowLineBreaks whether whitespace should be
 153  
      *     flagged at line breaks.
 154  
      */
 155  
     public void setAllowLineBreaks(boolean allowLineBreaks) {
 156  5
         this.allowLineBreaks = allowLineBreaks;
 157  5
     }
 158  
 }