From d5f3f494b1f2cd67bf2badf02a824a6172971a94 Mon Sep 17 00:00:00 2001 From: Luni-4 Date: Thu, 16 Sep 2021 19:40:56 +0200 Subject: [PATCH 1/2] Rename fn_args to args --- src/metrics/mod.rs | 2 +- src/metrics/{fn_args.rs => nargs.rs} | 0 src/output/dump_metrics.rs | 4 ++-- src/spaces.rs | 6 +++--- src/traits.rs | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) rename src/metrics/{fn_args.rs => nargs.rs} (100%) diff --git a/src/metrics/mod.rs b/src/metrics/mod.rs index d16f0322a..49d52291c 100644 --- a/src/metrics/mod.rs +++ b/src/metrics/mod.rs @@ -1,8 +1,8 @@ pub mod cognitive; pub mod cyclomatic; pub mod exit; -pub mod fn_args; pub mod halstead; pub mod loc; pub mod mi; +pub mod nargs; pub mod nom; diff --git a/src/metrics/fn_args.rs b/src/metrics/nargs.rs similarity index 100% rename from src/metrics/fn_args.rs rename to src/metrics/nargs.rs diff --git a/src/output/dump_metrics.rs b/src/output/dump_metrics.rs index 286c13281..962ee04ca 100644 --- a/src/output/dump_metrics.rs +++ b/src/output/dump_metrics.rs @@ -4,10 +4,10 @@ use termcolor::{Color, ColorChoice, ColorSpec, StandardStream, StandardStreamLoc use crate::cognitive; use crate::cyclomatic; use crate::exit; -use crate::fn_args; use crate::halstead; use crate::loc; use crate::mi; +use crate::nargs; use crate::nom; use crate::spaces::{CodeMetrics, FuncSpace}; @@ -255,7 +255,7 @@ fn dump_mi( } fn dump_nargs( - stats: &fn_args::Stats, + stats: &nargs::Stats, prefix: &str, last: bool, stdout: &mut StandardStreamLock, diff --git a/src/spaces.rs b/src/spaces.rs index 26601e88f..6181c8c4d 100644 --- a/src/spaces.rs +++ b/src/spaces.rs @@ -8,11 +8,11 @@ use crate::node::Node; use crate::cognitive::{self, Cognitive}; use crate::cyclomatic::{self, Cyclomatic}; use crate::exit::{self, Exit}; -use crate::fn_args::{self, NArgs}; use crate::getter::Getter; use crate::halstead::{self, Halstead, HalsteadMaps}; use crate::loc::{self, Loc}; use crate::mi::{self, Mi}; +use crate::nargs::{self, NArgs}; use crate::nom::{self, Nom}; use crate::dump_metrics::*; @@ -60,7 +60,7 @@ impl fmt::Display for SpaceKind { #[derive(Debug, Clone, Serialize)] pub struct CodeMetrics { /// `NArgs` data - pub nargs: fn_args::Stats, + pub nargs: nargs::Stats, /// `NExits` data pub nexits: exit::Stats, pub cognitive: cognitive::Stats, @@ -85,7 +85,7 @@ impl Default for CodeMetrics { loc: loc::Stats::default(), nom: nom::Stats::default(), mi: mi::Stats::default(), - nargs: fn_args::Stats::default(), + nargs: nargs::Stats::default(), nexits: exit::Stats::default(), } } diff --git a/src/traits.rs b/src/traits.rs index f855da1da..c73350818 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -7,12 +7,12 @@ use crate::checker::Checker; use crate::cognitive::Cognitive; use crate::cyclomatic::Cyclomatic; use crate::exit::Exit; -use crate::fn_args::NArgs; use crate::getter::Getter; use crate::halstead::Halstead; use crate::langs::*; use crate::loc::Loc; use crate::mi::Mi; +use crate::nargs::NArgs; use crate::node::Node; use crate::nom::Nom; use crate::parser::Filter; From be5b6ba80dea22440dfe457aa1a393ebf85507ed Mon Sep 17 00:00:00 2001 From: Luni-4 Date: Thu, 16 Sep 2021 19:43:10 +0200 Subject: [PATCH 2/2] Count closures arguments for the NArgs metric --- rust-code-analysis-web/src/web/server.rs | 10 +- src/checker.rs | 2 +- src/metrics/nargs.rs | 640 +++++++++++++++++++++-- src/output/dump_metrics.rs | 11 +- src/spaces.rs | 8 +- 5 files changed, 613 insertions(+), 58 deletions(-) diff --git a/rust-code-analysis-web/src/web/server.rs b/rust-code-analysis-web/src/web/server.rs index 2d1bc3721..eafba9624 100644 --- a/rust-code-analysis-web/src/web/server.rs +++ b/rust-code-analysis-web/src/web/server.rs @@ -633,7 +633,7 @@ mod tests { "end_line": 4, "metrics": {"cyclomatic": {"sum": 2.0, "average": 1.0}, "cognitive": {"sum": 0.0, "average": 0.0}, - "nargs": {"sum": 0.0, "average": 0.0}, + "nargs": {"total_functions": 0.0, "average_functions": 0.0, "total_closures": 0.0, "average_closures": 0.0, "total": 0.0, "average": 0.0}, "nexits": {"sum": 0.0, "average": 0.0}, "halstead": {"bugs": 0.000_942_552_557_372_941_4, "difficulty": 1.0, @@ -660,7 +660,7 @@ mod tests { "end_line": 4, "metrics": {"cyclomatic": {"sum": 1.0, "average": 1.0}, "cognitive": {"sum": 0.0, "average": 0.0}, - "nargs": {"sum": 0.0, "average": 0.0}, + "nargs": {"total_functions": 0.0, "average_functions": 0.0, "total_closures": 0.0, "average_closures": 0.0, "total": 0.0, "average": 0.0}, "nexits": {"sum": 0.0, "average": 0.0}, "halstead": {"bugs": 0.000_942_552_557_372_941_4, "difficulty": 1.0, @@ -713,7 +713,7 @@ mod tests { "end_line": 2, "metrics": {"cyclomatic": {"sum": 2.0, "average": 1.0}, "cognitive": {"sum": 0.0, "average": 0.0}, - "nargs": {"sum": 0.0, "average": 0.0}, + "nargs": {"total_functions": 0.0, "average_functions": 0.0, "total_closures": 0.0, "average_closures": 0.0, "total": 0.0, "average": 0.0}, "nexits": {"sum": 0.0, "average": 0.0}, "halstead": {"bugs": 0.000_942_552_557_372_941_4, "difficulty": 1.0, @@ -762,7 +762,7 @@ mod tests { "end_line": 2, "metrics": {"cyclomatic": {"sum": 2.0, "average": 1.0}, "cognitive": {"sum": 0.0, "average": 0.0}, - "nargs": {"sum": 0.0, "average": 0.0}, + "nargs": {"total_functions": 0.0, "average_functions": 0.0, "total_closures": 0.0, "average_closures": 0.0, "total": 0.0, "average": 0.0}, "nexits": {"sum": 0.0, "average": 0.0}, "halstead": {"bugs": 0.000_942_552_557_372_941_4, "difficulty": 1.0, @@ -789,7 +789,7 @@ mod tests { "end_line": 2, "metrics": {"cyclomatic": {"sum": 1.0, "average": 1.0}, "cognitive": {"sum": 0.0, "average": 0.0}, - "nargs": {"sum": 0.0, "average": 0.0}, + "nargs": {"total_functions": 0.0, "average_functions": 0.0, "total_closures": 0.0, "average_closures": 0.0, "total": 0.0, "average": 0.0}, "nexits": {"sum": 0.0, "average": 0.0}, "halstead": {"bugs": 0.000_942_552_557_372_941_4, "difficulty": 1.0, diff --git a/src/checker.rs b/src/checker.rs index d450bcb52..5e54f3b55 100644 --- a/src/checker.rs +++ b/src/checker.rs @@ -351,5 +351,5 @@ impl Checker for RustCode { TraitItem, ClosureExpression ); - mk_checker!(is_non_arg, LPAREN, COMMA, RPAREN, AttributeItem); + mk_checker!(is_non_arg, LPAREN, COMMA, RPAREN, PIPE, AttributeItem); } diff --git a/src/metrics/nargs.rs b/src/metrics/nargs.rs index 94dd256c2..208c37a44 100644 --- a/src/metrics/nargs.rs +++ b/src/metrics/nargs.rs @@ -8,18 +8,22 @@ use crate::*; /// The `NArgs` metric. /// /// This metric counts the number of arguments -/// of a function/method. +/// of functions/closures. #[derive(Debug, Clone)] pub struct Stats { - nargs: usize, - total_space_functions: usize, + fn_nargs: usize, + closure_nargs: usize, + total_functions: usize, + total_closures: usize, } impl Default for Stats { fn default() -> Self { Self { - nargs: 0, - total_space_functions: 1, + fn_nargs: 0, + closure_nargs: 0, + total_functions: 0, + total_closures: 0, } } } @@ -29,8 +33,12 @@ impl Serialize for Stats { where S: Serializer, { - let mut st = serializer.serialize_struct("nargs", 2)?; - st.serialize_field("sum", &self.nargs())?; + let mut st = serializer.serialize_struct("nargs", 6)?; + st.serialize_field("total_functions", &self.fn_args())?; + st.serialize_field("total_closures", &self.closure_args())?; + st.serialize_field("average_functions", &self.fn_args_average())?; + st.serialize_field("average_closures", &self.closure_args_average())?; + st.serialize_field("total", &self.nargs_total())?; st.serialize_field("average", &self.nargs_average())?; st.end() } @@ -40,8 +48,12 @@ impl fmt::Display for Stats { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!( f, - "sum: {}, average: {}", - self.nargs(), + "total_functions: {}, total_closures: {}, average_functions: {}, average_closures: {}, total: {}, average: {}", + self.fn_args(), + self.closure_args(), + self.fn_args_average(), + self.closure_args_average(), + self.nargs_total(), self.nargs_average() ) } @@ -50,24 +62,65 @@ impl fmt::Display for Stats { impl Stats { /// Merges a second `NArgs` metric into the first one pub fn merge(&mut self, other: &Stats) { - self.nargs += other.nargs; + self.fn_nargs += other.fn_nargs; + self.closure_nargs += other.closure_nargs; } - /// Returns the `NArgs` metric value - pub fn nargs(&self) -> f64 { - self.nargs as f64 + /// Returns the number of function arguments in a space. + #[inline(always)] + pub fn fn_args(&self) -> f64 { + self.fn_nargs as f64 + } + + /// Returns the number of closure arguments in a space. + #[inline(always)] + pub fn closure_args(&self) -> f64 { + self.closure_nargs as f64 + } + + /// Returns the average number of functions arguments in a space. + #[inline(always)] + pub fn fn_args_average(&self) -> f64 { + self.fn_nargs as f64 / self.total_functions.max(1) as f64 + } + + /// Returns the average number of closures arguments in a space. + #[inline(always)] + pub fn closure_args_average(&self) -> f64 { + self.closure_nargs as f64 / self.total_closures.max(1) as f64 + } + + /// Returns the total number of arguments of each function and + /// closure in a space. + #[inline(always)] + pub fn nargs_total(&self) -> f64 { + self.fn_args() + self.closure_args() } /// Returns the `NArgs` metric average value /// /// This value is computed dividing the `NArgs` value /// for the total number of functions/closures in a space. + #[inline(always)] pub fn nargs_average(&self) -> f64 { - self.nargs() / self.total_space_functions as f64 + self.nargs_total() / (self.total_functions + self.total_closures).max(1) as f64 } - pub(crate) fn finalize(&mut self, total_space_functions: usize) { - self.total_space_functions = total_space_functions; + pub(crate) fn finalize(&mut self, total_functions: usize, total_closures: usize) { + self.total_functions = total_functions; + self.total_closures = total_closures; + } +} + +#[inline(always)] +fn compute_args(node: &Node, nargs: &mut usize) { + if let Some(params) = node.object().child_by_field_name("parameters") { + let node_params = Node::new(params); + node_params.act_on_child(&mut |n| { + if !T::is_non_arg(n) { + *nargs += 1; + } + }); } } @@ -75,50 +128,47 @@ impl Stats { pub trait NArgs where Self: Checker, + Self: std::marker::Sized, { fn compute(node: &Node, stats: &mut Stats) { - if !Self::is_func(node) { + if Self::is_func(node) { + compute_args::(node, &mut stats.fn_nargs); return; } - if let Some(params) = node.object().child_by_field_name("parameters") { - let node_params = Node::new(params); - node_params.act_on_child(&mut |n| { - if !Self::is_non_arg(n) { - stats.nargs += 1; - } - }); + if Self::is_closure(node) { + compute_args::(node, &mut stats.closure_nargs); } } } impl NArgs for CppCode { fn compute(node: &Node, stats: &mut Stats) { - if !Self::is_func(node) { + if Self::is_func(node) { + if let Some(declarator) = node.object().child_by_field_name("declarator") { + let new_node = Node::new(declarator); + compute_args::(&new_node, &mut stats.fn_nargs); + } return; } - if let Some(declarator) = node.object().child_by_field_name("declarator") { - if let Some(params) = declarator.child_by_field_name("parameters") { - let node_params = Node::new(params); - node_params.act_on_child(&mut |n| { - if !Self::is_non_arg(n) { - stats.nargs += 1; - } - }); + if Self::is_closure(node) { + if let Some(declarator) = node.object().child_by_field_name("declarator") { + let new_node = Node::new(declarator); + compute_args::(&new_node, &mut stats.closure_nargs); } } } } -impl NArgs for PythonCode {} impl NArgs for MozjsCode {} impl NArgs for JavascriptCode {} impl NArgs for TypescriptCode {} impl NArgs for TsxCode {} -impl NArgs for RustCode {} impl NArgs for PreprocCode {} impl NArgs for CcommentCode {} +impl NArgs for RustCode {} +impl NArgs for PythonCode {} impl NArgs for JavaCode {} #[cfg(test)] @@ -128,7 +178,87 @@ mod tests { use super::*; #[test] - fn test_function_nargs() { + fn python_no_functions_and_closures() { + check_metrics!( + "a = 42", + "foo.py", + PythonParser, + nargs, + [ + (fn_args, 0, usize), + (closure_args, 0, usize), + (nargs_total, 0, usize) + ], + [ + (fn_args_average, 0.0), + (closure_args_average, 0.0), + (nargs_average, 0.0) + ] // 0 functions + 0 closures = 0 + ); + } + + #[test] + fn rust_no_functions_and_closures() { + check_metrics!( + "let a = 42;", + "foo.rs", + RustParser, + nargs, + [ + (fn_args, 0, usize), + (closure_args, 0, usize), + (nargs_total, 0, usize) + ], + [ + (fn_args_average, 0.0), + (closure_args_average, 0.0), + (nargs_average, 0.0) + ] // 0 functions + 0 closures = 0 + ); + } + + #[test] + fn cpp_no_functions_and_closures() { + check_metrics!( + "int a = 42;", + "foo.cpp", + CppParser, + nargs, + [ + (fn_args, 0, usize), + (closure_args, 0, usize), + (nargs_total, 0, usize) + ], + [ + (fn_args_average, 0.0), + (closure_args_average, 0.0), + (nargs_average, 0.0) + ] // 0 functions + 0 closures = 0 + ); + } + + #[test] + fn javascript_no_functions_and_closures() { + check_metrics!( + "var a = 42;", + "foo.js", + JavascriptParser, + nargs, + [ + (fn_args, 0, usize), + (closure_args, 0, usize), + (nargs_total, 0, usize) + ], + [ + (fn_args_average, 0.0), + (closure_args_average, 0.0), + (nargs_average, 0.0) + ] // 0 functions + 0 closures = 0 + ); + } + + #[test] + fn python_single_function() { check_metrics!( "def f(a, b): if a: @@ -136,13 +266,171 @@ mod tests { "foo.py", PythonParser, nargs, - [(nargs, 2, usize)], - [(nargs_average, 2.0)] // 1 function + [ + (fn_args, 2, usize), + (closure_args, 0, usize), + (nargs_total, 2, usize) + ], + [ + (fn_args_average, 2.0), + (closure_args_average, 0.0), + (nargs_average, 2.0) + ] // 1 function + ); + } + + #[test] + fn rust_single_function() { + check_metrics!( + "fn f(a: bool, b: usize) { + if a { + return a; + } + }", + "foo.rs", + RustParser, + nargs, + [ + (fn_args, 2, usize), + (closure_args, 0, usize), + (nargs_total, 2, usize) + ], + [ + (fn_args_average, 2.0), + (closure_args_average, 0.0), + (nargs_average, 2.0) + ] // 1 function + ); + } + + #[test] + fn c_single_function() { + check_metrics!( + "int f(int a, int b) { + if (a) { + return a; + } + }", + "foo.c", + CppParser, + nargs, + [ + (fn_args, 2, usize), + (closure_args, 0, usize), + (nargs_total, 2, usize) + ], + [ + (fn_args_average, 2.0), + (closure_args_average, 0.0), + (nargs_average, 2.0) + ] // 1 function + ); + } + + #[test] + fn javascript_single_function() { + check_metrics!( + "function f(a, b) { + return a * b; + }", + "foo.js", + JavascriptParser, + nargs, + [ + (fn_args, 2, usize), + (closure_args, 0, usize), + (nargs_total, 2, usize) + ], + [ + (fn_args_average, 2.0), + (closure_args_average, 0.0), + (nargs_average, 2.0) + ] // 1 function + ); + } + + #[test] + fn python_single_lambda() { + check_metrics!( + "bar = lambda a: True", + "foo.py", + PythonParser, + nargs, + [ + (fn_args, 0, usize), + (closure_args, 1, usize), + (nargs_total, 1, usize) + ], + [ + (fn_args_average, 0.0), + (closure_args_average, 1.0), + (nargs_average, 1.0) + ] // 1 lambda + ); + } + + #[test] + fn rust_single_closure() { + check_metrics!( + "let bar = |i: i32| -> i32 { i + 1 };", + "foo.rs", + RustParser, + nargs, + [ + (fn_args, 0, usize), + (closure_args, 1, usize), + (nargs_total, 1, usize) + ], + [ + (fn_args_average, 0.0), + (closure_args_average, 1.0), + (nargs_average, 1.0) + ] // 1 lambda ); } #[test] - fn test_functions_nargs() { + fn cpp_single_lambda() { + check_metrics!( + "auto bar = [](int x, int y) -> int { return x + y; };", + "foo.cpp", + CppParser, + nargs, + [ + (fn_args, 0, usize), + (closure_args, 2, usize), + (nargs_total, 2, usize) + ], + [ + (fn_args_average, 0.0), + (closure_args_average, 2.0), + (nargs_average, 2.0) + ] // 1 lambda + ); + } + + #[test] + fn javascript_single_closure() { + check_metrics!( + "function (a, b) {return a + b};", + "foo.js", + JavascriptParser, + nargs, + [ + (fn_args, 0, usize), + (closure_args, 2, usize), + (nargs_total, 2, usize) + ], + [ + (fn_args_average, 0.0), + (closure_args_average, 2.0), + (nargs_average, 2.0) + ] // 1 lambda + ); + } + + #[test] + fn python_functions() { check_metrics!( "def f(a, b): if a: @@ -153,8 +441,16 @@ mod tests { "foo.py", PythonParser, nargs, - [(nargs, 4, usize)], - [(nargs_average, 2.0)] // 2 functions + [ + (fn_args, 4, usize), + (closure_args, 0, usize), + (nargs_total, 4, usize) + ], + [ + (fn_args_average, 2.0), + (closure_args_average, 0.0), + (nargs_average, 2.0) + ] // 2 functions ); check_metrics!( @@ -167,13 +463,178 @@ mod tests { "foo.py", PythonParser, nargs, - [(nargs, 5, usize)], - [(nargs_average, 2.5)] // 2 functions + [ + (fn_args, 5, usize), + (closure_args, 0, usize), + (nargs_total, 5, usize) + ], + [ + (fn_args_average, 2.5), + (closure_args_average, 0.0), + (nargs_average, 2.5) + ] // 2 functions ); } #[test] - fn test_nested_functions_nargs() { + fn rust_functions() { + check_metrics!( + "fn f(a: bool, b: usize) { + if a { + return a; + } + } + fn f1(a: bool, b: usize) { + if a { + return a; + } + }", + "foo.rs", + RustParser, + nargs, + [ + (fn_args, 4, usize), + (closure_args, 0, usize), + (nargs_total, 4, usize) + ], + [ + (fn_args_average, 2.0), + (closure_args_average, 0.0), + (nargs_average, 2.0) + ] // 2 functions + ); + + check_metrics!( + "fn f(a: bool, b: usize) { + if a { + return a; + } + } + fn f1(a: bool, b: usize, c: usize) { + if a { + return a; + } + }", + "foo.rs", + RustParser, + nargs, + [ + (fn_args, 5, usize), + (closure_args, 0, usize), + (nargs_total, 5, usize) + ], + [ + (fn_args_average, 2.5), + (closure_args_average, 0.0), + (nargs_average, 2.5) + ] // 2 functions + ); + } + + #[test] + fn c_functions() { + check_metrics!( + "int f(int a, int b) { + if (a) { + return a; + } + } + int f1(int a, int b) { + if (a) { + return a; + } + }", + "foo.c", + CppParser, + nargs, + [ + (fn_args, 4, usize), + (closure_args, 0, usize), + (nargs_total, 4, usize) + ], + [ + (fn_args_average, 2.0), + (closure_args_average, 0.0), + (nargs_average, 2.0) + ] // 2 functions + ); + + check_metrics!( + "int f(int a, int b) { + if (a) { + return a; + } + } + int f1(int a, int b, int c) { + if (a) { + return a; + } + }", + "foo.c", + CppParser, + nargs, + [ + (fn_args, 5, usize), + (closure_args, 0, usize), + (nargs_total, 5, usize) + ], + [ + (fn_args_average, 2.5), + (closure_args_average, 0.0), + (nargs_average, 2.5) + ] // 2 functions + ); + } + + #[test] + fn javascript_functions() { + check_metrics!( + "function f(a, b) { + return a * b; + } + function f1(a, b) { + return a * b; + }", + "foo.js", + JavascriptParser, + nargs, + [ + (fn_args, 4, usize), + (closure_args, 0, usize), + (nargs_total, 4, usize) + ], + [ + (fn_args_average, 2.0), + (closure_args_average, 0.0), + (nargs_average, 2.0) + ] // 2 functions + ); + + check_metrics!( + "function f(a, b) { + return a * b; + } + function f1(a, b, c) { + return a * b; + }", + "foo.js", + JavascriptParser, + nargs, + [ + (fn_args, 5, usize), + (closure_args, 0, usize), + (nargs_total, 5, usize) + ], + [ + (fn_args_average, 2.5), + (closure_args_average, 0.0), + (nargs_average, 2.5) + ] // 2 functions + ); + } + + #[test] + fn python_nested_functions() { check_metrics!( "def f(a, b): def foo(a): @@ -184,9 +645,94 @@ mod tests { "foo.py", PythonParser, nargs, - // FIXME: Consider lambda arguments also - [(nargs, 3, usize)], - [(nargs_average, 0.75)] // 2 functions + 2 lambdas = 4 + [ + (fn_args, 3, usize), + (closure_args, 2, usize), + (nargs_total, 5, usize) + ], + [ + (fn_args_average, 1.5), + (closure_args_average, 1.0), + (nargs_average, 1.25) + ] // 2 functions + 2 lambdas = 4 + ); + } + + #[test] + fn rust_nested_functions() { + check_metrics!( + "fn f(a: i32, b: i32) -> i32 { + fn foo(a: i32) -> i32 { + return a; + } + let bar = |a: i32, b: i32| -> i32 { a + 1 }; + let bar1 = |b: i32| -> i32 { b + 1 }; + return bar(foo(a), a); + }", + "foo.rs", + RustParser, + nargs, + [ + (fn_args, 3, usize), + (closure_args, 3, usize), + (nargs_total, 6, usize) + ], + [ + (fn_args_average, 1.5), + (closure_args_average, 1.5), + (nargs_average, 1.5) + ] // 2 functions + 2 lambdas = 4 + ); + } + + #[test] + fn cpp_nested_functions() { + check_metrics!( + "int f(int a, int b, int c) { + auto foo = [](int x) -> int { return x; }; + auto bar = [](int x, int y) -> int { return x + y; }; + return bar(foo(a), a); + }", + "foo.cpp", + CppParser, + nargs, + [ + (fn_args, 3, usize), + (closure_args, 3, usize), + (nargs_total, 6, usize) + ], + [ + (fn_args_average, 3.0), + (closure_args_average, 1.5), + (nargs_average, 2.0) + ] // 1 function + 2 lambdas = 3 + ); + } + + #[test] + fn javascript_nested_functions() { + check_metrics!( + "function f(a, b) { + function foo(a, c) { + return a; + } + var bar = function (a, b) {return a + b}; + function (a) {return a}; + return bar(foo(a), a); + }", + "foo.js", + JavascriptParser, + nargs, + [ + (fn_args, 6, usize), + (closure_args, 1, usize), + (nargs_total, 7, usize) + ], + [ + (fn_args_average, 2.), + (closure_args_average, 1.), + (nargs_average, 1.75) + ] // 3 functions + 1 lambdas = 4 ); } } diff --git a/src/output/dump_metrics.rs b/src/output/dump_metrics.rs index 962ee04ca..fbb671e00 100644 --- a/src/output/dump_metrics.rs +++ b/src/output/dump_metrics.rs @@ -260,16 +260,19 @@ fn dump_nargs( last: bool, stdout: &mut StandardStreamLock, ) -> std::io::Result<()> { - let pref = if last { "`- " } else { "|- " }; + let (pref_child, pref) = if last { (" ", "`- ") } else { ("| ", "|- ") }; color!(stdout, Blue); write!(stdout, "{}{}", prefix, pref)?; color!(stdout, Green, true); - write!(stdout, "nargs: ")?; + writeln!(stdout, "nargs")?; - color!(stdout, White); - writeln!(stdout, "{}", stats.nargs()) + let prefix = format!("{}{}", prefix, pref_child); + dump_value("functions", stats.fn_args(), &prefix, false, stdout)?; + dump_value("closures", stats.closure_args(), &prefix, false, stdout)?; + dump_value("total", stats.nargs_total(), &prefix, false, stdout)?; + dump_value("average", stats.nargs_average(), &prefix, true, stdout) } fn dump_nexits( diff --git a/src/spaces.rs b/src/spaces.rs index 6181c8c4d..2f9455623 100644 --- a/src/spaces.rs +++ b/src/spaces.rs @@ -181,13 +181,19 @@ fn compute_halstead_and_mi(state: &mut State) { #[inline(always)] fn compute_averages(state: &mut State) { + let nom_functions = state.space.metrics.nom.functions() as usize; + let nom_closures = state.space.metrics.nom.closures() as usize; let nom_total = state.space.metrics.nom.total() as usize; // Cognitive average state.space.metrics.cognitive.finalize(nom_total); // Nexit average state.space.metrics.nexits.finalize(nom_total); // Nargs average - state.space.metrics.nargs.finalize(nom_total); + state + .space + .metrics + .nargs + .finalize(nom_functions, nom_closures); } fn finalize(state_stack: &mut Vec, diff_level: usize) {