github.com/graybobo/golang.org-package-offline-cache@v0.0.0-20200626051047-6608995c132f/x/tools/cmd/godex/print.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 // +build go1.5 6 7 package main 8 9 import ( 10 "bytes" 11 "fmt" 12 "go/token" 13 "io" 14 "math/big" 15 16 "golang.org/x/tools/go/exact" 17 "golang.org/x/tools/go/types" 18 ) 19 20 // TODO(gri) use tabwriter for alignment? 21 22 func print(w io.Writer, pkg *types.Package, filter func(types.Object) bool) { 23 var p printer 24 p.pkg = pkg 25 p.printPackage(pkg, filter) 26 p.printGccgoExtra(pkg) 27 io.Copy(w, &p.buf) 28 } 29 30 type printer struct { 31 pkg *types.Package 32 buf bytes.Buffer 33 indent int // current indentation level 34 last byte // last byte written 35 } 36 37 func (p *printer) print(s string) { 38 // Write the string one byte at a time. We care about the presence of 39 // newlines for indentation which we will see even in the presence of 40 // (non-corrupted) Unicode; no need to read one rune at a time. 41 for i := 0; i < len(s); i++ { 42 ch := s[i] 43 if ch != '\n' && p.last == '\n' { 44 // Note: This could lead to a range overflow for very large 45 // indentations, but it's extremely unlikely to happen for 46 // non-pathological code. 47 p.buf.WriteString("\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t"[:p.indent]) 48 } 49 p.buf.WriteByte(ch) 50 p.last = ch 51 } 52 } 53 54 func (p *printer) printf(format string, args ...interface{}) { 55 p.print(fmt.Sprintf(format, args...)) 56 } 57 58 // methodsFor returns the named type and corresponding methods if the type 59 // denoted by obj is not an interface and has methods. Otherwise it returns 60 // the zero value. 61 func methodsFor(obj *types.TypeName) (*types.Named, []*types.Selection) { 62 named, _ := obj.Type().(*types.Named) 63 if named == nil { 64 // A type name's type can also be the 65 // exported basic type unsafe.Pointer. 66 return nil, nil 67 } 68 if _, ok := named.Underlying().(*types.Interface); ok { 69 // ignore interfaces 70 return nil, nil 71 } 72 methods := combinedMethodSet(named) 73 if len(methods) == 0 { 74 return nil, nil 75 } 76 return named, methods 77 } 78 79 func (p *printer) printPackage(pkg *types.Package, filter func(types.Object) bool) { 80 // collect objects by kind 81 var ( 82 consts []*types.Const 83 typem []*types.Named // non-interface types with methods 84 typez []*types.TypeName // interfaces or types without methods 85 vars []*types.Var 86 funcs []*types.Func 87 builtins []*types.Builtin 88 methods = make(map[*types.Named][]*types.Selection) // method sets for named types 89 ) 90 scope := pkg.Scope() 91 for _, name := range scope.Names() { 92 obj := scope.Lookup(name) 93 if obj.Exported() { 94 // collect top-level exported and possibly filtered objects 95 if filter == nil || filter(obj) { 96 switch obj := obj.(type) { 97 case *types.Const: 98 consts = append(consts, obj) 99 case *types.TypeName: 100 // group into types with methods and types without 101 if named, m := methodsFor(obj); named != nil { 102 typem = append(typem, named) 103 methods[named] = m 104 } else { 105 typez = append(typez, obj) 106 } 107 case *types.Var: 108 vars = append(vars, obj) 109 case *types.Func: 110 funcs = append(funcs, obj) 111 case *types.Builtin: 112 // for unsafe.Sizeof, etc. 113 builtins = append(builtins, obj) 114 } 115 } 116 } else if filter == nil { 117 // no filtering: collect top-level unexported types with methods 118 if obj, _ := obj.(*types.TypeName); obj != nil { 119 // see case *types.TypeName above 120 if named, m := methodsFor(obj); named != nil { 121 typem = append(typem, named) 122 methods[named] = m 123 } 124 } 125 } 126 } 127 128 p.printf("package %s // %q\n", pkg.Name(), pkg.Path()) 129 130 p.printDecl("const", len(consts), func() { 131 for _, obj := range consts { 132 p.printObj(obj) 133 p.print("\n") 134 } 135 }) 136 137 p.printDecl("var", len(vars), func() { 138 for _, obj := range vars { 139 p.printObj(obj) 140 p.print("\n") 141 } 142 }) 143 144 p.printDecl("type", len(typez), func() { 145 for _, obj := range typez { 146 p.printf("%s ", obj.Name()) 147 p.writeType(p.pkg, obj.Type().Underlying()) 148 p.print("\n") 149 } 150 }) 151 152 // non-interface types with methods 153 for _, named := range typem { 154 first := true 155 if obj := named.Obj(); obj.Exported() { 156 if first { 157 p.print("\n") 158 first = false 159 } 160 p.printf("type %s ", obj.Name()) 161 p.writeType(p.pkg, named.Underlying()) 162 p.print("\n") 163 } 164 for _, m := range methods[named] { 165 if obj := m.Obj(); obj.Exported() { 166 if first { 167 p.print("\n") 168 first = false 169 } 170 p.printFunc(m.Recv(), obj.(*types.Func)) 171 p.print("\n") 172 } 173 } 174 } 175 176 if len(funcs) > 0 { 177 p.print("\n") 178 for _, obj := range funcs { 179 p.printFunc(nil, obj) 180 p.print("\n") 181 } 182 } 183 184 // TODO(gri) better handling of builtins (package unsafe only) 185 if len(builtins) > 0 { 186 p.print("\n") 187 for _, obj := range builtins { 188 p.printf("func %s() // builtin\n", obj.Name()) 189 } 190 } 191 192 p.print("\n") 193 } 194 195 func (p *printer) printDecl(keyword string, n int, printGroup func()) { 196 switch n { 197 case 0: 198 // nothing to do 199 case 1: 200 p.printf("\n%s ", keyword) 201 printGroup() 202 default: 203 p.printf("\n%s (\n", keyword) 204 p.indent++ 205 printGroup() 206 p.indent-- 207 p.print(")\n") 208 } 209 } 210 211 // absInt returns the absolute value of v as a *big.Int. 212 // v must be a numeric value. 213 func absInt(v exact.Value) *big.Int { 214 // compute big-endian representation of v 215 b := exact.Bytes(v) // little-endian 216 for i, j := 0, len(b)-1; i < j; i, j = i+1, j-1 { 217 b[i], b[j] = b[j], b[i] 218 } 219 return new(big.Int).SetBytes(b) 220 } 221 222 var ( 223 one = big.NewRat(1, 1) 224 ten = big.NewRat(10, 1) 225 ) 226 227 // floatString returns the string representation for a 228 // numeric value v in normalized floating-point format. 229 func floatString(v exact.Value) string { 230 if exact.Sign(v) == 0 { 231 return "0.0" 232 } 233 // x != 0 234 235 // convert |v| into a big.Rat x 236 x := new(big.Rat).SetFrac(absInt(exact.Num(v)), absInt(exact.Denom(v))) 237 238 // normalize x and determine exponent e 239 // (This is not very efficient, but also not speed-critical.) 240 var e int 241 for x.Cmp(ten) >= 0 { 242 x.Quo(x, ten) 243 e++ 244 } 245 for x.Cmp(one) < 0 { 246 x.Mul(x, ten) 247 e-- 248 } 249 250 // TODO(gri) Values such as 1/2 are easier to read in form 0.5 251 // rather than 5.0e-1. Similarly, 1.0e1 is easier to read as 252 // 10.0. Fine-tune best exponent range for readability. 253 254 s := x.FloatString(100) // good-enough precision 255 256 // trim trailing 0's 257 i := len(s) 258 for i > 0 && s[i-1] == '0' { 259 i-- 260 } 261 s = s[:i] 262 263 // add a 0 if the number ends in decimal point 264 if len(s) > 0 && s[len(s)-1] == '.' { 265 s += "0" 266 } 267 268 // add exponent and sign 269 if e != 0 { 270 s += fmt.Sprintf("e%+d", e) 271 } 272 if exact.Sign(v) < 0 { 273 s = "-" + s 274 } 275 276 // TODO(gri) If v is a "small" fraction (i.e., numerator and denominator 277 // are just a small number of decimal digits), add the exact fraction as 278 // a comment. For instance: 3.3333...e-1 /* = 1/3 */ 279 280 return s 281 } 282 283 // valString returns the string representation for the value v. 284 // Setting floatFmt forces an integer value to be formatted in 285 // normalized floating-point format. 286 // TODO(gri) Move this code into package exact. 287 func valString(v exact.Value, floatFmt bool) string { 288 switch v.Kind() { 289 case exact.Int: 290 if floatFmt { 291 return floatString(v) 292 } 293 case exact.Float: 294 return floatString(v) 295 case exact.Complex: 296 re := exact.Real(v) 297 im := exact.Imag(v) 298 var s string 299 if exact.Sign(re) != 0 { 300 s = floatString(re) 301 if exact.Sign(im) >= 0 { 302 s += " + " 303 } else { 304 s += " - " 305 im = exact.UnaryOp(token.SUB, im, 0) // negate im 306 } 307 } 308 // im != 0, otherwise v would be exact.Int or exact.Float 309 return s + floatString(im) + "i" 310 } 311 return v.String() 312 } 313 314 func (p *printer) printObj(obj types.Object) { 315 p.print(obj.Name()) 316 317 typ, basic := obj.Type().Underlying().(*types.Basic) 318 if basic && typ.Info()&types.IsUntyped != 0 { 319 // don't write untyped types 320 } else { 321 p.print(" ") 322 p.writeType(p.pkg, obj.Type()) 323 } 324 325 if obj, ok := obj.(*types.Const); ok { 326 floatFmt := basic && typ.Info()&(types.IsFloat|types.IsComplex) != 0 327 p.print(" = ") 328 p.print(valString(obj.Val(), floatFmt)) 329 } 330 } 331 332 func (p *printer) printFunc(recvType types.Type, obj *types.Func) { 333 p.print("func ") 334 sig := obj.Type().(*types.Signature) 335 if recvType != nil { 336 p.print("(") 337 p.writeType(p.pkg, recvType) 338 p.print(") ") 339 } 340 p.print(obj.Name()) 341 p.writeSignature(p.pkg, sig) 342 } 343 344 // combinedMethodSet returns the method set for a named type T 345 // merged with all the methods of *T that have different names than 346 // the methods of T. 347 // 348 // combinedMethodSet is analogous to types/typeutil.IntuitiveMethodSet 349 // but doesn't require a MethodSetCache. 350 // TODO(gri) If this functionality doesn't change over time, consider 351 // just calling IntuitiveMethodSet eventually. 352 func combinedMethodSet(T *types.Named) []*types.Selection { 353 // method set for T 354 mset := types.NewMethodSet(T) 355 var res []*types.Selection 356 for i, n := 0, mset.Len(); i < n; i++ { 357 res = append(res, mset.At(i)) 358 } 359 360 // add all *T methods with names different from T methods 361 pmset := types.NewMethodSet(types.NewPointer(T)) 362 for i, n := 0, pmset.Len(); i < n; i++ { 363 pm := pmset.At(i) 364 if obj := pm.Obj(); mset.Lookup(obj.Pkg(), obj.Name()) == nil { 365 res = append(res, pm) 366 } 367 } 368 369 return res 370 }