Skip to content

Commit 7cfa5e3

Browse files
authored
Fix calculation of FUNC_NESTING (#138)
* Correct depth counting Closes #133
1 parent c32f8f5 commit 7cfa5e3

File tree

6 files changed

+232
-6
lines changed

6 files changed

+232
-6
lines changed

src/MetricUtils.cpp

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,29 +10,46 @@
1010

1111
const SourceFileAndLine_t InvalidSourceAndLine = {false, 0, "", 0};
1212

13-
unsigned getControlDepth(const clang::Stmt *const p_stmt, clang::ASTContext *p_context) {
13+
bool isStmtAnIfFromElseIf(const clang::Stmt *const p_parentStmt, const clang::Stmt * const p_stmt) {
14+
if (p_parentStmt->getStmtClass() == clang::Stmt::IfStmtClass) {
15+
const clang::Stmt *elseStmt = static_cast<const clang::IfStmt *>(p_parentStmt)->getElse();
16+
if ((elseStmt == p_stmt) && (elseStmt->getStmtClass() == clang::Stmt::IfStmtClass)) {
17+
return true;
18+
}
19+
}
20+
return false;
21+
}
22+
23+
unsigned getControlDepth(const clang::Stmt *const p_stmt, clang::ASTContext *p_context,
24+
const bool p_childIsElseIf) {
1425
unsigned ret_val = 0;
1526

1627
clang::SourceLocation loc, sloc;
1728

1829
/* Examine all the parents */
1930
for (const auto &Parent : p_context->getParents(*p_stmt)) {
20-
/* Is the parent a Stmt? */
2131
const clang::Stmt *stmt = Parent.get<clang::Stmt>();
2232
if (stmt != NULL) {
23-
ret_val += getControlDepth(stmt, p_context);
33+
ret_val += getControlDepth(stmt, p_context, isStmtAnIfFromElseIf(stmt, p_stmt));
2434
}
2535
}
2636

2737
switch (p_stmt->getStmtClass()) {
28-
case clang::Stmt::IfStmtClass:
38+
case clang::Stmt::IfStmtClass: {
39+
/* We don't count "else if"s as increasing the depth, as the original "if" will already
40+
have done that */
41+
if (!p_childIsElseIf) {
42+
ret_val++;
43+
}
44+
}
45+
break;
2946
case clang::Stmt::SwitchStmtClass:
3047
case clang::Stmt::DoStmtClass:
3148
case clang::Stmt::WhileStmtClass:
3249
case clang::Stmt::ForStmtClass:
3350
ret_val += 1;
3451
#if 0
35-
std::cout << p_stmt->getStmtClassName() << ": " << ret_val << "\n";
52+
std::cout << "getControlDepth : " << p_stmt->getStmtClassName() << ": " << ret_val << "\n";
3653
#endif
3754
break;
3855
default:

src/MetricUtils.hpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@
2727
#include "MetricUnit.hpp"
2828
#include "clang/AST/ASTContext.h"
2929

30-
extern unsigned getControlDepth(const clang::Stmt *const p_stmt, clang::ASTContext *p_context);
30+
extern unsigned getControlDepth(const clang::Stmt *const p_stmt, clang::ASTContext *p_context,
31+
const bool p_childIsElseIf = false);
3132
extern size_t countNewlines(clang::StringRef &p_buffer);
3233
std::string makeRelative(const std::string &p_path);
3334
std::string makeRelative(const std::string &p_path, const std::string &p_cwd);

test/src/nesting.c

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
#include "nesting.h"
2+
3+
#if 0
4+
void dummy(void) {
5+
unsigned j;
6+
7+
NEST_MACRO(1, 2, j);
8+
}
9+
10+
#endif
11+
12+
unsigned elifer(unsigned x, unsigned y, unsigned z) {
13+
unsigned ret = 0;
14+
15+
if (x < 10) {
16+
/* Nesting level 1 */
17+
ret = 0;
18+
} else if (x > 100) {
19+
/* Nesting level 1 */
20+
if (y) {
21+
/* Nesting level 2 */
22+
ret = 100;
23+
} else if (z) {
24+
/* Nesting level 2 */
25+
ret = 200;
26+
}
27+
} else {
28+
/* Nesting level 1 */
29+
ret = 50;
30+
}
31+
32+
return ret;
33+
}
34+
35+
unsigned singleIf(unsigned y) {
36+
unsigned ret = 0;
37+
if (y) {
38+
ret = 1;
39+
}
40+
return ret;
41+
}
42+
43+
void else_ifs(int i){
44+
if (i == 1){
45+
/* Nesting level 1 */
46+
}
47+
else if (i == 2){
48+
/* Nesting level 1 */
49+
}
50+
else if (i == 3){
51+
/* Nesting level 1 */
52+
}
53+
else if (i == 4){
54+
/* Nesting level 1 */
55+
}
56+
else if (i == 5){
57+
/* Nesting level 1 */
58+
}
59+
}
60+
61+
void else_then_ifs(int i){
62+
if (i == 1){
63+
/* Nesting level 1 */
64+
}
65+
else {
66+
if (i == 2){
67+
/* Nesting level 2 */
68+
}
69+
else {
70+
if (i == 3){
71+
/* Nesting level 3 */
72+
}
73+
else {
74+
if (i == 4){
75+
/* Nesting level 4 */
76+
}
77+
else {
78+
if (i == 5){
79+
/* Nesting level 5 */
80+
}
81+
}
82+
}
83+
}
84+
}
85+
}
86+
87+
unsigned elser(unsigned x, unsigned y, unsigned z) {
88+
unsigned ret = 0;
89+
if (x) {
90+
/* Nesting level 1 */
91+
ret = 1;
92+
} else {
93+
/* Nesting level 1 */
94+
ret = 2;
95+
if (y) {
96+
/* Nesting level 2 */
97+
ret = 2;
98+
} else {
99+
ret = 6;
100+
/* Nesting level 2 */
101+
if (z) {
102+
/* Nesting level 3 */
103+
ret = 3;
104+
} else {
105+
/* Nesting level 3 */
106+
do {
107+
/* Nesting level 4 */
108+
ret = 4;
109+
} while (0);
110+
}
111+
}
112+
}
113+
/* Make sure that a 1-level nest at the end of the function doesn't
114+
effect a previously accumulated maximum nest level */
115+
if (y > ret) {
116+
ret = 0;
117+
}
118+
return ret;
119+
}
120+
121+
#if 0
122+
int main(void) {
123+
unsigned x = 0;
124+
125+
NEST_MACRO(1, 5, x);
126+
return x;
127+
}
128+
#endif

test/src/nesting.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#if !defined NESTING_H
2+
#define NESTING_H
3+
4+
#define NEST_MACRO(x, y, z) \
5+
do { \
6+
if (x) { \
7+
if (y) { \
8+
z = 0; \
9+
} \
10+
} \
11+
} while (0)
12+
13+
#endif

test/src/nesting2.c

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
#include "nesting.h"
2+
3+
unsigned something(unsigned x, unsigned y, unsigned z) {
4+
unsigned ret = 0;
5+
if (x) {
6+
/* Nesting level 1 */
7+
switch (y) {
8+
case 1:
9+
/* Nesting level 2 */
10+
if (z) {
11+
/* Nesting Level 3 */
12+
ret = 4;
13+
}
14+
break;
15+
default:
16+
/* Nesting level 2 */
17+
if (z > 5) {
18+
/* Nesting level 3 */
19+
if (z < 10) {
20+
/* Nesting level 4 */
21+
while (ret < 100) {
22+
unsigned i;
23+
/* Nesting level 5 */
24+
ret += z;
25+
for (i = 0; i < y; i++) {
26+
/* Nesting level 6 */
27+
do {
28+
/* Nesting level 7 */
29+
ret += 1;
30+
ret *= 2;
31+
} while (ret);
32+
}
33+
}
34+
}
35+
}
36+
break;
37+
}
38+
}
39+
return ret;
40+
}

test/tests/nesting.bats

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
load test_helper.bash
2+
3+
EXPECTED=$(cat <<EOF
4+
Global
5+
File: src\nesting.c
6+
Function: elifer
7+
Nesting Level: 2
8+
Function: else_ifs
9+
Nesting Level: 1
10+
Function: else_then_ifs
11+
Nesting Level: 5
12+
Function: elser
13+
Nesting Level: 4
14+
Function: singleIf
15+
Nesting Level: 1
16+
File: src\nesting.h
17+
File: src\nesting2.c
18+
Function: something
19+
Nesting Level: 7
20+
EOF
21+
)
22+
23+
@test "Function Nesting" {
24+
run $CCSM_EXE $TEST_SOURCE_DIR/nesting.c $TEST_SOURCE_DIR/nesting2.c --output-metrics=FUNC_NESTING --
25+
assert_success
26+
assert_ccsm_output "$EXPECTED"
27+
}

0 commit comments

Comments
 (0)