View Javadoc
1   ///////////////////////////////////////////////////////////////////////////////////////////////
2   // checkstyle: Checks Java source code and other text files for adherence to a set of rules.
3   // Copyright (C) 2001-2024 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.coding;
21  
22  import java.util.regex.Pattern;
23  
24  import com.puppycrawl.tools.checkstyle.FileStatefulCheck;
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.CommonUtil;
29  import com.puppycrawl.tools.checkstyle.utils.TokenUtil;
30  
31  /**
32   * <p>
33   * Checks if unnecessary parentheses are used in a statement or expression.
34   * The check will flag the following with warnings:
35   * </p>
36   * <pre>
37   * return (x);          // parens around identifier
38   * return (x + 1);      // parens around return value
39   * int x = (y / 2 + 1); // parens around assignment rhs
40   * for (int i = (0); i &lt; 10; i++) {  // parens around literal
41   * t -= (z + 1);                     // parens around assignment rhs
42   * boolean a = (x &gt; 7 &amp;&amp; y &gt; 5)      // parens around expression
43   *             || z &lt; 9;
44   * boolean b = (~a) &gt; -27            // parens around ~a
45   *             &amp;&amp; (a-- &lt; 30);        // parens around expression
46   * </pre>
47   * <p>
48   * The check is not "type aware", that is to say, it can't tell if parentheses
49   * are unnecessary based on the types in an expression. The check is partially aware about
50   * operator precedence but unaware about operator associativity.
51   * It won't catch cases such as:
52   * </p>
53   * <pre>
54   * int x = (a + b) + c; // 1st Case
55   * boolean p = true; // 2nd Case
56   * int q = 4;
57   * int r = 3;
58   * if (p == (q &lt;= r)) {}</pre>
59   * <p>
60   * In the first case, given that <em>a</em>, <em>b</em>, and <em>c</em> are
61   * all {@code int} variables, the parentheses around {@code a + b}
62   * are not needed.
63   * In the second case, parentheses are required as <em>q</em>, <em>r</em> are
64   * of type {@code int} and <em>p</em> is of type {@code boolean}
65   * and removing parentheses will give a compile-time error. Even if <em>q</em>
66   * and <em>r</em> were {@code boolean} still there will be no violation
67   * raised as check is not "type aware".
68   * </p>
69   * <p>
70   * The partial support for operator precedence includes cases of the following type:
71   * </p>
72   * <pre>
73   * boolean a = true, b = true;
74   * boolean c = false, d = false;
75   * if ((a &amp;&amp; b) || c) { // violation, unnecessary paren
76   * }
77   * if (a &amp;&amp; (b || c)) { // ok
78   * }
79   * if ((a == b) &amp;&amp; c) { // violation, unnecessary paren
80   * }
81   * String e = &quot;e&quot;;
82   * if ((e instanceof String) &amp;&amp; a || b) { // violation, unnecessary paren
83   * }
84   * int f = 0;
85   * int g = 0;
86   * if (!(f &gt;= g) // ok
87   *         &amp;&amp; (g &gt; f)) { // violation, unnecessary paren
88   * }
89   * if ((++f) &gt; g &amp;&amp; a) { // violation, unnecessary paren
90   * }
91   * </pre>
92   * <ul>
93   * <li>
94   * Property {@code tokens} - tokens to check
95   * Type is {@code java.lang.String[]}.
96   * Validation type is {@code tokenSet}.
97   * Default value is:
98   * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#EXPR">
99   * EXPR</a>,
100  * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#IDENT">
101  * IDENT</a>,
102  * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#NUM_DOUBLE">
103  * NUM_DOUBLE</a>,
104  * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#NUM_FLOAT">
105  * NUM_FLOAT</a>,
106  * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#NUM_INT">
107  * NUM_INT</a>,
108  * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#NUM_LONG">
109  * NUM_LONG</a>,
110  * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#STRING_LITERAL">
111  * STRING_LITERAL</a>,
112  * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#LITERAL_NULL">
113  * LITERAL_NULL</a>,
114  * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#LITERAL_FALSE">
115  * LITERAL_FALSE</a>,
116  * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#LITERAL_TRUE">
117  * LITERAL_TRUE</a>,
118  * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#ASSIGN">
119  * ASSIGN</a>,
120  * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#BAND_ASSIGN">
121  * BAND_ASSIGN</a>,
122  * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#BOR_ASSIGN">
123  * BOR_ASSIGN</a>,
124  * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#BSR_ASSIGN">
125  * BSR_ASSIGN</a>,
126  * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#BXOR_ASSIGN">
127  * BXOR_ASSIGN</a>,
128  * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#DIV_ASSIGN">
129  * DIV_ASSIGN</a>,
130  * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#MINUS_ASSIGN">
131  * MINUS_ASSIGN</a>,
132  * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#MOD_ASSIGN">
133  * MOD_ASSIGN</a>,
134  * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#PLUS_ASSIGN">
135  * PLUS_ASSIGN</a>,
136  * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#SL_ASSIGN">
137  * SL_ASSIGN</a>,
138  * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#SR_ASSIGN">
139  * SR_ASSIGN</a>,
140  * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#STAR_ASSIGN">
141  * STAR_ASSIGN</a>,
142  * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#LAMBDA">
143  * LAMBDA</a>,
144  * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#TEXT_BLOCK_LITERAL_BEGIN">
145  * TEXT_BLOCK_LITERAL_BEGIN</a>,
146  * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#LAND">
147  * LAND</a>,
148  * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#LOR">
149  * LOR</a>,
150  * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#LITERAL_INSTANCEOF">
151  * LITERAL_INSTANCEOF</a>,
152  * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#GT">
153  * GT</a>,
154  * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#LT">
155  * LT</a>,
156  * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#GE">
157  * GE</a>,
158  * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#LE">
159  * LE</a>,
160  * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#EQUAL">
161  * EQUAL</a>,
162  * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#NOT_EQUAL">
163  * NOT_EQUAL</a>,
164  * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#UNARY_MINUS">
165  * UNARY_MINUS</a>,
166  * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#UNARY_PLUS">
167  * UNARY_PLUS</a>,
168  * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#INC">
169  * INC</a>,
170  * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#DEC">
171  * DEC</a>,
172  * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#LNOT">
173  * LNOT</a>,
174  * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#BNOT">
175  * BNOT</a>,
176  * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#POST_INC">
177  * POST_INC</a>,
178  * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#POST_DEC">
179  * POST_DEC</a>.
180  * </li>
181  * </ul>
182  * <p>
183  * Parent is {@code com.puppycrawl.tools.checkstyle.TreeWalker}
184  * </p>
185  * <p>
186  * Violation Message Keys:
187  * </p>
188  * <ul>
189  * <li>
190  * {@code unnecessary.paren.assign}
191  * </li>
192  * <li>
193  * {@code unnecessary.paren.expr}
194  * </li>
195  * <li>
196  * {@code unnecessary.paren.ident}
197  * </li>
198  * <li>
199  * {@code unnecessary.paren.lambda}
200  * </li>
201  * <li>
202  * {@code unnecessary.paren.literal}
203  * </li>
204  * <li>
205  * {@code unnecessary.paren.return}
206  * </li>
207  * <li>
208  * {@code unnecessary.paren.string}
209  * </li>
210  * </ul>
211  *
212  * @since 3.4
213  */
214 @FileStatefulCheck
215 public class UnnecessaryParenthesesCheck extends AbstractCheck {
216 
217     /**
218      * A key is pointing to the warning message text in "messages.properties"
219      * file.
220      */
221     public static final String MSG_IDENT = "unnecessary.paren.ident";
222 
223     /**
224      * A key is pointing to the warning message text in "messages.properties"
225      * file.
226      */
227     public static final String MSG_ASSIGN = "unnecessary.paren.assign";
228 
229     /**
230      * A key is pointing to the warning message text in "messages.properties"
231      * file.
232      */
233     public static final String MSG_EXPR = "unnecessary.paren.expr";
234 
235     /**
236      * A key is pointing to the warning message text in "messages.properties"
237      * file.
238      */
239     public static final String MSG_LITERAL = "unnecessary.paren.literal";
240 
241     /**
242      * A key is pointing to the warning message text in "messages.properties"
243      * file.
244      */
245     public static final String MSG_STRING = "unnecessary.paren.string";
246 
247     /**
248      * A key is pointing to the warning message text in "messages.properties"
249      * file.
250      */
251     public static final String MSG_RETURN = "unnecessary.paren.return";
252 
253     /**
254      * A key is pointing to the warning message text in "messages.properties"
255      * file.
256      */
257     public static final String MSG_LAMBDA = "unnecessary.paren.lambda";
258 
259     /**
260      * Compiled pattern used to match newline control characters, for replacement.
261      */
262     private static final Pattern NEWLINE = Pattern.compile("\\R");
263 
264     /**
265      * String used to amend TEXT_BLOCK_CONTENT so that it matches STRING_LITERAL.
266      */
267     private static final String QUOTE = "\"";
268 
269     /** The maximum string length before we chop the string. */
270     private static final int MAX_QUOTED_LENGTH = 25;
271 
272     /** Token types for literals. */
273     private static final int[] LITERALS = {
274         TokenTypes.NUM_DOUBLE,
275         TokenTypes.NUM_FLOAT,
276         TokenTypes.NUM_INT,
277         TokenTypes.NUM_LONG,
278         TokenTypes.STRING_LITERAL,
279         TokenTypes.LITERAL_NULL,
280         TokenTypes.LITERAL_FALSE,
281         TokenTypes.LITERAL_TRUE,
282         TokenTypes.TEXT_BLOCK_LITERAL_BEGIN,
283     };
284 
285     /** Token types for assignment operations. */
286     private static final int[] ASSIGNMENTS = {
287         TokenTypes.ASSIGN,
288         TokenTypes.BAND_ASSIGN,
289         TokenTypes.BOR_ASSIGN,
290         TokenTypes.BSR_ASSIGN,
291         TokenTypes.BXOR_ASSIGN,
292         TokenTypes.DIV_ASSIGN,
293         TokenTypes.MINUS_ASSIGN,
294         TokenTypes.MOD_ASSIGN,
295         TokenTypes.PLUS_ASSIGN,
296         TokenTypes.SL_ASSIGN,
297         TokenTypes.SR_ASSIGN,
298         TokenTypes.STAR_ASSIGN,
299     };
300 
301     /** Token types for conditional operators. */
302     private static final int[] CONDITIONAL_OPERATOR = {
303         TokenTypes.LOR,
304         TokenTypes.LAND,
305     };
306 
307     /** Token types for relation operator. */
308     private static final int[] RELATIONAL_OPERATOR = {
309         TokenTypes.LITERAL_INSTANCEOF,
310         TokenTypes.GT,
311         TokenTypes.LT,
312         TokenTypes.GE,
313         TokenTypes.LE,
314         TokenTypes.EQUAL,
315         TokenTypes.NOT_EQUAL,
316     };
317 
318     /** Token types for unary and postfix operators. */
319     private static final int[] UNARY_AND_POSTFIX = {
320         TokenTypes.UNARY_MINUS,
321         TokenTypes.UNARY_PLUS,
322         TokenTypes.INC,
323         TokenTypes.DEC,
324         TokenTypes.LNOT,
325         TokenTypes.BNOT,
326         TokenTypes.POST_INC,
327         TokenTypes.POST_DEC,
328     };
329 
330     /** Token types for bitwise binary operator. */
331     private static final int[] BITWISE_BINARY_OPERATORS = {
332         TokenTypes.BXOR,
333         TokenTypes.BOR,
334         TokenTypes.BAND,
335     };
336 
337     /**
338      * Used to test if logging a warning in a parent node may be skipped
339      * because a warning was already logged on an immediate child node.
340      */
341     private DetailAST parentToSkip;
342     /** Depth of nested assignments.  Normally this will be 0 or 1. */
343     private int assignDepth;
344 
345     @Override
346     public int[] getDefaultTokens() {
347         return new int[] {
348             TokenTypes.EXPR,
349             TokenTypes.IDENT,
350             TokenTypes.NUM_DOUBLE,
351             TokenTypes.NUM_FLOAT,
352             TokenTypes.NUM_INT,
353             TokenTypes.NUM_LONG,
354             TokenTypes.STRING_LITERAL,
355             TokenTypes.LITERAL_NULL,
356             TokenTypes.LITERAL_FALSE,
357             TokenTypes.LITERAL_TRUE,
358             TokenTypes.ASSIGN,
359             TokenTypes.BAND_ASSIGN,
360             TokenTypes.BOR_ASSIGN,
361             TokenTypes.BSR_ASSIGN,
362             TokenTypes.BXOR_ASSIGN,
363             TokenTypes.DIV_ASSIGN,
364             TokenTypes.MINUS_ASSIGN,
365             TokenTypes.MOD_ASSIGN,
366             TokenTypes.PLUS_ASSIGN,
367             TokenTypes.SL_ASSIGN,
368             TokenTypes.SR_ASSIGN,
369             TokenTypes.STAR_ASSIGN,
370             TokenTypes.LAMBDA,
371             TokenTypes.TEXT_BLOCK_LITERAL_BEGIN,
372             TokenTypes.LAND,
373             TokenTypes.LOR,
374             TokenTypes.LITERAL_INSTANCEOF,
375             TokenTypes.GT,
376             TokenTypes.LT,
377             TokenTypes.GE,
378             TokenTypes.LE,
379             TokenTypes.EQUAL,
380             TokenTypes.NOT_EQUAL,
381             TokenTypes.UNARY_MINUS,
382             TokenTypes.UNARY_PLUS,
383             TokenTypes.INC,
384             TokenTypes.DEC,
385             TokenTypes.LNOT,
386             TokenTypes.BNOT,
387             TokenTypes.POST_INC,
388             TokenTypes.POST_DEC,
389         };
390     }
391 
392     @Override
393     public int[] getAcceptableTokens() {
394         return new int[] {
395             TokenTypes.EXPR,
396             TokenTypes.IDENT,
397             TokenTypes.NUM_DOUBLE,
398             TokenTypes.NUM_FLOAT,
399             TokenTypes.NUM_INT,
400             TokenTypes.NUM_LONG,
401             TokenTypes.STRING_LITERAL,
402             TokenTypes.LITERAL_NULL,
403             TokenTypes.LITERAL_FALSE,
404             TokenTypes.LITERAL_TRUE,
405             TokenTypes.ASSIGN,
406             TokenTypes.BAND_ASSIGN,
407             TokenTypes.BOR_ASSIGN,
408             TokenTypes.BSR_ASSIGN,
409             TokenTypes.BXOR_ASSIGN,
410             TokenTypes.DIV_ASSIGN,
411             TokenTypes.MINUS_ASSIGN,
412             TokenTypes.MOD_ASSIGN,
413             TokenTypes.PLUS_ASSIGN,
414             TokenTypes.SL_ASSIGN,
415             TokenTypes.SR_ASSIGN,
416             TokenTypes.STAR_ASSIGN,
417             TokenTypes.LAMBDA,
418             TokenTypes.TEXT_BLOCK_LITERAL_BEGIN,
419             TokenTypes.LAND,
420             TokenTypes.LOR,
421             TokenTypes.LITERAL_INSTANCEOF,
422             TokenTypes.GT,
423             TokenTypes.LT,
424             TokenTypes.GE,
425             TokenTypes.LE,
426             TokenTypes.EQUAL,
427             TokenTypes.NOT_EQUAL,
428             TokenTypes.UNARY_MINUS,
429             TokenTypes.UNARY_PLUS,
430             TokenTypes.INC,
431             TokenTypes.DEC,
432             TokenTypes.LNOT,
433             TokenTypes.BNOT,
434             TokenTypes.POST_INC,
435             TokenTypes.POST_DEC,
436             TokenTypes.BXOR,
437             TokenTypes.BOR,
438             TokenTypes.BAND,
439         };
440     }
441 
442     @Override
443     public int[] getRequiredTokens() {
444         // Check can work with any of acceptable tokens
445         return CommonUtil.EMPTY_INT_ARRAY;
446     }
447 
448     // -@cs[CyclomaticComplexity] All logs should be in visit token.
449     @Override
450     public void visitToken(DetailAST ast) {
451         final DetailAST parent = ast.getParent();
452 
453         if (isLambdaSingleParameterSurrounded(ast)) {
454             log(ast, MSG_LAMBDA);
455         }
456         else if (parent.getType() != TokenTypes.ANNOTATION_MEMBER_VALUE_PAIR) {
457             final int type = ast.getType();
458             final boolean surrounded = isSurrounded(ast);
459             // An identifier surrounded by parentheses.
460             if (surrounded && type == TokenTypes.IDENT) {
461                 parentToSkip = ast.getParent();
462                 log(ast, MSG_IDENT, ast.getText());
463             }
464             // A literal (numeric or string) surrounded by parentheses.
465             else if (surrounded && TokenUtil.isOfType(type, LITERALS)) {
466                 parentToSkip = ast.getParent();
467                 if (type == TokenTypes.STRING_LITERAL) {
468                     log(ast, MSG_STRING,
469                         chopString(ast.getText()));
470                 }
471                 else if (type == TokenTypes.TEXT_BLOCK_LITERAL_BEGIN) {
472                     // Strip newline control characters to keep message as single-line, add
473                     // quotes to make string consistent with STRING_LITERAL
474                     final String logString = QUOTE
475                         + NEWLINE.matcher(
476                             ast.getFirstChild().getText()).replaceAll("\\\\n")
477                         + QUOTE;
478                     log(ast, MSG_STRING, chopString(logString));
479                 }
480                 else {
481                     log(ast, MSG_LITERAL, ast.getText());
482                 }
483             }
484             // The rhs of an assignment surrounded by parentheses.
485             else if (TokenUtil.isOfType(type, ASSIGNMENTS)) {
486                 assignDepth++;
487                 final DetailAST last = ast.getLastChild();
488                 if (last.getType() == TokenTypes.RPAREN) {
489                     log(ast, MSG_ASSIGN);
490                 }
491             }
492         }
493     }
494 
495     @Override
496     public void leaveToken(DetailAST ast) {
497         final int type = ast.getType();
498         final DetailAST parent = ast.getParent();
499 
500         // shouldn't process assign in annotation pairs
501         if (type != TokenTypes.ASSIGN
502             || parent.getType() != TokenTypes.ANNOTATION_MEMBER_VALUE_PAIR) {
503             if (type == TokenTypes.EXPR) {
504                 checkExpression(ast);
505             }
506             else if (TokenUtil.isOfType(type, ASSIGNMENTS)) {
507                 assignDepth--;
508             }
509             else if (isSurrounded(ast) && unnecessaryParenAroundOperators(ast)) {
510                 log(ast.getPreviousSibling(), MSG_EXPR);
511             }
512         }
513     }
514 
515     /**
516      * Tests if the given {@code DetailAST} is surrounded by parentheses.
517      *
518      * @param ast the {@code DetailAST} to check if it is surrounded by
519      *        parentheses.
520      * @return {@code true} if {@code ast} is surrounded by
521      *         parentheses.
522      */
523     private static boolean isSurrounded(DetailAST ast) {
524         final DetailAST prev = ast.getPreviousSibling();
525         final DetailAST parent = ast.getParent();
526         final boolean isPreviousSiblingLeftParenthesis = prev != null
527                 && prev.getType() == TokenTypes.LPAREN;
528         final boolean isMethodCallWithUnnecessaryParenthesis =
529                 parent.getType() == TokenTypes.METHOD_CALL
530                 && parent.getPreviousSibling() != null
531                 && parent.getPreviousSibling().getType() == TokenTypes.LPAREN;
532         return isPreviousSiblingLeftParenthesis || isMethodCallWithUnnecessaryParenthesis;
533     }
534 
535     /**
536      * Tests if the given expression node is surrounded by parentheses.
537      *
538      * @param ast a {@code DetailAST} whose type is
539      *        {@code TokenTypes.EXPR}.
540      * @return {@code true} if the expression is surrounded by
541      *         parentheses.
542      */
543     private static boolean isExprSurrounded(DetailAST ast) {
544         return ast.getFirstChild().getType() == TokenTypes.LPAREN;
545     }
546 
547     /**
548      * Checks whether an expression is surrounded by parentheses.
549      *
550      * @param ast the {@code DetailAST} to check if it is surrounded by
551      *        parentheses.
552      */
553     private void checkExpression(DetailAST ast) {
554         // If 'parentToSkip' == 'ast', then we've already logged a
555         // warning about an immediate child node in visitToken, so we don't
556         // need to log another one here.
557         if (parentToSkip != ast && isExprSurrounded(ast)) {
558             if (ast.getParent().getType() == TokenTypes.LITERAL_RETURN) {
559                 log(ast, MSG_RETURN);
560             }
561             else if (assignDepth >= 1) {
562                 log(ast, MSG_ASSIGN);
563             }
564             else {
565                 log(ast, MSG_EXPR);
566             }
567         }
568     }
569 
570     /**
571      * Checks if conditional, relational, bitwise binary operator, unary and postfix operators
572      * in expressions are surrounded by unnecessary parentheses.
573      *
574      * @param ast the {@code DetailAST} to check if it is surrounded by
575      *        unnecessary parentheses.
576      * @return {@code true} if the expression is surrounded by
577      *         unnecessary parentheses.
578      */
579     private static boolean unnecessaryParenAroundOperators(DetailAST ast) {
580         final int type = ast.getType();
581         final boolean isConditionalOrRelational = TokenUtil.isOfType(type, CONDITIONAL_OPERATOR)
582                         || TokenUtil.isOfType(type, RELATIONAL_OPERATOR);
583         final boolean isBitwise = TokenUtil.isOfType(type, BITWISE_BINARY_OPERATORS);
584         final boolean hasUnnecessaryParentheses;
585         if (isConditionalOrRelational) {
586             hasUnnecessaryParentheses = checkConditionalOrRelationalOperator(ast);
587         }
588         else if (isBitwise) {
589             hasUnnecessaryParentheses = checkBitwiseBinaryOperator(ast);
590         }
591         else {
592             hasUnnecessaryParentheses = TokenUtil.isOfType(type, UNARY_AND_POSTFIX)
593                     && isBitWiseBinaryOrConditionalOrRelationalOperator(ast.getParent().getType());
594         }
595         return hasUnnecessaryParentheses;
596     }
597 
598     /**
599      * Check if conditional or relational operator has unnecessary parentheses.
600      *
601      * @param ast to check if surrounded by unnecessary parentheses
602      * @return true if unnecessary parenthesis
603      */
604     private static boolean checkConditionalOrRelationalOperator(DetailAST ast) {
605         final int type = ast.getType();
606         final int parentType = ast.getParent().getType();
607         final boolean isParentEqualityOperator =
608                 TokenUtil.isOfType(parentType, TokenTypes.EQUAL, TokenTypes.NOT_EQUAL);
609         final boolean result;
610         if (type == TokenTypes.LOR) {
611             result = !TokenUtil.isOfType(parentType, TokenTypes.LAND)
612                     && !TokenUtil.isOfType(parentType, BITWISE_BINARY_OPERATORS);
613         }
614         else if (type == TokenTypes.LAND) {
615             result = !TokenUtil.isOfType(parentType, BITWISE_BINARY_OPERATORS);
616         }
617         else {
618             result = true;
619         }
620         return result && !isParentEqualityOperator
621                 && isBitWiseBinaryOrConditionalOrRelationalOperator(parentType);
622     }
623 
624     /**
625      * Check if bitwise binary operator has unnecessary parentheses.
626      *
627      * @param ast to check if surrounded by unnecessary parentheses
628      * @return true if unnecessary parenthesis
629      */
630     private static boolean checkBitwiseBinaryOperator(DetailAST ast) {
631         final int type = ast.getType();
632         final int parentType = ast.getParent().getType();
633         final boolean result;
634         if (type == TokenTypes.BOR) {
635             result = !TokenUtil.isOfType(parentType, TokenTypes.BAND, TokenTypes.BXOR)
636                     && !TokenUtil.isOfType(parentType, RELATIONAL_OPERATOR);
637         }
638         else if (type == TokenTypes.BXOR) {
639             result = !TokenUtil.isOfType(parentType, TokenTypes.BAND)
640                     && !TokenUtil.isOfType(parentType, RELATIONAL_OPERATOR);
641         }
642         // we deal with bitwise AND here.
643         else {
644             result = !TokenUtil.isOfType(parentType, RELATIONAL_OPERATOR);
645         }
646         return result && isBitWiseBinaryOrConditionalOrRelationalOperator(parentType);
647     }
648 
649     /**
650      * Check if token type is bitwise binary or conditional or relational operator.
651      *
652      * @param type Token type to check
653      * @return true if it is bitwise binary or conditional operator
654      */
655     private static boolean isBitWiseBinaryOrConditionalOrRelationalOperator(int type) {
656         return TokenUtil.isOfType(type, CONDITIONAL_OPERATOR)
657                 || TokenUtil.isOfType(type, RELATIONAL_OPERATOR)
658                 || TokenUtil.isOfType(type, BITWISE_BINARY_OPERATORS);
659     }
660 
661     /**
662      * Tests if the given node has a single parameter, no defined type, and is surrounded
663      * by parentheses. This condition can only be true for lambdas.
664      *
665      * @param ast a {@code DetailAST} node
666      * @return {@code true} if the lambda has a single parameter, no defined type, and is
667      *         surrounded by parentheses.
668      */
669     private static boolean isLambdaSingleParameterSurrounded(DetailAST ast) {
670         final DetailAST firstChild = ast.getFirstChild();
671         boolean result = false;
672         if (TokenUtil.isOfType(firstChild, TokenTypes.LPAREN)) {
673             final DetailAST parameters = firstChild.getNextSibling();
674             if (parameters.getChildCount(TokenTypes.PARAMETER_DEF) == 1
675                     && !parameters.getFirstChild().findFirstToken(TokenTypes.TYPE).hasChildren()) {
676                 result = true;
677             }
678         }
679         return result;
680     }
681 
682     /**
683      * Returns the specified string chopped to {@code MAX_QUOTED_LENGTH}
684      * plus an ellipsis (...) if the length of the string exceeds {@code
685      * MAX_QUOTED_LENGTH}.
686      *
687      * @param value the string to potentially chop.
688      * @return the chopped string if {@code string} is longer than
689      *         {@code MAX_QUOTED_LENGTH}; otherwise {@code string}.
690      */
691     private static String chopString(String value) {
692         String result = value;
693         if (value.length() > MAX_QUOTED_LENGTH) {
694             result = value.substring(0, MAX_QUOTED_LENGTH) + "...\"";
695         }
696         return result;
697     }
698 
699 }