Skip to content

Commit

Permalink
Fix a corner case for blank metric
Browse files Browse the repository at this point in the history
  • Loading branch information
Luni-4 committed Mar 26, 2021
1 parent 6cb2b3f commit c659a51
Showing 1 changed file with 180 additions and 17 deletions.
197 changes: 180 additions & 17 deletions src/metrics/loc.rs
Expand Up @@ -14,7 +14,8 @@ pub struct Stats {
unit: bool,
lines: FxHashSet<usize>,
logical_lines: usize,
comment_lines: usize,
single_comment_lines: usize,
no_single_comment_lines: usize,
}

impl Serialize for Stats {
Expand Down Expand Up @@ -58,7 +59,8 @@ impl Stats {
self.logical_lines += other.logical_lines;

// Merge cloc lines
self.comment_lines += other.comment_lines;
self.single_comment_lines += other.single_comment_lines;
self.no_single_comment_lines += other.no_single_comment_lines;
}

/// The `Sloc` metric.
Expand Down Expand Up @@ -104,20 +106,15 @@ impl Stats {
pub fn cloc(&self) -> f64 {
// Comments are counted regardless of their placement
// https://en.wikipedia.org/wiki/Source_lines_of_code
self.comment_lines as f64
(self.single_comment_lines + self.no_single_comment_lines) as f64
}

/// The `Blank` metric.
///
/// Counts the number of blank lines in a scope
#[inline(always)]
pub fn blank(&self) -> f64 {
// This metric counts the number of blank lines in a code
// The if construct is needed because sometimes lloc and cloc
// coincide on the same lines, in that case lloc + cloc could be greater
// than the number of lines of a file.
let blank = self.sloc() - self.ploc() - self.cloc();
blank.max(0.0)
self.sloc() - self.ploc() - self.single_comment_lines as f64
}
}

Expand All @@ -142,6 +139,20 @@ fn init(node: &Node, stats: &mut Stats, is_func_space: bool, is_unit: bool) -> (
(start, end)
}

#[inline(always)]
// This function discriminates among the comments that are next to code lines and
// the ones that are on a single line. This difference is necessary in
// order to avoid having a wrong count for the blank metric.
fn cloc_lines(stats: &mut Stats, start: usize, end: usize) {
if stats.lines.contains(&start) {
// Comment next to a code line
stats.no_single_comment_lines += (end - start) + 1;
} else {
// Comment on a single line
stats.single_comment_lines += (end - start) + 1;
}
}

impl Loc for PythonCode {
fn compute(node: &Node, stats: &mut Stats, is_func_space: bool, is_unit: bool) {
use Python::*;
Expand All @@ -151,12 +162,12 @@ impl Loc for PythonCode {
match node.object().kind_id().into() {
DQUOTE | DQUOTE2 | Block | Module => {}
Comment => {
stats.comment_lines += (end - start) + 1;
cloc_lines(stats, start, end);
}
String => {
let parent = node.object().parent().unwrap();
if let ExpressionStatement = parent.kind_id().into() {
stats.comment_lines += (end - start) + 1;
cloc_lines(stats, start, end);
} else if parent.start_position().row != start {
stats.lines.insert(start);
}
Expand Down Expand Up @@ -201,7 +212,7 @@ impl Loc for MozjsCode {
match node.object().kind_id().into() {
String | DQUOTE | Program => {}
Comment => {
stats.comment_lines += (end - start) + 1;
cloc_lines(stats, start, end);
}
ExpressionStatement | ExportStatement | ImportStatement | StatementBlock
| IfStatement | SwitchStatement | ForStatement | ForInStatement | WhileStatement
Expand All @@ -226,7 +237,7 @@ impl Loc for JavascriptCode {
match node.object().kind_id().into() {
String | DQUOTE | Program => {}
Comment => {
stats.comment_lines += (end - start) + 1;
cloc_lines(stats, start, end);
}
ExpressionStatement | ExportStatement | ImportStatement | StatementBlock
| IfStatement | SwitchStatement | ForStatement | ForInStatement | WhileStatement
Expand All @@ -251,7 +262,7 @@ impl Loc for TypescriptCode {
match node.object().kind_id().into() {
String | DQUOTE | Program => {}
Comment => {
stats.comment_lines += (end - start) + 1;
cloc_lines(stats, start, end);
}
ExpressionStatement | ExportStatement | ImportStatement | StatementBlock
| IfStatement | SwitchStatement | ForStatement | ForInStatement | WhileStatement
Expand All @@ -276,7 +287,7 @@ impl Loc for TsxCode {
match node.object().kind_id().into() {
String | DQUOTE | Program => {}
Comment => {
stats.comment_lines += (end - start) + 1;
cloc_lines(stats, start, end);
}
ExpressionStatement | ExportStatement | ImportStatement | StatementBlock
| IfStatement | SwitchStatement | ForStatement | ForInStatement | WhileStatement
Expand All @@ -301,7 +312,7 @@ impl Loc for RustCode {
match node.object().kind_id().into() {
StringLiteral | RawStringLiteral | Block | SourceFile => {}
LineComment | BlockComment => {
stats.comment_lines += (end - start) + 1;
cloc_lines(stats, start, end);
}
Statement
| EmptyStatement
Expand Down Expand Up @@ -358,7 +369,7 @@ impl Loc for CppCode {
RawStringLiteral | StringLiteral | DeclarationList | FieldDeclarationList
| TranslationUnit => {}
Comment => {
stats.comment_lines += (end - start) + 1;
cloc_lines(stats, start, end);
}
WhileStatement | SwitchStatement | CaseStatement | IfStatement | ForStatement
| ReturnStatement | BreakStatement | ContinueStatement | GotoStatement
Expand Down Expand Up @@ -457,6 +468,158 @@ mod tests {
);
}

#[test]
fn python_zero_blank() {
check_metrics!(
"def ConnectToUpdateServer():
pool = 4
updateServer = -42
isConnected = False
currTry = 0
numRetries = 10 # Number of IPC connection retries before
# giving up.
numTries = 20 # Number of IPC connection tries before
# giving up.",
"foo.py",
PythonParser,
loc,
[
(sloc, 10, usize), // The number of lines is 10
(ploc, 7, usize), // The number of code lines is 7
(cloc, 4, usize), // The number of comments is 4
(blank, 1, usize) // The number of blank lines is 1
]
);
}

#[test]
fn python_no_blank() {
check_metrics!(
"def ConnectToUpdateServer():
pool = 4
updateServer = -42
isConnected = False
currTry = 0
numRetries = 10 # Number of IPC connection retries before
# giving up.
numTries = 20 # Number of IPC connection tries before
# giving up.",
"foo.py",
PythonParser,
loc,
[
(sloc, 9, usize), // The number of lines is 9
(ploc, 7, usize), // The number of code lines is 7
(cloc, 4, usize), // The number of comments is 4
(blank, 0, usize) // The number of blank lines is 0
]
);
}

#[test]
fn python_zero_blank_more_comments() {
check_metrics!(
"def ConnectToUpdateServer():
pool = 4
updateServer = -42
isConnected = False
currTry = 0 # Set this variable to 0
numRetries = 10 # Number of IPC connection retries before
# giving up.
numTries = 20 # Number of IPC connection tries before
# giving up.",
"foo.py",
PythonParser,
loc,
[
(sloc, 10, usize), // The number of lines is 10
(ploc, 7, usize), // The number of code lines is 7
(cloc, 5, usize), // The number of comments is 5
(blank, 1, usize) // The number of blank lines is 1
]
);
}

#[test]
fn rust_zero_blank() {
check_metrics!(
"fn ConnectToUpdateServer() {
let pool = 0;
let updateServer = -42;
let isConnected = false;
let currTry = 0;
let numRetries = 10; // Number of IPC connection retries before
// giving up.
let numTries = 20; // Number of IPC connection tries before
// giving up.
}",
"foo.rs",
RustParser,
loc,
[
(sloc, 11, usize), // The number of lines is 11
(ploc, 8, usize), // The number of code lines is 8
(cloc, 4, usize), // The number of comments is 4
(blank, 1, usize) // The number of blank lines is 1
]
);
}

#[test]
fn javascript_zero_blank() {
check_metrics!(
"function ConnectToUpdateServer() {
var pool = 0;
var updateServer = -42;
var isConnected = false;
var currTry = 0;
var numRetries = 10; // Number of IPC connection retries before
// giving up.
var numTries = 20; // Number of IPC connection tries before
// giving up.
}",
"foo.js",
JavascriptParser,
loc,
[
(sloc, 11, usize), // The number of lines is 11
(ploc, 8, usize), // The number of code lines is 8
(cloc, 4, usize), // The number of comments is 4
(blank, 1, usize) // The number of blank lines is 1
]
);
}

#[test]
fn cpp_zero_blank() {
check_metrics!(
"void ConnectToUpdateServer() {
int pool;
int updateServer = -42;
bool isConnected = false;
int currTry = 0;
const int numRetries = 10; // Number of IPC connection retries before
// giving up.
const int numTries = 20; // Number of IPC connection tries before
// giving up.
}",
"foo.cpp",
CppParser,
loc,
[
(sloc, 11, usize), // The number of lines is 11
(ploc, 8, usize), // The number of code lines is 8
(cloc, 4, usize), // The number of comments is 4
(blank, 1, usize) // The number of blank lines is 1
]
);
}

#[test]
fn python_cloc() {
check_metrics!(
Expand Down

0 comments on commit c659a51

Please sign in to comment.