@@ -17,8 +17,35 @@ func (*UnconditionalRecursionRule) Apply(file *lint.File, _ lint.Arguments) []li
17
17
failures = append (failures , failure )
18
18
}
19
19
20
- w := & lintUnconditionalRecursionRule {onFailure : onFailure }
21
- ast .Walk (w , file .AST )
20
+ // Range over global declarations of the file to detect func/method declarations and analyze them
21
+ for _ , decl := range file .AST .Decls {
22
+ n , ok := decl .(* ast.FuncDecl )
23
+ if ! ok {
24
+ continue // not a func/method declaration
25
+ }
26
+
27
+ if n .Body == nil {
28
+ continue // func/method with empty body => it can not be recursive
29
+ }
30
+
31
+ var rec * ast.Ident
32
+ switch {
33
+ case n .Recv == nil :
34
+ rec = nil
35
+ case n .Recv .NumFields () < 1 || len (n .Recv .List [0 ].Names ) < 1 :
36
+ rec = & ast.Ident {Name : "_" }
37
+ default :
38
+ rec = n .Recv .List [0 ].Names [0 ]
39
+ }
40
+
41
+ w := & lintUnconditionalRecursionRule {
42
+ onFailure : onFailure ,
43
+ currentFunc : & funcStatus {& funcDesc {rec , n .Name }, false },
44
+ }
45
+
46
+ ast .Walk (w , n .Body )
47
+ }
48
+
22
49
return failures
23
50
}
24
51
@@ -50,26 +77,14 @@ type lintUnconditionalRecursionRule struct {
50
77
inGoStatement bool
51
78
}
52
79
53
- // Visit will traverse the file AST.
54
- // The rule is based in the following algorithm: inside each function body we search for calls to the function itself.
80
+ // Visit will traverse function's body we search for calls to the function itself.
55
81
// We do not search inside conditional control structures (if, for, switch, ...) because any recursive call inside them is conditioned
56
82
// We do search inside conditional control structures are statements that will take the control out of the function (return, exit, panic)
57
83
// If we find conditional control exits, it means the function is NOT unconditionally-recursive
58
84
// If we find a recursive call before finding any conditional exit, a failure is generated
59
85
// In resume: if we found a recursive call control-dependent from the entry point of the function then we raise a failure.
60
86
func (w * lintUnconditionalRecursionRule ) Visit (node ast.Node ) ast.Visitor {
61
87
switch n := node .(type ) {
62
- case * ast.FuncDecl :
63
- var rec * ast.Ident
64
- switch {
65
- case n .Recv == nil :
66
- rec = nil
67
- case n .Recv .NumFields () < 1 || len (n .Recv .List [0 ].Names ) < 1 :
68
- rec = & ast.Ident {Name : "_" }
69
- default :
70
- rec = n .Recv .List [0 ].Names [0 ]
71
- }
72
- w .currentFunc = & funcStatus {& funcDesc {rec , n .Name }, false }
73
88
case * ast.CallExpr :
74
89
// check if call arguments has a recursive call
75
90
for _ , arg := range n .Args {
0 commit comments