Skip to content

Commit ef0a27c

Browse files
Add cyclomatic_sum field, fix issues related to this change
1 parent a507c7d commit ef0a27c

File tree

3 files changed

+107
-20
lines changed

3 files changed

+107
-20
lines changed

src/metrics/cyclomatic.rs

Lines changed: 100 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,21 @@
1+
use crate::checker::Checker;
2+
use crate::*;
13
use serde::ser::{SerializeStruct, Serializer};
24
use serde::Serialize;
35
use std::fmt;
46

5-
use crate::checker::Checker;
6-
use crate::*;
7-
87
/// The `Cyclomatic` metric.
98
#[derive(Debug, Clone)]
109
pub struct Stats {
10+
cyclomatic_sum: f64,
1111
cyclomatic: f64,
1212
n: usize,
1313
}
1414

1515
impl Default for Stats {
1616
fn default() -> Self {
1717
Self {
18+
cyclomatic_sum: 0.,
1819
cyclomatic: 1.,
1920
n: 1,
2021
}
@@ -27,7 +28,7 @@ impl Serialize for Stats {
2728
S: Serializer,
2829
{
2930
let mut st = serializer.serialize_struct("cyclomatic", 2)?;
30-
st.serialize_field("sum", &self.cyclomatic())?;
31+
st.serialize_field("sum", &self.cyclomatic_sum())?;
3132
st.serialize_field("average", &self.cyclomatic_average())?;
3233
st.end()
3334
}
@@ -38,30 +39,39 @@ impl fmt::Display for Stats {
3839
write!(
3940
f,
4041
"sum: {}, average: {}",
41-
self.cyclomatic(),
42-
self.cyclomatic_average()
42+
self.cyclomatic_sum(),
43+
self.cyclomatic_average(),
4344
)
4445
}
4546
}
4647

4748
impl Stats {
4849
/// Merges a second `Cyclomatic` metric into the first one
4950
pub fn merge(&mut self, other: &Stats) {
50-
self.cyclomatic += other.cyclomatic;
51+
self.cyclomatic_sum += other.cyclomatic_sum;
5152
self.n += other.n;
5253
}
5354

5455
/// Returns the `Cyclomatic` metric value
5556
pub fn cyclomatic(&self) -> f64 {
5657
self.cyclomatic
5758
}
59+
/// Returns the sum
60+
pub fn cyclomatic_sum(&self) -> f64 {
61+
self.cyclomatic_sum
62+
}
5863

5964
/// Returns the `Cyclomatic` metric average value
6065
///
6166
/// This value is computed dividing the `Cyclomatic` value for the
6267
/// number of spaces.
6368
pub fn cyclomatic_average(&self) -> f64 {
64-
self.cyclomatic() / self.n as f64
69+
self.cyclomatic_sum() / self.n as f64
70+
}
71+
72+
/// Last step for computing minimum and maximum value and update cyclomatic_sum
73+
pub fn compute_minmax(&mut self) {
74+
self.cyclomatic_sum += self.cyclomatic;
6575
}
6676
}
6777

@@ -190,9 +200,9 @@ mod tests {
190200
"foo.py",
191201
PythonParser,
192202
cyclomatic,
193-
[(cyclomatic, 6, usize)],
203+
[(cyclomatic_sum, 6, usize)],
194204
[
195-
(cyclomatic_average, 3.0) // nspace = 2 (func and unit)
205+
(cyclomatic_average, 3.0), // nspace = 2 (func and unit)
196206
]
197207
);
198208
}
@@ -207,9 +217,9 @@ mod tests {
207217
"foo.py",
208218
PythonParser,
209219
cyclomatic,
210-
[(cyclomatic, 4, usize)],
220+
[(cyclomatic_sum, 4, usize)],
211221
[
212-
(cyclomatic_average, 2.0) // nspace = 2 (func and unit)
222+
(cyclomatic_average, 2.0), // nspace = 2 (func and unit)
213223
]
214224
);
215225
}
@@ -228,9 +238,9 @@ mod tests {
228238
"foo.rs",
229239
RustParser,
230240
cyclomatic,
231-
[(cyclomatic, 5, usize)],
241+
[(cyclomatic_sum, 5, usize)],
232242
[
233-
(cyclomatic_average, 2.5) // nspace = 2 (func and unit)
243+
(cyclomatic_average, 2.5), // nspace = 2 (func and unit)
234244
]
235245
);
236246
}
@@ -257,9 +267,9 @@ mod tests {
257267
"foo.c",
258268
CppParser,
259269
cyclomatic,
260-
[(cyclomatic, 5, usize)],
270+
[(cyclomatic_sum, 5, usize)],
261271
[
262-
(cyclomatic_average, 2.5) // nspace = 2 (func and unit)
272+
(cyclomatic_average, 2.5), // nspace = 2 (func and unit)
263273
]
264274
);
265275
}
@@ -282,9 +292,81 @@ mod tests {
282292
"foo.c",
283293
CppParser,
284294
cyclomatic,
285-
[(cyclomatic, 5, usize)],
295+
[(cyclomatic_sum, 5, usize)],
296+
[
297+
(cyclomatic_average, 2.5), // nspace = 2 (func and unit)
298+
]
299+
);
300+
}
301+
#[test]
302+
fn c_unit_before() {
303+
check_metrics!(
304+
"
305+
int a=42;
306+
if(a==42) //+2(+1 unit space)
307+
{
308+
309+
}
310+
if(a==34) //+1
311+
{
312+
313+
}
314+
int sumOfPrimes(int max) { // +1
315+
int total = 0;
316+
OUT: for (int i = 1; i <= max; ++i) { // +1
317+
for (int j = 2; j < i; ++j) { // +1
318+
if (i % j == 0) { // +1
319+
continue OUT;
320+
}
321+
}
322+
total += i;
323+
}
324+
return total;
325+
}",
326+
"foo.c",
327+
CppParser,
328+
cyclomatic,
329+
[(cyclomatic_sum, 7, usize)],
330+
[
331+
(cyclomatic_average, 3.5), // nspace = 2 (func and unit)
332+
]
333+
);
334+
}
335+
/// Test to handle the case of min and max when merge happen before the final value of one module are setted.
336+
/// In this case the min value should be 3 because the unit space has 2 branches and a complexity of 3
337+
/// while the function sumOfPrimes has a complexity of 4.
338+
#[test]
339+
fn c_unit_after() {
340+
check_metrics!(
341+
"
342+
int sumOfPrimes(int max) { // +1
343+
int total = 0;
344+
OUT: for (int i = 1; i <= max; ++i) { // +1
345+
for (int j = 2; j < i; ++j) { // +1
346+
if (i % j == 0) { // +1
347+
continue OUT;
348+
}
349+
}
350+
total += i;
351+
}
352+
return total;
353+
}
354+
355+
int a=42;
356+
if(a==42) //+2(+1 unit space)
357+
{
358+
359+
}
360+
if(a==34) //+1
361+
{
362+
363+
}",
364+
"foo.c",
365+
CppParser,
366+
cyclomatic,
367+
[(cyclomatic_sum, 7, usize)],
286368
[
287-
(cyclomatic_average, 2.5) // nspace = 2 (func and unit)
369+
(cyclomatic_average, 3.5), // nspace = 2 (func and unit)
288370
]
289371
);
290372
}

src/metrics/mi.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ where
9696
stats.halstead_length = halstead.length();
9797
stats.halstead_vocabulary = halstead.vocabulary();
9898
stats.halstead_volume = halstead.volume();
99-
stats.cyclomatic = cyclomatic.cyclomatic();
99+
stats.cyclomatic = cyclomatic.cyclomatic_sum();
100100
stats.sloc = loc.sloc();
101101
stats.comments_percentage = loc.cloc() / stats.sloc;
102102
}

src/spaces.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,10 @@ fn compute_averages(state: &mut State) {
195195
.nargs
196196
.finalize(nom_functions, nom_closures);
197197
}
198+
#[inline(always)]
199+
fn compute_minmax(state: &mut State) {
200+
state.space.metrics.cyclomatic.compute_minmax();
201+
}
198202

199203
fn finalize<T: ParserTrait>(state_stack: &mut Vec<State>, diff_level: usize) {
200204
if state_stack.is_empty() {
@@ -203,14 +207,15 @@ fn finalize<T: ParserTrait>(state_stack: &mut Vec<State>, diff_level: usize) {
203207
for _ in 0..diff_level {
204208
if state_stack.len() == 1 {
205209
let mut last_state = state_stack.last_mut().unwrap();
210+
compute_minmax(&mut last_state);
206211
compute_halstead_and_mi::<T>(&mut last_state);
207212
compute_averages(&mut last_state);
208213
break;
209214
} else {
210215
let mut state = state_stack.pop().unwrap();
216+
compute_minmax(&mut state);
211217
compute_halstead_and_mi::<T>(&mut state);
212218
compute_averages(&mut state);
213-
214219
let mut last_state = state_stack.last_mut().unwrap();
215220
last_state.halstead_maps.merge(&state.halstead_maps);
216221
compute_halstead_and_mi::<T>(&mut last_state);

0 commit comments

Comments
 (0)