mirror of
https://github.com/golang/go
synced 2024-11-18 03:04:45 -07:00
internal/lsp: show a warning message when opening an "orphaned" file
Build tags are a common stumbling block for users of gopls, as build tagged files may be excluded from the initial workspace load without a clear warning. This change adds a check for every opened file to confirm if it maps to a package. If not, we show a message with suggestions. A follow-up improvement might be to check if the opened file actually has build tags to make the error message more precise (and give a better example config). Updates golang/go#31668 Change-Id: I829d8546edea65aa08274021bfde8ea2fb6eeaa1 Reviewed-on: https://go-review.googlesource.com/c/tools/+/253798 Run-TryBot: Rebecca Stambler <rstambler@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Robert Findley <rfindley@google.com>
This commit is contained in:
parent
d6107fe4b8
commit
53e29e9d12
@ -520,7 +520,7 @@ func f() {
|
|||||||
`
|
`
|
||||||
runner.Run(t, noModule, func(t *testing.T, env *Env) {
|
runner.Run(t, noModule, func(t *testing.T, env *Env) {
|
||||||
env.OpenFile("a.go")
|
env.OpenFile("a.go")
|
||||||
env.Await(env.DiagnosticAtRegexp("a.go", "fmt.Printl"), SomeShowMessage(""))
|
env.Await(env.DiagnosticAtRegexp("a.go", "fmt.Printl"), ShownMessage(""))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1313,3 +1313,39 @@ func main() {}
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestNotifyOrphanedFiles(t *testing.T) {
|
||||||
|
const files = `
|
||||||
|
-- go.mod --
|
||||||
|
module mod.com
|
||||||
|
|
||||||
|
go 1.12
|
||||||
|
-- a/a.go --
|
||||||
|
package a
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
var x int
|
||||||
|
}
|
||||||
|
-- a/a_ignore.go --
|
||||||
|
// +build ignore
|
||||||
|
|
||||||
|
package a
|
||||||
|
|
||||||
|
func _() {
|
||||||
|
var x int
|
||||||
|
}
|
||||||
|
`
|
||||||
|
run(t, files, func(t *testing.T, env *Env) {
|
||||||
|
env.Await(
|
||||||
|
CompletedWork(lsp.DiagnosticWorkTitle(lsp.FromInitialWorkspaceLoad), 1),
|
||||||
|
)
|
||||||
|
env.OpenFile("a/a.go")
|
||||||
|
env.Await(
|
||||||
|
env.DiagnosticAtRegexp("a/a.go", "x"),
|
||||||
|
)
|
||||||
|
env.OpenFile("a/a_ignore.go")
|
||||||
|
env.Await(
|
||||||
|
ShownMessage("No packages found for open file"),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
@ -389,8 +389,9 @@ func NoShowMessage() SimpleExpectation {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// SomeShowMessage asserts that the editor has received a ShowMessage with the given title.
|
// ShownMessage asserts that the editor has received a ShownMessage with the
|
||||||
func SomeShowMessage(title string) SimpleExpectation {
|
// given title.
|
||||||
|
func ShownMessage(title string) SimpleExpectation {
|
||||||
check := func(s State) (Verdict, interface{}) {
|
check := func(s State) (Verdict, interface{}) {
|
||||||
for _, m := range s.showMessage {
|
for _, m := range s.showMessage {
|
||||||
if strings.Contains(m.Message, title) {
|
if strings.Contains(m.Message, title) {
|
||||||
|
@ -11,7 +11,9 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
"golang.org/x/tools/internal/event"
|
||||||
"golang.org/x/tools/internal/jsonrpc2"
|
"golang.org/x/tools/internal/jsonrpc2"
|
||||||
|
"golang.org/x/tools/internal/lsp/debug/tag"
|
||||||
"golang.org/x/tools/internal/lsp/protocol"
|
"golang.org/x/tools/internal/lsp/protocol"
|
||||||
"golang.org/x/tools/internal/lsp/source"
|
"golang.org/x/tools/internal/lsp/source"
|
||||||
"golang.org/x/tools/internal/span"
|
"golang.org/x/tools/internal/span"
|
||||||
@ -89,16 +91,13 @@ func (s *Server) didOpen(ctx context.Context, params *protocol.DidOpenTextDocume
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return s.didModifyFiles(ctx, []source.FileModification{{
|
||||||
return s.didModifyFiles(ctx, []source.FileModification{
|
URI: uri,
|
||||||
{
|
Action: source.Open,
|
||||||
URI: uri,
|
Version: params.TextDocument.Version,
|
||||||
Action: source.Open,
|
Text: []byte(params.TextDocument.Text),
|
||||||
Version: params.TextDocument.Version,
|
LanguageID: params.TextDocument.LanguageID,
|
||||||
Text: []byte(params.TextDocument.Text),
|
}}, FromDidOpen)
|
||||||
LanguageID: params.TextDocument.LanguageID,
|
|
||||||
},
|
|
||||||
}, FromDidOpen)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) didChange(ctx context.Context, params *protocol.DidChangeTextDocumentParams) error {
|
func (s *Server) didChange(ctx context.Context, params *protocol.DidChangeTextDocumentParams) error {
|
||||||
@ -280,10 +279,17 @@ func (s *Server) didModifyFiles(ctx context.Context, modifications []source.File
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
diagnosticWG.Add(1)
|
diagnosticWG.Add(1)
|
||||||
go func(snapshot source.Snapshot) {
|
go func(snapshot source.Snapshot, uris []span.URI) {
|
||||||
defer diagnosticWG.Done()
|
defer diagnosticWG.Done()
|
||||||
s.diagnoseSnapshot(snapshot)
|
s.diagnoseSnapshot(snapshot)
|
||||||
}(snapshot)
|
|
||||||
|
// If files have been newly opened, check if we found packages for
|
||||||
|
// them. If not, notify this user that the file may be excluded
|
||||||
|
// because of build tags.
|
||||||
|
if cause == FromDidOpen {
|
||||||
|
s.checkForOrphanedFile(ctx, snapshot, uris)
|
||||||
|
}
|
||||||
|
}(snapshot, uris)
|
||||||
}
|
}
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
@ -307,6 +313,34 @@ func DiagnosticWorkTitle(cause ModificationSource) string {
|
|||||||
return fmt.Sprintf("diagnosing %v", cause)
|
return fmt.Sprintf("diagnosing %v", cause)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// checkForOrphanedFile checks that the given URIs can be mapped to packages.
|
||||||
|
// If they cannot and the workspace is not otherwise unloaded, it also surfaces
|
||||||
|
// a warning, suggesting that the user check the file for build tags.
|
||||||
|
func (s *Server) checkForOrphanedFile(ctx context.Context, snapshot source.Snapshot, uris []span.URI) {
|
||||||
|
// Only show the error message if we have packages in the workspace,
|
||||||
|
// but no package for the file.
|
||||||
|
if pkgs, err := snapshot.WorkspacePackages(ctx); err != nil || len(pkgs) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for _, uri := range uris {
|
||||||
|
pkgs, err := snapshot.PackagesForFile(ctx, uri, source.TypecheckWorkspace)
|
||||||
|
if len(pkgs) > 0 || err == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// TODO(rstambler): We should be able to parse the build tags in the
|
||||||
|
// file and show a more specific error message.
|
||||||
|
if err := s.client.ShowMessage(ctx, &protocol.ShowMessageParams{
|
||||||
|
Type: protocol.Error,
|
||||||
|
Message: fmt.Sprintf(`No packages found for open file %s: %v.
|
||||||
|
If this file contains build tags, try adding "-tags=<build tag>" to your gopls "buildFlag" configuration (see (https://github.com/golang/tools/blob/master/gopls/doc/settings.md#buildflags-string).
|
||||||
|
Otherwise, see the troubleshooting guidelines for help investigating (https://github.com/golang/tools/blob/master/gopls/doc/troubleshooting.md).
|
||||||
|
`, uri.Filename(), err),
|
||||||
|
}); err != nil {
|
||||||
|
event.Error(ctx, "warnAboutBuildTags: failed to show message", err, tag.URI.Of(uri))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Server) wasFirstChange(uri span.URI) bool {
|
func (s *Server) wasFirstChange(uri span.URI) bool {
|
||||||
s.changedFilesMu.Lock()
|
s.changedFilesMu.Lock()
|
||||||
defer s.changedFilesMu.Unlock()
|
defer s.changedFilesMu.Unlock()
|
||||||
|
Loading…
Reference in New Issue
Block a user