+345
-4
lines changedFilter options
+345
-4
lines changed Original file line number Diff line number Diff line change
@@ -23,6 +23,44 @@ it uses instead of the services they provide.
23
23
24
24
ATFD can be used to detect God Classes and Feature Envy. \[[Lanza05](#Lanza05)\]
25
25
26
+
## Class Fan Out Complexity (CLASS_FAN_OUT)
27
+
28
+
*Operation metric, class metric.* Can be computed on classes, enums and
29
+
concrete operations.
30
+
31
+
### Description
32
+
This counts the number of other classes a given class or operation relies on.
33
+
Classes from the package `java.lang` are ignored by default (can be changed via options).
34
+
Also primitives are not included into the count.
35
+
36
+
### Code example
37
+
38
+
```java
39
+
import java.util.*;
40
+
import java.io.IOException;
41
+
42
+
public class Foo { // total 8
43
+
public Set set = new HashSet(); // +2
44
+
public Map map = new HashMap(); // +2
45
+
public String string = ""; // from java.lang -> does not count by default
46
+
public Double number = 0.0; // from java.lang -> does not count by default
47
+
public int[] intArray = new int[3]; // primitive -> does not count
48
+
49
+
@Deprecated // from java.lang -> does not count by default
50
+
@Override // from java.lang -> does not count by default
51
+
public void foo(List list) throws Exception { // +1 (Exception is from java.lang)
52
+
throw new IOException(); // +1
53
+
}
54
+
55
+
public int getMapSize() {
56
+
return map.size(); // +1 because it uses the Class from the 'map' field
57
+
}
58
+
}
59
+
```
60
+
61
+
### Options
62
+
63
+
* Option `includeJavaLang`: Also include classes from the package `java.lang`
26
64
27
65
## Cyclomatic Complexity (CYCLO)
28
66
Original file line number Diff line number Diff line change
@@ -34,6 +34,11 @@ This is a {{ site.pmd.release_type }} release.
34
34
usages of `Executors` and `ExecutorService`. Both create new threads, which are not managed by a J2EE
35
35
server.
36
36
37
+
#### Java Metrics
38
+
39
+
* The new metric "Class Fan Out Complexity" has been added. See
40
+
[Java Metrics Documentation](pmd_java_metrics_index.html#class-fan-out-complexity-class_fan_out) for details.
41
+
37
42
### Fixed Issues
38
43
39
44
* core
@@ -61,7 +66,6 @@ This is a {{ site.pmd.release_type }} release.
61
66
62
67
### API Changes
63
68
64
-
65
69
#### Deprecated APIs
66
70
67
71
##### For removal
@@ -104,10 +108,11 @@ This is a {{ site.pmd.release_type }} release.
104
108
* [#2010](https://github.com/pmd/pmd/pull/2010): \[java] LawOfDemeter to support inner builder pattern - [Gregor Riegler](https://github.com/gregorriegler)
105
109
* [#2012](https://github.com/pmd/pmd/pull/2012): \[java] Fixes 336, slf4j log4j2 support - [Mark Hall](https://github.com/markhall82)
106
110
* [#2032](https://github.com/pmd/pmd/pull/2032): \[core] Allow adding SourceCode directly into CPD - [Nathan Braun](https://github.com/nbraun-Google)
107
-
* [#2047](https://github.com/pmd/pmd/pull/2047): \[java] Fix computation of metrics with annotations - [Andi](https://github.com/andipabst)
111
+
* [#2047](https://github.com/pmd/pmd/pull/2047): \[java] Fix computation of metrics with annotations - [Andi Pabst](https://github.com/andipabst)
108
112
* [#2065](https://github.com/pmd/pmd/pull/2065): \[java] Stop checking UR anomalies - [Carlos Macasaet](https://github.com/l0s)
109
113
* [#2070](https://github.com/pmd/pmd/pull/2070): \[core] Fix renderer tests for windows builds - [Saladoc](https://github.com/Saladoc)
110
114
* [#2073](https://github.com/pmd/pmd/pull/2073): \[test]\[core] Add expected and actual line of numbers to message wording - [snuyanzin](https://github.com/snuyanzin)
115
+
* [#2076](https://github.com/pmd/pmd/pull/2076): \[java] Add Metric ClassFanOutComplexity - [Andi Pabst](https://github.com/andipabst)
111
116
* [#2078](https://github.com/pmd/pmd/pull/2078): \[java] DoNotUseThreads should not warn on Runnable #1627 - [Michael Clay](https://github.com/mclay)
112
117
113
118
{% endtocmaker %}
Original file line number Diff line number Diff line change
@@ -6,6 +6,7 @@
6
6
7
7
import net.sourceforge.pmd.lang.java.ast.ASTAnyTypeDeclaration;
8
8
import net.sourceforge.pmd.lang.java.metrics.impl.AtfdMetric.AtfdClassMetric;
9
+
import net.sourceforge.pmd.lang.java.metrics.impl.ClassFanOutMetric.ClassFanOutClassMetric;
9
10
import net.sourceforge.pmd.lang.java.metrics.impl.LocMetric.LocClassMetric;
10
11
import net.sourceforge.pmd.lang.java.metrics.impl.NcssMetric.NcssClassMetric;
11
12
import net.sourceforge.pmd.lang.java.metrics.impl.NoamMetric;
@@ -74,7 +75,14 @@ public enum JavaClassMetricKey implements MetricKey<ASTAnyTypeDeclaration> {
74
75
*
75
76
* @see TccMetric
76
77
*/
77
-
TCC(new TccMetric());
78
+
TCC(new TccMetric()),
79
+
80
+
/**
81
+
* ClassFanOut Complexity
82
+
*
83
+
* @see ClassFanOutClassMetric
84
+
*/
85
+
CLASS_FAN_OUT(new ClassFanOutClassMetric());
78
86
79
87
80
88
private final JavaClassMetric calculator;
Original file line number Diff line number Diff line change
@@ -7,6 +7,7 @@
7
7
import net.sourceforge.pmd.lang.java.ast.ASTMethodOrConstructorDeclaration;
8
8
import net.sourceforge.pmd.lang.java.ast.MethodLikeNode;
9
9
import net.sourceforge.pmd.lang.java.metrics.impl.AtfdMetric.AtfdOperationMetric;
10
+
import net.sourceforge.pmd.lang.java.metrics.impl.ClassFanOutMetric.ClassFanOutOperationMetric;
10
11
import net.sourceforge.pmd.lang.java.metrics.impl.CycloMetric;
11
12
import net.sourceforge.pmd.lang.java.metrics.impl.LocMetric.LocOperationMetric;
12
13
import net.sourceforge.pmd.lang.java.metrics.impl.NcssMetric.NcssOperationMetric;
@@ -53,7 +54,14 @@ public enum JavaOperationMetricKey implements MetricKey<MethodLikeNode> {
53
54
*
54
55
* @see NpathMetric
55
56
*/
56
-
NPATH(new NpathMetric());
57
+
NPATH(new NpathMetric()),
58
+
59
+
/**
60
+
* ClassFanOut Complexity
61
+
*
62
+
* @see ClassFanOutOperationMetric
63
+
*/
64
+
CLASS_FAN_OUT(new ClassFanOutOperationMetric());
57
65
58
66
59
67
private final JavaOperationMetric calculator;
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
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.impl;
6
+
7
+
import org.apache.commons.lang3.mutable.MutableInt;
8
+
9
+
import net.sourceforge.pmd.lang.java.ast.ASTAnyTypeDeclaration;
10
+
import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceBodyDeclaration;
11
+
import net.sourceforge.pmd.lang.java.ast.MethodLikeNode;
12
+
import net.sourceforge.pmd.lang.java.metrics.impl.internal.ClassFanOutVisitor;
13
+
import net.sourceforge.pmd.lang.metrics.MetricOption;
14
+
import net.sourceforge.pmd.lang.metrics.MetricOptions;
15
+
16
+
17
+
/**
18
+
* The ClassFanOutComplexity counts the usage of other classes within this class.
19
+
*
20
+
* @author Andreas Pabst
21
+
* @since October 2019
22
+
*/
23
+
public final class ClassFanOutMetric {
24
+
25
+
public enum ClassFanOutOption implements MetricOption {
26
+
/** Whether to include Classes in the java.lang package. */
27
+
INCLUDE_JAVA_LANG("includeJavaLang");
28
+
29
+
private final String vName;
30
+
31
+
ClassFanOutOption(String valueName) {
32
+
this.vName = valueName;
33
+
}
34
+
35
+
@Override
36
+
public String valueName() {
37
+
return vName;
38
+
}
39
+
}
40
+
41
+
public static final class ClassFanOutClassMetric extends AbstractJavaClassMetric {
42
+
43
+
@Override
44
+
public double computeFor(ASTAnyTypeDeclaration node, MetricOptions options) {
45
+
MutableInt cfo = (MutableInt) node.jjtAccept(new ClassFanOutVisitor(options, node), new MutableInt(0));
46
+
return (double) cfo.getValue();
47
+
}
48
+
}
49
+
50
+
public static final class ClassFanOutOperationMetric extends AbstractJavaOperationMetric {
51
+
52
+
@Override
53
+
public boolean supports(MethodLikeNode node) {
54
+
return true;
55
+
}
56
+
57
+
@Override
58
+
public double computeFor(MethodLikeNode node, MetricOptions options) {
59
+
MutableInt cfo;
60
+
// look at the parent to catch annotations
61
+
if (node.jjtGetParent() instanceof ASTClassOrInterfaceBodyDeclaration) {
62
+
ASTClassOrInterfaceBodyDeclaration parent = (ASTClassOrInterfaceBodyDeclaration) node.jjtGetParent();
63
+
cfo = (MutableInt) parent.jjtAccept(new ClassFanOutVisitor(options, node), new MutableInt(0));
64
+
} else {
65
+
cfo = (MutableInt) node.jjtAccept(new ClassFanOutVisitor(options, node), new MutableInt(0));
66
+
}
67
+
68
+
return (double) cfo.getValue();
69
+
}
70
+
}
71
+
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
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.impl.internal;
6
+
7
+
import java.util.HashSet;
8
+
import java.util.Set;
9
+
10
+
import org.apache.commons.lang3.mutable.MutableInt;
11
+
12
+
import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceType;
13
+
import net.sourceforge.pmd.lang.java.ast.ASTName;
14
+
import net.sourceforge.pmd.lang.java.ast.JavaNode;
15
+
import net.sourceforge.pmd.lang.java.ast.JavaParserVisitorAdapter;
16
+
import net.sourceforge.pmd.lang.java.ast.TypeNode;
17
+
import net.sourceforge.pmd.lang.java.metrics.impl.ClassFanOutMetric.ClassFanOutOption;
18
+
import net.sourceforge.pmd.lang.metrics.MetricOptions;
19
+
20
+
21
+
/**
22
+
* Visitor for the ClassFanOut metric.
23
+
*
24
+
* @author Andreas Pabst
25
+
*/
26
+
public class ClassFanOutVisitor extends JavaParserVisitorAdapter {
27
+
28
+
private static final String JAVA_LANG_PACKAGE_NAME = "java.lang";
29
+
protected Set<Class<?>> classes = new HashSet<>();
30
+
private final boolean includeJavaLang;
31
+
32
+
@SuppressWarnings("PMD.UnusedFormalParameter")
33
+
public ClassFanOutVisitor(MetricOptions options, JavaNode topNode) {
34
+
includeJavaLang = options.getOptions().contains(ClassFanOutOption.INCLUDE_JAVA_LANG);
35
+
// topNode is unused, but we'll need it if we want to discount lambdas
36
+
// if we add it later, we break binary compatibility
37
+
}
38
+
39
+
@Override
40
+
public Object visit(ASTClassOrInterfaceType node, Object data) {
41
+
check(node, (MutableInt) data);
42
+
return super.visit(node, data);
43
+
}
44
+
45
+
@Override
46
+
public Object visit(ASTName node, Object data) {
47
+
check(node, (MutableInt) data);
48
+
return super.visit(node, data);
49
+
}
50
+
51
+
private void check(TypeNode node, MutableInt counter) {
52
+
if (!classes.contains(node.getType()) && shouldBeIncluded(node.getType())) {
53
+
classes.add(node.getType());
54
+
counter.increment();
55
+
}
56
+
}
57
+
58
+
private boolean shouldBeIncluded(Class<?> classToCheck) {
59
+
if (includeJavaLang || classToCheck == null) {
60
+
// include all packages
61
+
return true;
62
+
} else {
63
+
// exclude the java.lang package
64
+
Package packageToCheck = classToCheck.getPackage();
65
+
if (packageToCheck == null) {
66
+
return true;
67
+
}
68
+
69
+
return !JAVA_LANG_PACKAGE_NAME.equals(packageToCheck.getName());
70
+
}
71
+
}
72
+
}
Original file line number Diff line number Diff line change
@@ -38,6 +38,7 @@ public void setUp() {
38
38
addRule(RULESET, "WocTest");
39
39
addRule(RULESET, "TccTest");
40
40
addRule(RULESET, "AtfdTest");
41
+
addRule(RULESET, "CfoTest");
41
42
}
42
43
43
44
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
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.impl;
6
+
7
+
import java.util.Map;
8
+
9
+
import net.sourceforge.pmd.lang.java.metrics.api.JavaClassMetricKey;
10
+
import net.sourceforge.pmd.lang.java.metrics.api.JavaOperationMetricKey;
11
+
import net.sourceforge.pmd.lang.java.metrics.impl.ClassFanOutMetric.ClassFanOutOption;
12
+
import net.sourceforge.pmd.lang.metrics.MetricOption;
13
+
14
+
/**
15
+
* @author Andreas Pabst
16
+
*/
17
+
public class CfoTestRule extends AbstractMetricTestRule {
18
+
19
+
@Override
20
+
protected JavaClassMetricKey getClassKey() {
21
+
return JavaClassMetricKey.CLASS_FAN_OUT;
22
+
}
23
+
24
+
25
+
@Override
26
+
protected JavaOperationMetricKey getOpKey() {
27
+
return JavaOperationMetricKey.CLASS_FAN_OUT;
28
+
}
29
+
30
+
@Override
31
+
protected Map<String, MetricOption> optionMappings() {
32
+
Map<String, MetricOption> mappings = super.optionMappings();
33
+
mappings.put(ClassFanOutOption.INCLUDE_JAVA_LANG.valueName(), ClassFanOutOption.INCLUDE_JAVA_LANG);
34
+
return mappings;
35
+
}
36
+
}
You can’t perform that action at this time.
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4