diff options
Diffstat (limited to 'cmd/cvet/code_smells.go')
| -rw-r--r-- | cmd/cvet/code_smells.go | 64 |
1 files changed, 64 insertions, 0 deletions
diff --git a/cmd/cvet/code_smells.go b/cmd/cvet/code_smells.go new file mode 100644 index 0000000..f306d85 --- /dev/null +++ b/cmd/cvet/code_smells.go @@ -0,0 +1,64 @@ +package main + +import ( + "go/ast" + + "github.com/samber/lo" + "golang.org/x/tools/go/analysis" +) + +var codeSmellsAnalyzer = &analysis.Analyzer{ + Name: "logging", + Doc: "Logging best practices", + Run: run, +} + +func isIdent(node ast.Node, name string) bool { + if ident, ok := node.(*ast.Ident); ok { + return ident.Name == name + } + return false +} + +func isSelector(node ast.Node, left string, right string) bool { + if selector, ok := node.(*ast.SelectorExpr); ok { + return isIdent(selector.X, left) && isIdent(selector.Sel, right) + } + return false +} + +func visit(pass *analysis.Pass) func(node ast.Node) bool { + return func(node ast.Node) bool { + switch node := node.(type) { + case *ast.CallExpr: + checkLogUsage(pass, node) + case *ast.FuncDecl: + if isQueryFunc(node) { + checkQueryFunc(pass, node) + } + if isCommandFunc(node) { + checkCommandFunc(pass, node) + } + if field, ok := lo.Find(node.Type.Params.List, func(field *ast.Field) bool { + return isSelector(field.Type, "context", "Context") + }); ok { + if field != node.Type.Params.List[0] { + pass.Reportf(node.Pos(), "context.Context must be the first parameter") + } + if field.Names[0].Name != "ctx" { + pass.Reportf(node.Pos(), "context.Context parameter must be named ctx") + } + } + case *ast.BlockStmt: + checkLogBeforePanic(pass, node) + } + return true + } +} + +func run(pass *analysis.Pass) (interface{}, error) { + for _, file := range pass.Files { + ast.Inspect(file, visit(pass)) + } + return nil, nil //nolint:nilnil +} |
