Skip to content

Commit 7927dba

Browse files
committed
internal/lsp: build the packages config on demand from proper configuration
This moves the fileset down to the base cache, the overlays down to the session and stores the environment on the view. packages.Config is no longer part of any public API, and the config is build on demand by combining all the layers of cache. Also added some documentation to the main source pacakge interfaces. Change-Id: I058092ad2275d433864d1f58576fc55e194607a6 Reviewed-on: https://go-review.googlesource.com/c/tools/+/178017 Run-TryBot: Ian Cottrell <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Rebecca Stambler <[email protected]>
1 parent 2c78df6 commit 7927dba

30 files changed

+224
-175
lines changed

cmd/gopls/main.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,5 +17,5 @@ import (
1717
)
1818

1919
func main() {
20-
tool.Main(context.Background(), cmd.New(nil), os.Args[1:])
20+
tool.Main(context.Background(), cmd.New("", nil), os.Args[1:])
2121
}

internal/lsp/cache/cache.go

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,20 +5,31 @@
55
package cache
66

77
import (
8+
"go/token"
9+
810
"golang.org/x/tools/internal/lsp/source"
911
"golang.org/x/tools/internal/lsp/xlog"
12+
"golang.org/x/tools/internal/span"
1013
)
1114

1215
func New() source.Cache {
13-
return &cache{}
16+
return &cache{
17+
fset: token.NewFileSet(),
18+
}
1419
}
1520

1621
type cache struct {
22+
fset *token.FileSet
1723
}
1824

1925
func (c *cache) NewSession(log xlog.Logger) source.Session {
2026
return &session{
21-
cache: c,
22-
log: log,
27+
cache: c,
28+
log: log,
29+
overlays: make(map[span.URI][]byte),
2330
}
2431
}
32+
33+
func (c *cache) FileSet() *token.FileSet {
34+
return c.fset
35+
}

internal/lsp/cache/check.go

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"go/ast"
1111
"go/parser"
1212
"go/scanner"
13+
"go/token"
1314
"go/types"
1415

1516
"golang.org/x/tools/go/analysis"
@@ -49,6 +50,7 @@ func (v *view) parse(ctx context.Context, file source.File) ([]packages.Error, e
4950
view: v,
5051
seen: make(map[string]struct{}),
5152
ctx: ctx,
53+
fset: f.FileSet(),
5254
}
5355
// Start prefetching direct imports.
5456
for importPath := range f.meta.children {
@@ -69,12 +71,11 @@ func (v *view) parse(ctx context.Context, file source.File) ([]packages.Error, e
6971

7072
func (v *view) checkMetadata(ctx context.Context, f *goFile) ([]packages.Error, error) {
7173
if v.reparseImports(ctx, f, f.filename()) {
72-
cfg := v.config
73-
cfg.Mode = packages.LoadImports | packages.NeedTypesSizes
74-
pkgs, err := packages.Load(&cfg, fmt.Sprintf("file=%s", f.filename()))
74+
cfg := v.buildConfig()
75+
pkgs, err := packages.Load(cfg, fmt.Sprintf("file=%s", f.filename()))
7576
if len(pkgs) == 0 {
7677
if err == nil {
77-
err = fmt.Errorf("no packages found for %s", f.filename())
78+
err = fmt.Errorf("%s: no packages found", f.filename())
7879
}
7980
// Return this error as a diagnostic to the user.
8081
return []packages.Error{
@@ -104,7 +105,7 @@ func (v *view) reparseImports(ctx context.Context, f *goFile, filename string) b
104105
}
105106
// Get file content in case we don't already have it?
106107
f.read(ctx)
107-
parsed, _ := parser.ParseFile(v.config.Fset, filename, f.content, parser.ImportsOnly)
108+
parsed, _ := parser.ParseFile(f.FileSet(), filename, f.content, parser.ImportsOnly)
108109
if parsed == nil {
109110
return true
110111
}
@@ -173,7 +174,8 @@ type importer struct {
173174
// If we have seen a package that is already in this map, we have a circular import.
174175
seen map[string]struct{}
175176

176-
ctx context.Context
177+
ctx context.Context
178+
fset *token.FileSet
177179
}
178180

179181
func (imp *importer) Import(pkgPath string) (*types.Package, error) {
@@ -255,9 +257,10 @@ func (imp *importer) typeCheck(pkgPath string) (*pkg, error) {
255257
view: imp.view,
256258
seen: seen,
257259
ctx: imp.ctx,
260+
fset: imp.fset,
258261
},
259262
}
260-
check := types.NewChecker(cfg, imp.view.config.Fset, pkg.types, pkg.typesInfo)
263+
check := types.NewChecker(cfg, imp.fset, pkg.types, pkg.typesInfo)
261264
check.Files(pkg.syntax)
262265

263266
// Add every file in this package to our cache.
@@ -273,7 +276,7 @@ func (v *view) cachePackage(ctx context.Context, pkg *pkg, meta *metadata) {
273276
v.Session().Logger().Errorf(ctx, "invalid position for file %v", file.Name)
274277
continue
275278
}
276-
tok := v.config.Fset.File(file.Pos())
279+
tok := v.Session().Cache().FileSet().File(file.Pos())
277280
if tok == nil {
278281
v.Session().Logger().Errorf(ctx, "no token.File for %v", file.Name)
279282
continue
@@ -341,7 +344,7 @@ func (v *view) appendPkgError(pkg *pkg, err error) {
341344
}
342345
case types.Error:
343346
errs = append(errs, packages.Error{
344-
Pos: v.config.Fset.Position(err.Pos).String(),
347+
Pos: v.Session().Cache().FileSet().Position(err.Pos).String(),
345348
Msg: err.Msg,
346349
Kind: packages.TypeError,
347350
})

internal/lsp/cache/file.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -80,8 +80,8 @@ func (f *fileBase) GetContent(ctx context.Context) []byte {
8080
return f.content
8181
}
8282

83-
func (f *fileBase) GetFileSet(ctx context.Context) *token.FileSet {
84-
return f.view.config.Fset
83+
func (f *fileBase) FileSet() *token.FileSet {
84+
return f.view.Session().Cache().FileSet()
8585
}
8686

8787
func (f *goFile) GetToken(ctx context.Context) *token.File {
@@ -144,7 +144,9 @@ func (f *fileBase) read(ctx context.Context) {
144144
}
145145
}
146146
// We might have the content saved in an overlay.
147-
if content, ok := f.view.config.Overlay[f.filename()]; ok {
147+
f.view.session.overlayMu.Lock()
148+
defer f.view.session.overlayMu.Unlock()
149+
if content, ok := f.view.session.overlays[f.URI()]; ok {
148150
f.content = content
149151
return
150152
}

internal/lsp/cache/parse.go

Lines changed: 19 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ import (
1111
"go/parser"
1212
"go/scanner"
1313
"go/token"
14-
"io/ioutil"
1514
"os"
1615
"path/filepath"
1716
"strings"
@@ -20,6 +19,10 @@ import (
2019
"golang.org/x/tools/internal/span"
2120
)
2221

22+
func parseFile(fset *token.FileSet, filename string, src []byte) (*ast.File, error) {
23+
return parser.ParseFile(fset, filename, src, parser.AllErrors|parser.ParseComments)
24+
}
25+
2326
// We use a counting semaphore to limit
2427
// the number of parallel I/O calls per process.
2528
var ioLimit = make(chan bool, 20)
@@ -37,53 +40,43 @@ func (imp *importer) parseFiles(filenames []string) ([]*ast.File, []error) {
3740
parsed := make([]*ast.File, n)
3841
errors := make([]error, n)
3942
for i, filename := range filenames {
40-
if imp.view.config.Context.Err() != nil {
43+
if imp.ctx.Err() != nil {
4144
parsed[i] = nil
42-
errors[i] = imp.view.config.Context.Err()
45+
errors[i] = imp.ctx.Err()
4346
continue
4447
}
4548

4649
// First, check if we have already cached an AST for this file.
4750
f, err := imp.view.findFile(span.FileURI(filename))
48-
if err != nil {
51+
if err != nil || f == nil {
4952
parsed[i], errors[i] = nil, err
53+
continue
5054
}
51-
var fAST *ast.File
52-
if f != nil {
53-
if gof, ok := f.(*goFile); ok {
54-
fAST = gof.ast
55-
}
55+
gof, ok := f.(*goFile)
56+
if !ok {
57+
parsed[i], errors[i] = nil, fmt.Errorf("Non go file in parse call: %v", filename)
58+
continue
5659
}
5760

5861
wg.Add(1)
5962
go func(i int, filename string) {
6063
ioLimit <- true // wait
6164

62-
if fAST != nil {
63-
parsed[i], errors[i] = fAST, nil
65+
if gof.ast != nil {
66+
parsed[i], errors[i] = gof.ast, nil
6467
} else {
6568
// We don't have a cached AST for this file.
66-
var src []byte
67-
// Check for an available overlay.
68-
for f, contents := range imp.view.config.Overlay {
69-
if sameFile(f, filename) {
70-
src = contents
71-
}
72-
}
73-
var err error
74-
// We don't have an overlay, so we must read the file's contents.
69+
gof.read(imp.ctx)
70+
src := gof.content
7571
if src == nil {
76-
src, err = ioutil.ReadFile(filename)
77-
}
78-
if err != nil {
79-
parsed[i], errors[i] = nil, err
72+
parsed[i], errors[i] = nil, fmt.Errorf("No source for %v", filename)
8073
} else {
8174
// ParseFile may return both an AST and an error.
82-
parsed[i], errors[i] = imp.view.config.ParseFile(imp.view.config.Fset, filename, src)
75+
parsed[i], errors[i] = parseFile(imp.fset, filename, src)
8376

8477
// Fix any badly parsed parts of the AST.
8578
if file := parsed[i]; file != nil {
86-
tok := imp.view.config.Fset.File(file.Pos())
79+
tok := imp.fset.File(file.Pos())
8780
imp.view.fix(imp.ctx, parsed[i], tok, src)
8881
}
8982
}

internal/lsp/cache/session.go

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import (
1010
"strings"
1111
"sync"
1212

13-
"golang.org/x/tools/go/packages"
1413
"golang.org/x/tools/internal/lsp/source"
1514
"golang.org/x/tools/internal/lsp/xlog"
1615
"golang.org/x/tools/internal/span"
@@ -24,6 +23,9 @@ type session struct {
2423
viewMu sync.Mutex
2524
views []*view
2625
viewMap map[span.URI]source.View
26+
27+
overlayMu sync.Mutex
28+
overlays map[span.URI][]byte
2729
}
2830

2931
func (s *session) Shutdown(ctx context.Context) {
@@ -40,7 +42,7 @@ func (s *session) Cache() source.Cache {
4042
return s.cache
4143
}
4244

43-
func (s *session) NewView(name string, folder span.URI, config *packages.Config) source.View {
45+
func (s *session) NewView(name string, folder span.URI) source.View {
4446
s.viewMu.Lock()
4547
defer s.viewMu.Unlock()
4648
ctx := context.Background()
@@ -49,9 +51,7 @@ func (s *session) NewView(name string, folder span.URI, config *packages.Config)
4951
session: s,
5052
baseCtx: ctx,
5153
backgroundCtx: backgroundCtx,
52-
builtinPkg: builtinPkg(*config),
5354
cancel: cancel,
54-
config: *config,
5555
name: name,
5656
folder: folder,
5757
filesByURI: make(map[span.URI]viewFile),
@@ -65,9 +65,6 @@ func (s *session) NewView(name string, folder span.URI, config *packages.Config)
6565
},
6666
ignoredURIs: make(map[span.URI]struct{}),
6767
}
68-
for filename := range v.builtinPkg.Files {
69-
v.ignoredURIs[span.NewURI(filename)] = struct{}{}
70-
}
7168
s.views = append(s.views, v)
7269
// we always need to drop the view map
7370
s.viewMap = make(map[span.URI]source.View)
@@ -155,3 +152,26 @@ func (s *session) removeView(ctx context.Context, view *view) error {
155152
func (s *session) Logger() xlog.Logger {
156153
return s.log
157154
}
155+
156+
func (s *session) setOverlay(uri span.URI, content []byte) {
157+
s.overlayMu.Lock()
158+
defer s.overlayMu.Unlock()
159+
//TODO: we also need to invalidate anything that depended on this "file"
160+
if content == nil {
161+
delete(s.overlays, uri)
162+
return
163+
}
164+
s.overlays[uri] = content
165+
}
166+
167+
func (s *session) buildOverlay() map[string][]byte {
168+
s.overlayMu.Lock()
169+
defer s.overlayMu.Unlock()
170+
overlay := make(map[string][]byte)
171+
for uri, content := range s.overlays {
172+
if filename, err := uri.Filename(); err == nil {
173+
overlay[filename] = content
174+
}
175+
}
176+
return overlay
177+
}

0 commit comments

Comments
 (0)