proc: support DW_AT_go_package_name (#1757)

Use the name specified by compile unit attribute DW_AT_go_package_name,
introduced in Go 1.13, to map package names to package paths, instead of
trying to deduce it from names of types.
Also use this mapping for resolving global variables and function
expressions.
This commit is contained in:
Alessandro Arzilli 2019-11-25 18:10:18 +01:00 committed by Derek Parker
parent 834591f4b6
commit 151de14d08
9 changed files with 135 additions and 44 deletions

@ -3,3 +3,9 @@ package dirio
type SomeType struct { type SomeType struct {
X int X int
} }
var A string = "something"
func SomeFunction() {
println("hello world")
}

@ -8,6 +8,7 @@ import (
pkg1 "go/ast" pkg1 "go/ast"
pkg2 "net/http" pkg2 "net/http"
"github.com/go-delve/delve/_fixtures/internal/dir.io"
"github.com/go-delve/delve/_fixtures/internal/dir0/pkg" "github.com/go-delve/delve/_fixtures/internal/dir0/pkg"
"github.com/go-delve/delve/_fixtures/internal/dir0/renamedpackage" "github.com/go-delve/delve/_fixtures/internal/dir0/renamedpackage"
dir1pkg "github.com/go-delve/delve/_fixtures/internal/dir1/pkg" dir1pkg "github.com/go-delve/delve/_fixtures/internal/dir1/pkg"
@ -51,5 +52,5 @@ func main() {
m := t.Method(0) m := t.Method(0)
fmt.Println(m.Type.In(0)) fmt.Println(m.Type.In(0))
fmt.Println(m.Type.String()) fmt.Println(m.Type.String())
fmt.Println(badexpr, req, amap, amap2, dir0someType, dir1someType, amap3, anarray, achan, aslice, afunc, astruct, astruct2, iface2iface, iface3, pkg.SomeVar, pkg.A, dir1pkg.A) fmt.Println(badexpr, req, amap, amap2, dir0someType, dir1someType, amap3, anarray, achan, aslice, afunc, astruct, astruct2, iface2iface, iface3, pkg.SomeVar, pkg.A, dir1pkg.A, dirio.A, dirio.SomeFunction)
} }

@ -26,6 +26,7 @@ const (
AttrGoElem dwarf.Attr = 0x2902 AttrGoElem dwarf.Attr = 0x2902
AttrGoEmbeddedField dwarf.Attr = 0x2903 AttrGoEmbeddedField dwarf.Attr = 0x2903
AttrGoRuntimeType dwarf.Attr = 0x2904 AttrGoRuntimeType dwarf.Attr = 0x2904
AttrGoPackageName dwarf.Attr = 0x2905
) )
// Basic type encodings -- the value for AttrEncoding in a TagBaseType Entry. // Basic type encodings -- the value for AttrEncoding in a TagBaseType Entry.

@ -61,8 +61,16 @@ type BinaryInfo struct {
closer io.Closer closer io.Closer
sepDebugCloser io.Closer sepDebugCloser io.Closer
// Maps package names to package paths, needed to lookup types inside DWARF info // PackageMap maps package names to package paths, needed to lookup types inside DWARF info.
packageMap map[string]string // On Go1.12 this mapping is determined by using the last element of a package path, for example:
// github.com/go-delve/delve
// will map to 'delve' because it ends in '/delve'.
// Starting with Go1.13 debug_info will contain a special attribute
// (godwarf.AttrGoPackageName) containing the canonical package name for
// each package.
// If multiple packages have the same name the map entry will have more
// than one item in the slice.
PackageMap map[string][]string
frameEntries frame.FrameDescriptionEntries frameEntries frame.FrameDescriptionEntries
@ -1253,7 +1261,7 @@ func (bi *BinaryInfo) registerTypeToPackageMap(entry *dwarf.Entry) {
return return
} }
name := path[slash+1:] name := path[slash+1:]
bi.packageMap[name] = path bi.PackageMap[name] = []string{path}
} }
func (bi *BinaryInfo) loadDebugInfoMaps(image *Image, debugLineBytes []byte, wg *sync.WaitGroup, cont func()) { func (bi *BinaryInfo) loadDebugInfoMaps(image *Image, debugLineBytes []byte, wg *sync.WaitGroup, cont func()) {
@ -1267,8 +1275,8 @@ func (bi *BinaryInfo) loadDebugInfoMaps(image *Image, debugLineBytes []byte, wg
if bi.consts == nil { if bi.consts == nil {
bi.consts = make(map[dwarfRef]*constantType) bi.consts = make(map[dwarfRef]*constantType)
} }
if bi.packageMap == nil { if bi.PackageMap == nil {
bi.packageMap = make(map[string]string) bi.PackageMap = make(map[string][]string)
} }
if bi.inlinedCallLines == nil { if bi.inlinedCallLines == nil {
bi.inlinedCallLines = make(map[fileLine][]uint64) bi.inlinedCallLines = make(map[fileLine][]uint64)
@ -1329,6 +1337,10 @@ func (bi *BinaryInfo) loadDebugInfoMaps(image *Image, debugLineBytes []byte, wg
cu.producer = cu.producer[:semicolon] cu.producer = cu.producer[:semicolon]
} }
} }
gopkg, _ := entry.Val(godwarf.AttrGoPackageName).(string)
if cu.isgo && gopkg != "" {
bi.PackageMap[gopkg] = append(bi.PackageMap[gopkg], escapePackagePath(strings.Replace(cu.name, "\\", "/", -1)))
}
bi.compileUnits = append(bi.compileUnits, cu) bi.compileUnits = append(bi.compileUnits, cu)
if entry.Children { if entry.Children {
bi.loadDebugInfoMapsCompileUnit(ctxt, image, reader, cu) bi.loadDebugInfoMapsCompileUnit(ctxt, image, reader, cu)
@ -1370,6 +1382,8 @@ func (bi *BinaryInfo) loadDebugInfoMaps(image *Image, debugLineBytes []byte, wg
// loadDebugInfoMapsCompileUnit loads entry from a single compile unit. // loadDebugInfoMapsCompileUnit loads entry from a single compile unit.
func (bi *BinaryInfo) loadDebugInfoMapsCompileUnit(ctxt *loadDebugInfoMapsContext, image *Image, reader *reader.Reader, cu *compileUnit) { func (bi *BinaryInfo) loadDebugInfoMapsCompileUnit(ctxt *loadDebugInfoMapsContext, image *Image, reader *reader.Reader, cu *compileUnit) {
hasAttrGoPkgName := goversion.ProducerAfterOrEqual(cu.producer, 1, 13)
for entry, err := reader.Next(); entry != nil; entry, err = reader.Next() { for entry, err := reader.Next(); entry != nil; entry, err = reader.Next() {
if err != nil { if err != nil {
image.setLoadError("error reading debug_info: %v", err) image.setLoadError("error reading debug_info: %v", err)
@ -1391,7 +1405,7 @@ func (bi *BinaryInfo) loadDebugInfoMapsCompileUnit(ctxt *loadDebugInfoMapsContex
bi.types[name] = dwarfRef{image.index, entry.Offset} bi.types[name] = dwarfRef{image.index, entry.Offset}
} }
} }
if cu != nil && cu.isgo { if cu != nil && cu.isgo && !hasAttrGoPkgName {
bi.registerTypeToPackageMap(entry) bi.registerTypeToPackageMap(entry)
} }
image.registerRuntimeTypeToDIE(entry, ctxt.ardr) image.registerRuntimeTypeToDIE(entry, ctxt.ardr)
@ -1684,8 +1698,13 @@ func (bi *BinaryInfo) expandPackagesInType(expr ast.Expr) {
case *ast.SelectorExpr: case *ast.SelectorExpr:
switch x := e.X.(type) { switch x := e.X.(type) {
case *ast.Ident: case *ast.Ident:
if path, ok := bi.packageMap[x.Name]; ok { if len(bi.PackageMap[x.Name]) > 0 {
x.Name = path // There's no particular reason to expect the first entry to be the
// correct one if the package name is ambiguous, but trying all possible
// expansions of all types mentioned in the expression is complicated
// and, besides type assertions, users can always specify the type they
// want exactly, using a string.
x.Name = bi.PackageMap[x.Name][0]
} }
default: default:
bi.expandPackagesInType(e.X) bi.expandPackagesInType(e.X)
@ -1697,6 +1716,17 @@ func (bi *BinaryInfo) expandPackagesInType(expr ast.Expr) {
} }
} }
// escapePackagePath returns pkg with '.' replaced with '%2e' (in all
// elements of the path except the first one) like Go does in variable and
// type names.
func escapePackagePath(pkg string) string {
slash := strings.Index(pkg, "/")
if slash < 0 {
slash = 0
}
return pkg[:slash] + strings.Replace(pkg[slash:], ".", "%2e", -1)
}
// Looks up symbol (either functions or global variables) at address addr. // Looks up symbol (either functions or global variables) at address addr.
// Used by disassembly formatter. // Used by disassembly formatter.
func (bi *BinaryInfo) symLookup(addr uint64) (string, uint64) { func (bi *BinaryInfo) symLookup(addr uint64) (string, uint64) {

@ -379,7 +379,21 @@ func (scope *EvalScope) PackageVariables(cfg LoadConfig) ([]*Variable, error) {
return vars, nil return vars, nil
} }
func (scope *EvalScope) findGlobal(name string) (*Variable, error) { func (scope *EvalScope) findGlobal(pkgName, varName string) (*Variable, error) {
for _, pkgPath := range scope.BinInfo.PackageMap[pkgName] {
v, err := scope.findGlobalInternal(pkgPath + "." + varName)
if err != nil || v != nil {
return v, err
}
}
v, err := scope.findGlobalInternal(pkgName + "." + varName)
if err != nil || v != nil {
return v, err
}
return nil, fmt.Errorf("could not find symbol value for %s.%s", pkgName, varName)
}
func (scope *EvalScope) findGlobalInternal(name string) (*Variable, error) {
for _, pkgvar := range scope.BinInfo.packageVars { for _, pkgvar := range scope.BinInfo.packageVars {
if pkgvar.name == name || strings.HasSuffix(pkgvar.name, "/"+name) { if pkgvar.name == name || strings.HasSuffix(pkgvar.name, "/"+name) {
reader := pkgvar.cu.image.dwarfReader reader := pkgvar.cu.image.dwarfReader
@ -426,7 +440,7 @@ func (scope *EvalScope) findGlobal(name string) (*Variable, error) {
} }
} }
} }
return nil, fmt.Errorf("could not find symbol value for %s", name) return nil, nil
} }
// image returns the image containing the current function. // image returns the image containing the current function.
@ -608,7 +622,7 @@ func (scope *EvalScope) evalAST(t ast.Expr) (*Variable, error) {
return scope.g.variable.clone(), nil return scope.g.variable.clone(), nil
} else if maybePkg.Name == "runtime" && node.Sel.Name == "frameoff" { } else if maybePkg.Name == "runtime" && node.Sel.Name == "frameoff" {
return newConstant(constant.MakeInt64(scope.frameOffset), scope.Mem), nil return newConstant(constant.MakeInt64(scope.frameOffset), scope.Mem), nil
} else if v, err := scope.findGlobal(maybePkg.Name + "." + node.Sel.Name); err == nil { } else if v, err := scope.findGlobal(maybePkg.Name, node.Sel.Name); err == nil {
return v, nil return v, nil
} }
} }
@ -616,7 +630,7 @@ func (scope *EvalScope) evalAST(t ast.Expr) (*Variable, error) {
if maybePkg, ok := node.X.(*ast.BasicLit); ok && maybePkg.Kind == token.STRING { if maybePkg, ok := node.X.(*ast.BasicLit); ok && maybePkg.Kind == token.STRING {
pkgpath, err := strconv.Unquote(maybePkg.Value) pkgpath, err := strconv.Unquote(maybePkg.Value)
if err == nil { if err == nil {
if v, err := scope.findGlobal(pkgpath + "." + node.Sel.Name); err == nil { if v, err := scope.findGlobal(pkgpath, node.Sel.Name); err == nil {
return v, nil return v, nil
} }
} }
@ -1013,7 +1027,7 @@ func (scope *EvalScope) evalIdent(node *ast.Ident) (*Variable, error) {
// if it's not a local variable then it could be a package variable w/o explicit package name // if it's not a local variable then it could be a package variable w/o explicit package name
if scope.Fn != nil { if scope.Fn != nil {
if v, err := scope.findGlobal(scope.Fn.PackageName() + "." + node.Name); err == nil { if v, err := scope.findGlobal(scope.Fn.PackageName(), node.Name); err == nil {
v.Name = node.Name v.Name = node.Name
return v, nil return v, nil
} }

@ -15,7 +15,7 @@ type moduleData struct {
func loadModuleData(bi *BinaryInfo, mem MemoryReadWriter) ([]moduleData, error) { func loadModuleData(bi *BinaryInfo, mem MemoryReadWriter) ([]moduleData, error) {
scope := globalScope(bi, bi.Images[0], mem) scope := globalScope(bi, bi.Images[0], mem)
var md *Variable var md *Variable
md, err := scope.findGlobal("runtime.firstmoduledata") md, err := scope.findGlobal("runtime", "firstmoduledata")
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -131,7 +131,7 @@ func resolveNameOff(bi *BinaryInfo, mds []moduleData, typeAddr uintptr, off uint
func reflectOffsMapAccess(bi *BinaryInfo, off uintptr, mem MemoryReadWriter) (*Variable, error) { func reflectOffsMapAccess(bi *BinaryInfo, off uintptr, mem MemoryReadWriter) (*Variable, error) {
scope := globalScope(bi, bi.Images[0], mem) scope := globalScope(bi, bi.Images[0], mem)
reflectOffs, err := scope.findGlobal("runtime.reflectOffs") reflectOffs, err := scope.findGlobal("runtime", "reflectOffs")
if err != nil { if err != nil {
return nil, err return nil, err
} }

@ -216,7 +216,7 @@ func stripReceiverDecoration(in string) string {
return in[2 : len(in)-1] return in[2 : len(in)-1]
} }
func (spec *FuncLocationSpec) Match(sym proc.Function) bool { func (spec *FuncLocationSpec) Match(sym proc.Function, packageMap map[string][]string) bool {
if spec.BaseName != sym.BaseName() { if spec.BaseName != sym.BaseName() {
return false return false
} }
@ -231,17 +231,26 @@ func (spec *FuncLocationSpec) Match(sym proc.Function) bool {
return false return false
} }
} else { } else {
if !partialPathMatch(spec.PackageName, sym.PackageName()) { if !packageMatch(spec.PackageName, sym.PackageName(), packageMap) {
return false return false
} }
} }
} }
if spec.PackageOrReceiverName != "" && !partialPathMatch(spec.PackageOrReceiverName, sym.PackageName()) && spec.PackageOrReceiverName != recv { if spec.PackageOrReceiverName != "" && !packageMatch(spec.PackageOrReceiverName, sym.PackageName(), packageMap) && spec.PackageOrReceiverName != recv {
return false return false
} }
return true return true
} }
func packageMatch(specPkg, symPkg string, packageMap map[string][]string) bool {
for _, pkg := range packageMap[specPkg] {
if partialPackageMatch(pkg, symPkg) {
return true
}
}
return partialPackageMatch(specPkg, symPkg)
}
func (loc *RegexLocationSpec) Find(d *Debugger, scope *proc.EvalScope, locStr string, includeNonExecutableLines bool) ([]api.Location, error) { func (loc *RegexLocationSpec) Find(d *Debugger, scope *proc.EvalScope, locStr string, includeNonExecutableLines bool) ([]api.Location, error) {
funcs := d.target.BinInfo().Functions funcs := d.target.BinInfo().Functions
matches, err := regexFilterFuncs(loc.FuncRegex, funcs) matches, err := regexFilterFuncs(loc.FuncRegex, funcs)
@ -304,6 +313,10 @@ func partialPathMatch(expr, path string) bool {
expr = strings.ToLower(filepath.ToSlash(expr)) expr = strings.ToLower(filepath.ToSlash(expr))
path = strings.ToLower(filepath.ToSlash(path)) path = strings.ToLower(filepath.ToSlash(path))
} }
return partialPackageMatch(expr, path)
}
func partialPackageMatch(expr, path string) bool {
if len(expr) < len(path)-1 { if len(expr) < len(path)-1 {
return strings.HasSuffix(path, expr) && (path[len(path)-len(expr)-1] == '/') return strings.HasSuffix(path, expr) && (path[len(path)-len(expr)-1] == '/')
} else { } else {
@ -347,7 +360,7 @@ func (loc *NormalLocationSpec) Find(d *Debugger, scope *proc.EvalScope, locStr s
var candidateFuncs []string var candidateFuncs []string
if loc.FuncBase != nil { if loc.FuncBase != nil {
for _, f := range d.target.BinInfo().Functions { for _, f := range d.target.BinInfo().Functions {
if !loc.FuncBase.Match(f) { if !loc.FuncBase.Match(f, d.target.BinInfo().PackageMap) {
continue continue
} }
if loc.Base == f.Name { if loc.Base == f.Name {

@ -725,6 +725,13 @@ func TestClientServer_FindLocations(t *testing.T) {
} }
c.ClearBreakpoint(bp.ID) c.ClearBreakpoint(bp.ID)
}) })
if goversion.VersionAfterOrEqual(runtime.Version(), 1, 13) {
withTestClient2("pkgrenames", t, func(c service.Client) {
someFuncLoc := findLocationHelper(t, c, "github.com/go-delve/delve/_fixtures/internal/dir%2eio.SomeFunction:0", false, 1, 0)[0]
findLocationHelper(t, c, "dirio.SomeFunction:0", false, 1, someFuncLoc)
})
}
} }
func TestClientServer_FindLocationsAddr(t *testing.T) { func TestClientServer_FindLocationsAddr(t *testing.T) {

@ -971,6 +971,23 @@ func TestIssue426(t *testing.T) {
}) })
} }
func testPackageRenamesHelper(t *testing.T, p proc.Process, testcases []varTest) {
for _, tc := range testcases {
variable, err := evalVariable(p, tc.name, pnormalLoadConfig)
if tc.err == nil {
assertNoError(err, t, fmt.Sprintf("EvalExpression(%s) returned an error", tc.name))
assertVariable(t, variable, tc)
} else {
if err == nil {
t.Fatalf("Expected error %s, got no error (%s)", tc.err.Error(), tc.name)
}
if tc.err.Error() != err.Error() {
t.Fatalf("Unexpected error. Expected %s got %s", tc.err.Error(), err.Error())
}
}
}
}
func TestPackageRenames(t *testing.T) { func TestPackageRenames(t *testing.T) {
// Tests that the concrete type of an interface variable is resolved // Tests that the concrete type of an interface variable is resolved
// correctly in a few edge cases, in particular: // correctly in a few edge cases, in particular:
@ -999,41 +1016,43 @@ func TestPackageRenames(t *testing.T) {
{"aslice", true, `interface {}([]github.com/go-delve/delve/_fixtures/internal/dir0/pkg.SomeType) [{X: 3},{X: 4}]`, "", "interface {}", nil}, {"aslice", true, `interface {}([]github.com/go-delve/delve/_fixtures/internal/dir0/pkg.SomeType) [{X: 3},{X: 4}]`, "", "interface {}", nil},
{"afunc", true, `interface {}(func(github.com/go-delve/delve/_fixtures/internal/dir0/pkg.SomeType, github.com/go-delve/delve/_fixtures/internal/dir1/pkg.SomeType)) main.main.func1`, "", "interface {}", nil}, {"afunc", true, `interface {}(func(github.com/go-delve/delve/_fixtures/internal/dir0/pkg.SomeType, github.com/go-delve/delve/_fixtures/internal/dir1/pkg.SomeType)) main.main.func1`, "", "interface {}", nil},
{"astruct", true, `interface {}(*struct { A github.com/go-delve/delve/_fixtures/internal/dir1/pkg.SomeType; B github.com/go-delve/delve/_fixtures/internal/dir0/pkg.SomeType }) *{A: github.com/go-delve/delve/_fixtures/internal/dir1/pkg.SomeType {X: 1, Y: 2}, B: github.com/go-delve/delve/_fixtures/internal/dir0/pkg.SomeType {X: 3}}`, "", "interface {}", nil}, {"astruct", true, `interface {}(*struct { A github.com/go-delve/delve/_fixtures/internal/dir1/pkg.SomeType; B github.com/go-delve/delve/_fixtures/internal/dir0/pkg.SomeType }) *{A: github.com/go-delve/delve/_fixtures/internal/dir1/pkg.SomeType {X: 1, Y: 2}, B: github.com/go-delve/delve/_fixtures/internal/dir0/pkg.SomeType {X: 3}}`, "", "interface {}", nil},
{"astruct2", true, `interface {}(*struct { github.com/go-delve/delve/_fixtures/internal/dir1/pkg.SomeType; X int }) *{SomeType: github.com/go-delve/delve/_fixtures/internal/dir1/pkg.SomeType {X: 1, Y: 2}, X: 10}`, "", "interface {}", nil},
{"iface2iface", true, `interface {}(*interface { AMethod(int) int; AnotherMethod(int) int }) **github.com/go-delve/delve/_fixtures/internal/dir0/pkg.SomeType {X: 4}`, "", "interface {}", nil}, {"iface2iface", true, `interface {}(*interface { AMethod(int) int; AnotherMethod(int) int }) **github.com/go-delve/delve/_fixtures/internal/dir0/pkg.SomeType {X: 4}`, "", "interface {}", nil},
{`"dir0/pkg".A`, false, "0", "", "int", nil}, {`"dir0/pkg".A`, false, "0", "", "int", nil},
{`"dir1/pkg".A`, false, "1", "", "int", nil}, {`"dir1/pkg".A`, false, "1", "", "int", nil},
} }
ver, _ := goversion.Parse(runtime.Version()) testcases1_8 := []varTest{
if ver.Major > 0 && !ver.AfterOrEqual(goversion.GoVersion{1, 7, -1, 0, 0, ""}) { // before 1.9 embedded struct fields have fieldname == type
// Not supported on 1.6 or earlier {"astruct2", true, `interface {}(*struct { github.com/go-delve/delve/_fixtures/internal/dir1/pkg.SomeType; X int }) *{github.com/go-delve/delve/_fixtures/internal/dir1/pkg.SomeType: github.com/go-delve/delve/_fixtures/internal/dir1/pkg.SomeType {X: 1, Y: 2}, X: 10}`, "", "interface {}", nil},
}
testcases1_9 := []varTest{
{"astruct2", true, `interface {}(*struct { github.com/go-delve/delve/_fixtures/internal/dir1/pkg.SomeType; X int }) *{SomeType: github.com/go-delve/delve/_fixtures/internal/dir1/pkg.SomeType {X: 1, Y: 2}, X: 10}`, "", "interface {}", nil},
}
testcases1_13 := []varTest{
// needs DW_AT_go_package_name attribute added to Go1.13
{`dirio.A`, false, `"something"`, "", "string", nil},
}
if !goversion.VersionAfterOrEqual(runtime.Version(), 1, 7) {
return return
} }
protest.AllowRecording(t) protest.AllowRecording(t)
withTestProcess("pkgrenames", t, func(p proc.Process, fixture protest.Fixture) { withTestProcess("pkgrenames", t, func(p proc.Process, fixture protest.Fixture) {
assertNoError(proc.Continue(p), t, "Continue() returned an error") assertNoError(proc.Continue(p), t, "Continue() returned an error")
for _, tc := range testcases { testPackageRenamesHelper(t, p, testcases)
if ver.Major > 0 && !ver.AfterOrEqual(goversion.GoVersion{1, 9, -1, 0, 0, ""}) {
// before 1.9 embedded struct field have fieldname == type if goversion.VersionAfterOrEqual(runtime.Version(), 1, 9) {
if tc.name == "astruct2" { testPackageRenamesHelper(t, p, testcases1_9)
tc.value = `interface {}(*struct { github.com/go-delve/delve/_fixtures/internal/dir1/pkg.SomeType; X int }) *{github.com/go-delve/delve/_fixtures/internal/dir1/pkg.SomeType: github.com/go-delve/delve/_fixtures/internal/dir1/pkg.SomeType {X: 1, Y: 2}, X: 10}` } else {
} testPackageRenamesHelper(t, p, testcases1_8)
} }
variable, err := evalVariable(p, tc.name, pnormalLoadConfig)
if tc.err == nil { if goversion.VersionAfterOrEqual(runtime.Version(), 1, 13) {
assertNoError(err, t, fmt.Sprintf("EvalExpression(%s) returned an error", tc.name)) testPackageRenamesHelper(t, p, testcases1_13)
assertVariable(t, variable, tc)
} else {
if err == nil {
t.Fatalf("Expected error %s, got no error (%s)", tc.err.Error(), tc.name)
}
if tc.err.Error() != err.Error() {
t.Fatalf("Unexpected error. Expected %s got %s", tc.err.Error(), err.Error())
}
}
} }
}) })
} }
@ -1049,7 +1068,7 @@ func TestConstants(t *testing.T) {
{"bitZero", true, "1", "", "main.BitFieldType", nil}, {"bitZero", true, "1", "", "main.BitFieldType", nil},
{"bitOne", true, "2", "", "main.BitFieldType", nil}, {"bitOne", true, "2", "", "main.BitFieldType", nil},
{"constTwo", true, "2", "", "main.ConstType", nil}, {"constTwo", true, "2", "", "main.ConstType", nil},
{"pkg.SomeConst", true, "2", "", "int", nil}, {"pkg.SomeConst", false, "2", "", "int", nil},
} }
ver, _ := goversion.Parse(runtime.Version()) ver, _ := goversion.Parse(runtime.Version())
if ver.Major > 0 && !ver.AfterOrEqual(goversion.GoVersion{1, 10, -1, 0, 0, ""}) { if ver.Major > 0 && !ver.AfterOrEqual(goversion.GoVersion{1, 10, -1, 0, 0, ""}) {