1
0
mirror of https://github.com/golang/go synced 2024-11-18 16:04:44 -07:00

internal/lsp: handle metadata reloads for ad-hoc packages

Now that we are reloading metadata for workspace packages by package
path, ad-hoc packages get their metadata reloaded incorrectly. If an
ad-hoc package has no metadata, reload it by reloading the entire
directory.

Fixes golang/go#36753

Change-Id: Ie440f6f76a220009d487b7ceadcf40594643e969
Reviewed-on: https://go-review.googlesource.com/c/tools/+/216307
Run-TryBot: Rebecca Stambler <rstambler@golang.org>
Reviewed-by: Heschi Kreinick <heschi@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
This commit is contained in:
Rebecca Stambler 2020-01-25 16:41:35 -05:00
parent ab094738a9
commit a644f81d5e

View File

@ -540,12 +540,33 @@ func (s *snapshot) awaitLoaded(ctx context.Context) error {
if err := s.view.awaitInitialized(ctx); err != nil {
return err
}
// Make sure that the workspace is in a valid state.
return s.reloadWorkspace(ctx)
m, err := s.reloadWorkspace(ctx)
if err != nil {
return err
}
for _, m := range m {
s.setWorkspacePackage(ctx, m)
}
if err := s.reloadOrphanedFiles(ctx); err != nil {
return err
}
// Create package handles for all of the workspace packages.
for _, id := range s.workspacePackageIDs() {
if _, err := s.packageHandle(ctx, id); err != nil {
return err
}
}
return nil
}
// reloadWorkspace reloads the metadata for all invalidated workspace packages.
func (s *snapshot) reloadWorkspace(ctx context.Context) error {
func (s *snapshot) reloadWorkspace(ctx context.Context) ([]*metadata, error) {
// If the view's build configuration is invalid, we cannot reload by package path.
// Just reload the directory instead.
if !s.view.hasValidBuildConfiguration {
return s.load(ctx, viewLoadScope("LOAD_INVALID_VIEW"))
}
// See which of the workspace packages are missing metadata.
s.mu.Lock()
var pkgPaths []interface{}
@ -556,55 +577,52 @@ func (s *snapshot) reloadWorkspace(ctx context.Context) error {
}
s.mu.Unlock()
if len(pkgPaths) > 0 {
if m, err := s.load(ctx, pkgPaths...); err == nil {
for _, m := range m {
s.setWorkspacePackage(ctx, m)
}
}
if len(pkgPaths) == 0 {
return nil, nil
}
return s.load(ctx, pkgPaths...)
}
func (s *snapshot) reloadOrphanedFiles(ctx context.Context) error {
// When we load ./... or a package path directly, we may not get packages
// that exist only in overlays. As a workaround, we search all of the files
// available in the snapshot and reload their metadata individually using a
// file= query if the metadata is unavailable.
if scopes := s.orphanedFileScopes(); len(scopes) > 0 {
m, err := s.load(ctx, scopes...)
// If we failed to load some files, i.e. they have no metadata,
// mark the failures so we don't bother retrying until the file's
// content changes.
//
// TODO(rstambler): This may be an overestimate if the load stopped
// early for an unrelated errors. Add a fallback?
//
// Check for context cancellation so that we don't incorrectly mark files
// as unloadable, but don't return before setting all workspace packages.
if ctx.Err() == nil && err != nil {
s.mu.Lock()
for _, scope := range scopes {
uri := span.URI(scope.(fileURI))
if s.getMetadataForURILocked(uri) == nil {
s.unloadableFiles[uri] = struct{}{}
}
}
s.mu.Unlock()
}
for _, m := range m {
// If a package's files belong to this view, it is a workspace package
// and should be added to the set of workspace packages.
for _, uri := range m.compiledGoFiles {
if !contains(s.view.session.viewsOf(uri), s.view) {
continue
}
s.setWorkspacePackage(ctx, m)
}
}
scopes := s.orphanedFileScopes()
if len(scopes) == 0 {
return nil
}
// Create package handles for all of the workspace packages.
for _, id := range s.workspacePackageIDs() {
if _, err := s.packageHandle(ctx, id); err != nil {
return err
m, err := s.load(ctx, scopes...)
// If we failed to load some files, i.e. they have no metadata,
// mark the failures so we don't bother retrying until the file's
// content changes.
//
// TODO(rstambler): This may be an overestimate if the load stopped
// early for an unrelated errors. Add a fallback?
//
// Check for context cancellation so that we don't incorrectly mark files
// as unloadable, but don't return before setting all workspace packages.
if ctx.Err() == nil && err != nil {
s.mu.Lock()
for _, scope := range scopes {
uri := span.URI(scope.(fileURI))
if s.getMetadataForURILocked(uri) == nil {
s.unloadableFiles[uri] = struct{}{}
}
}
s.mu.Unlock()
}
for _, m := range m {
// If a package's files belong to this view, it is a workspace package
// and should be added to the set of workspace packages.
for _, uri := range m.compiledGoFiles {
if !contains(s.view.session.viewsOf(uri), s.view) {
continue
}
s.setWorkspacePackage(ctx, m)
}
}
return nil