Skip to content

x/tools/go/analysis: Generated test code passed in pass.Files #64436

@bombsimon

Description

@bombsimon

Go version

go1.20.1 linux/amd64

What operating system and processor architecture are you using (go env)?

GO111MODULE="auto"
GOARCH="amd64"
GOBIN=""
GOCACHE="/home/simon/.cache/go-build"
GOENV="/home/simon/.config/go/env"
GOEXE=""
GOEXPERIMENT=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOINSECURE=""
GOMODCACHE="/home/simon/go/pkg/mod"
GONOPROXY=""
GONOSUMDB=""
GOOS="linux"
GOPATH="/home/simon/go"
GOPRIVATE=""
GOPROXY="https://proxy.golang.org,direct"
GOROOT="/usr/local/go"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/usr/local/go/pkg/tool/linux_amd64"
GOVCS=""
GOVERSION="go1.20.1"
GCCGO="gccgo"
GOAMD64="v1"
AR="ar"
CC="gcc"
CXX="g++"
CGO_ENABLED="1"
GOMOD="/home/simon/tmp/analyzer-mre/go.mod"
GOWORK=""
CGO_CFLAGS="-O2 -g"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-O2 -g"
CGO_FFLAGS="-O2 -g"
CGO_LDFLAGS="-O2 -g"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -m64 -pthread -Wl,--no-gc-sections -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build74158799=/tmp/go-build -gno-record-gcc-switches"

What did you do?

The go toolchain will create a cached test file that calls testing.MainStart for all tests, benches, fuzzes and examples if a package contains any tests. When running an analysis.Analyzer on a package that contains tests, this generated file will be passed in pass.Files. Since this is not created by the user, any reports that affect this file cannot be addressed. F.ex. diagnostics from whitespace which is violated in this file.

Reproducible example

main.go

package main

import (
        "fmt"

        "golang.org/x/tools/go/analysis"
        "golang.org/x/tools/go/analysis/singlechecker"
)

var Analyzer = &analysis.Analyzer{
        Name: "example",
        Doc:  "example",
        Run:  run,
}

func run(pass *analysis.Pass) (interface{}, error) {
        for _, f := range pass.Files {
                filename := pass.Fset.PositionFor(f.Pos(), false).Filename
                fmt.Println(filename)
        }

        return nil, nil
}

func main() {
        singlechecker.Main(Analyzer)
}

main_test.go

package main

Running the code on itself:

› go run . ./...
/home/simon/.cache/go-build/90/9008f547841e25259dff735e6c1b3cd00116f6368db052541f1e4fcdb443f56c-d
/home/simon/tmp/analyzer-mre/main.go
/home/simon/tmp/analyzer-mre/main.go
/home/simon/tmp/analyzer-mre/main_test.go

The generated file

This is the generated file (contents of /home/simon/.cache/go-build/90/900...) from the go-build directory which may include violations.

Click to expand
// Code generated by 'go test'. DO NOT EDIT.

package main

import (
        "os"


        "testing"
        "testing/internal/testdeps"


        _ "a"


)

var tests = []testing.InternalTest{

}

var benchmarks = []testing.InternalBenchmark{

}

var fuzzTargets = []testing.InternalFuzzTarget{

}

var examples = []testing.InternalExample{

}

func init() {
        testdeps.ImportPath = "a"
}



func main() {

        m := testing.MainStart(testdeps.TestDeps{}, tests, benchmarks, fuzzTargets, examples)

        os.Exit(m.Run())

}

Additional details

One naive way to address this could be for me to skip files without a .go suffix. However, this is not a reliable solution since if I use the //line directive (put a comment like //line hello.tmpl:1 at the first line of my file) the Filename for the Position will be hello.tmpl. This might be possible to work around by using PositionFor instead but I think a better solution is to not pass the file.

What did you expect to see?

Only code that's not generated by the go toolchain to be analyzed.

What did you see instead?

Code generated and cached in GOCACHE directory being passed to the analyzer.

Metadata

Metadata

Assignees

No one assigned

    Labels

    FrozenDueToAgeToolsThis label describes issues relating to any tools in the x/tools repository.

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions