Skip to content

Commit 0f1c539

Browse files
committed
internal/lsp: show orphaned file warnings as diagnostics
Show message warnings are annoying to users. Instead, show a diagnostic for orphaned files. Right now, it will always be there (instead of on first open). Not sure if users will find this annoying or helpful. Fixes golang/go#31668 Change-Id: I5051072b00fee9018d447585fdd9cdfe9df7107a Reviewed-on: https://go-review.googlesource.com/c/tools/+/256977 Trust: Rebecca Stambler <[email protected]> Run-TryBot: Rebecca Stambler <[email protected]> Reviewed-by: Robert Findley <[email protected]> TryBot-Result: Go Bot <[email protected]> gopls-CI: kokoro <[email protected]>
1 parent 7b6ac5b commit 0f1c539

File tree

3 files changed

+69
-77
lines changed

3 files changed

+69
-77
lines changed

gopls/internal/regtest/diagnostics_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1348,7 +1348,7 @@ func _() {
13481348
)
13491349
env.OpenFile("a/a_ignore.go")
13501350
env.Await(
1351-
ShownMessage("No packages found for open file"),
1351+
DiagnosticAt("a/a_ignore.go", 2, 8),
13521352
)
13531353
})
13541354
}

internal/lsp/diagnostics.go

Lines changed: 68 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,20 @@ func (s *Server) diagnose(ctx context.Context, snapshot source.Snapshot, alwaysA
6565

6666
var reportsMu sync.Mutex
6767
reports := map[idWithAnalysis]map[string]*source.Diagnostic{}
68+
addReport := func(id source.VersionedFileIdentity, withAnalysis bool, diags []*source.Diagnostic) {
69+
reportsMu.Lock()
70+
defer reportsMu.Unlock()
71+
key := idWithAnalysis{
72+
id: id,
73+
withAnalysis: withAnalysis,
74+
}
75+
if _, ok := reports[key]; !ok {
76+
reports[key] = map[string]*source.Diagnostic{}
77+
}
78+
for _, d := range diags {
79+
reports[key][diagnosticKey(d)] = d
80+
}
81+
}
6882

6983
// First, diagnose the go.mod file.
7084
modReports, modErr := mod.Diagnostics(ctx, snapshot)
@@ -79,16 +93,7 @@ func (s *Server) diagnose(ctx context.Context, snapshot source.Snapshot, alwaysA
7993
event.Error(ctx, "missing URI for module diagnostics", fmt.Errorf("empty URI"), tag.Directory.Of(snapshot.View().Folder().Filename()))
8094
continue
8195
}
82-
key := idWithAnalysis{
83-
id: id,
84-
withAnalysis: true, // treat go.mod diagnostics like analyses
85-
}
86-
if _, ok := reports[key]; !ok {
87-
reports[key] = map[string]*source.Diagnostic{}
88-
}
89-
for _, d := range diags {
90-
reports[key][diagnosticKey(d)] = d
91-
}
96+
addReport(id, true, diags) // treat go.mod diagnostics like analyses
9297
}
9398

9499
// Diagnose all of the packages in the workspace.
@@ -166,18 +171,8 @@ If you believe this is a mistake, please file an issue: https://github.com/golan
166171
}
167172

168173
// Add all reports to the global map, checking for duplicates.
169-
reportsMu.Lock()
170174
for id, diags := range pkgReports {
171-
key := idWithAnalysis{
172-
id: id,
173-
withAnalysis: withAnalysis,
174-
}
175-
if _, ok := reports[key]; !ok {
176-
reports[key] = map[string]*source.Diagnostic{}
177-
}
178-
for _, d := range diags {
179-
reports[key][diagnosticKey(d)] = d
180-
}
175+
addReport(id, withAnalysis, diags)
181176
}
182177
// If gc optimization details are available, add them to the
183178
// diagnostic reports.
@@ -187,25 +182,66 @@ If you believe this is a mistake, please file an issue: https://github.com/golan
187182
event.Error(ctx, "warning: gc details", err, tag.Snapshot.Of(snapshot.ID()))
188183
}
189184
for id, diags := range gcReports {
190-
key := idWithAnalysis{
191-
id: id,
192-
withAnalysis: withAnalysis,
193-
}
194-
if _, ok := reports[key]; !ok {
195-
reports[key] = map[string]*source.Diagnostic{}
196-
}
197-
for _, d := range diags {
198-
reports[key][diagnosticKey(d)] = d
199-
}
185+
addReport(id, withAnalysis, diags)
200186
}
201187
}
202-
reportsMu.Unlock()
203188
}(pkg)
204189
}
190+
// Confirm that every opened file belongs to a package (if any exist in
191+
// the workspace). Otherwise, add a diagnostic to the file.
192+
if len(wsPkgs) > 0 {
193+
for _, o := range s.session.Overlays() {
194+
diagnostic := s.checkForOrphanedFile(ctx, snapshot, o.URI())
195+
if diagnostic == nil {
196+
continue
197+
}
198+
// Lock the reports map, since the per-package goroutines may
199+
// not have completed yet.
200+
addReport(o.VersionedFileIdentity(), true, []*source.Diagnostic{diagnostic})
201+
}
202+
}
205203
wg.Wait()
206204
return reports, showMsg
207205
}
208206

207+
// checkForOrphanedFile checks that the given URIs can be mapped to packages.
208+
// If they cannot and the workspace is not otherwise unloaded, it also surfaces
209+
// a warning, suggesting that the user check the file for build tags.
210+
func (s *Server) checkForOrphanedFile(ctx context.Context, snapshot source.Snapshot, uri span.URI) *source.Diagnostic {
211+
fh, err := snapshot.GetFile(ctx, uri)
212+
if err != nil || fh.Kind() != source.Go {
213+
return nil
214+
}
215+
pkgs, err := snapshot.PackagesForFile(ctx, uri, source.TypecheckWorkspace)
216+
if len(pkgs) > 0 || err == nil {
217+
return nil
218+
}
219+
pgf, err := snapshot.ParseGo(ctx, fh, source.ParseHeader)
220+
if err != nil {
221+
return nil
222+
}
223+
spn, err := span.NewRange(snapshot.FileSet(), pgf.File.Name.Pos(), pgf.File.Name.End()).Span()
224+
if err != nil {
225+
return nil
226+
}
227+
rng, err := pgf.Mapper.Range(spn)
228+
if err != nil {
229+
return nil
230+
}
231+
// TODO(rstambler): We should be able to parse the build tags in the
232+
// file and show a more specific error message. For now, put the diagnostic
233+
// on the package declaration.
234+
return &source.Diagnostic{
235+
Range: rng,
236+
Message: fmt.Sprintf(`No packages found for open file %s: %v.
237+
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).
238+
Otherwise, see the troubleshooting guidelines for help investigating (https://github.com/golang/tools/blob/master/gopls/doc/troubleshooting.md).
239+
`, uri.Filename(), err),
240+
Severity: protocol.SeverityWarning,
241+
Source: "compiler",
242+
}
243+
}
244+
209245
// diagnosticKey creates a unique identifier for a given diagnostic, since we
210246
// cannot use source.Diagnostics as map keys. This is used to de-duplicate
211247
// diagnostics.

internal/lsp/text_synchronization.go

Lines changed: 0 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,7 @@ import (
1111
"path/filepath"
1212
"sync"
1313

14-
"golang.org/x/tools/internal/event"
1514
"golang.org/x/tools/internal/jsonrpc2"
16-
"golang.org/x/tools/internal/lsp/debug/tag"
1715
"golang.org/x/tools/internal/lsp/protocol"
1816
"golang.org/x/tools/internal/lsp/source"
1917
"golang.org/x/tools/internal/span"
@@ -282,13 +280,6 @@ func (s *Server) didModifyFiles(ctx context.Context, modifications []source.File
282280
go func(snapshot source.Snapshot, uris []span.URI) {
283281
defer diagnosticWG.Done()
284282
s.diagnoseSnapshot(snapshot)
285-
286-
// If files have been newly opened, check if we found packages for
287-
// them. If not, notify this user that the file may be excluded
288-
// because of build tags.
289-
if cause == FromDidOpen {
290-
s.checkForOrphanedFile(ctx, snapshot, uris)
291-
}
292283
}(snapshot, uris)
293284
}
294285

@@ -313,41 +304,6 @@ func DiagnosticWorkTitle(cause ModificationSource) string {
313304
return fmt.Sprintf("diagnosing %v", cause)
314305
}
315306

316-
// checkForOrphanedFile checks that the given URIs can be mapped to packages.
317-
// If they cannot and the workspace is not otherwise unloaded, it also surfaces
318-
// a warning, suggesting that the user check the file for build tags.
319-
func (s *Server) checkForOrphanedFile(ctx context.Context, snapshot source.Snapshot, uris []span.URI) {
320-
// Only show the error message if we have packages in the workspace,
321-
// but no package for the file.
322-
if pkgs, err := snapshot.WorkspacePackages(ctx); err != nil || len(pkgs) == 0 {
323-
return
324-
}
325-
for _, uri := range uris {
326-
fh, err := snapshot.GetFile(ctx, uri)
327-
if err != nil {
328-
continue
329-
}
330-
if fh.Kind() != source.Go {
331-
continue
332-
}
333-
pkgs, err := snapshot.PackagesForFile(ctx, uri, source.TypecheckWorkspace)
334-
if len(pkgs) > 0 || err == nil {
335-
return
336-
}
337-
// TODO(rstambler): We should be able to parse the build tags in the
338-
// file and show a more specific error message.
339-
if err := s.client.ShowMessage(ctx, &protocol.ShowMessageParams{
340-
Type: protocol.Error,
341-
Message: fmt.Sprintf(`No packages found for open file %s: %v.
342-
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).
343-
Otherwise, see the troubleshooting guidelines for help investigating (https://github.com/golang/tools/blob/master/gopls/doc/troubleshooting.md).
344-
`, uri.Filename(), err),
345-
}); err != nil {
346-
event.Error(ctx, "warnAboutBuildTags: failed to show message", err, tag.URI.Of(uri))
347-
}
348-
}
349-
}
350-
351307
func (s *Server) wasFirstChange(uri span.URI) bool {
352308
s.changedFilesMu.Lock()
353309
defer s.changedFilesMu.Unlock()

0 commit comments

Comments
 (0)