Skip to content

Commit 5cdc274

Browse files
committed
internal/lsp: remove the last diagnostics pop-up warning
The "you are neither in a module nor your GOPATH" warning doesn't fit our current notification style, so adjust it to appear as a progress report and clean up the associated tests. Change-Id: I32b96f17f3b9715403e465e3e0f9705f5d859147 Reviewed-on: https://go-review.googlesource.com/c/tools/+/275537 Trust: Rebecca Stambler <rstambler@golang.org> Run-TryBot: Rebecca Stambler <rstambler@golang.org> gopls-CI: kokoro <noreply+kokoro@google.com> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Heschi Kreinick <heschi@google.com>
1 parent ef0c635 commit 5cdc274

File tree

7 files changed

+76
-122
lines changed

7 files changed

+76
-122
lines changed

gopls/internal/regtest/diagnostics_test.go

Lines changed: 11 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -538,43 +538,26 @@ func _() {
538538

539539
// Expect a module/GOPATH error if there is an error in the file at startup.
540540
// Tests golang/go#37279.
541-
func TestShowMessage_Issue37279(t *testing.T) {
541+
func TestShowCriticalError_Issue37279(t *testing.T) {
542542
const noModule = `
543543
-- a.go --
544544
package foo
545545
546-
func f() {
547-
fmt.Printl()
548-
}
549-
`
550-
runner.Run(t, noModule, func(t *testing.T, env *Env) {
551-
env.OpenFile("a.go")
552-
env.Await(env.DiagnosticAtRegexp("a.go", "fmt.Printl"), ShownMessage(""))
553-
})
554-
}
555-
556-
// Expect no module/GOPATH error if there is no error in the file.
557-
// Tests golang/go#37279.
558-
func TestNoShowMessage_Issue37279(t *testing.T) {
559-
const noModule = `
560-
-- a.go --
561-
package foo
546+
import "mod.com/hello"
562547
563548
func f() {
549+
hello.Goodbye()
564550
}
565551
`
566552
runner.Run(t, noModule, func(t *testing.T, env *Env) {
567553
env.OpenFile("a.go")
568554
env.Await(
569-
OnceMet(
570-
CompletedWork(lsp.DiagnosticWorkTitle(lsp.FromDidOpen), 1),
571-
NoDiagnostics("a.go"),
572-
),
573-
NoShowMessage(),
555+
OutstandingWork(lsp.WorkspaceLoadFailure, "outside of a module"),
556+
)
557+
env.RegexpReplace("a.go", `import "mod.com/hello"`, "")
558+
env.Await(
559+
NoOutstandingWork(),
574560
)
575-
// introduce an error, expect no Show Message
576-
env.RegexpReplace("a.go", "func", "fun")
577-
env.Await(env.DiagnosticAtRegexp("a.go", "fun"), NoShowMessage())
578561
})
579562
}
580563

@@ -1526,14 +1509,14 @@ package main
15261509
run(t, pkg, func(t *testing.T, env *Env) {
15271510
env.OpenFile("go.mod")
15281511
env.Await(
1529-
OutstandingWork("Error loading workspace", "unknown directive"),
1512+
OutstandingWork(lsp.WorkspaceLoadFailure, "unknown directive"),
15301513
)
15311514
env.EditBuffer("go.mod", fake.NewEdit(0, 0, 3, 0, `module mod.com
15321515
15331516
go 1.hello
15341517
`))
15351518
env.Await(
1536-
OutstandingWork("Error loading workspace", "invalid go version"),
1519+
OutstandingWork(lsp.WorkspaceLoadFailure, "invalid go version"),
15371520
)
15381521
env.RegexpReplace("go.mod", "go 1.hello", "go 1.12")
15391522
env.Await(
@@ -1681,7 +1664,7 @@ package b
16811664
env.Await(
16821665
env.DiagnosticAtRegexp("a/a.go", "package a"),
16831666
env.DiagnosticAtRegexp("b/go.mod", "module b.com"),
1684-
OutstandingWork("Error loading workspace", "gopls requires a module at the root of your workspace."),
1667+
OutstandingWork(lsp.WorkspaceLoadFailure, "gopls requires one module per workspace folder."),
16851668
)
16861669
})
16871670
})

internal/lsp/cache/load.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,7 @@ func (s *snapshot) WorkspaceLayoutError(ctx context.Context) *source.CriticalErr
234234
}
235235
s.mu.Unlock()
236236

237-
msg := `gopls requires a module at the root of your workspace.
237+
msg := `gopls requires one module per workspace folder.
238238
You can work with multiple modules by opening each one as a workspace folder.
239239
Improvements to this workflow will be coming soon (https://github.com/golang/go/issues/32394),
240240
and you can learn more here: https://github.com/golang/go/issues/36899.`

internal/lsp/cache/pkg.go

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -117,9 +117,20 @@ func (p *pkg) GetImport(pkgPath string) (source.Package, error) {
117117
}
118118

119119
func (p *pkg) MissingDependencies() []string {
120+
// We don't invalidate metadata for import deletions, so check the package
121+
// imports via the *types.Package. Only use metadata if p.types is nil.
122+
if p.types == nil {
123+
var md []string
124+
for i := range p.m.missingDeps {
125+
md = append(md, string(i))
126+
}
127+
return md
128+
}
120129
var md []string
121-
for i := range p.m.missingDeps {
122-
md = append(md, string(i))
130+
for _, pkg := range p.types.Imports() {
131+
if _, ok := p.m.missingDeps[packagePath(pkg.Path())]; ok {
132+
md = append(md, pkg.Path())
133+
}
123134
}
124135
return md
125136
}

internal/lsp/cache/view.go

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -528,11 +528,8 @@ func (s *snapshot) initialize(ctx context.Context, firstAttempt bool) {
528528

529529
// If we have multiple modules, we need to load them by paths.
530530
var scopes []interface{}
531-
var modErrors source.ErrorList
531+
var modErrors []*source.Error
532532
addError := func(uri span.URI, err error) {
533-
if modErrors == nil {
534-
modErrors = source.ErrorList{}
535-
}
536533
modErrors = append(modErrors, &source.Error{
537534
URI: uri,
538535
Category: "compiler",

internal/lsp/diagnostics.go

Lines changed: 49 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -68,14 +68,7 @@ func hashDiagnostics(diags ...*source.Diagnostic) string {
6868
func (s *Server) diagnoseDetached(snapshot source.Snapshot) {
6969
ctx := snapshot.BackgroundContext()
7070
ctx = xcontext.Detach(ctx)
71-
showWarning := s.diagnose(ctx, snapshot, false)
72-
if showWarning {
73-
// If a view has been created or the configuration changed, warn the user.
74-
s.client.ShowMessage(ctx, &protocol.ShowMessageParams{
75-
Type: protocol.Warning,
76-
Message: `You are neither in a module nor in your GOPATH. If you are using modules, please open your editor to a directory in your module. If you believe this warning is incorrect, please file an issue: https://github.com/golang/go/issues/new.`,
77-
})
78-
}
71+
s.diagnose(ctx, snapshot, false)
7972
s.publishDiagnostics(ctx, true, snapshot)
8073
}
8174

@@ -138,22 +131,22 @@ func (s *Server) diagnoseChangedFiles(ctx context.Context, snapshot source.Snaps
138131
go func(pkg source.Package) {
139132
defer wg.Done()
140133

141-
_ = s.diagnosePkg(ctx, snapshot, pkg, false)
134+
s.diagnosePkg(ctx, snapshot, pkg, false)
142135
}(pkg)
143136
}
144137
wg.Wait()
145138
}
146139

147140
// diagnose is a helper function for running diagnostics with a given context.
148141
// Do not call it directly. forceAnalysis is only true for testing purposes.
149-
func (s *Server) diagnose(ctx context.Context, snapshot source.Snapshot, forceAnalysis bool) bool {
142+
func (s *Server) diagnose(ctx context.Context, snapshot source.Snapshot, forceAnalysis bool) {
150143
ctx, done := event.Start(ctx, "Server.diagnose")
151144
defer done()
152145

153146
// Wait for a free diagnostics slot.
154147
select {
155148
case <-ctx.Done():
156-
return false
149+
return
157150
case s.diagnosticsSema <- struct{}{}:
158151
}
159152
defer func() {
@@ -163,7 +156,7 @@ func (s *Server) diagnose(ctx context.Context, snapshot source.Snapshot, forceAn
163156
// First, diagnose the go.mod file.
164157
modReports, modErr := mod.Diagnostics(ctx, snapshot)
165158
if ctx.Err() != nil {
166-
return false
159+
return
167160
}
168161
if modErr != nil {
169162
event.Error(ctx, "warning: diagnose go.mod", modErr, tag.Directory.Of(snapshot.View().Folder().Filename()), tag.Snapshot.Of(snapshot.ID()))
@@ -179,7 +172,14 @@ func (s *Server) diagnose(ctx context.Context, snapshot source.Snapshot, forceAn
179172
// Diagnose all of the packages in the workspace.
180173
wsPkgs, err := snapshot.WorkspacePackages(ctx)
181174
if s.shouldIgnoreError(ctx, snapshot, err) {
182-
return false
175+
return
176+
}
177+
// Even if packages didn't fail to load, we still may want to show
178+
// additional warnings.
179+
if err == nil {
180+
if msg := shouldShowAdHocPackagesWarning(snapshot, wsPkgs); msg != "" {
181+
err = fmt.Errorf(msg)
182+
}
183183
}
184184

185185
// Even if workspace packages were returned, there still may be an error
@@ -198,16 +198,15 @@ func (s *Server) diagnose(ctx context.Context, snapshot source.Snapshot, forceAn
198198
// error progress reports will be closed.
199199
s.showCriticalErrorStatus(ctx, snapshot, err)
200200

201-
if err != nil {
202-
event.Error(ctx, "errors diagnosing workspace", err, tag.Snapshot.Of(snapshot.ID()), tag.Directory.Of(snapshot.View().Folder()))
203-
return false
201+
// If there are no workspace packages, there is nothing to diagnose and
202+
// there are no orphaned files.
203+
if len(wsPkgs) == 0 {
204+
return
204205
}
205206

206207
var (
207-
wg sync.WaitGroup
208-
shouldShowMsgMu sync.Mutex
209-
shouldShowMsg bool
210-
seen = map[span.URI]struct{}{}
208+
wg sync.WaitGroup
209+
seen = map[span.URI]struct{}{}
211210
)
212211
for _, pkg := range wsPkgs {
213212
wg.Add(1)
@@ -219,33 +218,26 @@ func (s *Server) diagnose(ctx context.Context, snapshot source.Snapshot, forceAn
219218
go func(pkg source.Package) {
220219
defer wg.Done()
221220

222-
show := s.diagnosePkg(ctx, snapshot, pkg, forceAnalysis)
223-
if show {
224-
shouldShowMsgMu.Lock()
225-
shouldShowMsg = true
226-
shouldShowMsgMu.Unlock()
227-
}
221+
s.diagnosePkg(ctx, snapshot, pkg, forceAnalysis)
228222
}(pkg)
229223
}
230224
wg.Wait()
225+
231226
// Confirm that every opened file belongs to a package (if any exist in
232227
// the workspace). Otherwise, add a diagnostic to the file.
233-
if len(wsPkgs) > 0 {
234-
for _, o := range s.session.Overlays() {
235-
if _, ok := seen[o.URI()]; ok {
236-
continue
237-
}
238-
diagnostic := s.checkForOrphanedFile(ctx, snapshot, o)
239-
if diagnostic == nil {
240-
continue
241-
}
242-
s.storeDiagnostics(snapshot, o.URI(), orphanedSource, []*source.Diagnostic{diagnostic})
228+
for _, o := range s.session.Overlays() {
229+
if _, ok := seen[o.URI()]; ok {
230+
continue
243231
}
232+
diagnostic := s.checkForOrphanedFile(ctx, snapshot, o)
233+
if diagnostic == nil {
234+
continue
235+
}
236+
s.storeDiagnostics(snapshot, o.URI(), orphanedSource, []*source.Diagnostic{diagnostic})
244237
}
245-
return shouldShowMsg
246238
}
247239

248-
func (s *Server) diagnosePkg(ctx context.Context, snapshot source.Snapshot, pkg source.Package, alwaysAnalyze bool) bool {
240+
func (s *Server) diagnosePkg(ctx context.Context, snapshot source.Snapshot, pkg source.Package, alwaysAnalyze bool) {
249241
includeAnalysis := alwaysAnalyze // only run analyses for packages with open files
250242
var gcDetailsDir span.URI // find the package's optimization details, if available
251243
for _, pgf := range pkg.CompiledGoFiles() {
@@ -271,7 +263,7 @@ func (s *Server) diagnosePkg(ctx context.Context, snapshot source.Snapshot, pkg
271263
reports, err := source.Analyze(ctx, snapshot, pkg, typeCheckResults)
272264
if err != nil {
273265
event.Error(ctx, "warning: diagnose package", err, tag.Snapshot.Of(snapshot.ID()), tag.Package.Of(pkg.ID()))
274-
return false
266+
return
275267
}
276268
for uri, diags := range reports {
277269
s.storeDiagnostics(snapshot, uri, analysisSource, diags)
@@ -294,7 +286,6 @@ func (s *Server) diagnosePkg(ctx context.Context, snapshot source.Snapshot, pkg
294286
s.storeDiagnostics(snapshot, id.URI, gcDetailsSource, diags)
295287
}
296288
}
297-
return shouldWarn(snapshot, pkg)
298289
}
299290

300291
// storeDiagnostics stores results from a single diagnostic source. If merge is
@@ -329,21 +320,6 @@ func (s *Server) storeDiagnostics(snapshot source.Snapshot, uri span.URI, dsourc
329320
s.diagnostics[uri].reports[dsource] = report
330321
}
331322

332-
// shouldWarn reports whether we should warn the user about their build
333-
// configuration.
334-
func shouldWarn(snapshot source.Snapshot, pkg source.Package) bool {
335-
if snapshot.ValidBuildConfiguration() {
336-
return false
337-
}
338-
if len(pkg.MissingDependencies()) > 0 {
339-
return true
340-
}
341-
if len(pkg.CompiledGoFiles()) == 1 && hasUndeclaredErrors(pkg) {
342-
return true // The user likely opened a single file.
343-
}
344-
return false
345-
}
346-
347323
// clearDiagnosticSource clears all diagnostics for a given source type. It is
348324
// necessary for cases where diagnostics have been invalidated by something
349325
// other than a snapshot change, for example when gc_details is toggled.
@@ -355,22 +331,24 @@ func (s *Server) clearDiagnosticSource(dsource diagnosticSource) {
355331
}
356332
}
357333

358-
// hasUndeclaredErrors returns true if a package has a type error
359-
// about an undeclared symbol.
360-
//
361-
// TODO(findleyr): switch to using error codes in 1.16
362-
func hasUndeclaredErrors(pkg source.Package) bool {
363-
for _, err := range pkg.GetErrors() {
364-
if err.Kind != source.TypeError {
365-
continue
366-
}
367-
if strings.Contains(err.Message, "undeclared name:") {
368-
return true
334+
const adHocPackagesWarning = `You are outside of a module and outside of $GOPATH/src.
335+
If you are using modules, please open your editor to a directory in your module.
336+
If you believe this warning is incorrect, please file an issue: https://github.com/golang/go/issues/new.`
337+
338+
func shouldShowAdHocPackagesWarning(snapshot source.Snapshot, pkgs []source.Package) string {
339+
if snapshot.ValidBuildConfiguration() {
340+
return ""
341+
}
342+
for _, pkg := range pkgs {
343+
if len(pkg.MissingDependencies()) > 0 {
344+
return adHocPackagesWarning
369345
}
370346
}
371-
return false
347+
return ""
372348
}
373349

350+
const WorkspaceLoadFailure = "Error loading workspace"
351+
374352
// showCriticalErrorStatus shows the error as a progress report.
375353
// If the error is nil, it clears any existing error progress report.
376354
func (s *Server) showCriticalErrorStatus(ctx context.Context, snapshot source.Snapshot, err error) {
@@ -381,21 +359,18 @@ func (s *Server) showCriticalErrorStatus(ctx context.Context, snapshot source.Sn
381359
// status bar.
382360
var errMsg string
383361
if err != nil {
384-
// Some error messages can also be displayed as diagnostics. But don't
385-
// show source.ErrorLists as critical errors--only CriticalErrors
386-
// should be shown.
362+
event.Error(ctx, "errors loading workspace", err, tag.Snapshot.Of(snapshot.ID()), tag.Directory.Of(snapshot.View().Folder()))
363+
364+
// Some error messages can also be displayed as diagnostics.
387365
if criticalErr := (*source.CriticalError)(nil); errors.As(err, &criticalErr) {
388366
s.storeErrorDiagnostics(ctx, snapshot, typeCheckSource, criticalErr.ErrorList)
389-
} else if srcErrList := (source.ErrorList)(nil); errors.As(err, &srcErrList) {
390-
s.storeErrorDiagnostics(ctx, snapshot, typeCheckSource, srcErrList)
391-
return
392367
}
393368
errMsg = strings.Replace(err.Error(), "\n", " ", -1)
394369
}
395370

396371
if s.criticalErrorStatus == nil {
397372
if errMsg != "" {
398-
s.criticalErrorStatus = s.progress.start(ctx, "Error loading workspace", errMsg, nil, nil)
373+
s.criticalErrorStatus = s.progress.start(ctx, WorkspaceLoadFailure, errMsg, nil, nil)
399374
}
400375
return
401376
}

internal/lsp/mod/diagnostics.go

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,8 +69,6 @@ func ErrorsForMod(ctx context.Context, snapshot source.Snapshot, fh source.FileH
6969
// Some error messages can also be displayed as diagnostics.
7070
if criticalErr := (*source.CriticalError)(nil); errors.As(err, &criticalErr) {
7171
return criticalErr.ErrorList, nil
72-
} else if srcErrList := (source.ErrorList)(nil); errors.As(err, &srcErrList) {
73-
return srcErrList, nil
7472
}
7573
return nil, err
7674
}

internal/lsp/source/view.go

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -556,7 +556,7 @@ type Package interface {
556556

557557
type CriticalError struct {
558558
MainError error
559-
ErrorList
559+
ErrorList []*Error
560560
}
561561

562562
func (err *CriticalError) Error() string {
@@ -566,16 +566,6 @@ func (err *CriticalError) Error() string {
566566
return err.MainError.Error()
567567
}
568568

569-
type ErrorList []*Error
570-
571-
func (err ErrorList) Error() string {
572-
var list []string
573-
for _, e := range err {
574-
list = append(list, e.Error())
575-
}
576-
return strings.Join(list, "\n\t")
577-
}
578-
579569
// An Error corresponds to an LSP Diagnostic.
580570
// https://microsoft.github.io/language-server-protocol/specification#diagnostic
581571
type Error struct {

0 commit comments

Comments
 (0)