Skip to content

Commit f8deb4d

Browse files
committed
gopls: augmentation of the xrefs index to include cross-package references from assembly files.
This commit enhances the xrefs index to include references from assembly (.s) files. It processes assembly files, extracts cross-package references, and updates the index. Updates golang/go#71754
1 parent 4807619 commit f8deb4d

File tree

7 files changed

+62
-16
lines changed

7 files changed

+62
-16
lines changed

gopls/internal/cache/metadata/metadata.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,10 +48,12 @@ type Package struct {
4848
// These fields are as defined by go/packages.Package
4949
GoFiles []protocol.DocumentURI
5050
CompiledGoFiles []protocol.DocumentURI
51-
AsmFiles []protocol.DocumentURI
5251
IgnoredFiles []protocol.DocumentURI
5352
OtherFiles []protocol.DocumentURI
5453

54+
// These fields ares as defined by asm.File
55+
AsmFiles []protocol.DocumentURI
56+
5557
ForTest PackagePath // q in a "p [q.test]" package, else ""
5658
TypesSizes types.Sizes
5759
Errors []packages.Error // must be set for packages in import cycles

gopls/internal/cache/package.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ type syntaxPackage struct {
7171

7272
func (p *syntaxPackage) xrefs() []byte {
7373
p.xrefsOnce.Do(func() {
74-
p._xrefs = xrefs.Index(p.compiledGoFiles, p.types, p.typesInfo)
74+
p._xrefs = xrefs.Index(p.compiledGoFiles, p.types, p.typesInfo, p.asmFiles)
7575
})
7676
return p._xrefs
7777
}

gopls/internal/cache/parse.go

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -45,10 +45,9 @@ func parseGoImpl(ctx context.Context, fset *token.FileSet, fh file.Handle, mode
4545
return pgf, nil
4646
}
4747

48-
// parseAsmFiles pases the assembly files whose contents are provided by fhs.
48+
// parseAsmFiles parses the assembly files whose contents are provided by fhs.
4949
func parseAsmFiles(ctx context.Context, fhs ...file.Handle) ([]*asm.File, error) {
50-
pgfs := make([]*asm.File, len(fhs))
51-
50+
pafs := make([]*asm.File, len(fhs))
5251
for i, fh := range fhs {
5352
var err error
5453
content, err := fh.Content()
@@ -59,8 +58,7 @@ func parseAsmFiles(ctx context.Context, fhs ...file.Handle) ([]*asm.File, error)
5958
if ctx.Err() != nil {
6059
return nil, ctx.Err()
6160
}
62-
pgfs[i] = asm.Parse(content)
61+
pafs[i] = asm.Parse(fh.URI(), content)
6362
}
64-
return pgfs, nil
65-
63+
return pafs, nil
6664
}

gopls/internal/cache/xrefs/xrefs.go

Lines changed: 41 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,15 @@ import (
1717
"golang.org/x/tools/gopls/internal/cache/metadata"
1818
"golang.org/x/tools/gopls/internal/cache/parsego"
1919
"golang.org/x/tools/gopls/internal/protocol"
20+
"golang.org/x/tools/gopls/internal/util/asm"
2021
"golang.org/x/tools/gopls/internal/util/bug"
2122
"golang.org/x/tools/gopls/internal/util/frob"
23+
"golang.org/x/tools/gopls/internal/util/morestrings"
2224
)
2325

2426
// Index constructs a serializable index of outbound cross-references
2527
// for the specified type-checked package.
26-
func Index(files []*parsego.File, pkg *types.Package, info *types.Info) []byte {
28+
func Index(files []*parsego.File, pkg *types.Package, info *types.Info, asmFiles []*asm.File) []byte {
2729
// pkgObjects maps each referenced package Q to a mapping:
2830
// from each referenced symbol in Q to the ordered list
2931
// of references to that symbol from this package.
@@ -70,7 +72,7 @@ func Index(files []*parsego.File, pkg *types.Package, info *types.Info) []byte {
7072
// (e.g. local const/var/type).
7173
continue
7274
}
73-
gobObj = &gobObject{Path: path}
75+
gobObj = &gobObject{Path: path, isAsm: false}
7476
objects[obj] = gobObj
7577
}
7678

@@ -112,6 +114,37 @@ func Index(files []*parsego.File, pkg *types.Package, info *types.Info) []byte {
112114
}
113115
}
114116

117+
for fileIndex, af := range asmFiles {
118+
for _, id := range af.Idents {
119+
_, name, ok := morestrings.CutLast(id.Name, ".")
120+
if id.Kind != asm.Text {
121+
continue
122+
}
123+
obj := pkg.Scope().Lookup(name)
124+
if obj == nil {
125+
continue
126+
}
127+
objects := getObjects(pkg)
128+
gobObj, ok := objects[obj]
129+
if !ok {
130+
path, err := objectpathFor(obj)
131+
if err != nil {
132+
// Capitalized but not exported
133+
// (e.g. local const/var/type).
134+
continue
135+
}
136+
gobObj = &gobObject{Path: path, isAsm: true}
137+
objects[obj] = gobObj
138+
}
139+
if rng, err := af.NodeRange(id); err == nil {
140+
gobObj.Refs = append(gobObj.Refs, gobRef{
141+
FileIndex: fileIndex,
142+
Range: rng,
143+
})
144+
}
145+
}
146+
}
147+
115148
// Flatten the maps into slices, and sort for determinism.
116149
var packages []*gobPackage
117150
for p := range pkgObjects {
@@ -148,6 +181,9 @@ func Lookup(mp *metadata.Package, data []byte, targets map[metadata.PackagePath]
148181
if _, ok := objectSet[gobObj.Path]; ok {
149182
for _, ref := range gobObj.Refs {
150183
uri := mp.CompiledGoFiles[ref.FileIndex]
184+
if gobObj.isAsm {
185+
uri = mp.AsmFiles[ref.FileIndex]
186+
}
151187
locs = append(locs, protocol.Location{
152188
URI: uri,
153189
Range: ref.Range,
@@ -184,8 +220,9 @@ type gobPackage struct {
184220

185221
// A gobObject records all references to a particular symbol.
186222
type gobObject struct {
187-
Path objectpath.Path // symbol name within package; "" => import of package itself
188-
Refs []gobRef // locations of references within P, in lexical order
223+
Path objectpath.Path // symbol name within package; "" => import of package itself
224+
Refs []gobRef // locations of references within P, in lexical order
225+
isAsm bool // true if this is an assembly object
189226
}
190227

191228
type gobRef struct {

gopls/internal/goasm/definition.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ func Definition(ctx context.Context, snapshot *cache.Snapshot, fh file.Handle, p
4545
//
4646
// TODO(adonovan): make this just another
4747
// attribute of the type-checked cache.Package.
48-
file := asm.Parse(content)
48+
file := asm.Parse(fh.URI(), content)
4949

5050
// Figure out the selected symbol.
5151
// For now, just find the identifier around the cursor.

gopls/internal/util/asm/parse.go

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ import (
1111
"fmt"
1212
"strings"
1313
"unicode"
14+
15+
"golang.org/x/tools/gopls/internal/protocol"
1416
)
1517

1618
// Kind describes the nature of an identifier in an assembly file.
@@ -43,12 +45,19 @@ var kindString = [...]string{
4345

4446
// A file represents a parsed file of Go assembly language.
4547
type File struct {
48+
URI protocol.DocumentURI
4649
Idents []Ident
4750

51+
Mapper *protocol.Mapper // may map fixed Src, not file content
52+
4853
// TODO(adonovan): use token.File? This may be important in a
4954
// future in which analyzers can report diagnostics in .s files.
5055
}
5156

57+
func (f *File) NodeRange(ident Ident) (protocol.Range, error) {
58+
return f.Mapper.OffsetRange(ident.Offset, ident.End())
59+
}
60+
5261
// Ident represents an identifier in an assembly file.
5362
type Ident struct {
5463
Name string // symbol name (after correcting [·∕]); Name[0]='.' => current package
@@ -61,7 +70,7 @@ func (id Ident) End() int { return id.Offset + len(id.Name) }
6170

6271
// Parse extracts identifiers from Go assembly files.
6372
// Since it is a best-effort parser, it never returns an error.
64-
func Parse(content []byte) *File {
73+
func Parse(uri protocol.DocumentURI, content []byte) *File {
6574
var idents []Ident
6675
offset := 0 // byte offset of start of current line
6776

@@ -192,7 +201,7 @@ func Parse(content []byte) *File {
192201

193202
_ = scan.Err() // ignore scan errors
194203

195-
return &File{Idents: idents}
204+
return &File{Idents: idents, Mapper: protocol.NewMapper(uri, content), URI: uri}
196205
}
197206

198207
// isIdent reports whether s is a valid Go assembly identifier.

gopls/internal/util/asm/parse_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ TEXT ·g(SB),NOSPLIT,$0
3939
`[1:])
4040
const filename = "asm.s"
4141
m := protocol.NewMapper(protocol.URIFromPath(filename), src)
42-
file := asm.Parse(src)
42+
file := asm.Parse("", src)
4343

4444
want := `
4545
asm.s:5:6-11: data "hello"

0 commit comments

Comments
 (0)