Skip to content

Commit f0af81c

Browse files
adonovangopherbot
authored andcommitted
gopls/internal/goasm: support Definition in Go *.s assembly
This CL provides a minimal implementation of the Definition query within Go assembly files, plus a test. For now it only works for references to package-level symbols in the same package or a dependency. Details: - add file.Kind Asm and protocol.LanguageKind "go.s". - include .s files in metadata.Graph.IDs mapping. - set LanguageKind correctly in gopls CLI. Also: - add String() method to file.Handle. - add convenient forward deps iterator to Graph. - internal/extract: extract notes from .s files too. Updates golang/go#71754 Change-Id: I0c518c3279f825411221ebe23dc04654e129fc56 Reviewed-on: https://go-review.googlesource.com/c/tools/+/649461 Auto-Submit: Alan Donovan <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]> Reviewed-by: Alan Donovan <[email protected]> Reviewed-by: Robert Findley <[email protected]> Commit-Queue: Alan Donovan <[email protected]>
1 parent 300465c commit f0af81c

File tree

16 files changed

+304
-26
lines changed

16 files changed

+304
-26
lines changed

gopls/internal/cache/fs_memoized.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ type diskFile struct {
4141
err error
4242
}
4343

44+
func (h *diskFile) String() string { return h.uri.Path() }
45+
4446
func (h *diskFile) URI() protocol.DocumentURI { return h.uri }
4547

4648
func (h *diskFile) Identity() file.Identity {

gopls/internal/cache/fs_overlay.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,8 @@ type overlay struct {
6464
saved bool
6565
}
6666

67+
func (o *overlay) String() string { return o.uri.Path() }
68+
6769
func (o *overlay) URI() protocol.DocumentURI { return o.uri }
6870

6971
func (o *overlay) Identity() file.Identity {

gopls/internal/cache/metadata/graph.go

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@
55
package metadata
66

77
import (
8+
"iter"
89
"sort"
10+
"strings"
911

1012
"golang.org/x/tools/go/packages"
1113
"golang.org/x/tools/gopls/internal/protocol"
@@ -99,6 +101,11 @@ func newGraph(pkgs map[PackageID]*Package) *Graph {
99101
for _, uri := range mp.GoFiles {
100102
uris[uri] = struct{}{}
101103
}
104+
for _, uri := range mp.OtherFiles {
105+
if strings.HasSuffix(string(uri), ".s") { // assembly
106+
uris[uri] = struct{}{}
107+
}
108+
}
102109
for uri := range uris {
103110
uriIDs[uri] = append(uriIDs[uri], id)
104111
}
@@ -160,6 +167,35 @@ func (g *Graph) ReverseReflexiveTransitiveClosure(ids ...PackageID) map[PackageI
160167
return seen
161168
}
162169

170+
// ForwardReflexiveTransitiveClosure returns an iterator over the
171+
// specified nodes and all their forward dependencies, in an arbitrary
172+
// topological (dependencies-first) order. The order may vary.
173+
func (g *Graph) ForwardReflexiveTransitiveClosure(ids ...PackageID) iter.Seq[*Package] {
174+
return func(yield func(*Package) bool) {
175+
seen := make(map[PackageID]bool)
176+
var visit func(PackageID) bool
177+
visit = func(id PackageID) bool {
178+
if !seen[id] {
179+
seen[id] = true
180+
if mp := g.Packages[id]; mp != nil {
181+
for _, depID := range mp.DepsByPkgPath {
182+
if !visit(depID) {
183+
return false
184+
}
185+
}
186+
if !yield(mp) {
187+
return false
188+
}
189+
}
190+
}
191+
return true
192+
}
193+
for _, id := range ids {
194+
visit(id)
195+
}
196+
}
197+
}
198+
163199
// breakImportCycles breaks import cycles in the metadata by deleting
164200
// Deps* edges. It modifies only metadata present in the 'updates'
165201
// subset. This function has an internal test.

gopls/internal/cache/parse_cache_test.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,10 @@ type fakeFileHandle struct {
218218
hash file.Hash
219219
}
220220

221+
func (h fakeFileHandle) String() string {
222+
return h.uri.Path()
223+
}
224+
221225
func (h fakeFileHandle) URI() protocol.DocumentURI {
222226
return h.uri
223227
}

gopls/internal/cache/session.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1084,6 +1084,7 @@ type brokenFile struct {
10841084
err error
10851085
}
10861086

1087+
func (b brokenFile) String() string { return b.uri.Path() }
10871088
func (b brokenFile) URI() protocol.DocumentURI { return b.uri }
10881089
func (b brokenFile) Identity() file.Identity { return file.Identity{URI: b.uri} }
10891090
func (b brokenFile) SameContentsOnDisk() bool { return false }

gopls/internal/cache/snapshot.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -323,6 +323,8 @@ func fileKind(fh file.Handle) file.Kind {
323323
return file.Sum
324324
case ".work":
325325
return file.Work
326+
case ".s":
327+
return file.Asm
326328
}
327329
return file.UnknownKind
328330
}
@@ -645,13 +647,32 @@ func (s *Snapshot) Tests(ctx context.Context, ids ...PackageID) ([]*testfuncs.In
645647
return indexes, s.forEachPackage(ctx, ids, pre, post)
646648
}
647649

650+
// NarrowestMetadataForFile returns metadata for the narrowest package
651+
// (the one with the fewest files) that encloses the specified file.
652+
// The result may be a test variant, but never an intermediate test variant.
653+
func (snapshot *Snapshot) NarrowestMetadataForFile(ctx context.Context, uri protocol.DocumentURI) (*metadata.Package, error) {
654+
mps, err := snapshot.MetadataForFile(ctx, uri)
655+
if err != nil {
656+
return nil, err
657+
}
658+
metadata.RemoveIntermediateTestVariants(&mps)
659+
if len(mps) == 0 {
660+
return nil, fmt.Errorf("no package metadata for file %s", uri)
661+
}
662+
return mps[0], nil
663+
}
664+
648665
// MetadataForFile returns a new slice containing metadata for each
649666
// package containing the Go file identified by uri, ordered by the
650667
// number of CompiledGoFiles (i.e. "narrowest" to "widest" package),
651668
// and secondarily by IsIntermediateTestVariant (false < true).
652669
// The result may include tests and intermediate test variants of
653670
// importable packages.
654671
// It returns an error if the context was cancelled.
672+
//
673+
// TODO(adonovan): in nearly all cases the caller must use
674+
// [metadata.RemoveIntermediateTestVariants]. Make this a parameter to
675+
// force the caller to consider it (and reduce code).
655676
func (s *Snapshot) MetadataForFile(ctx context.Context, uri protocol.DocumentURI) ([]*metadata.Package, error) {
656677
if s.view.typ == AdHocView {
657678
// As described in golang/go#57209, in ad-hoc workspaces (where we load ./

gopls/internal/cmd/cmd.go

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -773,10 +773,25 @@ func (c *connection) openFile(ctx context.Context, uri protocol.DocumentURI) (*c
773773
return nil, file.err
774774
}
775775

776+
// Choose language ID from file extension.
777+
var langID protocol.LanguageKind // "" eventually maps to file.UnknownKind
778+
switch filepath.Ext(uri.Path()) {
779+
case ".go":
780+
langID = "go"
781+
case ".mod":
782+
langID = "go.mod"
783+
case ".sum":
784+
langID = "go.sum"
785+
case ".work":
786+
langID = "go.work"
787+
case ".s":
788+
langID = "go.s"
789+
}
790+
776791
p := &protocol.DidOpenTextDocumentParams{
777792
TextDocument: protocol.TextDocumentItem{
778793
URI: uri,
779-
LanguageID: "go",
794+
LanguageID: langID,
780795
Version: 1,
781796
Text: string(file.mapper.Content),
782797
},

gopls/internal/cmd/definition.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ func (d *definition) Run(ctx context.Context, args ...string) error {
9696
}
9797

9898
if len(locs) == 0 {
99-
return fmt.Errorf("%v: not an identifier", from)
99+
return fmt.Errorf("%v: no definition location (not an identifier?)", from)
100100
}
101101
file, err = conn.openFile(ctx, locs[0].URI)
102102
if err != nil {

gopls/internal/file/file.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ type Handle interface {
4949
// Content returns the contents of a file.
5050
// If the file is not available, returns a nil slice and an error.
5151
Content() ([]byte, error)
52+
// String returns the file's path.
53+
String() string
5254
}
5355

5456
// A Source maps URIs to Handles.

gopls/internal/file/kind.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ const (
2828
Tmpl
2929
// Work is a go.work file.
3030
Work
31+
// Asm is a Go assembly (.s) file.
32+
Asm
3133
)
3234

3335
func (k Kind) String() string {
@@ -42,13 +44,15 @@ func (k Kind) String() string {
4244
return "tmpl"
4345
case Work:
4446
return "go.work"
47+
case Asm:
48+
return "Go assembly"
4549
default:
4650
return fmt.Sprintf("internal error: unknown file kind %d", k)
4751
}
4852
}
4953

5054
// KindForLang returns the gopls file [Kind] associated with the given LSP
51-
// LanguageKind string from protocol.TextDocumentItem.LanguageID,
55+
// LanguageKind string from the LanguageID field of [protocol.TextDocumentItem],
5256
// or UnknownKind if the language is not one recognized by gopls.
5357
func KindForLang(langID protocol.LanguageKind) Kind {
5458
switch langID {
@@ -62,6 +66,8 @@ func KindForLang(langID protocol.LanguageKind) Kind {
6266
return Tmpl
6367
case "go.work":
6468
return Work
69+
case "go.s":
70+
return Asm
6571
default:
6672
return UnknownKind
6773
}

0 commit comments

Comments
 (0)