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