Skip to content

Commit c997a20

Browse files
committed
Retain the old ccn and add wmc as new metric
CCN by Class is deprecated and will be removed in v3. WMC should be used instead. To be BC compatible the CCN by Class will be retained until v3. Fixes #359
1 parent 6e3ebca commit c997a20

File tree

7 files changed

+59
-12
lines changed

7 files changed

+59
-12
lines changed

src/Hal/Metric/Class_/Complexity/CyclomaticComplexityVisitor.php

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,8 @@ public function leaveNode(Node $node)
5757
) {
5858
$class = $this->metrics->get(MetricClassNameGenerator::getName($node));
5959

60-
$ccn = 0;
60+
$ccn = 1;
61+
$wmc = 0;
6162
$ccnByMethod = [0]; // default maxMethodCcn if no methods are available
6263

6364
foreach ($node->stmts as $stmt) {
@@ -106,11 +107,13 @@ public function leaveNode(Node $node)
106107

107108
$methodCcn = $cb($stmt) + 1; // each method by default is CCN 1 even if it's empty
108109

109-
$ccn += $methodCcn;
110+
$wmc += $methodCcn;
111+
$ccn += $methodCcn - 1;
110112
$ccnByMethod[] = $methodCcn;
111113
}
112114
}
113115

116+
$class->set('wmc', $wmc);
114117
$class->set('ccn', $ccn);
115118
$class->set('ccnMethodMax', max($ccnByMethod));
116119
}

src/Hal/Metric/Consolidated.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ public function __construct(Metrics $metrics)
7474
'nbMethods' => 0,
7575
];
7676
$avg = (object)[
77+
'wmc' => [],
7778
'ccn' => [],
7879
'bugs' => [],
7980
'kanDefect' => [],

src/Hal/Report/Cli/Reporter.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ public function generate(Metrics $metrics)
8787
8888
Complexity
8989
Average Cyclomatic complexity by class {$avg->ccn}
90+
Average Weighted method count by class {$avg->wmc}
9091
Average Relative system complexity {$avg->relativeSystemComplexity}
9192
Average Difficulty {$avg->difficulty}
9293

src/Hal/Report/Html/template/complexity.php

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,15 @@
22
require __DIR__ . '/_header.php'; ?>
33

44
<div class="row">
5+
<div class="column">
6+
<div class="bloc bloc-number">
7+
<div class="label">Average weighted method count by class <small>(CC)</small></div>
8+
<div class="number">
9+
<?php echo $avg->wmc; ?>
10+
</div>
11+
<?php echo $this->getTrend('avg', 'wmc', true); ?>
12+
</div>
13+
</div>
514
<div class="column">
615
<div class="bloc bloc-number">
716
<div class="label">Average cyclomatic complexity by class</div>
@@ -22,34 +31,32 @@
2231
</div>
2332
<div class="column">
2433
<div class="bloc bloc-number">
25-
<div class="label">Average bugs by class
26-
<small>(Halstead)</small> <?php echo $this->getTrend('avg', 'bugs', true); ?>
27-
</div>
34+
<div class="label">Average bugs by class<small>(Halstead)</small></div>
2835
<div class="number">
2936
<?php echo $avg->bugs; ?>
3037
</div>
38+
<?php echo $this->getTrend('avg', 'bugs', true); ?>
3139
</div>
3240
</div>
3341
<div class="column">
3442
<div class="bloc bloc-number">
35-
<div class="label">average defects by class
36-
<small>(Kan)</small> <?php echo $this->getTrend('avg', 'kanDefect', true); ?>
37-
</div>
43+
<div class="label">average defects by class <small>(Kan)</small></div>
3844
<div class="number">
3945
<?php echo $avg->kanDefect; ?>
4046
</div>
47+
<?php echo $this->getTrend('avg', 'kanDefect', true); ?>
4148
</div>
4249
</div>
4350
</div>
4451

45-
4652
<div class="row">
4753
<div class="column">
4854
<div class="bloc">
4955
<table class="js-sort-table" id="table-length">
5056
<thead>
5157
<tr>
5258
<th>Class</th>
59+
<th class="js-sort-number">WMC</th>
5360
<th class="js-sort-number">Class cycl.</th>
5461
<th class="js-sort-number">Max method cycl.</th>
5562
<?php if ($config->has('junit')) { ?>
@@ -65,6 +72,7 @@
6572
foreach ($classes as $class) { ?>
6673
<tr>
6774
<td><?php echo $class['name']; ?></td>
75+
<td><?php echo isset($class['wmc']) ? $class['wmc'] : ''; ?></td>
6876
<td><?php echo isset($class['ccn']) ? $class['ccn'] : ''; ?></td>
6977
<td><?php echo isset($class['ccnMethodMax']) ? $class['ccnMethodMax'] : ''; ?></td>
7078
<?php if ($config->has('junit')) { ?>

src/Hal/Report/Html/template/index.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@
1111
<div class="column">
1212
<div class="bloc bloc-number">
1313
<div class="label"><a href="loc.html">Lines of code</a></div>
14-
<?php echo $this->getTrend('sum', 'loc'); ?>
1514
<div class="number"><?php echo $sum->loc; ?></div>
15+
<?php echo $this->getTrend('sum', 'loc'); ?>
1616
</div>
1717
</div>
1818
<div class="column">

src/Hal/Violation/Class_/TooComplexClassCode.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ public function apply(Metric $metric)
2929

3030
$this->metric = $metric;
3131

32-
if ($metric->get('ccn') > 50) {
32+
if ($metric->get('wmc') > 50) {
3333
$metric->get('violations')->add($this);
3434
}
3535
}

tests/Metric/Class_/Complexity/CyclomaticComplexityVisitorTest.php

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,26 @@
1010

1111
class CyclomaticComplexityVisitorTest extends \PHPUnit_Framework_TestCase
1212
{
13+
/**
14+
* @dataProvider provideExamplesForCcn
15+
*/
16+
public function testCcnOfClassesIsWellCalculated($example, $classname, $expectedCcn)
17+
{
18+
$metrics = new Metrics();
19+
20+
$parser = (new ParserFactory)->create(ParserFactory::PREFER_PHP7);
21+
$traverser = new NodeTraverser();
22+
$traverser->addVisitor(new NameResolver());
23+
$traverser->addVisitor(new ClassEnumVisitor($metrics));
24+
$traverser->addVisitor(new CyclomaticComplexityVisitor($metrics));
25+
26+
$code = file_get_contents($example);
27+
$stmts = $parser->parse($code);
28+
$traverser->traverse($stmts);
29+
30+
$this->assertSame($expectedCcn, $metrics->get($classname)->get('ccn'));
31+
}
32+
1333
/**
1434
* @dataProvider provideExamplesForWmc
1535
*/
@@ -27,7 +47,7 @@ public function testWeightedMethodCountOfClassesIsWellCalculated($example, $clas
2747
$stmts = $parser->parse($code);
2848
$traverser->traverse($stmts);
2949

30-
$this->assertSame($expectedWmc, $metrics->get($classname)->get('ccn'));
50+
$this->assertSame($expectedWmc, $metrics->get($classname)->get('wmc'));
3151
}
3252

3353
/**
@@ -64,6 +84,20 @@ public static function provideExamplesForWmc()
6484
];
6585
}
6686

87+
public static function provideExamplesForCcn()
88+
{
89+
return [
90+
'A' => [__DIR__ . '/../../examples/cyclomatic1.php', 'A', 8],
91+
'B' => [__DIR__ . '/../../examples/cyclomatic1.php', 'B', 4],
92+
'Foo\\C' => [__DIR__ . '/../../examples/cyclomatic_anon.php', 'Foo\\C', 1],
93+
'SwitchCase' => [__DIR__ . '/../../examples/cyclomatic_full.php', 'SwitchCase', 4],
94+
'IfElseif' => [__DIR__ . '/../../examples/cyclomatic_full.php', 'IfElseif', 7],
95+
'Loops' => [__DIR__ . '/../../examples/cyclomatic_full.php', 'Loops', 5],
96+
'CatchIt' => [__DIR__ . '/../../examples/cyclomatic_full.php', 'CatchIt', 3],
97+
'Logical' => [__DIR__ . '/../../examples/cyclomatic_full.php', 'Logical', 11],
98+
];
99+
}
100+
67101
public static function provideExamplesForMaxCc()
68102
{
69103
return [

0 commit comments

Comments
 (0)