fzipp / gocyclo

Calculate cyclomatic complexities of functions in Go source code.
BSD 3-Clause "New" or "Revised" License
1.35k stars 80 forks source link

proper counting of switch/case/default control structures #15

Closed paulbuis closed 3 years ago

paulbuis commented 7 years ago

gocyclo simply counts ast.CaseClause nodes to compute the cyclomatic complexity of a switch/case with optional default. The the default case should be counted even if it is absent (in which case we can ignore it if it is present and count the ast.SwitchStmt node instead) or maybe it should be ignored when it is present. I suppose ignoring it would be equivalent to not counting the else in an if/else.

The way the code is now is simple and elegant and I doubt the occasional off-by-one is a big deal.

There may be a similar issue with select statement and ast.CommClause nodes, but I haven't looked at that as closely.

paulbuis commented 7 years ago

Perhaps something like this modification would deal with this issue?

func (v *complexityVisitor) Visit(n ast.Node) ast.Visitor {
    switch n := n.(type) {
    case *ast.FuncDecl, *ast.FuncLit, *ast.IfStmt, *ast.ForStmt, *ast.RangeStmt:
        v.Complexity++
    case *ast.CaseClause: 
        if n.List != nil { // ignore default case
            v.Complexity++
        }
    case *ast.CommClause:
        if n.Stmt != nil { // ignore default case
            v.Complexity++
        }
    case *ast.BinaryExpr:
        if n.Op == token.LAND || n.Op == token.LOR {
            v.Complexity++
        }
    }
    return v
}