diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/metrics/api/JavaClassMetricKey.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/metrics/api/JavaClassMetricKey.java index 211f2824dc..544af36631 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/metrics/api/JavaClassMetricKey.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/metrics/api/JavaClassMetricKey.java @@ -6,7 +6,6 @@ package net.sourceforge.pmd.lang.java.metrics.api; import net.sourceforge.pmd.lang.java.ast.ASTAnyTypeDeclaration; import net.sourceforge.pmd.lang.java.metrics.impl.AtfdMetric.AtfdClassMetric; -import net.sourceforge.pmd.lang.java.metrics.impl.CycloMetric.CycloClassMetric; import net.sourceforge.pmd.lang.java.metrics.impl.LocMetric.LocClassMetric; import net.sourceforge.pmd.lang.java.metrics.impl.NcssMetric.NcssClassMetric; import net.sourceforge.pmd.lang.java.metrics.impl.WmcMetric; @@ -31,13 +30,6 @@ public enum JavaClassMetricKey implements MetricKey { */ WMC(new WmcMetric()), - /** - * Cyclomatic complexity. - * - * @see net.sourceforge.pmd.lang.java.metrics.impl.CycloMetric - */ - CYCLO(new CycloClassMetric()), - /** * Non Commenting Source Statements. * diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/metrics/api/JavaOperationMetricKey.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/metrics/api/JavaOperationMetricKey.java index a6236e6cd9..152a3bf4d9 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/metrics/api/JavaOperationMetricKey.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/metrics/api/JavaOperationMetricKey.java @@ -6,7 +6,7 @@ package net.sourceforge.pmd.lang.java.metrics.api; import net.sourceforge.pmd.lang.java.ast.ASTMethodOrConstructorDeclaration; import net.sourceforge.pmd.lang.java.metrics.impl.AtfdMetric.AtfdOperationMetric; -import net.sourceforge.pmd.lang.java.metrics.impl.CycloMetric.CycloOperationMetric; +import net.sourceforge.pmd.lang.java.metrics.impl.CycloMetric; import net.sourceforge.pmd.lang.java.metrics.impl.LocMetric.LocOperationMetric; import net.sourceforge.pmd.lang.java.metrics.impl.NcssMetric.NcssOperationMetric; import net.sourceforge.pmd.lang.java.metrics.impl.NpathMetric; @@ -27,9 +27,9 @@ public enum JavaOperationMetricKey implements MetricKey VERSION_MAP; @@ -54,26 +49,23 @@ public class CyclomaticComplexityRule extends AbstractJavaMetricsRule { "cycloVersion", "Choose a variant of Cyclo or the standard", VERSION_MAP, Version.STANDARD, MetricVersion.class, 3.0f); - private int reportLevel; - private boolean reportClasses = true; - private boolean reportMethods = true; + private int methodReportLevel; + private int classReportLevel; private MetricVersion cycloVersion = Version.STANDARD; public CyclomaticComplexityRule() { - definePropertyDescriptor(REPORT_LEVEL_DESCRIPTOR); - definePropertyDescriptor(REPORT_CLASSES_DESCRIPTOR); - definePropertyDescriptor(REPORT_METHODS_DESCRIPTOR); + definePropertyDescriptor(CLASS_LEVEL_DESCRIPTOR); + definePropertyDescriptor(METHOD_LEVEL_DESCRIPTOR); definePropertyDescriptor(CYCLO_VERSION_DESCRIPTOR); } @Override public Object visit(ASTCompilationUnit node, Object data) { - reportLevel = getProperty(REPORT_LEVEL_DESCRIPTOR); + methodReportLevel = getProperty(METHOD_LEVEL_DESCRIPTOR); + classReportLevel = getProperty(CLASS_LEVEL_DESCRIPTOR); cycloVersion = getProperty(CYCLO_VERSION_DESCRIPTOR); - reportClasses = getProperty(REPORT_CLASSES_DESCRIPTOR); - reportMethods = getProperty(REPORT_METHODS_DESCRIPTOR); super.visit(node, data); return data; @@ -85,14 +77,16 @@ public class CyclomaticComplexityRule extends AbstractJavaMetricsRule { super.visit(node, data); - if (reportClasses && JavaClassMetricKey.CYCLO.supports(node)) { - int classCyclo = (int) JavaMetrics.get(JavaClassMetricKey.CYCLO, node, cycloVersion); - int classHighest = (int) JavaMetrics.get(JavaOperationMetricKey.CYCLO, node, cycloVersion, ResultOption.HIGHEST); + if (JavaClassMetricKey.WMC.supports(node)) { + int classWmc = (int) JavaMetrics.get(JavaClassMetricKey.WMC, node, cycloVersion); + + if (classWmc >= classReportLevel) { + int classHighest = (int) JavaMetrics.get(JavaOperationMetricKey.CYCLO, node, cycloVersion, ResultOption.HIGHEST); - if (classCyclo >= reportLevel || classHighest >= reportLevel) { String[] messageParams = {node.getTypeKind().name().toLowerCase(), node.getImage(), - classCyclo + " (Highest = " + classHighest + ")", }; + " total", + classWmc + " (highest " + classHighest + ")", }; addViolation(data, node, messageParams); } @@ -104,13 +98,14 @@ public class CyclomaticComplexityRule extends AbstractJavaMetricsRule { @Override public final Object visit(ASTMethodOrConstructorDeclaration node, Object data) { - if (reportMethods) { - int cyclo = (int) JavaMetrics.get(JavaOperationMetricKey.CYCLO, node, cycloVersion); - if (cyclo >= reportLevel) { - addViolation(data, node, new String[] {node instanceof ASTMethodDeclaration ? "method" : "constructor", - node.getQualifiedName().getOperation(), "" + cyclo, }); - } + int cyclo = (int) JavaMetrics.get(JavaOperationMetricKey.CYCLO, node, cycloVersion); + if (cyclo >= methodReportLevel) { + addViolation(data, node, new String[] {node instanceof ASTMethodDeclaration ? "method" : "constructor", + node.getQualifiedName().getOperation(), + "", + "" + cyclo, }); } + return data; } diff --git a/pmd-java/src/main/resources/rulesets/java/metrics.xml b/pmd-java/src/main/resources/rulesets/java/metrics.xml index 38e7c9f722..1b6ee14b93 100644 --- a/pmd-java/src/main/resources/rulesets/java/metrics.xml +++ b/pmd-java/src/main/resources/rulesets/java/metrics.xml @@ -10,7 +10,7 @@ Complicated method - Standard - 3 + 2 - '.Complicated' has value 13 highest 21. '.Complicated#exception()' has value 4. - '.Complicated#example()' has value 21. + '.Complicated#example()' has value 23. Complicated method - Ignore boolean path version - 3 + 2 ignoreBooleanPaths - '.Complicated' has value 10 highest 14. '.Complicated#exception()' has value 4. '.Complicated#example()' has value 14. @@ -103,21 +101,6 @@ - - Empty class should count 0 - 1 - - '.Foo' has value 0 highest 0. - - - - - - - - #984 Cyclomatic complexity should treat constructors like methods - + #984 Cyclomatic complexity should treat constructors like methods false 1 @@ -201,27 +183,21 @@ - Interfaces are not supported - 0 + Ternary expression counts 1 + boolean complexity + 1 + + '.Foo#bar()' has value 3. + - - Avoid division by 0 when averaging a metric over no operations - -1 - 1 - '.Foo' has value NaN. - - - - - diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/metrics/xml/CyclomaticComplexity.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/metrics/xml/CyclomaticComplexity.xml index 98288e5906..2747ddcab4 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/metrics/xml/CyclomaticComplexity.xml +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/metrics/xml/CyclomaticComplexity.xml @@ -1,7 +1,7 @@ - + Simple method - 1 + 1 + 1 2 - The class 'Foo' has a Cyclomatic Complexity of 2 (Highest = 1). - The method 'foo()' has a Cyclomatic Complexity of 1. + The class 'Foo' has a total cyclomatic complexity of 1 (highest 1). + The method 'foo()' has a cyclomatic complexity of 1. testLessComplicatedThanReportLevel - 10 0 Complicated method - 10 - 2 + 1 - The class 'Complicated' has a Cyclomatic Complexity of 18 (Highest = 17). - The method 'example()' has a Cyclomatic Complexity of 17. + The method 'example()' has a cyclomatic complexity of 17. - + Complicated method (ignoreBooleanPath) - 10 ignoreBooleanPaths - 2 + 1 - The class 'Complicated' has a Cyclomatic Complexity of 11 (Highest = 10). - The method 'example()' has a Cyclomatic Complexity of 10. + The method 'example()' has a cyclomatic complexity of 10. - + Constructor - 1 - 2 + 1 + 1 - The class 'Foo' has a Cyclomatic Complexity of 2 (Highest = 1). - The constructor 'Foo()' has a Cyclomatic Complexity of 1. + The constructor 'Foo()' has a cyclomatic complexity of 1. - Testing new parameter showClassMethods - false + Test class report level + 17 + 999 1 - + - Testing new parameter showMethodsMethods - false + Test method report level + 999 + 17 1 - - - - - Testing default value of showClassMethods and reportClasses - 2 - + @@ -152,29 +143,22 @@ - #984 Cyclomatic complexity should treat constructors like methods: 1 - reportMethods=true - - false - true - 1 + #984 Cyclomatic complexity should treat constructors like methods: 1 - reportMethods=true + 1 1 - #984 Cyclomatic complexity should treat constructors like methods: 2 - - reportMethods=false - - false - false - 1 + #984 Cyclomatic complexity should treat constructors like methods: 2 -reportMethods=false + 999 0 #985 Suppressed methods shouldn't affect avg CyclomaticComplexity - 2 + 2 0 Standard Cyclo should count empty switch labels too - false - true - 2 + 2 1 - The method 'switchCase()' has a Cyclomatic Complexity of 3. + The method 'switchCase()' has a cyclomatic complexity of 3. IgnoreBooleanPaths Cyclo should not count empty switch labels - false - true ignoreBooleanPaths - 2 + 2 1 - The method 'switchCase()' has a Cyclomatic Complexity of 2. + The method 'switchCase()' has a cyclomatic complexity of 2. @@ -253,37 +233,133 @@ Standard Cyclo should count boolean paths - false - 2 + 2 1 - The method 'foo()' has a Cyclomatic Complexity of 8. + The method 'foo()' has a cyclomatic complexity of 8. IgnoreBooleanPaths Cyclo should not count boolean paths - false ignoreBooleanPaths - 2 + 2 1 - The method 'foo()' has a Cyclomatic Complexity of 4. + The method 'foo()' has a cyclomatic complexity of 4. - - Avoid division by 0 when averaging a metric over no operations - -1 - 1 - - - + + + + + + + Test many unreported methods + 1 + + The class 'Complicated' has a total cyclomatic complexity of 40 (highest 8). + +