1
1
package zerologlint
2
2
3
3
import (
4
+ "go/token"
4
5
"strings"
5
6
6
7
"golang.org/x/tools/go/analysis"
@@ -20,54 +21,33 @@ var Analyzer = &analysis.Analyzer{
20
21
},
21
22
}
22
23
24
+ type posser interface {
25
+ Pos () token.Pos
26
+ }
27
+
28
+ // posser is an interface just to hold both ssa.Call and ssa.Defer in our set
29
+ type callDefer interface {
30
+ Common () * ssa.CallCommon
31
+ Pos () token.Pos
32
+ }
33
+
23
34
func run (pass * analysis.Pass ) (interface {}, error ) {
24
35
srcFuncs := pass .ResultOf [buildssa .Analyzer ].(* buildssa.SSA ).SrcFuncs
25
36
26
- // This map holds all the ssa block that is a zerolog.Event type instance
37
+ // This set holds all the ssa block that is a zerolog.Event type instance
27
38
// that should be dispatched.
28
39
// Everytime the zerolog.Event is dispatched with Msg() or Send(),
29
- // deletes that block from this map .
40
+ // deletes that block from this set .
30
41
// At the end, check if the set is empty, or report the not dispatched block.
31
- set := make (map [ssa. Value ]struct {})
42
+ set := make (map [posser ]struct {})
32
43
33
44
for _ , sf := range srcFuncs {
34
45
for _ , b := range sf .Blocks {
35
46
for _ , instr := range b .Instrs {
36
47
if c , ok := instr .(* ssa.Call ); ok {
37
- v := c .Value ()
38
- // check if it's in github.com/rs/zerolog/log since there's some
39
- // functions in github.com/rs/zerolog that returns zerolog.Event
40
- // which should not be included
41
- if isInLogPkg (v ) {
42
- if isZerologEvent (v ) {
43
- // check if this is a new instance of zerolog.Event like logger := log.Error()
44
- // which should be dispatched afterwards at some point
45
- if len (v .Call .Args ) == 0 {
46
- set [v ] = struct {}{}
47
- }
48
- continue
49
- }
50
- }
51
-
52
- // if the call does not return zerolog.Event,
53
- // check if the base is zerolog.Event.
54
- // if so, check if the StaticCallee is Send() or Msg().
55
- // if so, remove the arg[0] from the set.
56
- for _ , arg := range v .Call .Args {
57
- if isZerologEvent (arg ) {
58
- if isDispatchMethod (v ) {
59
- val := getRootSsaValue (arg )
60
- // if there's branch, remove both ways from the set
61
- if phi , ok := val .(* ssa.Phi ); ok {
62
- for _ , edge := range phi .Edges {
63
- delete (set , edge )
64
- }
65
- } else {
66
- delete (set , val )
67
- }
68
- }
69
- }
70
- }
48
+ inspect (c , & set )
49
+ } else if c , ok := instr .(* ssa.Defer ); ok {
50
+ inspect (c , & set )
71
51
}
72
52
}
73
53
}
@@ -80,8 +60,46 @@ func run(pass *analysis.Pass) (interface{}, error) {
80
60
return nil , nil
81
61
}
82
62
83
- func isInLogPkg (c * ssa.Call ) bool {
84
- switch v := c .Call .Value .(type ) {
63
+ func inspect (cd callDefer , set * map [posser ]struct {}) {
64
+ c := cd .Common ()
65
+
66
+ // check if it's in github.com/rs/zerolog/log since there's some
67
+ // functions in github.com/rs/zerolog that returns zerolog.Event
68
+ // which should not be included
69
+ if isInLogPkg (* c ) {
70
+ if isZerologEvent (c .Value ) {
71
+ // check if this is a new instance of zerolog.Event like logger := log.Error()
72
+ // which should be dispatched afterwards at some point
73
+ if len (c .Args ) == 0 {
74
+ (* set )[cd ] = struct {}{}
75
+ }
76
+ return
77
+ }
78
+ }
79
+
80
+ // if the call does not return zerolog.Event,
81
+ // check if the base is zerolog.Event.
82
+ // if so, check if the StaticCallee is Send() or Msg().
83
+ // if so, remove the arg[0] from the set.
84
+ for _ , arg := range c .Args {
85
+ if isZerologEvent (arg ) {
86
+ if isDispatchMethod (* c ) {
87
+ val := getRootSsaValue (arg )
88
+ // if there's branch, remove both ways from the set
89
+ if phi , ok := val .(* ssa.Phi ); ok {
90
+ for _ , edge := range phi .Edges {
91
+ delete (* set , edge )
92
+ }
93
+ } else {
94
+ delete (* set , val )
95
+ }
96
+ }
97
+ }
98
+ }
99
+ }
100
+
101
+ func isInLogPkg (c ssa.CallCommon ) bool {
102
+ switch v := c .Value .(type ) {
85
103
case ssa.Member :
86
104
p := v .Package ()
87
105
if p == nil {
@@ -98,8 +116,8 @@ func isZerologEvent(v ssa.Value) bool {
98
116
return strings .HasSuffix (ts , "github.com/rs/zerolog.Event" )
99
117
}
100
118
101
- func isDispatchMethod (c * ssa.Call ) bool {
102
- m := c .Common (). StaticCallee ().Name ()
119
+ func isDispatchMethod (c ssa.CallCommon ) bool {
120
+ m := c .StaticCallee ().Name ()
103
121
if m == "Send" || m == "Msg" || m == "Msgf" || m == "MsgFunc" {
104
122
return true
105
123
}
0 commit comments