vault/tools/codechecker/pkg/godoctests/analyzer.go
miagilepner 8c18f24b9d
VAULT-17734, VAULT-17735: Combine linters (#21611)
* combine into one checker

* combine and simplify ci checks

* add to test package list

* remove testing test

* only run deprecations check

* only run deprecations check

* remove unneeded repo check

* fix bash options
2023-07-06 15:18:42 +02:00

82 lines
1.7 KiB
Go

// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
package godoctests
import (
"go/ast"
"strings"
"golang.org/x/tools/go/analysis"
"golang.org/x/tools/go/analysis/passes/inspect"
"golang.org/x/tools/go/ast/inspector"
)
var Analyzer = &analysis.Analyzer{
Name: "godoctests",
Doc: "Verifies that every go test has a go doc",
Run: run,
Requires: []*analysis.Analyzer{inspect.Analyzer},
}
func run(pass *analysis.Pass) (interface{}, error) {
inspector := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
nodeFilter := []ast.Node{
(*ast.FuncDecl)(nil),
}
inspector.Preorder(nodeFilter, func(node ast.Node) {
funcDecl, ok := node.(*ast.FuncDecl)
if !ok {
return
}
// starts with 'Test'
if !strings.HasPrefix(funcDecl.Name.Name, "Test") {
return
}
// has one parameter
params := funcDecl.Type.Params.List
if len(params) != 1 {
return
}
// parameter is a pointer
firstParamType, ok := params[0].Type.(*ast.StarExpr)
if !ok {
return
}
selector, ok := firstParamType.X.(*ast.SelectorExpr)
if !ok {
return
}
// the pointer comes from package 'testing'
selectorIdent, ok := selector.X.(*ast.Ident)
if !ok {
return
}
if selectorIdent.Name != "testing" {
return
}
// the pointer has type 'T'
if selector.Sel == nil || selector.Sel.Name != "T" {
return
}
// then there must be a godoc
if funcDecl.Doc == nil {
pass.Reportf(node.Pos(), "Test %s is missing a go doc",
funcDecl.Name.Name)
} else if !strings.HasPrefix(funcDecl.Doc.Text(), funcDecl.Name.Name) {
pass.Reportf(node.Pos(), "Test %s must have a go doc beginning with the function name",
funcDecl.Name.Name)
}
})
return nil, nil
}