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