Fix #109, #116, #131: don't report in deadcode about unused test functions in main package

This commit is contained in:
Denis Isaev 2018-06-28 10:09:44 +03:00 committed by Isaev Denis
parent 5ef542facd
commit 88ebabc4bc
3 changed files with 37 additions and 8 deletions

2
Gopkg.lock generated
View File

@ -69,7 +69,7 @@
branch = "master" branch = "master"
name = "github.com/golangci/go-misc" name = "github.com/golangci/go-misc"
packages = ["deadcode"] packages = ["deadcode"]
revision = "a61b005a223b50d3656798639dd87073ca5c1981" revision = "927a3d87b613e9f6f0fb7ef8bb8de8b83c30a5a2"
[[projects]] [[projects]]
branch = "master" branch = "master"

View File

@ -0,0 +1,15 @@
package main
import "testing"
func TestF(t *testing.T) {
}
func BenchmarkF(t *testing.B) {
}
func ExampleF() {
}

View File

@ -8,6 +8,7 @@ import (
"os" "os"
"path/filepath" "path/filepath"
"sort" "sort"
"strings"
"golang.org/x/tools/go/loader" "golang.org/x/tools/go/loader"
) )
@ -50,9 +51,8 @@ type Context struct {
program *loader.Program program *loader.Program
} }
// error formats the error to standard error, adding program // pos resolves a compact position encoding into a verbose one
// identification and a newline func (ctx *Context) pos(pos token.Pos) token.Position {
func (ctx *Context) errorf(pos token.Pos, format string, args ...interface{}) {
if ctx.cwd == "" { if ctx.cwd == "" {
ctx.cwd, _ = os.Getwd() ctx.cwd, _ = os.Getwd()
} }
@ -61,6 +61,13 @@ func (ctx *Context) errorf(pos token.Pos, format string, args ...interface{}) {
if err == nil { if err == nil {
p.Filename = f p.Filename = f
} }
return p
}
// error formats the error to standard error, adding program
// identification and a newline
func (ctx *Context) errorf(pos token.Pos, format string, args ...interface{}) {
p := ctx.pos(pos)
fmt.Fprintf(os.Stderr, p.String()+": "+format+"\n", args...) fmt.Fprintf(os.Stderr, p.String()+": "+format+"\n", args...)
exitCode = 2 exitCode = 2
} }
@ -73,18 +80,22 @@ func (ctx *Context) Process() []types.Object {
prog := ctx.program prog := ctx.program
var allUnused []types.Object var allUnused []types.Object
for _, pkg := range prog.Imported { for _, pkg := range prog.Imported {
unused := doPackage(prog, pkg) unused := ctx.doPackage(prog, pkg)
allUnused = append(allUnused, unused...) allUnused = append(allUnused, unused...)
} }
for _, pkg := range prog.Created { for _, pkg := range prog.Created {
unused := doPackage(prog, pkg) unused := ctx.doPackage(prog, pkg)
allUnused = append(allUnused, unused...) allUnused = append(allUnused, unused...)
} }
sort.Sort(objects(allUnused)) sort.Sort(objects(allUnused))
return allUnused return allUnused
} }
func doPackage(prog *loader.Program, pkg *loader.PackageInfo) []types.Object { func isTestFuncByName(name string) bool {
return strings.HasPrefix(name, "Test") || strings.HasPrefix(name, "Benchmark") || strings.HasPrefix(name, "Example")
}
func (ctx *Context) doPackage(prog *loader.Program, pkg *loader.PackageInfo) []types.Object {
used := make(map[types.Object]bool) used := make(map[types.Object]bool)
for _, file := range pkg.Files { for _, file := range pkg.Files {
ast.Inspect(file, func(n ast.Node) bool { ast.Inspect(file, func(n ast.Node) bool {
@ -107,7 +118,10 @@ func doPackage(prog *loader.Program, pkg *loader.PackageInfo) []types.Object {
continue continue
} }
obj := global.Lookup(name) obj := global.Lookup(name)
if !used[obj] && (pkg.Pkg.Name() == "main" || !ast.IsExported(name)) { _, isSig := obj.Type().(*types.Signature)
pos := ctx.pos(obj.Pos())
isTestMethod := isSig && isTestFuncByName(obj.Name()) && strings.HasSuffix(pos.Filename, "_test.go")
if !used[obj] && ((pkg.Pkg.Name() == "main" && !isTestMethod) || !ast.IsExported(name)) {
unused = append(unused, obj) unused = append(unused, obj)
} }
} }