From 81c8ef202badf76ecc653e9229ef0b99efed586b Mon Sep 17 00:00:00 2001 From: Nick Santos Date: Sun, 2 Feb 2020 16:57:51 -0500 Subject: [PATCH] cmd/go/internal/vet: print line numbers appropriately on list errors Fixes #36173 For reasons that are unclear to me, this commit: https://github.com/golang/go/commit/f1d5ce0185fe184c016016d55f1718778b799f6d introduces a TestPackagesFor function that strips line numbers from error messages. This commit introduces a new version of that function for 'go vet' that always keeps the line numbers. --- src/cmd/go/internal/get/get.go | 14 +- src/cmd/go/internal/load/pkg.go | 225 ++++++++++++------ src/cmd/go/internal/load/test.go | 20 +- src/cmd/go/internal/modload/import.go | 14 +- src/cmd/go/internal/work/action.go | 2 +- .../testdata/script/mod_ambiguous_import.txt | 3 +- .../script/test_import_error_stack.txt | 3 + src/cmd/go/testdata/script/vet_internal.txt | 72 ++++++ 8 files changed, 260 insertions(+), 93 deletions(-) create mode 100644 src/cmd/go/testdata/script/vet_internal.txt diff --git a/src/cmd/go/internal/get/get.go b/src/cmd/go/internal/get/get.go index 500e3e0da6dd16..3c2498b065ff20 100644 --- a/src/cmd/go/internal/get/get.go +++ b/src/cmd/go/internal/get/get.go @@ -271,10 +271,10 @@ func download(arg string, parent *load.Package, stk *load.ImportStack, mode int) // Download if the package is missing, or update if we're using -u. if p.Dir == "" || *getU { // The actual download. - stk.Push(arg) + stk.Push(arg, nil) err := downloadPackage(p) if err != nil { - base.Errorf("%s", &load.PackageError{ImportStack: stk.Copy(), Err: err}) + base.Errorf("%s", load.NewPackageError(stk, err)) stk.Pop() return } @@ -329,7 +329,7 @@ func download(arg string, parent *load.Package, stk *load.ImportStack, mode int) if isWildcard { // Report both the real package and the // wildcard in any error message. - stk.Push(p.ImportPath) + stk.Push(p.ImportPath, nil) } // Process dependencies, now that we know what they are. @@ -352,11 +352,9 @@ func download(arg string, parent *load.Package, stk *load.ImportStack, mode int) orig = p.Internal.Build.Imports[i] } if j, ok := load.FindVendor(orig); ok { - stk.Push(path) - err := &load.PackageError{ - ImportStack: stk.Copy(), - Err: load.ImportErrorf(path, "%s must be imported as %s", path, path[j+len("vendor/"):]), - } + stk.Push(path, nil) + err := load.NewPackageError(stk, + load.ImportErrorf(path, "%s must be imported as %s", path, path[j+len("vendor/"):])) stk.Pop() base.Errorf("%s", err) continue diff --git a/src/cmd/go/internal/load/pkg.go b/src/cmd/go/internal/load/pkg.go index 369a79b7164d37..a7e119b025fc86 100644 --- a/src/cmd/go/internal/load/pkg.go +++ b/src/cmd/go/internal/load/pkg.go @@ -304,39 +304,93 @@ func (p *Package) copyBuild(pp *build.Package) { // A PackageError describes an error loading information about a package. type PackageError struct { - ImportStack []string // shortest path from package named on command line to this one - Pos string // position of error - Err error // the error itself - IsImportCycle bool // the error is an import cycle - Hard bool // whether the error is soft or hard; soft errors are ignored in some places + importStack ImportStack // shortest path from package named on command line to this one + Err error // the error itself + IsImportCycle bool // the error is an import cycle + Hard bool // whether the error is soft or hard; soft errors are ignored in some places +} + +func NewPackageError(stk *ImportStack, err error) *PackageError { + return &PackageError{ + importStack: stk.Copy(), + Err: err, + } +} + +// For backwards-compatibility with the text/template CLI API, +// expose the position of the last stack frame. +func (p *PackageError) Pos() string { + frame := p.importStack.LastFrame() + if !frame.IsPosValid() { + return "" + } + return frame.ShortPos() +} + +// For backwards-compatibility with the text/template CLI API, +// export the import stack as a list of paths. +func (p *PackageError) ImportStack() []string { + paths := []string{} + for _, frame := range p.importStack { + paths = append(paths, frame.Path) + } + return paths } func (p *PackageError) Error() string { + stack := p.importStack + // Import cycles deserve special treatment. if p.IsImportCycle { - return fmt.Sprintf("%s\npackage %s\n", p.Err, strings.Join(p.ImportStack, "\n\timports ")) + return fmt.Sprintf("%s\npackage %s\n", p.Err, strings.Join(p.ImportStack(), "\n\timports ")) } - if p.Pos != "" { - // Omit import stack. The full path to the file where the error - // is the most important thing. - return p.Pos + ": " + p.Err.Error() + + // If this is a direct dependency with valid token info, + // just print that file/line/column directly. + if len(stack) <= 2 && stack.LastFrame().IsPosValid() { + return stack.LastFrame().ShortPos() + ": " + p.Err.Error() } - // If the error is an ImportPathError, and the last path on the stack appears - // in the error message, omit that path from the stack to avoid repetition. - // If an ImportPathError wraps another ImportPathError that matches the - // last path on the stack, we don't omit the path. An error like - // "package A imports B: error loading C caused by B" would not be clearer - // if "imports B" were omitted. - stack := p.ImportStack + // Otherwise, try to print out a full stack trace. + trace := []string{} + var ierr ImportPathError - if len(stack) > 0 && errors.As(p.Err, &ierr) && ierr.ImportPath() == stack[len(stack)-1] { - stack = stack[:len(stack)-1] + isImportPathError := errors.As(p.Err, &ierr) + + for i, frame := range stack { + if i == len(stack)-1 { + // If the error is an ImportPathError, and the last path on the stack appears + // in the error message, omit that path from the stack to avoid repetition. + // If an ImportPathError wraps another ImportPathError that matches the + // last path on the stack, we don't omit the path. An error like + // "package A imports B: error loading C caused by B" would not be clearer + // if "imports B" were omitted. + if isImportPathError && ierr.ImportPath() == frame.Path { + break + } + } + + // If this is an import path error, the second-to-last stack frame is + // the important one, because it's the one with the problem import. + // Look at the last stack frame to find the return pointer + // to the position in this file. + if isImportPathError && i == len(stack)-2 && stack.LastFrame().IsPosValid() { + trace = append(trace, stack.LastFrame().ShortPos()) + break + } + + if i == 0 { + trace = append(trace, "package "+frame.Path) + continue + } + + trace = append(trace, "imports "+frame.Path) } - if len(stack) == 0 { + + if len(trace) == 0 { return p.Err.Error() } - return "package " + strings.Join(stack, "\n\timports ") + ": " + p.Err.Error() + return strings.Join(trace, "\n\t") + ": " + p.Err.Error() } // PackageError implements MarshalJSON so that Err is marshaled as a string @@ -346,7 +400,7 @@ func (p *PackageError) MarshalJSON() ([]byte, error) { ImportStack []string Pos string Err string - }{p.ImportStack, p.Pos, p.Err.Error()} + }{p.ImportStack(), p.Pos(), p.Err.Error()} return json.Marshal(perr) } @@ -392,35 +446,84 @@ func (e *importError) ImportPath() string { return e.importPath } -// An ImportStack is a stack of import paths, possibly with the suffix " (test)" appended. -// The import path of a test package is the import path of the corresponding -// non-test package with the suffix "_test" added. -type ImportStack []string +type ImportStackFrame struct { + // The import path, possibly with the suffix " (test)" appended. + // The import path of a test package is the import path of the corresponding + // non-test package with the suffix "_test" added. + Path string + + // The file position info of the importer, + // including line and column number. + Pos token.Position +} + +func NewImportStackFrame(path string, importPos []token.Position) ImportStackFrame { + result := ImportStackFrame{Path: path} + if len(importPos) > 0 { + result.Pos = importPos[0] + } + return result +} + +func (f ImportStackFrame) IsPosValid() bool { + return f.Pos.IsValid() +} + +func (f ImportStackFrame) ShortPos() string { + if !f.IsPosValid() { + return f.Path + } + pos := f.Pos + pos.Filename = base.ShortPath(pos.Filename) + return pos.String() +} -func (s *ImportStack) Push(p string) { - *s = append(*s, p) +type ImportStack []ImportStackFrame + +func (s ImportStack) LastFrame() ImportStackFrame { + if len(s) == 0 { + return ImportStackFrame{} + } + return s[len(s)-1] +} + +// Pushes a path onto the stack, and marks where it was imported. +func (s *ImportStack) Push(path string, importPos []token.Position) { + var pos token.Position + if len(importPos) > 0 { + pos = importPos[0] + } + *s = append(*s, ImportStackFrame{Path: path, Pos: pos}) } func (s *ImportStack) Pop() { *s = (*s)[0 : len(*s)-1] } -func (s *ImportStack) Copy() []string { - return append([]string{}, *s...) +func (s *ImportStack) Copy() ImportStack { + return append(ImportStack{}, (*s)...) } -// shorterThan reports whether sp is shorter than t. -// We use this to record the shortest import sequence +// betterThan reports whether sp is better than t for error reporting. +// We generally prefer the shortest import sequence // that leads to a particular package. -func (sp *ImportStack) shorterThan(t []string) bool { +func (sp *ImportStack) betterThan(t ImportStack) bool { s := *sp + + // If one stack has position info and one does not, prefer the + // one with positions. + if s.LastFrame().IsPosValid() != t.LastFrame().IsPosValid() { + return s.LastFrame().IsPosValid() + } + if len(s) != len(t) { return len(s) < len(t) } - // If they are the same length, settle ties using string ordering. + + // If they are the same length, settle ties using path string ordering for i := range s { - if s[i] != t[i] { - return s[i] < t[i] + if s[i].Path != t[i].Path { + return s[i].Path < t[i].Path } } return false // they are equal @@ -536,7 +639,7 @@ func loadImport(pre *preload, path, srcDir string, parent *Package, stk *ImportS panic("LoadImport called with empty package path") } - stk.Push(path) + stk.Push(path, importPos) defer stk.Pop() var parentPath, parentRoot string @@ -555,7 +658,7 @@ func loadImport(pre *preload, path, srcDir string, parent *Package, stk *ImportS PackagePublic: PackagePublic{ ImportPath: path, Error: &PackageError{ - ImportStack: stk.Copy(), + importStack: stk.Copy(), Err: err, }, }, @@ -576,13 +679,10 @@ func loadImport(pre *preload, path, srcDir string, parent *Package, stk *ImportS // loadPackageData may return bp != nil even if an error occurs, // in order to return partial information. p.load(stk, bp, err) - if p.Error != nil && p.Error.Pos == "" { - p = setErrorPos(p, importPos) - } if !cfg.ModulesEnabled && path != cleanImport(path) { p.Error = &PackageError{ - ImportStack: stk.Copy(), + importStack: stk.Copy(), Err: fmt.Errorf("non-canonical import path: %q should be %q", path, pathpkg.Clean(path)), } p.Incomplete = true @@ -591,21 +691,21 @@ func loadImport(pre *preload, path, srcDir string, parent *Package, stk *ImportS // Checked on every import because the rules depend on the code doing the importing. if perr := disallowInternal(srcDir, parent, parentPath, p, stk); perr != p { - return setErrorPos(perr, importPos) + return perr } if mode&ResolveImport != 0 { if perr := disallowVendor(srcDir, path, p, stk); perr != p { - return setErrorPos(perr, importPos) + return perr } } if p.Name == "main" && parent != nil && parent.Dir != p.Dir { perr := *p perr.Error = &PackageError{ - ImportStack: stk.Copy(), + importStack: stk.Copy(), Err: ImportErrorf(path, "import %q is a program, not an importable package", path), } - return setErrorPos(&perr, importPos) + return &perr } if p.Internal.Local && parent != nil && !parent.Internal.Local { @@ -617,24 +717,15 @@ func loadImport(pre *preload, path, srcDir string, parent *Package, stk *ImportS err = ImportErrorf(path, "local import %q in non-local package", path) } perr.Error = &PackageError{ - ImportStack: stk.Copy(), + importStack: stk.Copy(), Err: err, } - return setErrorPos(&perr, importPos) + return &perr } return p } -func setErrorPos(p *Package, importPos []token.Position) *Package { - if len(importPos) > 0 { - pos := importPos[0] - pos.Filename = base.ShortPath(pos.Filename) - p.Error.Pos = pos.String() - } - return p -} - // loadPackageData loads information needed to construct a *Package. The result // is cached, and later calls to loadPackageData for the same package will return // the same data. @@ -1198,7 +1289,7 @@ func reusePackage(p *Package, stk *ImportStack) *Package { if p.Internal.Imports == nil { if p.Error == nil { p.Error = &PackageError{ - ImportStack: stk.Copy(), + importStack: stk.Copy(), Err: errors.New("import cycle not allowed"), IsImportCycle: true, } @@ -1207,8 +1298,8 @@ func reusePackage(p *Package, stk *ImportStack) *Package { } // Don't rewrite the import stack in the error if we have an import cycle. // If we do, we'll lose the path that describes the cycle. - if p.Error != nil && !p.Error.IsImportCycle && stk.shorterThan(p.Error.ImportStack) { - p.Error.ImportStack = stk.Copy() + if p.Error != nil && !p.Error.IsImportCycle && stk.betterThan(p.Error.importStack) { + p.Error.importStack = stk.Copy() } return p } @@ -1232,7 +1323,7 @@ func disallowInternal(srcDir string, importer *Package, importerPath string, p * // as if it were generated into the testing directory tree // (it's actually in a temporary directory outside any Go tree). // This cleans up a former kludge in passing functionality to the testing package. - if strings.HasPrefix(p.ImportPath, "testing/internal") && len(*stk) >= 2 && (*stk)[len(*stk)-2] == "testmain" { + if strings.HasPrefix(p.ImportPath, "testing/internal") && len(*stk) >= 2 && (*stk)[len(*stk)-2].Path == "testmain" { return p } @@ -1301,7 +1392,7 @@ func disallowInternal(srcDir string, importer *Package, importerPath string, p * // Internal is present, and srcDir is outside parent's tree. Not allowed. perr := *p perr.Error = &PackageError{ - ImportStack: stk.Copy(), + importStack: stk.Copy(), Err: ImportErrorf(p.ImportPath, "use of internal package "+p.ImportPath+" not allowed"), } perr.Incomplete = true @@ -1347,7 +1438,7 @@ func disallowVendor(srcDir string, path string, p *Package, stk *ImportStack) *P if i, ok := FindVendor(path); ok { perr := *p perr.Error = &PackageError{ - ImportStack: stk.Copy(), + importStack: stk.Copy(), Err: ImportErrorf(path, "%s must be imported as %s", path, path[i+len("vendor/"):]), } perr.Incomplete = true @@ -1401,7 +1492,7 @@ func disallowVendorVisibility(srcDir string, p *Package, stk *ImportStack) *Pack // Vendor is present, and srcDir is outside parent's tree. Not allowed. perr := *p perr.Error = &PackageError{ - ImportStack: stk.Copy(), + importStack: stk.Copy(), Err: errors.New("use of vendored package not allowed"), } perr.Incomplete = true @@ -1526,7 +1617,7 @@ func (p *Package) load(stk *ImportStack, bp *build.Package, err error) { setError := func(err error) { if p.Error == nil { p.Error = &PackageError{ - ImportStack: stk.Copy(), + importStack: stk.Copy(), Err: err, } } @@ -1797,7 +1888,7 @@ func (p *Package) collectDeps() { // depending on what tries to import it. // Prefer to record entries with errors, so we can report them. p0 := deps[path] - if p0 == nil || p1.Error != nil && (p0.Error == nil || len(p0.Error.ImportStack) > len(p1.Error.ImportStack)) { + if p0 == nil || p1.Error != nil && (p0.Error == nil || len(p0.Error.importStack) > len(p1.Error.importStack)) { deps[path] = p1 for _, p2 := range p1.Internal.Imports { if deps[p2.ImportPath] != p2 { @@ -2226,7 +2317,7 @@ func GoFilesPackage(gofiles []string) *Package { pkg := new(Package) pkg.Internal.Local = true pkg.Internal.CmdlineFiles = true - stk.Push("main") + stk.Push("main", nil) pkg.load(&stk, bp, err) stk.Pop() pkg.Internal.LocalPrefix = dirToImportPath(dir) diff --git a/src/cmd/go/internal/load/test.go b/src/cmd/go/internal/load/test.go index fefc7d2e307d9f..20508f31f55035 100644 --- a/src/cmd/go/internal/load/test.go +++ b/src/cmd/go/internal/load/test.go @@ -54,9 +54,7 @@ func TestPackagesFor(p *Package, cover *TestCover) (pmain, ptest, pxtest *Packag break } if len(p1.DepsErrors) > 0 { - perr := p1.DepsErrors[0] - perr.Pos = "" // show full import stack - err = perr + err = p1.DepsErrors[0] break } } @@ -100,7 +98,7 @@ func TestPackagesAndErrors(p *Package, cover *TestCover) (pmain, ptest, pxtest * var ptestErr, pxtestErr *PackageError var imports, ximports []*Package var stk ImportStack - stk.Push(p.ImportPath + " (test)") + stk.Push(p.ImportPath+" (test)", nil) rawTestImports := str.StringList(p.TestImports) for i, path := range p.TestImports { p1 := loadImport(pre, path, p.Dir, p, &stk, p.Internal.Build.TestImportPos[path], ResolveImport) @@ -109,7 +107,7 @@ func TestPackagesAndErrors(p *Package, cover *TestCover) (pmain, ptest, pxtest * // Can't change that code, because that code is only for loading the // non-test copy of a package. ptestErr = &PackageError{ - ImportStack: testImportStack(stk[0], p1, p.ImportPath), + importStack: testImportStack(stk[0], p1, p.ImportPath), Err: errors.New("import cycle not allowed in test"), IsImportCycle: true, } @@ -118,7 +116,7 @@ func TestPackagesAndErrors(p *Package, cover *TestCover) (pmain, ptest, pxtest * imports = append(imports, p1) } stk.Pop() - stk.Push(p.ImportPath + "_test") + stk.Push(p.ImportPath+"_test", nil) pxtestNeedsPtest := false rawXTestImports := str.StringList(p.XTestImports) for i, path := range p.XTestImports { @@ -230,7 +228,7 @@ func TestPackagesAndErrors(p *Package, cover *TestCover) (pmain, ptest, pxtest * // The generated main also imports testing, regexp, and os. // Also the linker introduces implicit dependencies reported by LinkerDeps. - stk.Push("testmain") + stk.Push("testmain", nil) deps := TestMainDeps // cap==len, so safe for append for _, d := range LinkerDeps(p) { deps = append(deps, d) @@ -331,19 +329,19 @@ func TestPackagesAndErrors(p *Package, cover *TestCover) (pmain, ptest, pxtest * return pmain, ptest, pxtest } -func testImportStack(top string, p *Package, target string) []string { - stk := []string{top, p.ImportPath} +func testImportStack(top ImportStackFrame, p *Package, target string) ImportStack { + stk := ImportStack{top, ImportStackFrame{Path: p.ImportPath}} Search: for p.ImportPath != target { for _, p1 := range p.Internal.Imports { if p1.ImportPath == target || str.Contains(p1.Deps, target) { - stk = append(stk, p1.ImportPath) + stk = append(stk, ImportStackFrame{Path: p1.ImportPath}) p = p1 continue Search } } // Can't happen, but in case it does... - stk = append(stk, "") + stk = append(stk, ImportStackFrame{Path: ""}) break } return stk diff --git a/src/cmd/go/internal/modload/import.go b/src/cmd/go/internal/modload/import.go index 5906d648b49afd..44be5f61bae105 100644 --- a/src/cmd/go/internal/modload/import.go +++ b/src/cmd/go/internal/modload/import.go @@ -62,11 +62,15 @@ func (e *ImportMissingError) ImportPath() string { // modules in the build list, or found in both the main module and its vendor // directory. type AmbiguousImportError struct { - ImportPath string + importPath string Dirs []string Modules []module.Version // Either empty or 1:1 with Dirs. } +func (e *AmbiguousImportError) ImportPath() string { + return e.importPath +} + func (e *AmbiguousImportError) Error() string { locType := "modules" if len(e.Modules) == 0 { @@ -74,7 +78,7 @@ func (e *AmbiguousImportError) Error() string { } var buf strings.Builder - fmt.Fprintf(&buf, "ambiguous import: found package %s in multiple %s:", e.ImportPath, locType) + fmt.Fprintf(&buf, "ambiguous import: found package %s in multiple %s:", e.ImportPath(), locType) for i, dir := range e.Dirs { buf.WriteString("\n\t") @@ -93,6 +97,8 @@ func (e *AmbiguousImportError) Error() string { return buf.String() } +var _ load.ImportPathError = &AmbiguousImportError{} + // Import finds the module and directory in the build list // containing the package with the given import path. // The answer must be unique: Import returns an error @@ -134,7 +140,7 @@ func Import(path string) (m module.Version, dir string, err error) { mainDir, mainOK := dirInModule(path, targetPrefix, ModRoot(), true) vendorDir, vendorOK := dirInModule(path, "", filepath.Join(ModRoot(), "vendor"), false) if mainOK && vendorOK { - return module.Version{}, "", &AmbiguousImportError{ImportPath: path, Dirs: []string{mainDir, vendorDir}} + return module.Version{}, "", &AmbiguousImportError{importPath: path, Dirs: []string{mainDir, vendorDir}} } // Prefer to return main directory if there is one, // Note that we're not checking that the package exists. @@ -174,7 +180,7 @@ func Import(path string) (m module.Version, dir string, err error) { return mods[0], dirs[0], nil } if len(mods) > 0 { - return module.Version{}, "", &AmbiguousImportError{ImportPath: path, Dirs: dirs, Modules: mods} + return module.Version{}, "", &AmbiguousImportError{importPath: path, Dirs: dirs, Modules: mods} } // Look up module containing the package, for addition to the build list. diff --git a/src/cmd/go/internal/work/action.go b/src/cmd/go/internal/work/action.go index e3cb87fbb9adfd..2d82e37e8ceef7 100644 --- a/src/cmd/go/internal/work/action.go +++ b/src/cmd/go/internal/work/action.go @@ -472,7 +472,7 @@ func (b *Builder) vetAction(mode, depMode BuildMode, p *load.Package) *Action { // vet expects to be able to import "fmt". var stk load.ImportStack - stk.Push("vet") + stk.Push("vet", nil) p1 := load.LoadImportWithFlags("fmt", p.Dir, p, &stk, nil, 0) stk.Pop() aFmt := b.CompileAction(ModeBuild, depMode, p1) diff --git a/src/cmd/go/testdata/script/mod_ambiguous_import.txt b/src/cmd/go/testdata/script/mod_ambiguous_import.txt index 61e632a29ccf54..1be85946283ccc 100644 --- a/src/cmd/go/testdata/script/mod_ambiguous_import.txt +++ b/src/cmd/go/testdata/script/mod_ambiguous_import.txt @@ -11,12 +11,11 @@ go build ./importy # An import provided by both the main module and the vendor directory # should be flagged as an error only when -mod=vendor is set. -# TODO: This error message is a bit redundant. mkdir vendor/example.com/m/importy cp $WORK/importy/importy.go vendor/example.com/m/importy/importy.go go build example.com/m/importy ! go build -mod=vendor example.com/m/importy -stderr '^can.t load package: package example.com/m/importy: ambiguous import: found package example.com/m/importy in multiple directories:\n\t'$WORK'[/\\]importy\n\t'$WORK'[/\\]vendor[/\\]example.com[/\\]m[/\\]importy$' +stderr '^can.t load package: ambiguous import: found package example.com/m/importy in multiple directories:\n\t'$WORK'[/\\]importy\n\t'$WORK'[/\\]vendor[/\\]example.com[/\\]m[/\\]importy$' -- $WORK/go.mod -- module example.com/m diff --git a/src/cmd/go/testdata/script/test_import_error_stack.txt b/src/cmd/go/testdata/script/test_import_error_stack.txt index 3b796053f7cfd1..c66c1213a428c0 100644 --- a/src/cmd/go/testdata/script/test_import_error_stack.txt +++ b/src/cmd/go/testdata/script/test_import_error_stack.txt @@ -1,6 +1,9 @@ ! go test testdep/p1 stderr 'package testdep/p1 \(test\)\n\timports testdep/p2\n\timports testdep/p3: build constraints exclude all Go files ' # check for full import stack +! go vet testdep/p1 +stderr 'package testdep/p1 \(test\)\n\timports testdep/p2\n\timports testdep/p3: build constraints exclude all Go files ' # check for full import stack + -- testdep/p1/p1.go -- package p1 -- testdep/p1/p1_test.go -- diff --git a/src/cmd/go/testdata/script/vet_internal.txt b/src/cmd/go/testdata/script/vet_internal.txt new file mode 100644 index 00000000000000..3417b51139b340 --- /dev/null +++ b/src/cmd/go/testdata/script/vet_internal.txt @@ -0,0 +1,72 @@ +env GO111MODULE=off + +# Issue 36173. Verify that "go vet" prints line numbers on load errors. + +! go vet a/a.go +stderr 'a.go:5:3: use of internal package' + +! go vet a/a_test.go +stderr 'a_test.go:4:3: use of internal package' + +! go vet a +stderr 'a.go:5:3: use of internal package' + +go vet b/b.go +! stderr 'use of internal package' + +! go vet b/b_test.go +stderr 'b_test.go:4:3: use of internal package' + +! go vet depends-on-a/depends-on-a.go +stderr 'a.go:5:3: use of internal package' + +! go vet depends-on-a/depends-on-a_test.go +stderr 'package command-line-arguments \(test\)' +stderr 'a.go:5:3: use of internal package a/x/internal/y not allowed' + +! go vet depends-on-a +stderr 'a.go:5:3: use of internal package' + +-- a/a.go -- +// A package with bad imports in both src and test +package a + +import ( + _ "a/x/internal/y" +) + +-- a/a_test.go -- +package a + +import ( + _ "a/x/internal/y" +) + +-- b/b.go -- +// A package with a bad import in test only +package b + +-- b/b_test.go -- +package b + +import ( + _ "a/x/internal/y" +) + +-- depends-on-a/depends-on-a.go -- +// A package that depends on a package with a bad import +package depends + +import ( + _ "a" +) + +-- depends-on-a/depends-on-a_test.go -- +package depends + +import ( + _ "a" +) + +-- a/x/internal/y/y.go -- +package y