fix #965
This commit is contained in:
737
cl/_testdefer/gobuild/in.go
Normal file
737
cl/_testdefer/gobuild/in.go
Normal file
@@ -0,0 +1,737 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"go/ast"
|
||||||
|
"go/doc"
|
||||||
|
"go/token"
|
||||||
|
"io/fs"
|
||||||
|
"os"
|
||||||
|
pathpkg "path"
|
||||||
|
"runtime"
|
||||||
|
"slices"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func IsLocalImport(path string) bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func isAbsPath(path string) bool {
|
||||||
|
return strings.HasPrefix(path, "/")
|
||||||
|
}
|
||||||
|
|
||||||
|
func isDir(path string) bool {
|
||||||
|
fi, err := os.Stat(path)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return fi.IsDir()
|
||||||
|
}
|
||||||
|
|
||||||
|
func isFile(path string) bool {
|
||||||
|
fi, err := os.Stat(path)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return fi.Mode().IsRegular()
|
||||||
|
}
|
||||||
|
|
||||||
|
func joinPath(a string, b ...string) string {
|
||||||
|
if isAbsPath(b[0]) {
|
||||||
|
return b[0]
|
||||||
|
}
|
||||||
|
return pathpkg.Join(append([]string{a}, b...)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func nameExt(path string) string {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func gopath() []string {
|
||||||
|
all := make([]string, 0, 10)
|
||||||
|
for _, p := range strings.Split(os.Getenv("GOPATH"), ":") {
|
||||||
|
if p != "" {
|
||||||
|
all = append(all, p)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return all
|
||||||
|
}
|
||||||
|
|
||||||
|
type Context struct {
|
||||||
|
InstallSuffix string
|
||||||
|
Compiler string
|
||||||
|
GOOS string
|
||||||
|
GOARCH string
|
||||||
|
GOROOT string
|
||||||
|
CgoEnabled bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type Package struct {
|
||||||
|
ImportPath string
|
||||||
|
Dir string
|
||||||
|
Goroot bool
|
||||||
|
Root string
|
||||||
|
ConflictDir string
|
||||||
|
SrcRoot string
|
||||||
|
PkgRoot string
|
||||||
|
BinDir string
|
||||||
|
PkgTargetRoot string
|
||||||
|
PkgObj string
|
||||||
|
InvalidGoFiles []string
|
||||||
|
IgnoredGoFiles []string
|
||||||
|
IgnoredOtherFiles []string
|
||||||
|
CgoFiles []string
|
||||||
|
XTestGoFiles []string
|
||||||
|
TestGoFiles []string
|
||||||
|
GoFiles []string
|
||||||
|
Directives []Directive
|
||||||
|
TestDirectives []Directive
|
||||||
|
XTestDirectives []Directive
|
||||||
|
BinaryOnly bool
|
||||||
|
Name string
|
||||||
|
Doc string
|
||||||
|
ImportComment string
|
||||||
|
AllTags []string
|
||||||
|
EmbedPatterns []string
|
||||||
|
TestEmbedPatterns []string
|
||||||
|
XTestEmbedPatterns []string
|
||||||
|
Imports []string
|
||||||
|
TestImports []string
|
||||||
|
XTestImports []string
|
||||||
|
EmbedPatternPos map[string][]token.Position
|
||||||
|
TestEmbedPatternPos map[string][]token.Position
|
||||||
|
XTestEmbedPatternPos map[string][]token.Position
|
||||||
|
ImportPos map[string][]token.Position
|
||||||
|
TestImportPos map[string][]token.Position
|
||||||
|
XTestImportPos map[string][]token.Position
|
||||||
|
SFiles []string
|
||||||
|
}
|
||||||
|
|
||||||
|
type Directive struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
type MultiplePackageError struct {
|
||||||
|
Dir string
|
||||||
|
Packages []string
|
||||||
|
Files []string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *MultiplePackageError) Error() string {
|
||||||
|
return fmt.Sprintf("multiple packages in single directory: %s\n\t%s\n\t%s", e.Dir, strings.Join(e.Packages, "\n\t"), strings.Join(e.Files, "\n\t"))
|
||||||
|
}
|
||||||
|
|
||||||
|
type ImportMode = uint
|
||||||
|
|
||||||
|
const (
|
||||||
|
IgnoreVendor ImportMode = 1 << iota
|
||||||
|
AllowBinary
|
||||||
|
FindOnly
|
||||||
|
ImportComment
|
||||||
|
)
|
||||||
|
|
||||||
|
func importGo(ctx *Context, p *Package, path, srcDir string, mode ImportMode) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func hasSubdir(root, sub string) (string, bool) {
|
||||||
|
return sub, true
|
||||||
|
}
|
||||||
|
|
||||||
|
func hasGoFiles(ctxt *Context, file string) bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func isStandardImportPath(path string) bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func readDir(name string) ([]os.DirEntry, error) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func findImportComment(data []byte) (s string, line int) {
|
||||||
|
return "", 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func saveCgo(ctxt *Context, filename string, p *Package, doc *ast.CommentGroup) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func cleanDecls(m map[string][]token.Position) ([]string, map[string][]token.Position) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func fileListForExt(p *Package, ext string) *[]string {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type fileInfo struct {
|
||||||
|
name string // full name including dir
|
||||||
|
header []byte
|
||||||
|
fset *token.FileSet
|
||||||
|
parsed *ast.File
|
||||||
|
parseErr error
|
||||||
|
imports []fileImport
|
||||||
|
embeds []fileEmbed
|
||||||
|
directives []Directive
|
||||||
|
}
|
||||||
|
|
||||||
|
type fileImport struct {
|
||||||
|
path string
|
||||||
|
pos token.Pos
|
||||||
|
doc *ast.CommentGroup
|
||||||
|
}
|
||||||
|
|
||||||
|
type fileEmbed struct {
|
||||||
|
pattern string
|
||||||
|
pos token.Position
|
||||||
|
}
|
||||||
|
|
||||||
|
func matchFile(ctxt *Context, dir, name string, allTags map[string]bool, binaryOnly *bool, fset *token.FileSet) (*fileInfo, error) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var errNoModules = errors.New("no modules")
|
||||||
|
|
||||||
|
type godebug struct {
|
||||||
|
name string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewGodebug(name string) *godebug {
|
||||||
|
return &godebug{
|
||||||
|
name: name,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *godebug) IncNonDefault() {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *godebug) Value() string {
|
||||||
|
return g.name
|
||||||
|
}
|
||||||
|
|
||||||
|
var installgoroot = NewGodebug("installgoroot")
|
||||||
|
|
||||||
|
func IsStandardPackage(a, b, c string) bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
type NoGoError struct {
|
||||||
|
Dir string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *NoGoError) Error() string {
|
||||||
|
return "no Go files in " + e.Dir
|
||||||
|
}
|
||||||
|
|
||||||
|
func Import(ctxt *Context, path string, srcDir string, mode ImportMode) (*Package, error) {
|
||||||
|
p := &Package{
|
||||||
|
ImportPath: path,
|
||||||
|
}
|
||||||
|
if path == "" {
|
||||||
|
return p, fmt.Errorf("import %q: invalid import path", path)
|
||||||
|
}
|
||||||
|
|
||||||
|
var pkgtargetroot string
|
||||||
|
var pkga string
|
||||||
|
var pkgerr error
|
||||||
|
suffix := ""
|
||||||
|
if ctxt.InstallSuffix != "" {
|
||||||
|
suffix = "_" + ctxt.InstallSuffix
|
||||||
|
}
|
||||||
|
switch ctxt.Compiler {
|
||||||
|
case "gccgo":
|
||||||
|
pkgtargetroot = "pkg/gccgo_" + ctxt.GOOS + "_" + ctxt.GOARCH + suffix
|
||||||
|
case "gc":
|
||||||
|
pkgtargetroot = "pkg/" + ctxt.GOOS + "_" + ctxt.GOARCH + suffix
|
||||||
|
default:
|
||||||
|
// Save error for end of function.
|
||||||
|
pkgerr = fmt.Errorf("import %q: unknown compiler %q", path, ctxt.Compiler)
|
||||||
|
}
|
||||||
|
setPkga := func() {
|
||||||
|
switch ctxt.Compiler {
|
||||||
|
case "gccgo":
|
||||||
|
dir, elem := pathpkg.Split(p.ImportPath)
|
||||||
|
pkga = pkgtargetroot + "/" + dir + "lib" + elem + ".a"
|
||||||
|
case "gc":
|
||||||
|
pkga = pkgtargetroot + "/" + p.ImportPath + ".a"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setPkga()
|
||||||
|
|
||||||
|
binaryOnly := false
|
||||||
|
if IsLocalImport(path) {
|
||||||
|
pkga = "" // local imports have no installed path
|
||||||
|
if srcDir == "" {
|
||||||
|
return p, fmt.Errorf("import %q: import relative to unknown directory", path)
|
||||||
|
}
|
||||||
|
if !isAbsPath(path) {
|
||||||
|
p.Dir = joinPath(srcDir, path)
|
||||||
|
}
|
||||||
|
// p.Dir directory may or may not exist. Gather partial information first, check if it exists later.
|
||||||
|
// Determine canonical import path, if any.
|
||||||
|
// Exclude results where the import path would include /testdata/.
|
||||||
|
inTestdata := func(sub string) bool {
|
||||||
|
return strings.Contains(sub, "/testdata/") || strings.HasSuffix(sub, "/testdata") || strings.HasPrefix(sub, "testdata/") || sub == "testdata"
|
||||||
|
}
|
||||||
|
if ctxt.GOROOT != "" {
|
||||||
|
root := joinPath(runtime.GOROOT(), "src")
|
||||||
|
if sub, ok := hasSubdir(root, p.Dir); ok && !inTestdata(sub) {
|
||||||
|
p.Goroot = true
|
||||||
|
p.ImportPath = sub
|
||||||
|
p.Root = ctxt.GOROOT
|
||||||
|
setPkga() // p.ImportPath changed
|
||||||
|
goto Found
|
||||||
|
}
|
||||||
|
}
|
||||||
|
all := gopath()
|
||||||
|
for i, root := range all {
|
||||||
|
rootsrc := joinPath(root, "src")
|
||||||
|
if sub, ok := hasSubdir(rootsrc, p.Dir); ok && !inTestdata(sub) {
|
||||||
|
// We found a potential import path for dir,
|
||||||
|
// but check that using it wouldn't find something
|
||||||
|
// else first.
|
||||||
|
if runtime.GOROOT() != "" && ctxt.Compiler != "gccgo" {
|
||||||
|
if dir := joinPath(runtime.GOROOT(), "src", sub); isDir(dir) {
|
||||||
|
p.ConflictDir = dir
|
||||||
|
goto Found
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, earlyRoot := range all[:i] {
|
||||||
|
if dir := joinPath(earlyRoot, "src", sub); isDir(dir) {
|
||||||
|
p.ConflictDir = dir
|
||||||
|
goto Found
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// sub would not name some other directory instead of this one.
|
||||||
|
// Record it.
|
||||||
|
p.ImportPath = sub
|
||||||
|
p.Root = root
|
||||||
|
setPkga() // p.ImportPath changed
|
||||||
|
goto Found
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// It's okay that we didn't find a root containing dir.
|
||||||
|
// Keep going with the information we have.
|
||||||
|
} else {
|
||||||
|
if strings.HasPrefix(path, "/") {
|
||||||
|
return p, fmt.Errorf("import %q: cannot import absolute path", path)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := importGo(ctxt, p, path, srcDir, mode); err == nil {
|
||||||
|
goto Found
|
||||||
|
} else if err != errNoModules {
|
||||||
|
return p, err
|
||||||
|
}
|
||||||
|
|
||||||
|
gopath := gopath() // needed twice below; avoid computing many times
|
||||||
|
|
||||||
|
// tried records the location of unsuccessful package lookups
|
||||||
|
var tried struct {
|
||||||
|
vendor []string
|
||||||
|
goroot string
|
||||||
|
gopath []string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Vendor directories get first chance to satisfy import.
|
||||||
|
if mode&IgnoreVendor == 0 && srcDir != "" {
|
||||||
|
searchVendor := func(root string, isGoroot bool) bool {
|
||||||
|
sub, ok := hasSubdir(root, srcDir)
|
||||||
|
if !ok || !strings.HasPrefix(sub, "src/") || strings.Contains(sub, "/testdata/") {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
for {
|
||||||
|
vendor := joinPath(root, sub, "vendor")
|
||||||
|
if isDir(vendor) {
|
||||||
|
dir := joinPath(vendor, path)
|
||||||
|
if isDir(dir) && hasGoFiles(ctxt, dir) {
|
||||||
|
p.Dir = dir
|
||||||
|
p.ImportPath = strings.TrimPrefix(pathpkg.Join(sub, "vendor", path), "src/")
|
||||||
|
p.Goroot = isGoroot
|
||||||
|
p.Root = root
|
||||||
|
setPkga() // p.ImportPath changed
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
tried.vendor = append(tried.vendor, dir)
|
||||||
|
}
|
||||||
|
i := strings.LastIndex(sub, "/")
|
||||||
|
if i < 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
sub = sub[:i]
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if ctxt.Compiler != "gccgo" && ctxt.GOROOT != "" && searchVendor(ctxt.GOROOT, true) {
|
||||||
|
goto Found
|
||||||
|
}
|
||||||
|
for _, root := range gopath {
|
||||||
|
if searchVendor(root, false) {
|
||||||
|
goto Found
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine directory from import path.
|
||||||
|
if ctxt.GOROOT != "" {
|
||||||
|
// If the package path starts with "vendor/", only search GOROOT before
|
||||||
|
// GOPATH if the importer is also within GOROOT. That way, if the user has
|
||||||
|
// vendored in a package that is subsequently included in the standard
|
||||||
|
// distribution, they'll continue to pick up their own vendored copy.
|
||||||
|
gorootFirst := srcDir == "" || !strings.HasPrefix(path, "vendor/")
|
||||||
|
if !gorootFirst {
|
||||||
|
_, gorootFirst = hasSubdir(runtime.GOROOT(), srcDir)
|
||||||
|
}
|
||||||
|
if gorootFirst {
|
||||||
|
dir := joinPath(runtime.GOROOT(), "src", path)
|
||||||
|
if ctxt.Compiler != "gccgo" {
|
||||||
|
isDir := isDir(dir)
|
||||||
|
binaryOnly = !isDir && mode&AllowBinary != 0 && pkga != "" && isFile(joinPath(runtime.GOROOT(), pkga))
|
||||||
|
if isDir || binaryOnly {
|
||||||
|
p.Dir = dir
|
||||||
|
p.Goroot = true
|
||||||
|
p.Root = runtime.GOROOT()
|
||||||
|
goto Found
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tried.goroot = dir
|
||||||
|
}
|
||||||
|
if ctxt.Compiler == "gccgo" && IsStandardPackage(runtime.GOROOT(), ctxt.Compiler, path) {
|
||||||
|
// TODO(bcmills): Setting p.Dir here is misleading, because gccgo
|
||||||
|
// doesn't actually load its standard-library packages from this
|
||||||
|
// directory. See if we can leave it unset.
|
||||||
|
p.Dir = joinPath(runtime.GOROOT(), "src", path)
|
||||||
|
p.Goroot = true
|
||||||
|
p.Root = runtime.GOROOT()
|
||||||
|
goto Found
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, root := range gopath {
|
||||||
|
dir := joinPath(root, "src", path)
|
||||||
|
isDir := isDir(dir)
|
||||||
|
binaryOnly = !isDir && mode&AllowBinary != 0 && pkga != "" && isFile(joinPath(root, pkga))
|
||||||
|
if isDir || binaryOnly {
|
||||||
|
p.Dir = dir
|
||||||
|
p.Root = root
|
||||||
|
goto Found
|
||||||
|
}
|
||||||
|
tried.gopath = append(tried.gopath, dir)
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we tried GOPATH first due to a "vendor/" prefix, fall back to GOPATH.
|
||||||
|
// That way, the user can still get useful results from 'go list' for
|
||||||
|
// standard-vendored paths passed on the command line.
|
||||||
|
if runtime.GOROOT() != "" && tried.goroot == "" {
|
||||||
|
dir := joinPath(runtime.GOROOT(), "src", path)
|
||||||
|
if ctxt.Compiler != "gccgo" {
|
||||||
|
isDir := isDir(dir)
|
||||||
|
binaryOnly = !isDir && mode&AllowBinary != 0 && pkga != "" && isFile(joinPath(runtime.GOROOT(), pkga))
|
||||||
|
if isDir || binaryOnly {
|
||||||
|
p.Dir = dir
|
||||||
|
p.Goroot = true
|
||||||
|
p.Root = runtime.GOROOT()
|
||||||
|
goto Found
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tried.goroot = dir
|
||||||
|
}
|
||||||
|
|
||||||
|
// package was not found
|
||||||
|
var paths []string
|
||||||
|
format := "\t%s (vendor tree)"
|
||||||
|
for _, dir := range tried.vendor {
|
||||||
|
paths = append(paths, fmt.Sprintf(format, dir))
|
||||||
|
format = "\t%s"
|
||||||
|
}
|
||||||
|
if tried.goroot != "" {
|
||||||
|
paths = append(paths, fmt.Sprintf("\t%s (from $GOROOT)", tried.goroot))
|
||||||
|
} else {
|
||||||
|
paths = append(paths, "\t($GOROOT not set)")
|
||||||
|
}
|
||||||
|
format = "\t%s (from $GOPATH)"
|
||||||
|
for _, dir := range tried.gopath {
|
||||||
|
paths = append(paths, fmt.Sprintf(format, dir))
|
||||||
|
format = "\t%s"
|
||||||
|
}
|
||||||
|
if len(tried.gopath) == 0 {
|
||||||
|
paths = append(paths, "\t($GOPATH not set. For more details see: 'go help gopath')")
|
||||||
|
}
|
||||||
|
return p, fmt.Errorf("cannot find package %q in any of:\n%s", path, strings.Join(paths, "\n"))
|
||||||
|
}
|
||||||
|
|
||||||
|
Found:
|
||||||
|
if p.Root != "" {
|
||||||
|
p.SrcRoot = joinPath(p.Root, "src")
|
||||||
|
p.PkgRoot = joinPath(p.Root, "pkg")
|
||||||
|
p.BinDir = joinPath(p.Root, "bin")
|
||||||
|
if pkga != "" {
|
||||||
|
// Always set PkgTargetRoot. It might be used when building in shared
|
||||||
|
// mode.
|
||||||
|
p.PkgTargetRoot = joinPath(p.Root, pkgtargetroot)
|
||||||
|
|
||||||
|
// Set the install target if applicable.
|
||||||
|
if !p.Goroot || (installgoroot.Value() == "all" && p.ImportPath != "unsafe" && p.ImportPath != "builtin") {
|
||||||
|
if p.Goroot {
|
||||||
|
installgoroot.IncNonDefault()
|
||||||
|
}
|
||||||
|
p.PkgObj = joinPath(p.Root, pkga)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If it's a local import path, by the time we get here, we still haven't checked
|
||||||
|
// that p.Dir directory exists. This is the right time to do that check.
|
||||||
|
// We can't do it earlier, because we want to gather partial information for the
|
||||||
|
// non-nil *Package returned when an error occurs.
|
||||||
|
// We need to do this before we return early on FindOnly flag.
|
||||||
|
if IsLocalImport(path) && !isDir(p.Dir) {
|
||||||
|
if ctxt.Compiler == "gccgo" && p.Goroot {
|
||||||
|
// gccgo has no sources for GOROOT packages.
|
||||||
|
return p, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// package was not found
|
||||||
|
return p, fmt.Errorf("cannot find package %q in:\n\t%s", p.ImportPath, p.Dir)
|
||||||
|
}
|
||||||
|
|
||||||
|
if mode&FindOnly != 0 {
|
||||||
|
return p, pkgerr
|
||||||
|
}
|
||||||
|
if binaryOnly && (mode&AllowBinary) != 0 {
|
||||||
|
return p, pkgerr
|
||||||
|
}
|
||||||
|
|
||||||
|
if ctxt.Compiler == "gccgo" && p.Goroot {
|
||||||
|
// gccgo has no sources for GOROOT packages.
|
||||||
|
return p, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
dirs, err := readDir(p.Dir)
|
||||||
|
if err != nil {
|
||||||
|
return p, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var badGoError error
|
||||||
|
badGoFiles := make(map[string]bool)
|
||||||
|
badGoFile := func(name string, err error) {
|
||||||
|
if badGoError == nil {
|
||||||
|
badGoError = err
|
||||||
|
}
|
||||||
|
if !badGoFiles[name] {
|
||||||
|
p.InvalidGoFiles = append(p.InvalidGoFiles, name)
|
||||||
|
badGoFiles[name] = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var Sfiles []string // files with ".S"(capital S)/.sx(capital s equivalent for case insensitive filesystems)
|
||||||
|
var firstFile, firstCommentFile string
|
||||||
|
embedPos := make(map[string][]token.Position)
|
||||||
|
testEmbedPos := make(map[string][]token.Position)
|
||||||
|
xTestEmbedPos := make(map[string][]token.Position)
|
||||||
|
importPos := make(map[string][]token.Position)
|
||||||
|
testImportPos := make(map[string][]token.Position)
|
||||||
|
xTestImportPos := make(map[string][]token.Position)
|
||||||
|
allTags := make(map[string]bool)
|
||||||
|
fset := token.NewFileSet()
|
||||||
|
for _, d := range dirs {
|
||||||
|
if d.IsDir() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if d.Type() == fs.ModeSymlink {
|
||||||
|
if isDir(joinPath(p.Dir, d.Name())) {
|
||||||
|
// Symlinks to directories are not source files.
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
name := d.Name()
|
||||||
|
ext := nameExt(name)
|
||||||
|
|
||||||
|
info, err := matchFile(ctxt, p.Dir, name, allTags, &p.BinaryOnly, fset)
|
||||||
|
if err != nil && strings.HasSuffix(name, ".go") {
|
||||||
|
badGoFile(name, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if info == nil {
|
||||||
|
if strings.HasPrefix(name, "_") || strings.HasPrefix(name, ".") {
|
||||||
|
// not due to build constraints - don't report
|
||||||
|
} else if ext == ".go" {
|
||||||
|
p.IgnoredGoFiles = append(p.IgnoredGoFiles, name)
|
||||||
|
} else if fileListForExt(p, ext) != nil {
|
||||||
|
p.IgnoredOtherFiles = append(p.IgnoredOtherFiles, name)
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Going to save the file. For non-Go files, can stop here.
|
||||||
|
switch ext {
|
||||||
|
case ".go":
|
||||||
|
// keep going
|
||||||
|
case ".S", ".sx":
|
||||||
|
// special case for cgo, handled at end
|
||||||
|
Sfiles = append(Sfiles, name)
|
||||||
|
continue
|
||||||
|
default:
|
||||||
|
if list := fileListForExt(p, ext); list != nil {
|
||||||
|
*list = append(*list, name)
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
data, filename := info.header, info.name
|
||||||
|
|
||||||
|
if info.parseErr != nil {
|
||||||
|
badGoFile(name, info.parseErr)
|
||||||
|
// Fall through: we might still have a partial AST in info.parsed,
|
||||||
|
// and we want to list files with parse errors anyway.
|
||||||
|
}
|
||||||
|
|
||||||
|
var pkg string
|
||||||
|
if info.parsed != nil {
|
||||||
|
pkg = info.parsed.Name.Name
|
||||||
|
if pkg == "documentation" {
|
||||||
|
p.IgnoredGoFiles = append(p.IgnoredGoFiles, name)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
isTest := strings.HasSuffix(name, "_test.go")
|
||||||
|
isXTest := false
|
||||||
|
if isTest && strings.HasSuffix(pkg, "_test") && p.Name != pkg {
|
||||||
|
isXTest = true
|
||||||
|
pkg = pkg[:len(pkg)-len("_test")]
|
||||||
|
}
|
||||||
|
|
||||||
|
if p.Name == "" {
|
||||||
|
p.Name = pkg
|
||||||
|
firstFile = name
|
||||||
|
} else if pkg != p.Name {
|
||||||
|
// TODO(#45999): The choice of p.Name is arbitrary based on file iteration
|
||||||
|
// order. Instead of resolving p.Name arbitrarily, we should clear out the
|
||||||
|
// existing name and mark the existing files as also invalid.
|
||||||
|
badGoFile(name, &MultiplePackageError{
|
||||||
|
Dir: p.Dir,
|
||||||
|
Packages: []string{p.Name, pkg},
|
||||||
|
Files: []string{firstFile, name},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
// Grab the first package comment as docs, provided it is not from a test file.
|
||||||
|
if info.parsed != nil && info.parsed.Doc != nil && p.Doc == "" && !isTest && !isXTest {
|
||||||
|
p.Doc = doc.Synopsis(info.parsed.Doc.Text())
|
||||||
|
}
|
||||||
|
|
||||||
|
if mode&ImportComment != 0 {
|
||||||
|
qcom, line := findImportComment(data)
|
||||||
|
if line != 0 {
|
||||||
|
com, err := strconv.Unquote(qcom)
|
||||||
|
if err != nil {
|
||||||
|
badGoFile(name, fmt.Errorf("%s:%d: cannot parse import comment", filename, line))
|
||||||
|
} else if p.ImportComment == "" {
|
||||||
|
p.ImportComment = com
|
||||||
|
firstCommentFile = name
|
||||||
|
} else if p.ImportComment != com {
|
||||||
|
badGoFile(name, fmt.Errorf("found import comments %q (%s) and %q (%s) in %s", p.ImportComment, firstCommentFile, com, name, p.Dir))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Record imports and information about cgo.
|
||||||
|
isCgo := false
|
||||||
|
for _, imp := range info.imports {
|
||||||
|
if imp.path == "C" {
|
||||||
|
if isTest {
|
||||||
|
badGoFile(name, fmt.Errorf("use of cgo in test %s not supported", filename))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
isCgo = true
|
||||||
|
if imp.doc != nil {
|
||||||
|
if err := saveCgo(ctxt, filename, p, imp.doc); err != nil {
|
||||||
|
badGoFile(name, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var fileList *[]string
|
||||||
|
var importMap, embedMap map[string][]token.Position
|
||||||
|
var directives *[]Directive
|
||||||
|
switch {
|
||||||
|
case isCgo:
|
||||||
|
allTags["cgo"] = true
|
||||||
|
if ctxt.CgoEnabled {
|
||||||
|
fileList = &p.CgoFiles
|
||||||
|
importMap = importPos
|
||||||
|
embedMap = embedPos
|
||||||
|
directives = &p.Directives
|
||||||
|
} else {
|
||||||
|
// Ignore imports and embeds from cgo files if cgo is disabled.
|
||||||
|
fileList = &p.IgnoredGoFiles
|
||||||
|
}
|
||||||
|
case isXTest:
|
||||||
|
fileList = &p.XTestGoFiles
|
||||||
|
importMap = xTestImportPos
|
||||||
|
embedMap = xTestEmbedPos
|
||||||
|
directives = &p.XTestDirectives
|
||||||
|
case isTest:
|
||||||
|
fileList = &p.TestGoFiles
|
||||||
|
importMap = testImportPos
|
||||||
|
embedMap = testEmbedPos
|
||||||
|
directives = &p.TestDirectives
|
||||||
|
default:
|
||||||
|
fileList = &p.GoFiles
|
||||||
|
importMap = importPos
|
||||||
|
embedMap = embedPos
|
||||||
|
directives = &p.Directives
|
||||||
|
}
|
||||||
|
*fileList = append(*fileList, name)
|
||||||
|
if importMap != nil {
|
||||||
|
for _, imp := range info.imports {
|
||||||
|
importMap[imp.path] = append(importMap[imp.path], fset.Position(imp.pos))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if embedMap != nil {
|
||||||
|
for _, emb := range info.embeds {
|
||||||
|
embedMap[emb.pattern] = append(embedMap[emb.pattern], emb.pos)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if directives != nil {
|
||||||
|
*directives = append(*directives, info.directives...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for tag := range allTags {
|
||||||
|
p.AllTags = append(p.AllTags, tag)
|
||||||
|
}
|
||||||
|
slices.Sort(p.AllTags)
|
||||||
|
|
||||||
|
p.EmbedPatterns, p.EmbedPatternPos = cleanDecls(embedPos)
|
||||||
|
p.TestEmbedPatterns, p.TestEmbedPatternPos = cleanDecls(testEmbedPos)
|
||||||
|
p.XTestEmbedPatterns, p.XTestEmbedPatternPos = cleanDecls(xTestEmbedPos)
|
||||||
|
|
||||||
|
p.Imports, p.ImportPos = cleanDecls(importPos)
|
||||||
|
p.TestImports, p.TestImportPos = cleanDecls(testImportPos)
|
||||||
|
p.XTestImports, p.XTestImportPos = cleanDecls(xTestImportPos)
|
||||||
|
|
||||||
|
// add the .S/.sx files only if we are using cgo
|
||||||
|
// (which means gcc will compile them).
|
||||||
|
// The standard assemblers expect .s files.
|
||||||
|
if len(p.CgoFiles) > 0 {
|
||||||
|
p.SFiles = append(p.SFiles, Sfiles...)
|
||||||
|
slices.Sort(p.SFiles)
|
||||||
|
} else {
|
||||||
|
p.IgnoredOtherFiles = append(p.IgnoredOtherFiles, Sfiles...)
|
||||||
|
slices.Sort(p.IgnoredOtherFiles)
|
||||||
|
}
|
||||||
|
|
||||||
|
if badGoError != nil {
|
||||||
|
return p, badGoError
|
||||||
|
}
|
||||||
|
if len(p.GoFiles)+len(p.CgoFiles)+len(p.TestGoFiles)+len(p.XTestGoFiles) == 0 {
|
||||||
|
return p, &NoGoError{p.Dir}
|
||||||
|
}
|
||||||
|
return p, pkgerr
|
||||||
|
}
|
||||||
206
cl/_testdefer/gobuild/out.txt
Normal file
206
cl/_testdefer/gobuild/out.txt
Normal file
@@ -0,0 +1,206 @@
|
|||||||
|
0: always
|
||||||
|
1: cond
|
||||||
|
2: cond
|
||||||
|
3: cond
|
||||||
|
4: cond
|
||||||
|
6: cond
|
||||||
|
8: cond
|
||||||
|
7: cond
|
||||||
|
9: cond
|
||||||
|
5: cond
|
||||||
|
10: cond
|
||||||
|
11: cond
|
||||||
|
12: cond
|
||||||
|
13: cond
|
||||||
|
33: cond
|
||||||
|
34: cond
|
||||||
|
14: cond
|
||||||
|
35: cond
|
||||||
|
15: cond
|
||||||
|
36: cond
|
||||||
|
37: cond
|
||||||
|
16: cond
|
||||||
|
40: cond
|
||||||
|
19: cond
|
||||||
|
38: cond
|
||||||
|
17: cond
|
||||||
|
18: cond
|
||||||
|
43: cond
|
||||||
|
42: cond
|
||||||
|
41: cond
|
||||||
|
21: loop
|
||||||
|
22: loop
|
||||||
|
24: loop
|
||||||
|
23: cond
|
||||||
|
27: cond
|
||||||
|
25: cond
|
||||||
|
28: cond
|
||||||
|
26: cond
|
||||||
|
29: loop
|
||||||
|
30: loop
|
||||||
|
31: cond
|
||||||
|
32: cond
|
||||||
|
44: loop
|
||||||
|
45: loop
|
||||||
|
39: cond
|
||||||
|
46: cond
|
||||||
|
48: cond
|
||||||
|
49: cond
|
||||||
|
50: cond
|
||||||
|
51: cond
|
||||||
|
52: cond
|
||||||
|
54: cond
|
||||||
|
59: cond
|
||||||
|
58: cond
|
||||||
|
56: cond
|
||||||
|
57: cond
|
||||||
|
61: cond
|
||||||
|
60: cond
|
||||||
|
55: cond
|
||||||
|
53: cond
|
||||||
|
63: cond
|
||||||
|
62: cond
|
||||||
|
47: cond
|
||||||
|
64: loop
|
||||||
|
65: loop
|
||||||
|
68: loop
|
||||||
|
73: loop
|
||||||
|
72: loop
|
||||||
|
66: cond
|
||||||
|
70: cond
|
||||||
|
71: cond
|
||||||
|
76: cond
|
||||||
|
69: cond
|
||||||
|
74: cond
|
||||||
|
67: cond
|
||||||
|
77: cond
|
||||||
|
82: cond
|
||||||
|
81: cond
|
||||||
|
79: cond
|
||||||
|
80: cond
|
||||||
|
84: cond
|
||||||
|
83: cond
|
||||||
|
78: cond
|
||||||
|
20: cond
|
||||||
|
75: cond
|
||||||
|
96: cond
|
||||||
|
98: cond
|
||||||
|
100: cond
|
||||||
|
102: cond
|
||||||
|
101: cond
|
||||||
|
99: cond
|
||||||
|
103: cond
|
||||||
|
104: cond
|
||||||
|
97: cond
|
||||||
|
107: cond
|
||||||
|
106: cond
|
||||||
|
105: cond
|
||||||
|
111: cond
|
||||||
|
112: cond
|
||||||
|
110: cond
|
||||||
|
115: cond
|
||||||
|
108: cond
|
||||||
|
109: cond
|
||||||
|
113: cond
|
||||||
|
114: cond
|
||||||
|
118: cond
|
||||||
|
116: cond
|
||||||
|
117: cond
|
||||||
|
119: cond
|
||||||
|
120: cond
|
||||||
|
85: loop
|
||||||
|
86: loop
|
||||||
|
87: cond
|
||||||
|
88: cond
|
||||||
|
90: cond
|
||||||
|
89: cond
|
||||||
|
91: loop
|
||||||
|
92: loop
|
||||||
|
93: cond
|
||||||
|
94: cond
|
||||||
|
95: cond
|
||||||
|
121: loop
|
||||||
|
122: loop
|
||||||
|
123: cond
|
||||||
|
124: cond
|
||||||
|
125: cond
|
||||||
|
126: cond
|
||||||
|
129: cond
|
||||||
|
127: cond
|
||||||
|
128: cond
|
||||||
|
130: cond
|
||||||
|
131: cond
|
||||||
|
133: cond
|
||||||
|
137: cond
|
||||||
|
139: cond
|
||||||
|
132: cond
|
||||||
|
143: cond
|
||||||
|
140: cond
|
||||||
|
134: cond
|
||||||
|
135: cond
|
||||||
|
144: cond
|
||||||
|
138: cond
|
||||||
|
141: cond
|
||||||
|
136: cond
|
||||||
|
145: cond
|
||||||
|
142: cond
|
||||||
|
147: cond
|
||||||
|
146: cond
|
||||||
|
151: cond
|
||||||
|
150: cond
|
||||||
|
148: cond
|
||||||
|
149: cond
|
||||||
|
152: cond
|
||||||
|
154: cond
|
||||||
|
155: cond
|
||||||
|
153: cond
|
||||||
|
161: cond
|
||||||
|
160: cond
|
||||||
|
159: cond
|
||||||
|
158: cond
|
||||||
|
156: cond
|
||||||
|
157: cond
|
||||||
|
162: cond
|
||||||
|
164: cond
|
||||||
|
165: cond
|
||||||
|
166: cond
|
||||||
|
167: cond
|
||||||
|
168: cond
|
||||||
|
169: cond
|
||||||
|
163: cond
|
||||||
|
170: loop
|
||||||
|
171: loop
|
||||||
|
173: loop
|
||||||
|
174: loop
|
||||||
|
172: cond
|
||||||
|
175: cond
|
||||||
|
179: cond
|
||||||
|
181: cond
|
||||||
|
176: cond
|
||||||
|
182: cond
|
||||||
|
183: cond
|
||||||
|
180: cond
|
||||||
|
185: cond
|
||||||
|
177: cond
|
||||||
|
184: cond
|
||||||
|
186: cond
|
||||||
|
178: cond
|
||||||
|
187: cond
|
||||||
|
189: loop
|
||||||
|
190: loop
|
||||||
|
188: cond
|
||||||
|
191: cond
|
||||||
|
193: loop
|
||||||
|
194: loop
|
||||||
|
192: cond
|
||||||
|
195: cond
|
||||||
|
196: loop
|
||||||
|
197: loop
|
||||||
|
198: cond
|
||||||
|
199: cond
|
||||||
|
201: cond
|
||||||
|
200: cond
|
||||||
|
202: cond
|
||||||
|
203: cond
|
||||||
|
204: cond
|
||||||
|
205: cond
|
||||||
@@ -60,11 +60,14 @@ func findLoop(states []*blockState, path []int, from, iblk int) []int {
|
|||||||
path = append(path, iblk)
|
path = append(path, iblk)
|
||||||
self := states[iblk]
|
self := states[iblk]
|
||||||
for _, succ := range self.succs {
|
for _, succ := range self.succs {
|
||||||
if states[succ].fdel {
|
if s := states[succ]; s.fdel || s.loop {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if pos := find(path, succ); pos >= 0 {
|
if pos := find(path, succ); pos >= 0 {
|
||||||
if pos > 0 {
|
if pos > 0 {
|
||||||
|
for _, i := range path[pos:] { // mark inner loop
|
||||||
|
states[i].loop = true
|
||||||
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
for _, i := range path {
|
for _, i := range path {
|
||||||
@@ -72,6 +75,11 @@ func findLoop(states []*blockState, path []int, from, iblk int) []int {
|
|||||||
s.loop = true
|
s.loop = true
|
||||||
s.fdel = true
|
s.fdel = true
|
||||||
}
|
}
|
||||||
|
for _, s := range states { // clear inner loop mark
|
||||||
|
if !s.fdel {
|
||||||
|
s.loop = false
|
||||||
|
}
|
||||||
|
}
|
||||||
return path
|
return path
|
||||||
}
|
}
|
||||||
if ret := findLoop(states, path, from, succ); len(ret) > 0 {
|
if ret := findLoop(states, path, from, succ); len(ret) > 0 {
|
||||||
|
|||||||
@@ -44,6 +44,9 @@ func TestTestdefer(t *testing.T) {
|
|||||||
if strings.HasPrefix(name, "firstloop") {
|
if strings.HasPrefix(name, "firstloop") {
|
||||||
return "Loop"
|
return "Loop"
|
||||||
}
|
}
|
||||||
|
if strings.HasPrefix(name, "gobuild") {
|
||||||
|
return "Import"
|
||||||
|
}
|
||||||
return "main"
|
return "main"
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user