Skip to content

Commit 361c744

Browse files
authored
refactor (rule/function-length): replace AST walker by iteration over declarations (#1166)
1 parent fcfd6ad commit 361c744

File tree

1 file changed

+48
-68
lines changed

1 file changed

+48
-68
lines changed

rule/function_length.go

Lines changed: 48 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -28,17 +28,40 @@ func (r *FunctionLength) Apply(file *lint.File, arguments lint.Arguments) []lint
2828
r.configureOnce.Do(func() { r.configure(arguments) })
2929

3030
var failures []lint.Failure
31+
for _, decl := range file.AST.Decls {
32+
funcDecl, ok := decl.(*ast.FuncDecl)
33+
if !ok {
34+
continue
35+
}
3136

32-
walker := lintFuncLength{
33-
file: file,
34-
maxStmt: r.maxStmt,
35-
maxLines: r.maxLines,
36-
onFailure: func(failure lint.Failure) {
37-
failures = append(failures, failure)
38-
},
39-
}
37+
body := funcDecl.Body
38+
emptyBody := body == nil || len(body.List) == 0
39+
if emptyBody {
40+
return nil
41+
}
42+
43+
if r.maxStmt > 0 {
44+
stmtCount := r.countStmts(body.List)
45+
if stmtCount > r.maxStmt {
46+
failures = append(failures, lint.Failure{
47+
Confidence: 1,
48+
Failure: fmt.Sprintf("maximum number of statements per function exceeded; max %d but got %d", r.maxStmt, stmtCount),
49+
Node: funcDecl,
50+
})
51+
}
52+
}
4053

41-
ast.Walk(walker, file.AST)
54+
if r.maxLines > 0 {
55+
lineCount := r.countLines(body, file)
56+
if lineCount > r.maxLines {
57+
failures = append(failures, lint.Failure{
58+
Confidence: 1,
59+
Failure: fmt.Sprintf("maximum number of lines per function exceeded; max %d but got %d", r.maxLines, lineCount),
60+
Node: funcDecl,
61+
})
62+
}
63+
}
64+
}
4265

4366
return failures
4467
}
@@ -80,79 +103,35 @@ func (*FunctionLength) parseArguments(arguments lint.Arguments) (maxStmt, maxLin
80103
return maxStmt, maxLines
81104
}
82105

83-
type lintFuncLength struct {
84-
file *lint.File
85-
maxStmt int
86-
maxLines int
87-
onFailure func(lint.Failure)
88-
}
89-
90-
func (w lintFuncLength) Visit(n ast.Node) ast.Visitor {
91-
node, ok := n.(*ast.FuncDecl)
92-
if !ok {
93-
return w
94-
}
95-
96-
body := node.Body
97-
emptyBody := body == nil || len(node.Body.List) == 0
98-
if emptyBody {
99-
return nil
100-
}
101-
102-
if w.maxStmt > 0 {
103-
stmtCount := w.countStmts(node.Body.List)
104-
if stmtCount > w.maxStmt {
105-
w.onFailure(lint.Failure{
106-
Confidence: 1,
107-
Failure: fmt.Sprintf("maximum number of statements per function exceeded; max %d but got %d", w.maxStmt, stmtCount),
108-
Node: node,
109-
})
110-
}
111-
}
112-
113-
if w.maxLines > 0 {
114-
lineCount := w.countLines(node.Body)
115-
if lineCount > w.maxLines {
116-
w.onFailure(lint.Failure{
117-
Confidence: 1,
118-
Failure: fmt.Sprintf("maximum number of lines per function exceeded; max %d but got %d", w.maxLines, lineCount),
119-
Node: node,
120-
})
121-
}
122-
}
123-
124-
return nil
125-
}
126-
127-
func (w lintFuncLength) countLines(b *ast.BlockStmt) int {
128-
return w.file.ToPosition(b.End()).Line - w.file.ToPosition(b.Pos()).Line - 1
106+
func (*FunctionLength) countLines(b *ast.BlockStmt, file *lint.File) int {
107+
return file.ToPosition(b.End()).Line - file.ToPosition(b.Pos()).Line - 1
129108
}
130109

131-
func (w lintFuncLength) countStmts(b []ast.Stmt) int {
110+
func (r *FunctionLength) countStmts(b []ast.Stmt) int {
132111
count := 0
133112
for _, s := range b {
134113
switch stmt := s.(type) {
135114
case *ast.BlockStmt:
136-
count += w.countStmts(stmt.List)
115+
count += r.countStmts(stmt.List)
137116
case *ast.IfStmt:
138-
count += 1 + w.countBodyListStmts(stmt)
117+
count += 1 + r.countBodyListStmts(stmt)
139118
if stmt.Else != nil {
140119
elseBody, ok := stmt.Else.(*ast.BlockStmt)
141120
if ok {
142-
count += w.countStmts(elseBody.List)
121+
count += r.countStmts(elseBody.List)
143122
}
144123
}
145124
case *ast.ForStmt, *ast.RangeStmt,
146125
*ast.SwitchStmt, *ast.TypeSwitchStmt, *ast.SelectStmt:
147-
count += 1 + w.countBodyListStmts(stmt)
126+
count += 1 + r.countBodyListStmts(stmt)
148127
case *ast.CaseClause:
149-
count += w.countStmts(stmt.Body)
128+
count += r.countStmts(stmt.Body)
150129
case *ast.AssignStmt:
151-
count += 1 + w.countFuncLitStmts(stmt.Rhs[0])
130+
count += 1 + r.countFuncLitStmts(stmt.Rhs[0])
152131
case *ast.GoStmt:
153-
count += 1 + w.countFuncLitStmts(stmt.Call.Fun)
132+
count += 1 + r.countFuncLitStmts(stmt.Call.Fun)
154133
case *ast.DeferStmt:
155-
count += 1 + w.countFuncLitStmts(stmt.Call.Fun)
134+
count += 1 + r.countFuncLitStmts(stmt.Call.Fun)
156135
default:
157136
count++
158137
}
@@ -161,14 +140,15 @@ func (w lintFuncLength) countStmts(b []ast.Stmt) int {
161140
return count
162141
}
163142

164-
func (w lintFuncLength) countFuncLitStmts(stmt ast.Expr) int {
143+
func (r *FunctionLength) countFuncLitStmts(stmt ast.Expr) int {
165144
if block, ok := stmt.(*ast.FuncLit); ok {
166-
return w.countStmts(block.Body.List)
145+
return r.countStmts(block.Body.List)
167146
}
147+
168148
return 0
169149
}
170150

171-
func (w lintFuncLength) countBodyListStmts(t any) int {
151+
func (r *FunctionLength) countBodyListStmts(t any) int {
172152
i := reflect.ValueOf(t).Elem().FieldByName(`Body`).Elem().FieldByName(`List`).Interface()
173-
return w.countStmts(i.([]ast.Stmt))
153+
return r.countStmts(i.([]ast.Stmt))
174154
}

0 commit comments

Comments
 (0)