Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions go/packages/packages_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3843,3 +3843,35 @@ import _ "errors"
t.Errorf("packages checked = %v, want a and errors", checked)
}
}

func TestCgoExportDataPosition(t *testing.T) {
testAllOrModulesParallel(t, func(t *testing.T, exporter packagestest.Exporter) {
testenv.NeedsTool(t, "cgo")
exported := packagestest.Export(t, exporter, []packagestest.Module{{
Name: "golang.org/fake",
Files: map[string]any{
"c/c.go": "package c\nimport \"C\"\n\nfunc F() {}\n\n//line c.go:70000\nfunc G() {}\nfunc H() {}\n",
"p/p.go": "package p\nimport \"golang.org/fake/c\"\nvar _, _, _ = c.F, c.G, c.H\n",
},
}})
exported.Config.Env = append(exported.Config.Env, "CGO_ENABLED=1")
exported.Config.Mode = packages.LoadSyntax
pkgs, err := packages.Load(exported.Config, "golang.org/fake/p")
if err != nil || len(pkgs) != 1 || len(pkgs[0].Errors) != 0 {
t.Fatalf("Load: %v, %v", pkgs, err)
}
wantLines := map[string]int{"F": 4, "G": 70000, "H": 70001}
for id, obj := range pkgs[0].TypesInfo.Uses {
if want, ok := wantLines[id.Name]; ok {
pos := pkgs[0].Fset.Position(obj.Pos())
if filepath.Base(pos.Filename) != "c.go" || pos.Line != want {
t.Errorf("position of c.%s = %v, want c.go:%d", id.Name, pos, want)
}
delete(wantLines, id.Name)
}
}
for name := range wantLines {
t.Errorf("missing use of c.%s", name)
}
})
}
29 changes: 19 additions & 10 deletions internal/gcimporter/bimport.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,12 @@ const deltaNewFile = -64 // see cmd/compile/internal/gc/bexport.go
// Synthesize a token.Pos
type fakeFileSet struct {
fset *token.FileSet
files map[string]*fileInfo
files map[fileKey]*fileInfo
}

type fileKey struct {
name string
lineBase int
}

type fileInfo struct {
Expand All @@ -37,17 +42,21 @@ const maxlines = 64 * 1024
func (s *fakeFileSet) pos(file string, line, column int) token.Pos {
_ = column // TODO(mdempsky): Make use of column.

// Since we don't know the set of needed file positions, we reserve maxlines
// positions per file. We delay calling token.File.SetLines until all
// positions have been calculated (by way of fakeFileSet.setLines), so that
// we can avoid setting unnecessary lines. See also golang/go#46586.
f := s.files[file]
// Use fixed-size windows so high line numbers can share the same
// line table. Delay SetLines until all positions have been calculated
// to avoid setting unnecessary lines. See golang/go#46586.
key := fileKey{name: file}
if line > maxlines {
key.lineBase = (line - 1) / maxlines * maxlines
line -= key.lineBase
}
f := s.files[key]
if f == nil {
f = &fileInfo{file: s.fset.AddFile(file, -1, maxlines)}
s.files[file] = f
}
if line > maxlines {
line = 1
if key.lineBase != 0 {
f.file.AddLineColumnInfo(0, file, key.lineBase+1, 1)
}
s.files[key] = f
}
if line > f.lastline {
f.lastline = line
Expand Down
2 changes: 1 addition & 1 deletion internal/gcimporter/iimport.go
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,7 @@ func iimportCommon(fset *token.FileSet, getPackages GetPackagesFunc, data []byte

fake: fakeFileSet{
fset: fset,
files: make(map[string]*fileInfo),
files: make(map[fileKey]*fileInfo),
},
}
defer p.fake.setLines() // set lines for files in fset
Expand Down
61 changes: 26 additions & 35 deletions internal/gcimporter/ureader.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ type pkgReader struct {

// lazily initialized arrays corresponding to the unified IR
// PosBase, Pkg, and Type sections, respectively.
posBases []string // position bases (i.e., file names)
posBases []positionBase
pkgs []*types.Package
typs []types.Type

Expand Down Expand Up @@ -96,13 +96,13 @@ func readUnifiedPackage(fset *token.FileSet, ctxt *types.Context, imports map[st

fake: fakeFileSet{
fset: fset,
files: make(map[string]*fileInfo),
files: make(map[fileKey]*fileInfo),
},

ctxt: ctxt,
imports: imports,

posBases: make([]string, input.NumElems(pkgbits.RelocPosBase)),
posBases: make([]positionBase, input.NumElems(pkgbits.RelocPosBase)),
pkgs: make([]*types.Package, input.NumElems(pkgbits.RelocPkg)),
typs: make([]types.Type, input.NumElems(pkgbits.RelocType)),
}
Expand Down Expand Up @@ -194,52 +194,43 @@ func (pr *pkgReader) retireReader(r *reader) {

// @@@ Positions

type positionBase struct {
filename string
lineOffset int
}

func (r *reader) pos() token.Pos {
r.Sync(pkgbits.SyncPos)
if !r.Bool() {
return token.NoPos
}

// TODO(mdempsky): Delta encoding.
posBase := r.posBase()
line := r.Uint()
col := r.Uint()
return r.p.fake.pos(posBase, int(line), int(col))
}

func (r *reader) posBase() string {
return r.p.posBaseIdx(r.Reloc(pkgbits.RelocPosBase))
base := r.p.posBaseIdx(r.Reloc(pkgbits.RelocPosBase))
line := int(r.Uint()) + base.lineOffset
col := int(r.Uint())
return r.p.fake.pos(base.filename, line, col)
}

func (pr *pkgReader) posBaseIdx(idx pkgbits.Index) string {
if b := pr.posBases[idx]; b != "" {
func (pr *pkgReader) posBaseIdx(idx pkgbits.Index) positionBase {
if b := pr.posBases[idx]; b.filename != "" {
return b
}

var filename string
{
r := pr.tempReader(pkgbits.RelocPosBase, idx, pkgbits.SyncPosBase)

// Within types2, position bases have a lot more details (e.g.,
// keeping track of where //line directives appeared exactly).
//
// For go/types, we just track the file name.

filename = r.String()

if r.Bool() { // file base
// Was: "b = token.NewTrimmedFileBase(filename, true)"
} else { // line base
pos := r.pos()
line := r.Uint()
col := r.Uint()

// Was: "b = token.NewLineBase(pos, filename, true, line, col)"
_, _, _ = pos, line, col
r := pr.tempReader(pkgbits.RelocPosBase, idx, pkgbits.SyncPosBase)
b := positionBase{filename: r.String()}
if !r.Bool() { // line directive
r.Sync(pkgbits.SyncPos)
var physicalLine int
if r.Bool() {
r.Reloc(pkgbits.RelocPosBase)
physicalLine = int(r.Uint())
r.Uint() // physical column
}
pr.retireReader(r)
b.lineOffset = int(r.Uint()) - physicalLine
r.Uint() // directive column
}
b := filename
pr.retireReader(r)
pr.posBases[idx] = b
return b
}
Expand Down
Loading