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