@@ -6,15 +6,21 @@ package cache
6
6
7
7
import (
8
8
"context"
9
+ "fmt"
9
10
"go/ast"
10
11
"go/token"
11
12
"go/types"
13
+ "runtime"
12
14
"strings"
15
+ "sync"
13
16
17
+ "golang.org/x/sync/errgroup"
18
+ "golang.org/x/tools/gopls/internal/cache/metadata"
14
19
"golang.org/x/tools/gopls/internal/cache/parsego"
15
20
"golang.org/x/tools/gopls/internal/file"
16
21
"golang.org/x/tools/gopls/internal/protocol"
17
22
"golang.org/x/tools/gopls/internal/util/astutil"
23
+ "golang.org/x/tools/internal/event"
18
24
)
19
25
20
26
// Symbol holds a precomputed symbol value. Note: we avoid using the
@@ -26,6 +32,64 @@ type Symbol struct {
26
32
Range protocol.Range
27
33
}
28
34
35
+ // Symbols extracts and returns symbol information for every file contained in
36
+ // a loaded package. It awaits snapshot loading.
37
+ //
38
+ // If workspaceOnly is set, this only includes symbols from files in a
39
+ // workspace package. Otherwise, it returns symbols from all loaded packages.
40
+ func (s * Snapshot ) Symbols (ctx context.Context , workspaceOnly bool ) (map [protocol.DocumentURI ][]Symbol , error ) {
41
+ var (
42
+ meta []* metadata.Package
43
+ err error
44
+ )
45
+ if workspaceOnly {
46
+ meta , err = s .WorkspaceMetadata (ctx )
47
+ } else {
48
+ meta , err = s .AllMetadata (ctx )
49
+ }
50
+ if err != nil {
51
+ return nil , fmt .Errorf ("loading metadata: %v" , err )
52
+ }
53
+
54
+ goFiles := make (map [protocol.DocumentURI ]struct {})
55
+ for _ , mp := range meta {
56
+ for _ , uri := range mp .GoFiles {
57
+ goFiles [uri ] = struct {}{}
58
+ }
59
+ for _ , uri := range mp .CompiledGoFiles {
60
+ goFiles [uri ] = struct {}{}
61
+ }
62
+ }
63
+
64
+ // Symbolize them in parallel.
65
+ var (
66
+ group errgroup.Group
67
+ nprocs = 2 * runtime .GOMAXPROCS (- 1 ) // symbolize is a mix of I/O and CPU
68
+ resultMu sync.Mutex
69
+ result = make (map [protocol.DocumentURI ][]Symbol )
70
+ )
71
+ group .SetLimit (nprocs )
72
+ for uri := range goFiles {
73
+ uri := uri
74
+ group .Go (func () error {
75
+ symbols , err := s .symbolize (ctx , uri )
76
+ if err != nil {
77
+ return err
78
+ }
79
+ resultMu .Lock ()
80
+ result [uri ] = symbols
81
+ resultMu .Unlock ()
82
+ return nil
83
+ })
84
+ }
85
+ // Keep going on errors, but log the first failure.
86
+ // Partial results are better than no symbol results.
87
+ if err := group .Wait (); err != nil {
88
+ event .Error (ctx , "getting snapshot symbols" , err )
89
+ }
90
+ return result , nil
91
+ }
92
+
29
93
// symbolize returns the result of symbolizing the file identified by uri, using a cache.
30
94
func (s * Snapshot ) symbolize (ctx context.Context , uri protocol.DocumentURI ) ([]Symbol , error ) {
31
95
0 commit comments