mirror of
https://github.com/golang/go.git
synced 2025-05-05 15:43:04 +00:00
internal/lsp: fix race condition in metadata handling
The metadata was being added to the cache before it was fully computed. Change-Id: I6931476a715f0383f7739fa4e950dcaa6cbec4fe Reviewed-on: https://go-review.googlesource.com/c/tools/+/204562 Run-TryBot: Rebecca Stambler <rstambler@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Ian Cottrell <iancottrell@google.com>
This commit is contained in:
parent
423eeaeda5
commit
979d74e0bb
28
internal/lsp/cache/load.go
vendored
28
internal/lsp/cache/load.go
vendored
@ -45,7 +45,6 @@ func (s *snapshot) load(ctx context.Context, uri span.URI) ([]*metadata, error)
|
|||||||
if err == context.Canceled {
|
if err == context.Canceled {
|
||||||
return nil, errors.Errorf("no metadata for %s: %v", uri.Filename(), err)
|
return nil, errors.Errorf("no metadata for %s: %v", uri.Filename(), err)
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Print(ctx, "go/packages.Load", tag.Of("packages", len(pkgs)))
|
log.Print(ctx, "go/packages.Load", tag.Of("packages", len(pkgs)))
|
||||||
if len(pkgs) == 0 {
|
if len(pkgs) == 0 {
|
||||||
if err == nil {
|
if err == nil {
|
||||||
@ -149,7 +148,7 @@ func (s *snapshot) updateMetadata(ctx context.Context, uri span.URI, pkgs []*pac
|
|||||||
log.Print(ctx, "go/packages.Load", tag.Of("package", pkg.PkgPath), tag.Of("files", pkg.CompiledGoFiles))
|
log.Print(ctx, "go/packages.Load", tag.Of("package", pkg.PkgPath), tag.Of("files", pkg.CompiledGoFiles))
|
||||||
|
|
||||||
// Set the metadata for this package.
|
// Set the metadata for this package.
|
||||||
if err := s.updateImports(ctx, packagePath(pkg.PkgPath), pkg, cfg); err != nil {
|
if err := s.updateImports(ctx, packagePath(pkg.PkgPath), pkg, cfg, map[packageID]struct{}{}); err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
m := s.getMetadata(packageID(pkg.ID))
|
m := s.getMetadata(packageID(pkg.ID))
|
||||||
@ -167,16 +166,21 @@ func (s *snapshot) updateMetadata(ctx context.Context, uri span.URI, pkgs []*pac
|
|||||||
return results, prevMissingImports, nil
|
return results, prevMissingImports, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *snapshot) updateImports(ctx context.Context, pkgPath packagePath, pkg *packages.Package, cfg *packages.Config) error {
|
func (s *snapshot) updateImports(ctx context.Context, pkgPath packagePath, pkg *packages.Package, cfg *packages.Config, seen map[packageID]struct{}) error {
|
||||||
|
id := packageID(pkg.ID)
|
||||||
|
if _, ok := seen[id]; ok {
|
||||||
|
return errors.Errorf("import cycle detected: %q", id)
|
||||||
|
}
|
||||||
// Recreate the metadata rather than reusing it to avoid locking.
|
// Recreate the metadata rather than reusing it to avoid locking.
|
||||||
m := &metadata{
|
m := &metadata{
|
||||||
id: packageID(pkg.ID),
|
id: id,
|
||||||
pkgPath: pkgPath,
|
pkgPath: pkgPath,
|
||||||
name: pkg.Name,
|
name: pkg.Name,
|
||||||
typesSizes: pkg.TypesSizes,
|
typesSizes: pkg.TypesSizes,
|
||||||
errors: pkg.Errors,
|
errors: pkg.Errors,
|
||||||
config: cfg,
|
config: cfg,
|
||||||
}
|
}
|
||||||
|
seen[id] = struct{}{}
|
||||||
for _, filename := range pkg.CompiledGoFiles {
|
for _, filename := range pkg.CompiledGoFiles {
|
||||||
uri := span.FileURI(filename)
|
uri := span.FileURI(filename)
|
||||||
m.files = append(m.files, uri)
|
m.files = append(m.files, uri)
|
||||||
@ -184,16 +188,14 @@ func (s *snapshot) updateImports(ctx context.Context, pkgPath packagePath, pkg *
|
|||||||
s.addID(uri, m.id)
|
s.addID(uri, m.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add the metadata to the cache.
|
copied := make(map[packageID]struct{})
|
||||||
s.setMetadata(m)
|
for k, v := range seen {
|
||||||
|
copied[k] = v
|
||||||
|
}
|
||||||
for importPath, importPkg := range pkg.Imports {
|
for importPath, importPkg := range pkg.Imports {
|
||||||
importPkgPath := packagePath(importPath)
|
importPkgPath := packagePath(importPath)
|
||||||
importID := packageID(importPkg.ID)
|
importID := packageID(importPkg.ID)
|
||||||
|
|
||||||
if importPkgPath == pkgPath {
|
|
||||||
return errors.Errorf("cycle detected in %s", importPath)
|
|
||||||
}
|
|
||||||
m.deps = append(m.deps, importID)
|
m.deps = append(m.deps, importID)
|
||||||
|
|
||||||
// Don't remember any imports with significant errors.
|
// Don't remember any imports with significant errors.
|
||||||
@ -206,10 +208,14 @@ func (s *snapshot) updateImports(ctx context.Context, pkgPath packagePath, pkg *
|
|||||||
}
|
}
|
||||||
dep := s.getMetadata(importID)
|
dep := s.getMetadata(importID)
|
||||||
if dep == nil {
|
if dep == nil {
|
||||||
if err := s.updateImports(ctx, importPkgPath, importPkg, cfg); err != nil {
|
if err := s.updateImports(ctx, importPkgPath, importPkg, cfg, copied); err != nil {
|
||||||
log.Error(ctx, "error in dependency", err)
|
log.Error(ctx, "error in dependency", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add the metadata to the cache.
|
||||||
|
s.setMetadata(m)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -61,7 +61,7 @@ func (r *runner) Diagnostics(t *testing.T, uri span.URI, want []source.Diagnosti
|
|||||||
}
|
}
|
||||||
_, found := got[expect]
|
_, found := got[expect]
|
||||||
if !found {
|
if !found {
|
||||||
t.Errorf("missing diagnostic %q", expect)
|
t.Errorf("missing diagnostic %q, %v", expect, got)
|
||||||
} else {
|
} else {
|
||||||
delete(got, expect)
|
delete(got, expect)
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user