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