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