Skip to content

Commit

Permalink
starting point
Browse files Browse the repository at this point in the history
  • Loading branch information
ykadowak committed Feb 23, 2023
1 parent a0ccf2d commit 4d88067
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 24 deletions.
4 changes: 1 addition & 3 deletions testdata/src/a/a.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ import "github.com/rs/zerolog/log"

func f() {
// The pattern can be written in regular expression.
var gopher int // want "identifier is gopher"
print(gopher) // want "identifier is gopher"
var err error
log.Error().Err(err) // want "missing Msg() or Send()"
log.Error().Err(err) // want "missing Msg call for zerolog log method"
}
69 changes: 48 additions & 21 deletions zerologlint.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,39 +2,66 @@ package zerologlint

import (
"go/ast"
"go/types"

"golang.org/x/tools/go/analysis"
"golang.org/x/tools/go/analysis/passes/inspect"
"golang.org/x/tools/go/ast/inspector"
)

const doc = "zerologlint is ..."

// Analyzer is ...
var Analyzer = &analysis.Analyzer{
Name: "zerologlint",
Doc: doc,
Name: "logmsg",
Doc: "check that zerolog log methods have a final Msg call",
Run: run,
Requires: []*analysis.Analyzer{
inspect.Analyzer,
},
}

func run(pass *analysis.Pass) (any, error) {
inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)

nodeFilter := []ast.Node{
(*ast.Ident)(nil),
func run(pass *analysis.Pass) (interface{}, error) {
for _, f := range pass.Files {
if !hasZerologImport(f) {
continue
}
ast.Inspect(f, func(n ast.Node) bool {
switch n := n.(type) {
case *ast.CallExpr:
if isLogMethod(n.Fun, pass.TypesInfo) && !hasMsgCall(n.Args, pass.TypesInfo) {
pass.Reportf(n.Pos(), "missing Msg call for zerolog log method")
}
}
return true
})
}
return nil, nil
}

inspect.Preorder(nodeFilter, func(n ast.Node) {
switch n := n.(type) {
case *ast.Ident:
if n.Name == "gopher" {
pass.Reportf(n.Pos(), "identifier is gopher")
func hasZerologImport(f *ast.File) bool {
for _, imp := range f.Imports {
if imp.Path.Value == `"github.com/rs/zerolog/log"` {
return true
}
}
return false
}

func isLogMethod(expr ast.Expr, info *types.Info) bool {
if sel, ok := expr.(*ast.SelectorExpr); ok {
if id, ok := sel.X.(*ast.Ident); ok {
if obj := info.ObjectOf(id); obj != nil {
switch sel.Sel.Name {
case "Debug", "Info", "Warn", "Error", "Fatal", "Panic":
return true
}
}
}
})
}
return false
}

return nil, nil
func hasMsgCall(args []ast.Expr, info *types.Info) bool {
for _, arg := range args {
if call, ok := arg.(*ast.CallExpr); ok {
if sel, ok := call.Fun.(*ast.SelectorExpr); ok && sel.Sel.Name == "Msg" && len(call.Args) == 1 {
return true
}
}
}
return false
}
1 change: 1 addition & 0 deletions zerologlint_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"golang.org/x/tools/go/analysis/analysistest"
)


// TestAnalyzer is a test for Analyzer.
func TestAnalyzer(t *testing.T) {
testdata := testutil.WithModules(t, analysistest.TestData(), nil)
Expand Down

0 comments on commit 4d88067

Please sign in to comment.