Skip to content

Commit 2df749d

Browse files
committed
fix: refactor + improve metrics
1 parent 322d624 commit 2df749d

File tree

5 files changed

+485
-178
lines changed

5 files changed

+485
-178
lines changed

analyzer/analyzer.go

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
package analyzer
2+
3+
import (
4+
"go/ast"
5+
"go/parser"
6+
"go/token"
7+
"math"
8+
)
9+
10+
// FileAnalyzer represents a file analyzer.
11+
type FileAnalyzer struct {
12+
fset *token.FileSet
13+
ast *ast.File
14+
}
15+
16+
func NewFileAnalyzer(filename string, content []byte) (*FileAnalyzer, error) {
17+
fset := token.NewFileSet()
18+
node, err := parser.ParseFile(fset, filename, content, parser.ParseComments)
19+
if err != nil {
20+
return nil, err
21+
}
22+
23+
return &FileAnalyzer{
24+
fset: fset,
25+
ast: node,
26+
}, nil
27+
}
28+
29+
// AnalyzeFunction analyzes a function declaration and returns the metrics.
30+
func (fa *FileAnalyzer) AnalyzeFunction(funcDecl *ast.FuncDecl) *MetricsResult {
31+
if funcDecl == nil || funcDecl.Name == nil {
32+
return nil
33+
}
34+
35+
cyclomaticComplexity := fa.CalculateCyclomaticComplexity(funcDecl)
36+
cognitiveComplexity := fa.CalculateCognitiveComplexity(funcDecl)
37+
linesOfCode := fa.CountLinesOfCode(funcDecl)
38+
volume, difficulty, effort := fa.calculateHalsteadMetrics(funcDecl)
39+
maintainabilityIndex := fa.CalculateMaintainabilityIndex(cyclomaticComplexity, volume, linesOfCode)
40+
nestedDepth := fa.calculateNestedDepth(funcDecl)
41+
commentDensity := fa.calculateCommentDensity(funcDecl)
42+
paramCount := 0
43+
if funcDecl.Type.Params != nil {
44+
for _, field := range funcDecl.Type.Params.List {
45+
paramCount += len(field.Names)
46+
}
47+
}
48+
returnCount := fa.countReturnStatements(funcDecl)
49+
50+
if math.IsNaN(volume) || math.IsInf(volume, 0) {
51+
volume = 0
52+
}
53+
if math.IsNaN(difficulty) || math.IsInf(difficulty, 0) {
54+
difficulty = 0
55+
}
56+
if math.IsNaN(effort) || math.IsInf(effort, 0) {
57+
effort = 0
58+
}
59+
if math.IsNaN(maintainabilityIndex) || math.IsInf(maintainabilityIndex, 0) {
60+
maintainabilityIndex = 0
61+
}
62+
if math.IsNaN(commentDensity) || math.IsInf(commentDensity, 0) {
63+
commentDensity = 0
64+
}
65+
66+
return &MetricsResult{
67+
Name: funcDecl.Name.Name,
68+
CyclomaticComplexity: cyclomaticComplexity,
69+
CognitiveComplexity: cognitiveComplexity,
70+
LinesOfCode: linesOfCode,
71+
HalsteadVolume: math.Round(volume*100) / 100,
72+
HalsteadDifficulty: math.Round(difficulty*100) / 100,
73+
HalsteadEffort: math.Round(effort*100) / 100,
74+
MaintainabilityIndex: math.Round(maintainabilityIndex*100) / 100,
75+
NestedDepth: nestedDepth,
76+
CommentDensity: math.Round(commentDensity*100) / 100,
77+
FunctionParameters: paramCount,
78+
ReturnStatements: returnCount,
79+
}
80+
}
81+
82+
// AnalyzeFile analyzes a file and returns the metrics for each function.
83+
func (fa *FileAnalyzer) AnalyzeFile() []*MetricsResult {
84+
var results []*MetricsResult
85+
86+
ast.Inspect(fa.ast, func(n ast.Node) bool {
87+
if funcDecl, ok := n.(*ast.FuncDecl); ok {
88+
result := fa.AnalyzeFunction(funcDecl)
89+
if result != nil {
90+
results = append(results, result)
91+
}
92+
}
93+
return true
94+
})
95+
96+
return results
97+
}

0 commit comments

Comments
 (0)