Closed t-b closed 1 year ago
It will begin by adding 1 point for the function declaration, after that it will add 1 point for every
if
,while
,for
andcase
.
I don't want to just accept this solution (it seems more like a hack), so I will try to prove it. According to your Wikipedia link the cyclomatic complexity is calculated like this:
M=E-N+2P
where,
The directed graph contains all single instructions including function definition as single nodes and the possible control flow is represented as directed edges between these nodes. An empty function has only a single node and one connected component: M=0-1+2*1=1
. Fine.
All of our instructions does only change the number of nodes and edges and do not add more connected components. In the result we will only have one connected component so we can fix the number P
at 1.
All normal instructions that have no influence to the control flow introduces one node and one edge into the graph which results in no difference to M
. We can ignore them.
The atomic if
instruction introduces three nodes (if-statement, true-case, false-case) and four edges (from if to true/false, from true/false to next node). This will change M
by 4-3+2*0=1
.
An atomic while
instruction introduces two nodes (while, body) and three edges (from while to body, from body to while, from while to next node). This will change M
by 3-2+2*0=1
An atomic do-while
instruction introduces three nodes (do-statement, body, while-check) and four edges (do-statement to body, body to while-check, while-check to do-statement, while-check to next node). This will change M
by 4-3+2*0=1
.
An atomic for
instruction introduces two nodes (for, body) and three edges (from for to body, from body to for, from for to next node). This will change M
by 3-2+2*0=1
.
A switch
instruction is like a list of n
if
-instructions. n
is the same number of the case
instructions. So, we only need to count the number of case
and add one for each.
A normal if
, while
, do-while
and for
statement can contain more than one conditions combined with &&
or ||
. Each condition has to be counted separately as they can be rewritten as nested if-statements. The number of conditions is the same number of atomic if
-statements.
From Wikipedia: However, this is true only for decision points counted at the lowest, machine-level instructions.[4] Decisions involving compound predicates like those found in high-level languages like IF cond1 AND cond2 THEN ... should be counted in terms of predicate variables involved, i.e. in this example one should count two decision points, because at machine level it is equivalent to IF cond1 THEN IF cond2 THEN ...
In the result. I mostly agree with your simplification but we need to count the number of conditions inside if
, while
and for
. As long as there is no better solution we can hack this by counting the number of &&
and ||
and add one to it.
We also need to count the ternary operator cond ? a : b
as they can be rewritten to an if
-statement. Doing this we also have to count SelectString(cond, b, a)
as this is the ternary operator variant for strings.
Very nice derivation! There is also SelectNumber
btw.
Thinking about this, this can be done with a set of regular expressions. There is no need for an Igor parser & lexer. To prevent wrong matches with strings we can add a preprocess to remove the content of strings:
// original line
string op = SelectString(condition, "||", "&&")
// preprocessed line
string op = SelectString(condition, "", "")
We are only interested in the number of (?<!\w)if\s*\(
, (?<!\w)while\s*\(
, (?<!\w)for\s*\(
, (?<!\w)case\s*:
, &&
, \|\|
, \?
, (?<!\w)SelectString\s*\(
, (?<!\w)SelectNumber\s*\(
matches and therefore is the content of strings irrelevant.
I would think that try/catch
is also a condition or?
See https://en.wikipedia.org/wiki/Cyclomatic_complexity.
According to 1 this is "just"