// Copyright 2025 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package analyzerutil import ( "go/ast" "strings" "golang.org/x/tools/go/analysis" "golang.org/x/tools/internal/packagepath" "golang.org/x/tools/internal/stdlib" "golang.org/x/tools/internal/versions" ) // FileUsesGoVersion reports whether the specified file may use features of the // specified version of Go (e.g. "go1.24"). // // Tip: we recommend using this check "late", just before calling // pass.Report, rather than "early" (when entering each ast.File, or // each candidate node of interest, during the traversal), because the // operation is not free, yet is not a highly selective filter: the // fraction of files that pass most version checks is high and // increases over time. func FileUsesGoVersion(pass *analysis.Pass, file *ast.File, version string) (_res bool) { fileVersion := pass.TypesInfo.FileVersions[file] // Standard packages that are part of toolchain bootstrapping // are not considered to use a version of Go later than the // current bootstrap toolchain version. // The bootstrap rule does not cover tests, // and some tests (e.g. debug/elf/file_test.go) rely on this. pkgpath := pass.Pkg.Path() if packagepath.IsStdPackage(pkgpath) && stdlib.IsBootstrapPackage(pkgpath) && // (excludes "*_test" external test packages) !strings.HasSuffix(pass.Fset.File(file.Pos()).Name(), "_test.go") { // (excludes all tests) fileVersion = stdlib.BootstrapVersion.String() // package must bootstrap } return !versions.Before(fileVersion, version) }