1 |
| |
2 |
| |
3 |
| |
4 |
| package net.sourceforge.pmd.stat; |
5 |
| |
6 |
| import java.util.Iterator; |
7 |
| import java.util.List; |
8 |
| import java.util.Map; |
9 |
| import java.util.Set; |
10 |
| import java.util.SortedSet; |
11 |
| import java.util.TreeSet; |
12 |
| |
13 |
| import net.sourceforge.pmd.AbstractRule; |
14 |
| import net.sourceforge.pmd.PropertyDescriptor; |
15 |
| import net.sourceforge.pmd.RuleContext; |
16 |
| import net.sourceforge.pmd.properties.DoubleProperty; |
17 |
| import net.sourceforge.pmd.properties.IntegerProperty; |
18 |
| |
19 |
| |
20 |
| |
21 |
| |
22 |
| |
23 |
| public abstract class StatisticalRule extends AbstractRule { |
24 |
| |
25 |
| public static double DELTA = 0.000005; |
26 |
| |
27 |
| private SortedSet dataPoints = new TreeSet(); |
28 |
| |
29 |
| private int count = 0; |
30 |
| private double total = 0.0; |
31 |
| |
32 |
| private static final PropertyDescriptor sigmaDescriptor = new DoubleProperty( |
33 |
| "sigma", "Sigma value", 0, 1.0f |
34 |
| ); |
35 |
| |
36 |
| private static final PropertyDescriptor minimumDescriptor = new DoubleProperty( |
37 |
| "minimum", "Minimum value", 0, 1.0f |
38 |
| ); |
39 |
| |
40 |
| private static final PropertyDescriptor topScoreDescriptor = new IntegerProperty( |
41 |
| "topscore", "Top score value", 0, 1.0f |
42 |
| ); |
43 |
| |
44 |
| private static final Map propertyDescriptorsByName = asFixedMap( new PropertyDescriptor[] { |
45 |
| sigmaDescriptor, minimumDescriptor, topScoreDescriptor |
46 |
| }); |
47 |
| |
48 |
| |
49 |
23738
| public void addDataPoint(DataPoint point) {
|
50 |
23738
| count++;
|
51 |
23738
| total += point.getScore();
|
52 |
23738
| dataPoints.add(point);
|
53 |
| } |
54 |
| |
55 |
194
| public void apply(List acus, RuleContext ctx) {
|
56 |
194
| visitAll(acus, ctx);
|
57 |
| |
58 |
194
| double deviation;
|
59 |
194
| double minimum = 0.0;
|
60 |
| |
61 |
194
| if (hasProperty("sigma")) {
|
62 |
108
| deviation = getStdDev();
|
63 |
108
| double sigma = getDoubleProperty(sigmaDescriptor);
|
64 |
108
| minimum = getMean() + (sigma * deviation);
|
65 |
| } |
66 |
| |
67 |
194
| if (hasProperty("minimum")) {
|
68 |
145
| double mMin = getDoubleProperty(minimumDescriptor);
|
69 |
145
| if (mMin > minimum) {
|
70 |
115
| minimum = mMin;
|
71 |
| } |
72 |
| } |
73 |
| |
74 |
194
| SortedSet newPoints = applyMinimumValue(dataPoints, minimum);
|
75 |
| |
76 |
194
| if (hasProperty("topscore")) {
|
77 |
108
| int topScore = getIntProperty(topScoreDescriptor);
|
78 |
108
| if (newPoints.size() >= topScore) {
|
79 |
48
| newPoints = applyTopScore(newPoints, topScore);
|
80 |
| } |
81 |
| } |
82 |
| |
83 |
194
| makeViolations(ctx, newPoints);
|
84 |
| |
85 |
194
| double low = 0.0d;
|
86 |
194
| double high = 0.0d;
|
87 |
194
| if (!dataPoints.isEmpty()) {
|
88 |
194
| low = ((DataPoint) dataPoints.first()).getScore();
|
89 |
194
| high = ((DataPoint) dataPoints.last()).getScore();
|
90 |
| } |
91 |
| |
92 |
194
| ctx.getReport().addMetric(new Metric(this.getName(), count, total, low, high, getMean(), getStdDev()));
|
93 |
| |
94 |
194
| dataPoints.clear();
|
95 |
| } |
96 |
| |
97 |
568
| protected double getMean() {
|
98 |
568
| return total / count;
|
99 |
| } |
100 |
| |
101 |
302
| protected double getStdDev() {
|
102 |
302
| if (dataPoints.size() < 2) {
|
103 |
36
| return Double.NaN;
|
104 |
| } |
105 |
| |
106 |
266
| Iterator points = dataPoints.iterator();
|
107 |
266
| double mean = getMean();
|
108 |
266
| double deltaSq = 0.0;
|
109 |
266
| double scoreMinusMean;
|
110 |
| |
111 |
266
| while (points.hasNext()) {
|
112 |
26502
| scoreMinusMean = ((DataPoint) points.next()).getScore() - mean;
|
113 |
26502
| deltaSq += (scoreMinusMean * scoreMinusMean);
|
114 |
| } |
115 |
| |
116 |
266
| return Math.sqrt(deltaSq / (dataPoints.size() - 1));
|
117 |
| } |
118 |
| |
119 |
194
| protected SortedSet applyMinimumValue(SortedSet pointSet, double minValue) {
|
120 |
194
| Iterator points = pointSet.iterator();
|
121 |
194
| SortedSet RC = new TreeSet();
|
122 |
194
| double threshold = minValue - DELTA;
|
123 |
| |
124 |
194
| while (points.hasNext()) {
|
125 |
15738
| DataPoint point = (DataPoint) points.next();
|
126 |
| |
127 |
15738
| if (point.getScore() > threshold) {
|
128 |
4196
| RC.add(point);
|
129 |
| } |
130 |
| } |
131 |
194
| return RC;
|
132 |
| } |
133 |
| |
134 |
48
| protected SortedSet applyTopScore(SortedSet points, int topScore) {
|
135 |
48
| SortedSet s = new TreeSet();
|
136 |
48
| Object[] arr = points.toArray();
|
137 |
48
| for (int i = arr.length - 1; i >= (arr.length - topScore); i--) {
|
138 |
606
| s.add(arr[i]);
|
139 |
| } |
140 |
48
| return s;
|
141 |
| } |
142 |
| |
143 |
180
| protected void makeViolations(RuleContext ctx, Set p) {
|
144 |
180
| Iterator points = p.iterator();
|
145 |
180
| while (points.hasNext()) {
|
146 |
2233
| DataPoint point = (DataPoint) points.next();
|
147 |
2233
| addViolationWithMessage(ctx, point.getNode(), point.getMessage());
|
148 |
| } |
149 |
| } |
150 |
| |
151 |
0
| protected Map propertiesByName() {
|
152 |
0
| return propertyDescriptorsByName;
|
153 |
| } |
154 |
| } |