aboutsummaryrefslogtreecommitdiff
path: root/gopls/internal/lsp/protocol/generate/typenames.go
diff options
context:
space:
mode:
authorDan Willemsen <dwillemsen@google.com>2023-03-15 13:19:36 -0400
committerDan Willemsen <dwillemsen@google.com>2023-03-15 14:18:08 -0400
commit09c5a32afc5b66f28f166a68afe1fc71afbf9b73 (patch)
tree194d7b0e539d014393564a256bec571e18d6533a /gopls/internal/lsp/protocol/generate/typenames.go
parentf10932f763d058b0dcb3acfb795c869996fef47b (diff)
parent031fc75960d487b0b15db12fb328676236a3a39c (diff)
downloadgolang-x-tools-09c5a32afc5b66f28f166a68afe1fc71afbf9b73.tar.gz
Upgrade golang-x-tools to v0.7.0HEADmastermain
Not using external_updater this time to switch to the new upstream tags. Test: treehugger Change-Id: I31488b4958a366ed7f183bb387d3e1446acc13ae
Diffstat (limited to 'gopls/internal/lsp/protocol/generate/typenames.go')
-rw-r--r--gopls/internal/lsp/protocol/generate/typenames.go184
1 files changed, 184 insertions, 0 deletions
diff --git a/gopls/internal/lsp/protocol/generate/typenames.go b/gopls/internal/lsp/protocol/generate/typenames.go
new file mode 100644
index 000000000..8bacdd2a1
--- /dev/null
+++ b/gopls/internal/lsp/protocol/generate/typenames.go
@@ -0,0 +1,184 @@
+// Copyright 2022 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.
+
+//go:build go1.19
+// +build go1.19
+
+package main
+
+import (
+ "fmt"
+ "log"
+ "strings"
+)
+
+var typeNames = make(map[*Type]string)
+var genTypes []*newType
+
+func findTypeNames(model Model) {
+ for _, s := range model.Structures {
+ for _, e := range s.Extends {
+ nameType(e, nil) // all references
+ }
+ for _, m := range s.Mixins {
+ nameType(m, nil) // all references
+ }
+ for _, p := range s.Properties {
+ nameType(p.Type, []string{s.Name, p.Name})
+ }
+ }
+ for _, t := range model.Enumerations {
+ nameType(t.Type, []string{t.Name})
+ }
+ for _, t := range model.TypeAliases {
+ nameType(t.Type, []string{t.Name})
+ }
+ for _, r := range model.Requests {
+ nameType(r.Params, []string{"Param", r.Method})
+ nameType(r.Result, []string{"Result", r.Method})
+ nameType(r.RegistrationOptions, []string{"RegOpt", r.Method})
+ }
+ for _, n := range model.Notifications {
+ nameType(n.Params, []string{"Param", n.Method})
+ nameType(n.RegistrationOptions, []string{"RegOpt", n.Method})
+ }
+}
+
+// nameType populates typeNames[t] with the computed name of the type.
+// path is the list of enclosing constructs in the JSON model.
+func nameType(t *Type, path []string) string {
+ if t == nil || typeNames[t] != "" {
+ return ""
+ }
+ switch t.Kind {
+ case "base":
+ typeNames[t] = t.Name
+ return t.Name
+ case "reference":
+ typeNames[t] = t.Name
+ return t.Name
+ case "array":
+ nm := "[]" + nameType(t.Element, append(path, "Elem"))
+ typeNames[t] = nm
+ return nm
+ case "map":
+ key := nameType(t.Key, nil) // never a generated type
+ value := nameType(t.Value.(*Type), append(path, "Value"))
+ nm := "map[" + key + "]" + value
+ typeNames[t] = nm
+ return nm
+ // generated types
+ case "and":
+ nm := nameFromPath("And", path)
+ typeNames[t] = nm
+ for _, it := range t.Items {
+ nameType(it, append(path, "Item"))
+ }
+ genTypes = append(genTypes, &newType{
+ name: nm,
+ typ: t,
+ kind: "and",
+ items: t.Items,
+ line: t.Line,
+ })
+ return nm
+ case "literal":
+ nm := nameFromPath("Lit", path)
+ typeNames[t] = nm
+ for _, p := range t.Value.(ParseLiteral).Properties {
+ nameType(p.Type, append(path, p.Name))
+ }
+ genTypes = append(genTypes, &newType{
+ name: nm,
+ typ: t,
+ kind: "literal",
+ properties: t.Value.(ParseLiteral).Properties,
+ line: t.Line,
+ })
+ return nm
+ case "tuple":
+ nm := nameFromPath("Tuple", path)
+ typeNames[t] = nm
+ for _, it := range t.Items {
+ nameType(it, append(path, "Item"))
+ }
+ genTypes = append(genTypes, &newType{
+ name: nm,
+ typ: t,
+ kind: "tuple",
+ items: t.Items,
+ line: t.Line,
+ })
+ return nm
+ case "or":
+ nm := nameFromPath("Or", path)
+ typeNames[t] = nm
+ for i, it := range t.Items {
+ // these names depend on the ordering within the "or" type
+ nameType(it, append(path, fmt.Sprintf("Item%d", i)))
+ }
+ // this code handles an "or" of stringLiterals (_InitializeParams.trace)
+ names := make(map[string]int)
+ msg := ""
+ for _, it := range t.Items {
+ if line, ok := names[typeNames[it]]; ok {
+ // duplicate component names are bad
+ msg += fmt.Sprintf("lines %d %d dup, %s for %s\n", line, it.Line, typeNames[it], nm)
+ }
+ names[typeNames[it]] = t.Line
+ }
+ // this code handles an "or" of stringLiterals (_InitializeParams.trace)
+ if len(names) == 1 {
+ var solekey string
+ for k := range names {
+ solekey = k // the sole name
+ }
+ if solekey == "string" { // _InitializeParams.trace
+ typeNames[t] = "string"
+ return "string"
+ }
+ // otherwise unexpected
+ log.Printf("unexpected: single-case 'or' type has non-string key %s: %s", nm, solekey)
+ log.Fatal(msg)
+ } else if len(names) == 2 {
+ // if one of the names is null, just use the other, rather than generating an "or".
+ // This removes about 40 types from the generated code. An entry in goplsStar
+ // could be added to handle the null case, if necessary.
+ newNm := ""
+ sawNull := false
+ for k := range names {
+ if k == "null" {
+ sawNull = true
+ } else {
+ newNm = k
+ }
+ }
+ if sawNull {
+ typeNames[t] = newNm
+ return newNm
+ }
+ }
+ genTypes = append(genTypes, &newType{
+ name: nm,
+ typ: t,
+ kind: "or",
+ items: t.Items,
+ line: t.Line,
+ })
+ return nm
+ case "stringLiteral": // a single type, like 'kind' or 'rename'
+ typeNames[t] = "string"
+ return "string"
+ default:
+ log.Fatalf("nameType: %T unexpected, line:%d path:%v", t, t.Line, path)
+ panic("unreachable in nameType")
+ }
+}
+
+func nameFromPath(prefix string, path []string) string {
+ nm := prefix + "_" + strings.Join(path, "_")
+ // methods have slashes
+ nm = strings.ReplaceAll(nm, "/", "_")
+ return nm
+}