• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

pmd / pmd / 19

29 May 2025 04:22PM UTC coverage: 77.723% (-0.03%) from 77.757%
19

push

github

adangel
Fix #5621: [java] Fix FPs with UnusedPrivateMethod (#5727)

Merge pull request #5727 from oowekyala:issue5621-unusedprivatemethod

17705 of 23734 branches covered (74.6%)

Branch coverage included in aggregate %.

50 of 52 new or added lines in 9 files covered. (96.15%)

81 existing lines in 6 files now uncovered.

38845 of 49024 relevant lines covered (79.24%)

0.8 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

90.91
/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/metrics/internal/CycloVisitor.java
1
/*
2
 * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
3
 */
4

5
package net.sourceforge.pmd.lang.java.metrics.internal;
6

7
import org.apache.commons.lang3.mutable.MutableInt;
8
import org.checkerframework.checker.nullness.qual.Nullable;
9

10
import net.sourceforge.pmd.lang.java.ast.ASTAssertStatement;
11
import net.sourceforge.pmd.lang.java.ast.ASTCatchClause;
12
import net.sourceforge.pmd.lang.java.ast.ASTConditionalExpression;
13
import net.sourceforge.pmd.lang.java.ast.ASTDoStatement;
14
import net.sourceforge.pmd.lang.java.ast.ASTExecutableDeclaration;
15
import net.sourceforge.pmd.lang.java.ast.ASTExpression;
16
import net.sourceforge.pmd.lang.java.ast.ASTForStatement;
17
import net.sourceforge.pmd.lang.java.ast.ASTForeachStatement;
18
import net.sourceforge.pmd.lang.java.ast.ASTIfStatement;
19
import net.sourceforge.pmd.lang.java.ast.ASTSwitchBranch;
20
import net.sourceforge.pmd.lang.java.ast.ASTSwitchExpression;
21
import net.sourceforge.pmd.lang.java.ast.ASTSwitchFallthroughBranch;
22
import net.sourceforge.pmd.lang.java.ast.ASTSwitchLike;
23
import net.sourceforge.pmd.lang.java.ast.ASTSwitchStatement;
24
import net.sourceforge.pmd.lang.java.ast.ASTThrowStatement;
25
import net.sourceforge.pmd.lang.java.ast.ASTWhileStatement;
26
import net.sourceforge.pmd.lang.java.ast.JavaNode;
27
import net.sourceforge.pmd.lang.java.ast.JavaVisitorBase;
28
import net.sourceforge.pmd.lang.java.ast.internal.JavaAstUtils;
29
import net.sourceforge.pmd.lang.java.metrics.JavaMetrics.CycloOption;
30
import net.sourceforge.pmd.lang.metrics.MetricOptions;
31

32

33
/**
34
 * Visitor for the Cyclo metric.
35
 *
36
 * @author Clément Fournier
37
 * @since 6.7.0
38
 */
39
public class CycloVisitor extends JavaVisitorBase<MutableInt, Void> {
40

41

42
    protected final boolean considerBooleanPaths;
43
    protected final boolean considerAssert;
44
    private final JavaNode topNode;
45

46

47
    public CycloVisitor(MetricOptions options, JavaNode topNode) {
1✔
48
        considerBooleanPaths = !options.getOptions().contains(CycloOption.IGNORE_BOOLEAN_PATHS);
1✔
49
        considerAssert = options.getOptions().contains(CycloOption.CONSIDER_ASSERT);
1✔
50
        this.topNode = topNode;
1✔
51
    }
1✔
52

53

54
    @Override
55
    public final Void visitJavaNode(JavaNode localNode, MutableInt data) {
56
        return localNode.isFindBoundary() && !localNode.equals(topNode) ? null : super.visitJavaNode(localNode, data);
1!
57
    }
58

59
    @Override
60
    public Void visit(ASTSwitchExpression node, MutableInt data) {
61
        return handleSwitch(node, data);
1✔
62
    }
63

64
    @Override
65
    public Void visit(ASTSwitchStatement node, MutableInt data) {
66
        return handleSwitch(node, data);
1✔
67
    }
68

69
    private Void handleSwitch(ASTSwitchLike node, MutableInt data) {
70
        if (considerBooleanPaths) {
1✔
71
            data.add(booleanExpressionComplexity(node.getTestedExpression()));
1✔
72
        }
73

74
        for (ASTSwitchBranch branch : node) {
1✔
75
            if (branch.getLabel().isDefault()) {
1✔
76
                // like for "else", default is not a decision point
77
                continue;
1✔
78
            }
79

80
            if (considerBooleanPaths) {
1✔
81
                data.add(JavaAstUtils.numAlternatives(branch));
1✔
82
            } else if (branch instanceof ASTSwitchFallthroughBranch
1!
83
                && ((ASTSwitchFallthroughBranch) branch).getStatements().nonEmpty()) {
1✔
84
                data.increment();
1✔
85
            }
86
        }
1✔
87

88
        return visitJavaNode(node, data);
1✔
89
    }
90

91

92
    @Override
93
    public Void visit(ASTConditionalExpression node, MutableInt data) {
94
        data.increment();
1✔
95
        if (considerBooleanPaths) {
1✔
96
            data.add(booleanExpressionComplexity(node.getCondition()));
1✔
97
        }
98
        return super.visit(node, data);
1✔
99
    }
100

101

102
    @Override
103
    public Void visit(ASTWhileStatement node, MutableInt data) {
104
        data.increment();
1✔
105
        if (considerBooleanPaths) {
1✔
106
            data.add(booleanExpressionComplexity(node.getCondition()));
1✔
107
        }
108
        return super.visit(node, data);
1✔
109
    }
110

111

112
    @Override
113
    public Void visit(ASTIfStatement node, MutableInt data) {
114
        data.increment();
1✔
115
        if (considerBooleanPaths) {
1✔
116
            data.add(booleanExpressionComplexity(node.getCondition()));
1✔
117
        }
118

119
        return super.visit(node, data);
1✔
120
    }
121

122

123
    @Override
124
    public Void visit(ASTForStatement node, MutableInt data) {
125
        data.increment();
1✔
126

127
        if (considerBooleanPaths) {
1✔
128
            data.add(booleanExpressionComplexity(node.getCondition()));
1✔
129
        }
130

131
        return super.visit(node, data);
1✔
132
    }
133

134
    @Override
135
    public Void visit(ASTForeachStatement node, MutableInt data) {
136
        data.increment();
1✔
137
        return super.visit(node, data);
1✔
138
    }
139

140
    @Override
141
    public Void visitMethodOrCtor(ASTExecutableDeclaration node, MutableInt data) {
142
        data.increment();
1✔
143
        return super.visitMethodOrCtor(node, data);
1✔
144
    }
145

146
    @Override
147
    public Void visit(ASTDoStatement node, MutableInt data) {
148
        data.increment();
1✔
149
        if (considerBooleanPaths) {
1✔
150
            data.add(booleanExpressionComplexity(node.getCondition()));
1✔
151
        }
152

153
        return super.visit(node, data);
1✔
154
    }
155

156

157
    @Override
158
    public Void visit(ASTCatchClause node, MutableInt data) {
159
        data.increment();
1✔
160
        return super.visit(node, data);
1✔
161
    }
162

163

164
    @Override
165
    public Void visit(ASTThrowStatement node, MutableInt data) {
166
        data.increment();
1✔
167
        return super.visit(node, data);
1✔
168
    }
169

170

171
    @Override
172
    public Void visit(ASTAssertStatement node, MutableInt data) {
173
        if (considerAssert) {
1✔
174
            data.add(2); // equivalent to if (condition) { throw .. }
1✔
175

176
            if (considerBooleanPaths) {
1✔
177
                data.add(booleanExpressionComplexity(node.getCondition()));
1✔
178
            }
179
        }
180

181
        return super.visit(node, data);
1✔
182
    }
183

184
    /**
185
     * Evaluates the number of paths through a boolean expression. This is the total number of {@code &&} and {@code ||}
186
     * operators appearing in the expression. This is used in the calculation of cyclomatic and n-path complexity.
187
     *
188
     * @param expr Expression to analyse
189
     *
190
     * @return The number of paths through the expression
191
     */
192
    public static int booleanExpressionComplexity(@Nullable ASTExpression expr) {
193
        if (expr == null) {
1!
194
            return 0;
×
195
        }
196

197
        if (expr instanceof ASTConditionalExpression) {
1!
UNCOV
198
            ASTConditionalExpression conditional = (ASTConditionalExpression) expr;
×
UNCOV
199
            return booleanExpressionComplexity(conditional.getCondition())
×
UNCOV
200
                + booleanExpressionComplexity(conditional.getThenBranch())
×
UNCOV
201
                + booleanExpressionComplexity(conditional.getElseBranch())
×
202
                + 2;
203
        } else {
204
            return expr.descendantsOrSelf()
1✔
205
                       .filter(JavaAstUtils::isConditional)
1✔
206
                       .count();
1✔
207
        }
208
    }
209
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc