aboutsummaryrefslogtreecommitdiff
path: root/internal/lsp/source/diagnostics.go
blob: e393c2f9426b613b1210096b0fe3bc0e65bf4dc8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package source

import (
	"context"

	"golang.org/x/tools/internal/lsp/protocol"
	"golang.org/x/tools/internal/span"
)

type SuggestedFix struct {
	Title      string
	Edits      map[span.URI][]protocol.TextEdit
	Command    *protocol.Command
	ActionKind protocol.CodeActionKind
}

type RelatedInformation struct {
	URI     span.URI
	Range   protocol.Range
	Message string
}

func Analyze(ctx context.Context, snapshot Snapshot, pkg Package, includeConvenience bool) (map[span.URI][]*Diagnostic, error) {
	// Exit early if the context has been canceled. This also protects us
	// from a race on Options, see golang/go#36699.
	if ctx.Err() != nil {
		return nil, ctx.Err()
	}

	categories := []map[string]*Analyzer{}
	if includeConvenience {
		categories = append(categories, snapshot.View().Options().ConvenienceAnalyzers)
	}
	// If we had type errors, don't run any other analyzers.
	if !pkg.HasTypeErrors() {
		categories = append(categories, snapshot.View().Options().DefaultAnalyzers, snapshot.View().Options().StaticcheckAnalyzers)
	}
	var analyzers []*Analyzer
	for _, cat := range categories {
		for _, a := range cat {
			analyzers = append(analyzers, a)
		}
	}

	analysisDiagnostics, err := snapshot.Analyze(ctx, pkg.ID(), analyzers)
	if err != nil {
		return nil, err
	}

	reports := map[span.URI][]*Diagnostic{}
	// Report diagnostics and errors from root analyzers.
	for _, diag := range analysisDiagnostics {
		reports[diag.URI] = append(reports[diag.URI], diag)
	}
	return reports, nil
}

func FileDiagnostics(ctx context.Context, snapshot Snapshot, uri span.URI) (VersionedFileIdentity, []*Diagnostic, error) {
	fh, err := snapshot.GetVersionedFile(ctx, uri)
	if err != nil {
		return VersionedFileIdentity{}, nil, err
	}
	pkg, _, err := GetParsedFile(ctx, snapshot, fh, NarrowestPackage)
	if err != nil {
		return VersionedFileIdentity{}, nil, err
	}
	diagnostics, err := snapshot.DiagnosePackage(ctx, pkg)
	if err != nil {
		return VersionedFileIdentity{}, nil, err
	}
	fileDiags := diagnostics[fh.URI()]
	if !pkg.HasListOrParseErrors() {
		analysisDiags, err := Analyze(ctx, snapshot, pkg, false)
		if err != nil {
			return VersionedFileIdentity{}, nil, err
		}
		fileDiags = append(fileDiags, analysisDiags[fh.URI()]...)
	}
	return fh.VersionedFileIdentity(), fileDiags, nil
}