diff --git a/rust-code-analysis-cli/src/web/server.rs b/rust-code-analysis-cli/src/web/server.rs index 70a244f10..caacad52d 100644 --- a/rust-code-analysis-cli/src/web/server.rs +++ b/rust-code-analysis-cli/src/web/server.rs @@ -632,7 +632,7 @@ mod tests { "start_line": 1, "end_line": 4, "metrics": {"cyclomatic": {"sum": 2.0, "average": 1.0}, - "cognitive": 0.0, + "cognitive": {"sum": 0.0, "average": 0.0}, "nargs": 0., "nexits": 0., "halstead": {"bugs": 0.000_942_552_557_372_941_4, @@ -659,7 +659,7 @@ mod tests { "start_line": 3, "end_line": 4, "metrics": {"cyclomatic": {"sum": 1.0, "average": 1.0}, - "cognitive": 0.0, + "cognitive": {"sum": 0.0, "average": 0.0}, "nargs": 0., "nexits": 0., "halstead": {"bugs": 0.000_942_552_557_372_941_4, @@ -712,7 +712,7 @@ mod tests { "start_line": 1, "end_line": 2, "metrics": {"cyclomatic": {"sum": 2.0, "average": 1.0}, - "cognitive": 0.0, + "cognitive": {"sum": 0.0, "average": 0.0}, "nargs": 0., "nexits": 0., "halstead": {"bugs": 0.000_942_552_557_372_941_4, @@ -761,7 +761,7 @@ mod tests { "start_line": 1, "end_line": 2, "metrics": {"cyclomatic": {"sum": 2.0, "average": 1.0}, - "cognitive": 0.0, + "cognitive": {"sum": 0.0, "average": 0.0}, "nargs": 0., "nexits": 0., "halstead": {"bugs": 0.000_942_552_557_372_941_4, @@ -788,7 +788,7 @@ mod tests { "start_line": 1, "end_line": 2, "metrics": {"cyclomatic": {"sum": 1.0, "average": 1.0}, - "cognitive": 0.0, + "cognitive": {"sum": 0.0, "average": 0.0}, "nargs": 0., "nexits": 0., "halstead": {"bugs": 0.000_942_552_557_372_941_4, diff --git a/src/metrics/cognitive.rs b/src/metrics/cognitive.rs index d648933c2..ac42b8062 100644 --- a/src/metrics/cognitive.rs +++ b/src/metrics/cognitive.rs @@ -1,4 +1,4 @@ -use serde::ser::Serializer; +use serde::ser::{SerializeStruct, Serializer}; use serde::Serialize; use std::fmt; @@ -19,6 +19,7 @@ use crate::*; pub struct Stats { structural: usize, nesting: usize, + total_space_functions: usize, boolean_seq: BoolSequence, } @@ -27,6 +28,7 @@ impl Default for Stats { Self { structural: 0, nesting: 0, + total_space_functions: 1, boolean_seq: BoolSequence::default(), } } @@ -37,13 +39,21 @@ impl Serialize for Stats { where S: Serializer, { - serializer.serialize_f64(self.cognitive()) + let mut st = serializer.serialize_struct("cognitive", 2)?; + st.serialize_field("sum", &self.cognitive())?; + st.serialize_field("average", &self.cognitive_average())?; + st.end() } } impl fmt::Display for Stats { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}", self.cognitive()) + write!( + f, + "sum: {}, average: {}", + self.cognitive(), + self.cognitive_average() + ) } } @@ -57,6 +67,18 @@ impl Stats { pub fn cognitive(&self) -> f64 { self.structural as f64 } + + /// Returns the `Cognitive Complexity` metric average value + /// + /// This value is computed dividing the `Cognitive Complexity` value + /// for the total number of functions/closures in a space. + pub fn cognitive_average(&self) -> f64 { + self.cognitive() / self.total_space_functions as f64 + } + + pub(crate) fn finalize(&mut self, total_space_functions: usize) { + self.total_space_functions = total_space_functions; + } } #[doc(hidden)] @@ -405,7 +427,7 @@ mod tests { "foo.py", PythonParser, cognitive, - [(cognitive, 4, usize)] + [(cognitive, 4, usize), (cognitive_average, 4.0)] ); check_metrics!( @@ -420,7 +442,7 @@ mod tests { "foo.rs", RustParser, cognitive, - [(cognitive, 4, usize)] + [(cognitive, 4, usize), (cognitive_average, 4.0)] ); check_metrics!( @@ -435,7 +457,7 @@ mod tests { "foo.c", CppParser, cognitive, - [(cognitive, 4, usize)] + [(cognitive, 4, usize), (cognitive_average, 4.0)] ); check_metrics!( @@ -450,7 +472,7 @@ mod tests { "foo.js", MozjsParser, cognitive, - [(cognitive, 4, usize)] + [(cognitive, 4, usize), (cognitive_average, 4.0)] ); } @@ -463,7 +485,7 @@ mod tests { "foo.py", PythonParser, cognitive, - [(cognitive, 2, usize)] + [(cognitive, 2, usize), (cognitive_average, 2.0)] ); check_metrics!( @@ -475,7 +497,7 @@ mod tests { "foo.rs", RustParser, cognitive, - [(cognitive, 2, usize)] + [(cognitive, 2, usize), (cognitive_average, 2.0)] ); check_metrics!( @@ -487,7 +509,7 @@ mod tests { "foo.c", CppParser, cognitive, - [(cognitive, 2, usize)] + [(cognitive, 2, usize), (cognitive_average, 2.0)] ); check_metrics!( @@ -499,7 +521,7 @@ mod tests { "foo.js", MozjsParser, cognitive, - [(cognitive, 2, usize)] + [(cognitive, 2, usize), (cognitive_average, 2.0)] ); check_metrics!( @@ -511,7 +533,7 @@ mod tests { "foo.rs", RustParser, cognitive, - [(cognitive, 2, usize)] + [(cognitive, 2, usize), (cognitive_average, 2.0)] ); check_metrics!( @@ -523,7 +545,7 @@ mod tests { "foo.c", CppParser, cognitive, - [(cognitive, 2, usize)] + [(cognitive, 2, usize), (cognitive_average, 2.0)] ); check_metrics!( @@ -535,7 +557,7 @@ mod tests { "foo.js", MozjsParser, cognitive, - [(cognitive, 2, usize)] + [(cognitive, 2, usize), (cognitive_average, 2.0)] ); } @@ -550,7 +572,7 @@ mod tests { "foo.rs", RustParser, cognitive, - [(cognitive, 2, usize)] + [(cognitive, 2, usize), (cognitive_average, 2.0)] ); check_metrics!( @@ -562,7 +584,7 @@ mod tests { "foo.rs", RustParser, cognitive, - [(cognitive, 3, usize)] + [(cognitive, 3, usize), (cognitive_average, 3.0)] ); check_metrics!( @@ -574,7 +596,7 @@ mod tests { "foo.c", CppParser, cognitive, - [(cognitive, 3, usize)] + [(cognitive, 3, usize), (cognitive_average, 3.0)] ); check_metrics!( @@ -586,7 +608,7 @@ mod tests { "foo.js", MozjsParser, cognitive, - [(cognitive, 3, usize)] + [(cognitive, 3, usize), (cognitive_average, 3.0)] ); check_metrics!( @@ -598,7 +620,7 @@ mod tests { "foo.rs", RustParser, cognitive, - [(cognitive, 4, usize)] + [(cognitive, 4, usize), (cognitive_average, 4.0)] ); check_metrics!( @@ -610,7 +632,7 @@ mod tests { "foo.c", CppParser, cognitive, - [(cognitive, 4, usize)] + [(cognitive, 4, usize), (cognitive_average, 4.0)] ); check_metrics!( @@ -622,7 +644,7 @@ mod tests { "foo.js", MozjsParser, cognitive, - [(cognitive, 4, usize)] + [(cognitive, 4, usize), (cognitive_average, 4.0)] ); } @@ -635,7 +657,7 @@ mod tests { "foo.py", PythonParser, cognitive, - [(cognitive, 3, usize)] + [(cognitive, 3, usize), (cognitive_average, 3.0)] ); check_metrics!( @@ -647,7 +669,7 @@ mod tests { "foo.rs", RustParser, cognitive, - [(cognitive, 3, usize)] + [(cognitive, 3, usize), (cognitive_average, 3.0)] ); check_metrics!( @@ -659,7 +681,7 @@ mod tests { "foo.c", CppParser, cognitive, - [(cognitive, 3, usize)] + [(cognitive, 3, usize), (cognitive_average, 3.0)] ); check_metrics!( @@ -671,7 +693,7 @@ mod tests { "foo.js", MozjsParser, cognitive, - [(cognitive, 3, usize)] + [(cognitive, 3, usize), (cognitive_average, 3.0)] ); } @@ -687,7 +709,7 @@ mod tests { "foo.py", PythonParser, cognitive, - [(cognitive, 3, usize)] + [(cognitive, 3, usize), (cognitive_average, 3.0)] ); } @@ -701,7 +723,7 @@ mod tests { "foo.py", PythonParser, cognitive, - [(cognitive, 3, usize)] + [(cognitive, 3, usize), (cognitive_average, 3.0)] ); check_metrics!( @@ -723,7 +745,7 @@ mod tests { "foo.rs", RustParser, cognitive, - [(cognitive, 11, usize)] + [(cognitive, 11, usize), (cognitive_average, 11.0)] ); check_metrics!( @@ -745,7 +767,7 @@ mod tests { "foo.c", CppParser, cognitive, - [(cognitive, 11, usize)] + [(cognitive, 11, usize), (cognitive_average, 11.0)] ); check_metrics!( @@ -767,7 +789,7 @@ mod tests { "foo.js", MozjsParser, cognitive, - [(cognitive, 11, usize)] + [(cognitive, 11, usize), (cognitive_average, 11.0)] ); check_metrics!( @@ -782,7 +804,7 @@ mod tests { "foo.rs", RustParser, cognitive, - [(cognitive, 3, usize)] + [(cognitive, 3, usize), (cognitive_average, 3.0)] ); } @@ -797,7 +819,7 @@ mod tests { "foo.py", PythonParser, cognitive, - [(cognitive, 6, usize)] + [(cognitive, 6, usize), (cognitive_average, 6.0)] ); check_metrics!( @@ -814,7 +836,7 @@ mod tests { "foo.rs", RustParser, cognitive, - [(cognitive, 6, usize)] + [(cognitive, 6, usize), (cognitive_average, 6.0)] ); } @@ -831,11 +853,11 @@ mod tests { "foo.py", PythonParser, cognitive, - [(cognitive, 4, usize)] + [(cognitive, 4, usize), (cognitive_average, 4.0)] ); check_metrics!( - "asyncOnChannelRedirect(oldChannel, newChannel, flags, callback) { + "function asyncOnChannelRedirect(oldChannel, newChannel, flags, callback) { for (const collector of this.collectors) { try { collector._onChannelRedirect(oldChannel, newChannel, flags); @@ -851,7 +873,7 @@ mod tests { "foo.js", JavascriptParser, cognitive, - [(cognitive, 3, usize)] + [(cognitive, 3, usize), (cognitive_average, 3.0)] ); } @@ -877,7 +899,7 @@ mod tests { "foo.rs", RustParser, cognitive, - [(cognitive, 11, usize)] + [(cognitive, 11, usize), (cognitive_average, 11.0)] ); } @@ -896,7 +918,7 @@ mod tests { "foo.c", CppParser, cognitive, - [(cognitive, 7, usize)] + [(cognitive, 7, usize), (cognitive_average, 7.0)] ); } @@ -922,7 +944,7 @@ mod tests { "foo.c", CppParser, cognitive, - [(cognitive, 1, usize)] + [(cognitive, 1, usize), (cognitive_average, 1.0)] ); check_metrics!( @@ -945,7 +967,7 @@ mod tests { "foo.js", MozjsParser, cognitive, - [(cognitive, 1, usize)] + [(cognitive, 1, usize), (cognitive_average, 1.0)] ); } @@ -959,7 +981,7 @@ mod tests { "foo.py", PythonParser, cognitive, - [(cognitive, 4, usize)] + [(cognitive, 4, usize), (cognitive_average, 4.0)] ); } @@ -976,7 +998,8 @@ mod tests { "foo.py", PythonParser, cognitive, - [(cognitive, 5, usize)] + // 2 functions + 2 lamdas = 4 + [(cognitive, 5, usize), (cognitive_average, 1.25)] ); } @@ -1000,7 +1023,7 @@ mod tests { "foo.py", PythonParser, cognitive, - [(cognitive, 9, usize)] + [(cognitive, 9, usize), (cognitive_average, 9.0)] ); } } diff --git a/src/spaces.rs b/src/spaces.rs index d92b34c8c..50ea009b9 100644 --- a/src/spaces.rs +++ b/src/spaces.rs @@ -179,6 +179,15 @@ fn compute_halstead_and_mi<'a, T: ParserTrait>(state: &mut State<'a>) { ); } +#[inline(always)] +fn compute_average<'a>(state: &mut State<'a>) { + state + .space + .metrics + .cognitive + .finalize(state.space.metrics.nom.total() as usize); +} + fn finalize<'a, T: ParserTrait>(state_stack: &mut Vec>, diff_level: usize) { if state_stack.is_empty() { return; @@ -187,10 +196,12 @@ fn finalize<'a, T: ParserTrait>(state_stack: &mut Vec>, diff_level: us if state_stack.len() == 1 { let mut last_state = state_stack.last_mut().unwrap(); compute_halstead_and_mi::(&mut last_state); + compute_average(&mut last_state); break; } else { let mut state = state_stack.pop().unwrap(); compute_halstead_and_mi::(&mut state); + compute_average(&mut state); let mut last_state = state_stack.last_mut().unwrap(); last_state.halstead_maps.merge(&state.halstead_maps);