golang.org/x/tools@v0.21.0/cmd/godex/writetype.go (about) 1 // Copyright 2014 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 // This file implements writing of types. The functionality is lifted 6 // directly from go/types, but now contains various modifications for 7 // nicer output. 8 // 9 // TODO(gri) back-port once we have a fixed interface and once the 10 // go/types API is not frozen anymore for the 1.3 release; and remove 11 // this implementation if possible. 12 13 package main 14 15 import ( 16 "go/types" 17 18 "golang.org/x/tools/internal/aliases" 19 ) 20 21 func (p *printer) writeType(this *types.Package, typ types.Type) { 22 p.writeTypeInternal(this, typ, make([]types.Type, 8)) 23 } 24 25 // From go/types - leave for now to ease back-porting this code. 26 const GcCompatibilityMode = false 27 28 func (p *printer) writeTypeInternal(this *types.Package, typ types.Type, visited []types.Type) { 29 // Theoretically, this is a quadratic lookup algorithm, but in 30 // practice deeply nested composite types with unnamed component 31 // types are uncommon. This code is likely more efficient than 32 // using a map. 33 for _, t := range visited { 34 if t == typ { 35 p.printf("○%T", typ) // cycle to typ 36 return 37 } 38 } 39 visited = append(visited, typ) 40 41 switch t := typ.(type) { 42 case nil: 43 p.print("<nil>") 44 45 case *types.Basic: 46 if t.Kind() == types.UnsafePointer { 47 p.print("unsafe.") 48 } 49 if GcCompatibilityMode { 50 // forget the alias names 51 switch t.Kind() { 52 case types.Byte: 53 t = types.Typ[types.Uint8] 54 case types.Rune: 55 t = types.Typ[types.Int32] 56 } 57 } 58 p.print(t.Name()) 59 60 case *types.Array: 61 p.printf("[%d]", t.Len()) 62 p.writeTypeInternal(this, t.Elem(), visited) 63 64 case *types.Slice: 65 p.print("[]") 66 p.writeTypeInternal(this, t.Elem(), visited) 67 68 case *types.Struct: 69 n := t.NumFields() 70 if n == 0 { 71 p.print("struct{}") 72 return 73 } 74 75 p.print("struct {\n") 76 p.indent++ 77 for i := 0; i < n; i++ { 78 f := t.Field(i) 79 if !f.Anonymous() { 80 p.printf("%s ", f.Name()) 81 } 82 p.writeTypeInternal(this, f.Type(), visited) 83 if tag := t.Tag(i); tag != "" { 84 p.printf(" %q", tag) 85 } 86 p.print("\n") 87 } 88 p.indent-- 89 p.print("}") 90 91 case *types.Pointer: 92 p.print("*") 93 p.writeTypeInternal(this, t.Elem(), visited) 94 95 case *types.Tuple: 96 p.writeTuple(this, t, false, visited) 97 98 case *types.Signature: 99 p.print("func") 100 p.writeSignatureInternal(this, t, visited) 101 102 case *types.Interface: 103 // We write the source-level methods and embedded types rather 104 // than the actual method set since resolved method signatures 105 // may have non-printable cycles if parameters have anonymous 106 // interface types that (directly or indirectly) embed the 107 // current interface. For instance, consider the result type 108 // of m: 109 // 110 // type T interface{ 111 // m() interface{ T } 112 // } 113 // 114 n := t.NumMethods() 115 if n == 0 { 116 p.print("interface{}") 117 return 118 } 119 120 p.print("interface {\n") 121 p.indent++ 122 if GcCompatibilityMode { 123 // print flattened interface 124 // (useful to compare against gc-generated interfaces) 125 for i := 0; i < n; i++ { 126 m := t.Method(i) 127 p.print(m.Name()) 128 p.writeSignatureInternal(this, m.Type().(*types.Signature), visited) 129 p.print("\n") 130 } 131 } else { 132 // print explicit interface methods and embedded types 133 for i, n := 0, t.NumExplicitMethods(); i < n; i++ { 134 m := t.ExplicitMethod(i) 135 p.print(m.Name()) 136 p.writeSignatureInternal(this, m.Type().(*types.Signature), visited) 137 p.print("\n") 138 } 139 for i, n := 0, t.NumEmbeddeds(); i < n; i++ { 140 typ := t.EmbeddedType(i) 141 p.writeTypeInternal(this, typ, visited) 142 p.print("\n") 143 } 144 } 145 p.indent-- 146 p.print("}") 147 148 case *types.Map: 149 p.print("map[") 150 p.writeTypeInternal(this, t.Key(), visited) 151 p.print("]") 152 p.writeTypeInternal(this, t.Elem(), visited) 153 154 case *types.Chan: 155 var s string 156 var parens bool 157 switch t.Dir() { 158 case types.SendRecv: 159 s = "chan " 160 // chan (<-chan T) requires parentheses 161 if c, _ := t.Elem().(*types.Chan); c != nil && c.Dir() == types.RecvOnly { 162 parens = true 163 } 164 case types.SendOnly: 165 s = "chan<- " 166 case types.RecvOnly: 167 s = "<-chan " 168 default: 169 panic("unreachable") 170 } 171 p.print(s) 172 if parens { 173 p.print("(") 174 } 175 p.writeTypeInternal(this, t.Elem(), visited) 176 if parens { 177 p.print(")") 178 } 179 180 case *aliases.Alias: 181 // TODO(adonovan): display something aliasy. 182 p.writeTypeInternal(this, aliases.Unalias(t), visited) 183 184 case *types.Named: 185 s := "<Named w/o object>" 186 if obj := t.Obj(); obj != nil { 187 if pkg := obj.Pkg(); pkg != nil { 188 if pkg != this { 189 p.print(pkg.Path()) 190 p.print(".") 191 } 192 // TODO(gri): function-local named types should be displayed 193 // differently from named types at package level to avoid 194 // ambiguity. 195 } 196 s = obj.Name() 197 } 198 p.print(s) 199 200 default: 201 // For externally defined implementations of Type. 202 p.print(t.String()) 203 } 204 } 205 206 func (p *printer) writeTuple(this *types.Package, tup *types.Tuple, variadic bool, visited []types.Type) { 207 p.print("(") 208 for i, n := 0, tup.Len(); i < n; i++ { 209 if i > 0 { 210 p.print(", ") 211 } 212 v := tup.At(i) 213 if name := v.Name(); name != "" { 214 p.print(name) 215 p.print(" ") 216 } 217 typ := v.Type() 218 if variadic && i == n-1 { 219 p.print("...") 220 typ = typ.(*types.Slice).Elem() 221 } 222 p.writeTypeInternal(this, typ, visited) 223 } 224 p.print(")") 225 } 226 227 func (p *printer) writeSignature(this *types.Package, sig *types.Signature) { 228 p.writeSignatureInternal(this, sig, make([]types.Type, 8)) 229 } 230 231 func (p *printer) writeSignatureInternal(this *types.Package, sig *types.Signature, visited []types.Type) { 232 p.writeTuple(this, sig.Params(), sig.Variadic(), visited) 233 234 res := sig.Results() 235 n := res.Len() 236 if n == 0 { 237 // no result 238 return 239 } 240 241 p.print(" ") 242 if n == 1 && res.At(0).Name() == "" { 243 // single unnamed result 244 p.writeTypeInternal(this, res.At(0).Type(), visited) 245 return 246 } 247 248 // multiple or named result(s) 249 p.writeTuple(this, res, false, visited) 250 }