Giant blob of minor changes
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / golang.org / x / tools@v0.0.0-20201105173854-bc9fc8d8c4bc / internal / lsp / helper / helper.go
1 // Invoke with //go:generate helper/helper -t Server -d protocol/tsserver.go -u lsp -o server_gen.go
2 // invoke in internal/lsp
3 package main
4
5 import (
6         "bytes"
7         "flag"
8         "fmt"
9         "go/ast"
10         "go/format"
11         "go/parser"
12         "go/token"
13         "log"
14         "os"
15         "sort"
16         "strings"
17         "text/template"
18 )
19
20 var (
21         typ = flag.String("t", "Server", "generate code for this type")
22         def = flag.String("d", "", "the file the type is defined in") // this relies on punning
23         use = flag.String("u", "", "look for uses in this package")
24         out = flag.String("o", "", "where to write the generated file")
25 )
26
27 func main() {
28         log.SetFlags(log.Lshortfile)
29         flag.Parse()
30         if *typ == "" || *def == "" || *use == "" || *out == "" {
31                 flag.PrintDefaults()
32                 return
33         }
34         // read the type definition and see what methods we're looking for
35         doTypes()
36
37         // parse the package and see which methods are defined
38         doUses()
39
40         output()
41 }
42
43 // replace "\\\n" with nothing before using
44 var tmpl = `
45 package lsp
46
47 // code generated by helper. DO NOT EDIT.
48
49 import (
50         "context"
51
52         "golang.org/x/tools/internal/lsp/protocol"
53 )
54
55 {{range $key, $v := .Stuff}}
56 func (s *{{$.Type}}) {{$v.Name}}({{.Param}}) {{.Result}} {
57         {{if ne .Found ""}} return s.{{.Internal}}({{.Invoke}})\
58         {{else}}return {{if lt 1 (len .Results)}}nil, {{end}}notImplemented("{{.Name}}"){{end}}
59 }
60 {{end}}
61 `
62
63 func output() {
64         // put in empty param names as needed
65         for _, t := range types {
66                 if t.paramnames == nil {
67                         t.paramnames = make([]string, len(t.paramtypes))
68                 }
69                 for i, p := range t.paramtypes {
70                         cm := ""
71                         if i > 0 {
72                                 cm = ", "
73                         }
74                         t.Param += fmt.Sprintf("%s%s %s", cm, t.paramnames[i], p)
75                         this := t.paramnames[i]
76                         if this == "_" {
77                                 this = "nil"
78                         }
79                         t.Invoke += fmt.Sprintf("%s%s", cm, this)
80                 }
81                 if len(t.Results) > 1 {
82                         t.Result = "("
83                 }
84                 for i, r := range t.Results {
85                         cm := ""
86                         if i > 0 {
87                                 cm = ", "
88                         }
89                         t.Result += fmt.Sprintf("%s%s", cm, r)
90                 }
91                 if len(t.Results) > 1 {
92                         t.Result += ")"
93                 }
94         }
95
96         fd, err := os.Create(*out)
97         if err != nil {
98                 log.Fatal(err)
99         }
100         t, err := template.New("foo").Parse(tmpl)
101         if err != nil {
102                 log.Fatal(err)
103         }
104         type par struct {
105                 Type  string
106                 Stuff []*Function
107         }
108         p := par{*typ, types}
109         if false { // debugging the template
110                 t.Execute(os.Stderr, &p)
111         }
112         buf := bytes.NewBuffer(nil)
113         err = t.Execute(buf, &p)
114         if err != nil {
115                 log.Fatal(err)
116         }
117         ans, err := format.Source(bytes.Replace(buf.Bytes(), []byte("\\\n"), []byte{}, -1))
118         if err != nil {
119                 log.Fatal(err)
120         }
121         fd.Write(ans)
122 }
123
124 func doUses() {
125         fset := token.NewFileSet()
126         pkgs, err := parser.ParseDir(fset, *use, nil, 0)
127         if err != nil {
128                 log.Fatalf("%q:%v", *use, err)
129         }
130         pkg := pkgs["lsp"] // CHECK
131         files := pkg.Files
132         for fname, f := range files {
133                 for _, d := range f.Decls {
134                         fd, ok := d.(*ast.FuncDecl)
135                         if !ok {
136                                 continue
137                         }
138                         nm := fd.Name.String()
139                         if ast.IsExported(nm) {
140                                 // we're looking for things like didChange
141                                 continue
142                         }
143                         if fx, ok := byname[nm]; ok {
144                                 if fx.Found != "" {
145                                         log.Fatalf("found %s in %s and %s", fx.Internal, fx.Found, fname)
146                                 }
147                                 fx.Found = fname
148                                 // and the Paramnames
149                                 ft := fd.Type
150                                 for _, f := range ft.Params.List {
151                                         nm := ""
152                                         if len(f.Names) > 0 {
153                                                 nm = f.Names[0].String()
154                                         }
155                                         fx.paramnames = append(fx.paramnames, nm)
156                                 }
157                         }
158                 }
159         }
160         if false {
161                 for i, f := range types {
162                         log.Printf("%d %s %s", i, f.Internal, f.Found)
163                 }
164         }
165 }
166
167 type Function struct {
168         Name       string
169         Internal   string // first letter lower case
170         paramtypes []string
171         paramnames []string
172         Results    []string
173         Param      string
174         Result     string // do it in code, easier than in a template
175         Invoke     string
176         Found      string // file it was found in
177 }
178
179 var types []*Function
180 var byname = map[string]*Function{} // internal names
181
182 func doTypes() {
183         fset := token.NewFileSet()
184         f, err := parser.ParseFile(fset, *def, nil, 0)
185         if err != nil {
186                 log.Fatal(err)
187         }
188         fd, err := os.Create("/tmp/ast")
189         if err != nil {
190                 log.Fatal(err)
191         }
192         ast.Fprint(fd, fset, f, ast.NotNilFilter)
193         ast.Inspect(f, inter)
194         sort.Slice(types, func(i, j int) bool { return types[i].Name < types[j].Name })
195         if false {
196                 for i, f := range types {
197                         log.Printf("%d %s(%v) %v", i, f.Name, f.paramtypes, f.Results)
198                 }
199         }
200 }
201
202 func inter(n ast.Node) bool {
203         x, ok := n.(*ast.TypeSpec)
204         if !ok || x.Name.Name != *typ {
205                 return true
206         }
207         m := x.Type.(*ast.InterfaceType).Methods.List
208         for _, fld := range m {
209                 fn := fld.Type.(*ast.FuncType)
210                 p := fn.Params.List
211                 r := fn.Results.List
212                 fx := &Function{
213                         Name: fld.Names[0].String(),
214                 }
215                 fx.Internal = strings.ToLower(fx.Name[:1]) + fx.Name[1:]
216                 for _, f := range p {
217                         fx.paramtypes = append(fx.paramtypes, whatis(f.Type))
218                 }
219                 for _, f := range r {
220                         fx.Results = append(fx.Results, whatis(f.Type))
221                 }
222                 types = append(types, fx)
223                 byname[fx.Internal] = fx
224         }
225         return false
226 }
227
228 func whatis(x ast.Expr) string {
229         switch n := x.(type) {
230         case *ast.SelectorExpr:
231                 return whatis(n.X) + "." + n.Sel.String()
232         case *ast.StarExpr:
233                 return "*" + whatis(n.X)
234         case *ast.Ident:
235                 if ast.IsExported(n.Name) {
236                         // these are from package protocol
237                         return "protocol." + n.Name
238                 }
239                 return n.Name
240         case *ast.ArrayType:
241                 return "[]" + whatis(n.Elt)
242         case *ast.InterfaceType:
243                 return "interface{}"
244         default:
245                 log.Fatalf("Fatal %T", x)
246                 return fmt.Sprintf("%T", x)
247         }
248 }