1
2
3
4
5 package driverutil
6
7
8
9 import (
10 "cmp"
11 "encoding/json"
12 "fmt"
13 "go/token"
14 "io"
15 "log"
16 "os"
17 "strings"
18
19 "golang.org/x/tools/go/analysis"
20 )
21
22
23
24
25
26
27
28 func PrintPlain(out io.Writer, fset *token.FileSet, contextLines int, diag analysis.Diagnostic) {
29 print := func(pos, end token.Pos, message string) {
30 posn := fset.Position(pos)
31 fmt.Fprintf(out, "%s: %s\n", posn, message)
32
33
34 if contextLines >= 0 {
35 end := fset.Position(end)
36 if !end.IsValid() {
37 end = posn
38 }
39
40
41 data, _ := os.ReadFile(posn.Filename)
42 lines := strings.Split(string(data), "\n")
43 for i := posn.Line - contextLines; i <= end.Line+contextLines; i++ {
44 if 1 <= i && i <= len(lines) {
45 fmt.Fprintf(out, "%d\t%s\n", i, lines[i-1])
46 }
47 }
48 }
49 }
50
51 print(diag.Pos, diag.End, diag.Message)
52 for _, rel := range diag.Related {
53 print(rel.Pos, rel.End, "\t"+rel.Message)
54 }
55 }
56
57
58
59 type JSONTree map[string]map[string]any
60
61
62
63
64 type JSONTextEdit struct {
65 Filename string `json:"filename"`
66 Start int `json:"start"`
67 End int `json:"end"`
68 New string `json:"new"`
69 }
70
71
72
73
74 type JSONSuggestedFix struct {
75 Message string `json:"message"`
76 Edits []JSONTextEdit `json:"edits"`
77 }
78
79
80 type JSONDiagnostic struct {
81 Category string `json:"category,omitempty"`
82 Posn string `json:"posn"`
83 End string `json:"end"`
84 Message string `json:"message"`
85 SuggestedFixes []JSONSuggestedFix `json:"suggested_fixes,omitempty"`
86 Related []JSONRelatedInformation `json:"related,omitempty"`
87 }
88
89
90
91 type JSONRelatedInformation struct {
92 Posn string `json:"posn"`
93 End string `json:"end"`
94 Message string `json:"message"`
95 }
96
97
98
99 func (tree JSONTree) Add(fset *token.FileSet, id, name string, diags []analysis.Diagnostic, err error) {
100 var v any
101 if err != nil {
102 type jsonError struct {
103 Err string `json:"error"`
104 }
105 v = jsonError{err.Error()}
106 } else if len(diags) > 0 {
107 diagnostics := make([]JSONDiagnostic, 0, len(diags))
108 for _, f := range diags {
109 var fixes []JSONSuggestedFix
110 for _, fix := range f.SuggestedFixes {
111 var edits []JSONTextEdit
112 for _, edit := range fix.TextEdits {
113 edits = append(edits, JSONTextEdit{
114 Filename: fset.Position(edit.Pos).Filename,
115 Start: fset.Position(edit.Pos).Offset,
116 End: fset.Position(edit.End).Offset,
117 New: string(edit.NewText),
118 })
119 }
120 fixes = append(fixes, JSONSuggestedFix{
121 Message: fix.Message,
122 Edits: edits,
123 })
124 }
125 var related []JSONRelatedInformation
126 for _, r := range f.Related {
127 related = append(related, JSONRelatedInformation{
128 Posn: fset.Position(r.Pos).String(),
129 End: fset.Position(cmp.Or(r.End, r.Pos)).String(),
130 Message: r.Message,
131 })
132 }
133 jdiag := JSONDiagnostic{
134 Category: f.Category,
135 Posn: fset.Position(f.Pos).String(),
136 End: fset.Position(cmp.Or(f.End, f.Pos)).String(),
137 Message: f.Message,
138 SuggestedFixes: fixes,
139 Related: related,
140 }
141 diagnostics = append(diagnostics, jdiag)
142 }
143 v = diagnostics
144 }
145 if v != nil {
146 m, ok := tree[id]
147 if !ok {
148 m = make(map[string]any)
149 tree[id] = m
150 }
151 m[name] = v
152 }
153 }
154
155 func (tree JSONTree) Print(out io.Writer) error {
156 data, err := json.MarshalIndent(tree, "", "\t")
157 if err != nil {
158 log.Panicf("internal error: JSON marshaling failed: %v", err)
159 }
160 _, err = fmt.Fprintf(out, "%s\n", data)
161 return err
162 }
163
View as plain text