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