Skip to content

Commit 556b741

Browse files
committed
gopls: implement reference support for goasm files
This commit adds support for reference relationships in Go assembly (.goasm) files within the references file. It implements the logic to identify and record references in goasm file types, enabling reference lookups and navigation for Go assembly code. Updates golang/go#71754
1 parent a4113fc commit 556b741

File tree

4 files changed

+135
-1
lines changed

4 files changed

+135
-1
lines changed

gopls/internal/cache/package.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,3 +206,17 @@ func (p *Package) TypeErrors() []types.Error {
206206
func (p *Package) AsmFiles() []*asm.File {
207207
return p.pkg.asmFiles
208208
}
209+
210+
func (p *Package) AsmFile(uri protocol.DocumentURI) (*asm.File, error) {
211+
return p.pkg.AsmFile(uri)
212+
}
213+
214+
func (pkg *syntaxPackage) AsmFile(uri protocol.DocumentURI) (*asm.File, error) {
215+
for _, af := range pkg.asmFiles {
216+
if af.URI == uri {
217+
return af, nil
218+
}
219+
}
220+
221+
return nil, fmt.Errorf("no parsed file for %s in %v", uri, pkg.id)
222+
}

gopls/internal/goasm/references.go

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
// Copyright 2025 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
// Package goasm provides language-server features for files in Go
6+
// assembly language (https://go.dev/doc/asm).
7+
package goasm
8+
9+
import (
10+
"context"
11+
"fmt"
12+
"go/ast"
13+
14+
"golang.org/x/tools/gopls/internal/cache"
15+
"golang.org/x/tools/gopls/internal/cache/metadata"
16+
"golang.org/x/tools/gopls/internal/file"
17+
"golang.org/x/tools/gopls/internal/protocol"
18+
"golang.org/x/tools/gopls/internal/util/asm"
19+
"golang.org/x/tools/gopls/internal/util/morestrings"
20+
"golang.org/x/tools/internal/event"
21+
)
22+
23+
func References(ctx context.Context, snapshot *cache.Snapshot, fh file.Handle, position protocol.Position) ([]protocol.Location, error) {
24+
ctx, done := event.Start(ctx, "goasm.References")
25+
defer done()
26+
27+
pkg, asmFile, err := GetPackageID(ctx, snapshot, fh.URI())
28+
if err != nil {
29+
return nil, err
30+
}
31+
32+
// Read the file.
33+
content, err := fh.Content()
34+
if err != nil {
35+
return nil, err
36+
}
37+
mapper := protocol.NewMapper(fh.URI(), content)
38+
offset, err := mapper.PositionOffset(position)
39+
if err != nil {
40+
return nil, err
41+
}
42+
43+
// // Parse the assembly.
44+
// file := asm.Parse(fh.URI(), content)
45+
46+
// Figure out the selected symbol.
47+
// For now, just find the identifier around the cursor.
48+
var found *asm.Ident
49+
for _, id := range asmFile.Idents {
50+
if id.Offset <= offset && offset <= id.End() {
51+
found = &id
52+
break
53+
}
54+
}
55+
if found == nil {
56+
return nil, fmt.Errorf("not an identifier")
57+
}
58+
59+
sym := found.Name
60+
var locations []protocol.Location
61+
_, name, ok := morestrings.CutLast(sym, ".")
62+
if !ok {
63+
return nil, fmt.Errorf("not found")
64+
}
65+
// return localReferences(pkg, targets, true, report)
66+
for _, pgf := range pkg.CompiledGoFiles() {
67+
for curId := range pgf.Cursor.Preorder((*ast.Ident)(nil)) {
68+
id := curId.Node().(*ast.Ident)
69+
if id.Name == name {
70+
loc, err := pgf.NodeLocation(id)
71+
if err != nil {
72+
return nil, err
73+
}
74+
locations = append(locations, loc)
75+
}
76+
}
77+
}
78+
79+
for _, asmFile := range pkg.AsmFiles() {
80+
for _, id := range asmFile.Idents {
81+
if id.Name != sym {
82+
continue
83+
}
84+
if rng, err := asmFile.NodeRange(id); err == nil {
85+
asmLocation := protocol.Location{
86+
URI: asmFile.URI,
87+
Range: rng,
88+
}
89+
locations = append(locations, asmLocation)
90+
}
91+
}
92+
}
93+
94+
return locations, nil
95+
}
96+
97+
func GetPackageID(ctx context.Context, snapshot *cache.Snapshot, uri protocol.DocumentURI) (*cache.Package, *asm.File, error) {
98+
mps, err := snapshot.MetadataForFile(ctx, uri)
99+
if err != nil {
100+
return nil, nil, err
101+
}
102+
metadata.RemoveIntermediateTestVariants(&mps)
103+
if len(mps) == 0 {
104+
return nil, nil, fmt.Errorf("no package metadata for file %s", uri)
105+
}
106+
mp := mps[0]
107+
pkgs, err := snapshot.TypeCheck(ctx, mp.ID)
108+
if err != nil {
109+
return nil, nil, err
110+
}
111+
pkg := pkgs[0]
112+
asmFile, err := pkg.AsmFile(uri)
113+
if err != nil {
114+
return nil, nil, err // "can't happen"
115+
}
116+
return pkg, asmFile, nil
117+
}

gopls/internal/golang/references.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -631,7 +631,7 @@ func localReferences(pkg *cache.Package, targets map[types.Object]bool, correspo
631631
URI: pgf.URI,
632632
Range: rng,
633633
}
634-
report(asmLocation, false)
634+
report(asmLocation, true)
635635
}
636636
}
637637
}

gopls/internal/server/references.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"context"
99

1010
"golang.org/x/tools/gopls/internal/file"
11+
"golang.org/x/tools/gopls/internal/goasm"
1112
"golang.org/x/tools/gopls/internal/golang"
1213
"golang.org/x/tools/gopls/internal/label"
1314
"golang.org/x/tools/gopls/internal/protocol"
@@ -35,6 +36,8 @@ func (s *server) References(ctx context.Context, params *protocol.ReferenceParam
3536
return template.References(ctx, snapshot, fh, params)
3637
case file.Go:
3738
return golang.References(ctx, snapshot, fh, params.Position, params.Context.IncludeDeclaration)
39+
case file.Asm:
40+
return goasm.References(ctx, snapshot, fh, params.Position)
3841
}
3942
return nil, nil // empty result
4043
}

0 commit comments

Comments
 (0)