Will Murphy 1af07a4775 initial working build of custom linter
Signed-off-by: Will Murphy <will.murphy@anchore.com>
2024-05-02 11:07:01 -04:00

86 lines
1.9 KiB
Go

package ensuredefer
import (
"github.com/golangci/plugin-module-register/register"
"go/ast"
"golang.org/x/tools/go/analysis"
"golang.org/x/tools/go/analysis/passes/inspect"
"golang.org/x/tools/go/ast/inspector"
)
func init() {
register.Plugin("ensuredefer", func(conf any) (register.LinterPlugin, error) {
return &analyzerPlugin{}, nil
})
}
func run(pass *analysis.Pass) (any, error) {
insp := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
nodeFilter := []ast.Node{
(*ast.ExprStmt)(nil),
(*ast.DeferStmt)(nil),
}
insp.Preorder(nodeFilter, func(node ast.Node) {
// if we have a *ast.ExprStmt that calls internal.CloseAndLogError, report a problem.
// (if the function is correctly called in a defer statement, the block will have
switch t := node.(type) {
case *ast.ExprStmt:
if !isExprStmtAllowed(t, pass) {
pass.Reportf(t.Pos(), "internal.CloseAndLogError must be called in defer")
}
}
})
return nil, nil
}
func isExprStmtAllowed(e *ast.ExprStmt, pass *analysis.Pass) bool {
call, ok := e.X.(*ast.CallExpr)
if !ok {
return true
}
sel, ok := call.Fun.(*ast.SelectorExpr)
if !ok {
return true
}
obj := pass.TypesInfo.Uses[sel.Sel]
if obj == nil {
return true
}
pkg := obj.Pkg()
if pkg == nil {
return true
}
if pkg.Path() == "github.com/anchore/syft/internal" && sel.Sel.Name == "CloseAndLogError" {
return false
}
return true
}
func NewAnalyzer() *analysis.Analyzer {
analyzer := analysis.Analyzer{
Name: "ensuredefer",
Doc: "enforce that specified functions are called in defer statements",
Run: run,
Requires: []*analysis.Analyzer{inspect.Analyzer},
}
return &analyzer
}
var analyzerInstance = NewAnalyzer()
type analyzerPlugin struct{}
func (p *analyzerPlugin) BuildAnalyzers() ([]*analysis.Analyzer, error) {
return []*analysis.Analyzer{
analyzerInstance,
}, nil
}
func (p *analyzerPlugin) GetLoadMode() string {
//TODO: what does this do
return register.LoadModeSyntax
}