BooleanExpressionComplexityCheck.java

1
////////////////////////////////////////////////////////////////////////////////
2
// checkstyle: Checks Java source code for adherence to a set of rules.
3
// Copyright (C) 2001-2017 the original author or authors.
4
//
5
// This library is free software; you can redistribute it and/or
6
// modify it under the terms of the GNU Lesser General Public
7
// License as published by the Free Software Foundation; either
8
// version 2.1 of the License, or (at your option) any later version.
9
//
10
// This library is distributed in the hope that it will be useful,
11
// but WITHOUT ANY WARRANTY; without even the implied warranty of
12
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13
// Lesser General Public License for more details.
14
//
15
// You should have received a copy of the GNU Lesser General Public
16
// License along with this library; if not, write to the Free Software
17
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18
////////////////////////////////////////////////////////////////////////////////
19
20
package com.puppycrawl.tools.checkstyle.checks.metrics;
21
22
import java.util.ArrayDeque;
23
import java.util.Deque;
24
25
import com.puppycrawl.tools.checkstyle.api.AbstractCheck;
26
import com.puppycrawl.tools.checkstyle.api.DetailAST;
27
import com.puppycrawl.tools.checkstyle.api.TokenTypes;
28
import com.puppycrawl.tools.checkstyle.utils.CheckUtils;
29
30
/**
31
 * Restricts nested boolean operators (&&, ||, &, | and ^) to
32
 * a specified depth (default = 3).
33
 * Note: &, | and ^ are not checked if they are part of constructor or
34
 * method call because they can be applied to non boolean variables and
35
 * Checkstyle does not know types of methods from different classes.
36
 *
37
 * @author <a href="mailto:simon@redhillconsulting.com.au">Simon Harris</a>
38
 * @author o_sukhodolsky
39
 */
40
public final class BooleanExpressionComplexityCheck extends AbstractCheck {
41
42
    /**
43
     * A key is pointing to the warning message text in "messages.properties"
44
     * file.
45
     */
46
    public static final String MSG_KEY = "booleanExpressionComplexity";
47
48
    /** Default allowed complexity. */
49
    private static final int DEFAULT_MAX = 3;
50
51
    /** Stack of contexts. */
52
    private final Deque<Context> contextStack = new ArrayDeque<>();
53
    /** Maximum allowed complexity. */
54
    private int max;
55
    /** Current context. */
56
    private Context context = new Context(false);
57
58
    /** Creates new instance of the check. */
59
    public BooleanExpressionComplexityCheck() {
60
        max = DEFAULT_MAX;
61
    }
62
63
    @Override
64
    public int[] getDefaultTokens() {
65 1 1. getDefaultTokens : mutated return of Object value for com/puppycrawl/tools/checkstyle/checks/metrics/BooleanExpressionComplexityCheck::getDefaultTokens to ( if (x != null) null else throw new RuntimeException ) → KILLED
        return new int[] {
66
            TokenTypes.CTOR_DEF,
67
            TokenTypes.METHOD_DEF,
68
            TokenTypes.EXPR,
69
            TokenTypes.LAND,
70
            TokenTypes.BAND,
71
            TokenTypes.LOR,
72
            TokenTypes.BOR,
73
            TokenTypes.BXOR,
74
        };
75
    }
76
77
    @Override
78
    public int[] getRequiredTokens() {
79 1 1. getRequiredTokens : mutated return of Object value for com/puppycrawl/tools/checkstyle/checks/metrics/BooleanExpressionComplexityCheck::getRequiredTokens to ( if (x != null) null else throw new RuntimeException ) → KILLED
        return new int[] {
80
            TokenTypes.CTOR_DEF,
81
            TokenTypes.METHOD_DEF,
82
            TokenTypes.EXPR,
83
        };
84
    }
85
86
    @Override
87
    public int[] getAcceptableTokens() {
88 1 1. getAcceptableTokens : mutated return of Object value for com/puppycrawl/tools/checkstyle/checks/metrics/BooleanExpressionComplexityCheck::getAcceptableTokens to ( if (x != null) null else throw new RuntimeException ) → KILLED
        return new int[] {
89
            TokenTypes.CTOR_DEF,
90
            TokenTypes.METHOD_DEF,
91
            TokenTypes.EXPR,
92
            TokenTypes.LAND,
93
            TokenTypes.BAND,
94
            TokenTypes.LOR,
95
            TokenTypes.BOR,
96
            TokenTypes.BXOR,
97
        };
98
    }
99
100
    /**
101
     * Setter for maximum allowed complexity.
102
     * @param max new maximum allowed complexity.
103
     */
104
    public void setMax(int max) {
105
        this.max = max;
106
    }
107
108
    @Override
109
    public void visitToken(DetailAST ast) {
110
        switch (ast.getType()) {
111
            case TokenTypes.CTOR_DEF:
112
            case TokenTypes.METHOD_DEF:
113 1 1. visitToken : removed call to com/puppycrawl/tools/checkstyle/checks/metrics/BooleanExpressionComplexityCheck::visitMethodDef → KILLED
                visitMethodDef(ast);
114
                break;
115
            case TokenTypes.EXPR:
116 1 1. visitToken : removed call to com/puppycrawl/tools/checkstyle/checks/metrics/BooleanExpressionComplexityCheck::visitExpr → KILLED
                visitExpr();
117
                break;
118
            case TokenTypes.BOR:
119 2 1. visitToken : negated conditional → KILLED
2. visitToken : negated conditional → KILLED
                if (!isPipeOperator(ast) && !isPassedInParameter(ast)) {
120 1 1. visitToken : removed call to com/puppycrawl/tools/checkstyle/checks/metrics/BooleanExpressionComplexityCheck$Context::visitBooleanOperator → KILLED
                    context.visitBooleanOperator();
121
                }
122
                break;
123
            case TokenTypes.BAND:
124
            case TokenTypes.BXOR:
125 1 1. visitToken : negated conditional → KILLED
                if (!isPassedInParameter(ast)) {
126 1 1. visitToken : removed call to com/puppycrawl/tools/checkstyle/checks/metrics/BooleanExpressionComplexityCheck$Context::visitBooleanOperator → KILLED
                    context.visitBooleanOperator();
127
                }
128
                break;
129
            case TokenTypes.LAND:
130
            case TokenTypes.LOR:
131 1 1. visitToken : removed call to com/puppycrawl/tools/checkstyle/checks/metrics/BooleanExpressionComplexityCheck$Context::visitBooleanOperator → KILLED
                context.visitBooleanOperator();
132
                break;
133
            default:
134
                throw new IllegalArgumentException("Unknown type: " + ast);
135
        }
136
    }
137
138
    /**
139
     * Checks if logical operator is part of constructor or method call.
140
     * @param logicalOperator logical operator
141
     * @return true if logical operator is part of constructor or method call
142
     */
143
    private static boolean isPassedInParameter(DetailAST logicalOperator) {
144 2 1. isPassedInParameter : negated conditional → KILLED
2. isPassedInParameter : replaced return of integer sized value with (x == 0 ? 1 : 0) → KILLED
        return logicalOperator.getParent().getType() == TokenTypes.EXPR
145 1 1. isPassedInParameter : negated conditional → KILLED
            && logicalOperator.getParent().getParent().getType() == TokenTypes.ELIST;
146
    }
147
148
    /**
149
     * Checks if {@link TokenTypes#BOR binary OR} is applied to exceptions
150
     * in
151
     * <a href="http://docs.oracle.com/javase/specs/jls/se8/html/jls-14.html#jls-14.20">
152
     * multi-catch</a> (pipe-syntax).
153
     * @param binaryOr {@link TokenTypes#BOR binary or}
154
     * @return true if binary or is applied to exceptions in multi-catch.
155
     */
156
    private static boolean isPipeOperator(DetailAST binaryOr) {
157 2 1. isPipeOperator : negated conditional → KILLED
2. isPipeOperator : replaced return of integer sized value with (x == 0 ? 1 : 0) → KILLED
        return binaryOr.getParent().getType() == TokenTypes.TYPE;
158
    }
159
160
    @Override
161
    public void leaveToken(DetailAST ast) {
162
        switch (ast.getType()) {
163
            case TokenTypes.CTOR_DEF:
164
            case TokenTypes.METHOD_DEF:
165 1 1. leaveToken : removed call to com/puppycrawl/tools/checkstyle/checks/metrics/BooleanExpressionComplexityCheck::leaveMethodDef → SURVIVED
                leaveMethodDef();
166
                break;
167
            case TokenTypes.EXPR:
168 1 1. leaveToken : removed call to com/puppycrawl/tools/checkstyle/checks/metrics/BooleanExpressionComplexityCheck::leaveExpr → KILLED
                leaveExpr(ast);
169
                break;
170
            default:
171
                // Do nothing
172
        }
173
    }
174
175
    /**
176
     * Creates new context for a given method.
177
     * @param ast a method we start to check.
178
     */
179
    private void visitMethodDef(DetailAST ast) {
180 1 1. visitMethodDef : removed call to java/util/Deque::push → KILLED
        contextStack.push(context);
181 1 1. visitMethodDef : negated conditional → KILLED
        final boolean check = !CheckUtils.isEqualsMethod(ast);
182
        context = new Context(check);
183
    }
184
185
    /** Removes old context. */
186
    private void leaveMethodDef() {
187
        context = contextStack.pop();
188
    }
189
190
    /** Creates and pushes new context. */
191
    private void visitExpr() {
192 1 1. visitExpr : removed call to java/util/Deque::push → KILLED
        contextStack.push(context);
193
        context = new Context(context.isChecking());
194
    }
195
196
    /**
197
     * Restores previous context.
198
     * @param ast expression we leave.
199
     */
200
    private void leaveExpr(DetailAST ast) {
201 1 1. leaveExpr : removed call to com/puppycrawl/tools/checkstyle/checks/metrics/BooleanExpressionComplexityCheck$Context::checkCount → KILLED
        context.checkCount(ast);
202
        context = contextStack.pop();
203
    }
204
205
    /**
206
     * Represents context (method/expression) in which we check complexity.
207
     *
208
     * @author <a href="mailto:simon@redhillconsulting.com.au">Simon Harris</a>
209
     * @author o_sukhodolsky
210
     */
211
    private class Context {
212
        /**
213
         * Should we perform check in current context or not.
214
         * Usually false if we are inside equals() method.
215
         */
216
        private final boolean checking;
217
        /** Count of boolean operators. */
218
        private int count;
219
220
        /**
221
         * Creates new instance.
222
         * @param checking should we check in current context or not.
223
         */
224
        Context(boolean checking) {
225
            this.checking = checking;
226
            count = 0;
227
        }
228
229
        /**
230
         * Getter for checking property.
231
         * @return should we check in current context or not.
232
         */
233
        public boolean isChecking() {
234 1 1. isChecking : replaced return of integer sized value with (x == 0 ? 1 : 0) → KILLED
            return checking;
235
        }
236
237
        /** Increases operator counter. */
238
        public void visitBooleanOperator() {
239 1 1. visitBooleanOperator : Replaced integer addition with subtraction → KILLED
            ++count;
240
        }
241
242
        /**
243
         * Checks if we violates maximum allowed complexity.
244
         * @param ast a node we check now.
245
         */
246
        public void checkCount(DetailAST ast) {
247 3 1. checkCount : changed conditional boundary → KILLED
2. checkCount : negated conditional → KILLED
3. checkCount : negated conditional → KILLED
            if (checking && count > max) {
248
                final DetailAST parentAST = ast.getParent();
249
250 1 1. checkCount : removed call to com/puppycrawl/tools/checkstyle/checks/metrics/BooleanExpressionComplexityCheck::log → KILLED
                log(parentAST.getLineNo(), parentAST.getColumnNo(),
251
                    MSG_KEY, count, max);
252
            }
253
        }
254
    }
255
}

Mutations

65

1.1
Location : getDefaultTokens
Killed by : com.puppycrawl.tools.checkstyle.checks.metrics.BooleanExpressionComplexityCheckTest.testNullPointerException(com.puppycrawl.tools.checkstyle.checks.metrics.BooleanExpressionComplexityCheckTest)
mutated return of Object value for com/puppycrawl/tools/checkstyle/checks/metrics/BooleanExpressionComplexityCheck::getDefaultTokens to ( if (x != null) null else throw new RuntimeException ) → KILLED

79

1.1
Location : getRequiredTokens
Killed by : com.puppycrawl.tools.checkstyle.checks.metrics.BooleanExpressionComplexityCheckTest.testNullPointerException(com.puppycrawl.tools.checkstyle.checks.metrics.BooleanExpressionComplexityCheckTest)
mutated return of Object value for com/puppycrawl/tools/checkstyle/checks/metrics/BooleanExpressionComplexityCheck::getRequiredTokens to ( if (x != null) null else throw new RuntimeException ) → KILLED

88

1.1
Location : getAcceptableTokens
Killed by : com.puppycrawl.tools.checkstyle.checks.metrics.BooleanExpressionComplexityCheckTest.testNoBitwise(com.puppycrawl.tools.checkstyle.checks.metrics.BooleanExpressionComplexityCheckTest)
mutated return of Object value for com/puppycrawl/tools/checkstyle/checks/metrics/BooleanExpressionComplexityCheck::getAcceptableTokens to ( if (x != null) null else throw new RuntimeException ) → KILLED

113

1.1
Location : visitToken
Killed by : com.puppycrawl.tools.checkstyle.checks.metrics.BooleanExpressionComplexityCheckTest.testNoBitwise(com.puppycrawl.tools.checkstyle.checks.metrics.BooleanExpressionComplexityCheckTest)
removed call to com/puppycrawl/tools/checkstyle/checks/metrics/BooleanExpressionComplexityCheck::visitMethodDef → KILLED

116

1.1
Location : visitToken
Killed by : com.puppycrawl.tools.checkstyle.checks.metrics.BooleanExpressionComplexityCheckTest.testNullPointerException(com.puppycrawl.tools.checkstyle.checks.metrics.BooleanExpressionComplexityCheckTest)
removed call to com/puppycrawl/tools/checkstyle/checks/metrics/BooleanExpressionComplexityCheck::visitExpr → KILLED

119

1.1
Location : visitToken
Killed by : com.puppycrawl.tools.checkstyle.checks.metrics.BooleanExpressionComplexityCheckTest.test(com.puppycrawl.tools.checkstyle.checks.metrics.BooleanExpressionComplexityCheckTest)
negated conditional → KILLED

2.2
Location : visitToken
Killed by : com.puppycrawl.tools.checkstyle.checks.metrics.BooleanExpressionComplexityCheckTest.test(com.puppycrawl.tools.checkstyle.checks.metrics.BooleanExpressionComplexityCheckTest)
negated conditional → KILLED

120

1.1
Location : visitToken
Killed by : com.puppycrawl.tools.checkstyle.checks.metrics.BooleanExpressionComplexityCheckTest.test(com.puppycrawl.tools.checkstyle.checks.metrics.BooleanExpressionComplexityCheckTest)
removed call to com/puppycrawl/tools/checkstyle/checks/metrics/BooleanExpressionComplexityCheck$Context::visitBooleanOperator → KILLED

125

1.1
Location : visitToken
Killed by : com.puppycrawl.tools.checkstyle.checks.metrics.BooleanExpressionComplexityCheckTest.test(com.puppycrawl.tools.checkstyle.checks.metrics.BooleanExpressionComplexityCheckTest)
negated conditional → KILLED

126

1.1
Location : visitToken
Killed by : com.puppycrawl.tools.checkstyle.checks.metrics.BooleanExpressionComplexityCheckTest.test(com.puppycrawl.tools.checkstyle.checks.metrics.BooleanExpressionComplexityCheckTest)
removed call to com/puppycrawl/tools/checkstyle/checks/metrics/BooleanExpressionComplexityCheck$Context::visitBooleanOperator → KILLED

131

1.1
Location : visitToken
Killed by : com.puppycrawl.tools.checkstyle.checks.metrics.BooleanExpressionComplexityCheckTest.test(com.puppycrawl.tools.checkstyle.checks.metrics.BooleanExpressionComplexityCheckTest)
removed call to com/puppycrawl/tools/checkstyle/checks/metrics/BooleanExpressionComplexityCheck$Context::visitBooleanOperator → KILLED

144

1.1
Location : isPassedInParameter
Killed by : com.puppycrawl.tools.checkstyle.checks.metrics.BooleanExpressionComplexityCheckTest.test(com.puppycrawl.tools.checkstyle.checks.metrics.BooleanExpressionComplexityCheckTest)
negated conditional → KILLED

2.2
Location : isPassedInParameter
Killed by : com.puppycrawl.tools.checkstyle.checks.metrics.BooleanExpressionComplexityCheckTest.test(com.puppycrawl.tools.checkstyle.checks.metrics.BooleanExpressionComplexityCheckTest)
replaced return of integer sized value with (x == 0 ? 1 : 0) → KILLED

145

1.1
Location : isPassedInParameter
Killed by : com.puppycrawl.tools.checkstyle.checks.metrics.BooleanExpressionComplexityCheckTest.test(com.puppycrawl.tools.checkstyle.checks.metrics.BooleanExpressionComplexityCheckTest)
negated conditional → KILLED

157

1.1
Location : isPipeOperator
Killed by : com.puppycrawl.tools.checkstyle.checks.metrics.BooleanExpressionComplexityCheckTest.test(com.puppycrawl.tools.checkstyle.checks.metrics.BooleanExpressionComplexityCheckTest)
negated conditional → KILLED

2.2
Location : isPipeOperator
Killed by : com.puppycrawl.tools.checkstyle.checks.metrics.BooleanExpressionComplexityCheckTest.test(com.puppycrawl.tools.checkstyle.checks.metrics.BooleanExpressionComplexityCheckTest)
replaced return of integer sized value with (x == 0 ? 1 : 0) → KILLED

165

1.1
Location : leaveToken
Killed by : none
removed call to com/puppycrawl/tools/checkstyle/checks/metrics/BooleanExpressionComplexityCheck::leaveMethodDef → SURVIVED

168

1.1
Location : leaveToken
Killed by : com.puppycrawl.tools.checkstyle.checks.metrics.BooleanExpressionComplexityCheckTest.test(com.puppycrawl.tools.checkstyle.checks.metrics.BooleanExpressionComplexityCheckTest)
removed call to com/puppycrawl/tools/checkstyle/checks/metrics/BooleanExpressionComplexityCheck::leaveExpr → KILLED

180

1.1
Location : visitMethodDef
Killed by : com.puppycrawl.tools.checkstyle.checks.metrics.BooleanExpressionComplexityCheckTest.testNoBitwise(com.puppycrawl.tools.checkstyle.checks.metrics.BooleanExpressionComplexityCheckTest)
removed call to java/util/Deque::push → KILLED

181

1.1
Location : visitMethodDef
Killed by : com.puppycrawl.tools.checkstyle.checks.metrics.BooleanExpressionComplexityCheckTest.test(com.puppycrawl.tools.checkstyle.checks.metrics.BooleanExpressionComplexityCheckTest)
negated conditional → KILLED

192

1.1
Location : visitExpr
Killed by : com.puppycrawl.tools.checkstyle.checks.metrics.BooleanExpressionComplexityCheckTest.testNullPointerException(com.puppycrawl.tools.checkstyle.checks.metrics.BooleanExpressionComplexityCheckTest)
removed call to java/util/Deque::push → KILLED

201

1.1
Location : leaveExpr
Killed by : com.puppycrawl.tools.checkstyle.checks.metrics.BooleanExpressionComplexityCheckTest.test(com.puppycrawl.tools.checkstyle.checks.metrics.BooleanExpressionComplexityCheckTest)
removed call to com/puppycrawl/tools/checkstyle/checks/metrics/BooleanExpressionComplexityCheck$Context::checkCount → KILLED

234

1.1
Location : isChecking
Killed by : com.puppycrawl.tools.checkstyle.checks.metrics.BooleanExpressionComplexityCheckTest.test(com.puppycrawl.tools.checkstyle.checks.metrics.BooleanExpressionComplexityCheckTest)
replaced return of integer sized value with (x == 0 ? 1 : 0) → KILLED

239

1.1
Location : visitBooleanOperator
Killed by : com.puppycrawl.tools.checkstyle.checks.metrics.BooleanExpressionComplexityCheckTest.test(com.puppycrawl.tools.checkstyle.checks.metrics.BooleanExpressionComplexityCheckTest)
Replaced integer addition with subtraction → KILLED

247

1.1
Location : checkCount
Killed by : com.puppycrawl.tools.checkstyle.checks.metrics.BooleanExpressionComplexityCheckTest.test(com.puppycrawl.tools.checkstyle.checks.metrics.BooleanExpressionComplexityCheckTest)
changed conditional boundary → KILLED

2.2
Location : checkCount
Killed by : com.puppycrawl.tools.checkstyle.checks.metrics.BooleanExpressionComplexityCheckTest.test(com.puppycrawl.tools.checkstyle.checks.metrics.BooleanExpressionComplexityCheckTest)
negated conditional → KILLED

3.3
Location : checkCount
Killed by : com.puppycrawl.tools.checkstyle.checks.metrics.BooleanExpressionComplexityCheckTest.testNoBitwise(com.puppycrawl.tools.checkstyle.checks.metrics.BooleanExpressionComplexityCheckTest)
negated conditional → KILLED

250

1.1
Location : checkCount
Killed by : com.puppycrawl.tools.checkstyle.checks.metrics.BooleanExpressionComplexityCheckTest.test(com.puppycrawl.tools.checkstyle.checks.metrics.BooleanExpressionComplexityCheckTest)
removed call to com/puppycrawl/tools/checkstyle/checks/metrics/BooleanExpressionComplexityCheck::log → KILLED

Active mutators

Tests examined


Report generated by PIT 1.2.4