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.
17 // TODO(gri) use tabwriter for alignment?
19 func print(w io.Writer, pkg *types.Package, filter func(types.Object) bool) {
22 p.printPackage(pkg, filter)
23 p.printGccgoExtra(pkg)
30 indent int // current indentation level
31 last byte // last byte written
34 func (p *printer) print(s string) {
35 // Write the string one byte at a time. We care about the presence of
36 // newlines for indentation which we will see even in the presence of
37 // (non-corrupted) Unicode; no need to read one rune at a time.
38 for i := 0; i < len(s); i++ {
40 if ch != '\n' && p.last == '\n' {
41 // Note: This could lead to a range overflow for very large
42 // indentations, but it's extremely unlikely to happen for
43 // non-pathological code.
44 p.buf.WriteString("\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t"[:p.indent])
51 func (p *printer) printf(format string, args ...interface{}) {
52 p.print(fmt.Sprintf(format, args...))
55 // methodsFor returns the named type and corresponding methods if the type
56 // denoted by obj is not an interface and has methods. Otherwise it returns
58 func methodsFor(obj *types.TypeName) (*types.Named, []*types.Selection) {
59 named, _ := obj.Type().(*types.Named)
61 // A type name's type can also be the
62 // exported basic type unsafe.Pointer.
65 if _, ok := named.Underlying().(*types.Interface); ok {
69 methods := combinedMethodSet(named)
70 if len(methods) == 0 {
76 func (p *printer) printPackage(pkg *types.Package, filter func(types.Object) bool) {
77 // collect objects by kind
80 typem []*types.Named // non-interface types with methods
81 typez []*types.TypeName // interfaces or types without methods
84 builtins []*types.Builtin
85 methods = make(map[*types.Named][]*types.Selection) // method sets for named types
88 for _, name := range scope.Names() {
89 obj := scope.Lookup(name)
91 // collect top-level exported and possibly filtered objects
92 if filter == nil || filter(obj) {
93 switch obj := obj.(type) {
95 consts = append(consts, obj)
97 // group into types with methods and types without
98 if named, m := methodsFor(obj); named != nil {
99 typem = append(typem, named)
102 typez = append(typez, obj)
105 vars = append(vars, obj)
107 funcs = append(funcs, obj)
109 // for unsafe.Sizeof, etc.
110 builtins = append(builtins, obj)
113 } else if filter == nil {
114 // no filtering: collect top-level unexported types with methods
115 if obj, _ := obj.(*types.TypeName); obj != nil {
116 // see case *types.TypeName above
117 if named, m := methodsFor(obj); named != nil {
118 typem = append(typem, named)
125 p.printf("package %s // %q\n", pkg.Name(), pkg.Path())
127 p.printDecl("const", len(consts), func() {
128 for _, obj := range consts {
134 p.printDecl("var", len(vars), func() {
135 for _, obj := range vars {
141 p.printDecl("type", len(typez), func() {
142 for _, obj := range typez {
143 p.printf("%s ", obj.Name())
147 p.writeType(p.pkg, typ)
149 p.writeType(p.pkg, typ.Underlying())
155 // non-interface types with methods
156 for _, named := range typem {
158 if obj := named.Obj(); obj.Exported() {
163 p.printf("type %s ", obj.Name())
164 p.writeType(p.pkg, named.Underlying())
167 for _, m := range methods[named] {
168 if obj := m.Obj(); obj.Exported() {
173 p.printFunc(m.Recv(), obj.(*types.Func))
181 for _, obj := range funcs {
182 p.printFunc(nil, obj)
187 // TODO(gri) better handling of builtins (package unsafe only)
188 if len(builtins) > 0 {
190 for _, obj := range builtins {
191 p.printf("func %s() // builtin\n", obj.Name())
198 func (p *printer) printDecl(keyword string, n int, printGroup func()) {
203 p.printf("\n%s ", keyword)
206 p.printf("\n%s (\n", keyword)
214 // absInt returns the absolute value of v as a *big.Int.
215 // v must be a numeric value.
216 func absInt(v constant.Value) *big.Int {
217 // compute big-endian representation of v
218 b := constant.Bytes(v) // little-endian
219 for i, j := 0, len(b)-1; i < j; i, j = i+1, j-1 {
220 b[i], b[j] = b[j], b[i]
222 return new(big.Int).SetBytes(b)
226 one = big.NewRat(1, 1)
227 ten = big.NewRat(10, 1)
230 // floatString returns the string representation for a
231 // numeric value v in normalized floating-point format.
232 func floatString(v constant.Value) string {
233 if constant.Sign(v) == 0 {
238 // convert |v| into a big.Rat x
239 x := new(big.Rat).SetFrac(absInt(constant.Num(v)), absInt(constant.Denom(v)))
241 // normalize x and determine exponent e
242 // (This is not very efficient, but also not speed-critical.)
244 for x.Cmp(ten) >= 0 {
253 // TODO(gri) Values such as 1/2 are easier to read in form 0.5
254 // rather than 5.0e-1. Similarly, 1.0e1 is easier to read as
255 // 10.0. Fine-tune best exponent range for readability.
257 s := x.FloatString(100) // good-enough precision
261 for i > 0 && s[i-1] == '0' {
266 // add a 0 if the number ends in decimal point
267 if len(s) > 0 && s[len(s)-1] == '.' {
271 // add exponent and sign
273 s += fmt.Sprintf("e%+d", e)
275 if constant.Sign(v) < 0 {
279 // TODO(gri) If v is a "small" fraction (i.e., numerator and denominator
280 // are just a small number of decimal digits), add the exact fraction as
281 // a comment. For instance: 3.3333...e-1 /* = 1/3 */
286 // valString returns the string representation for the value v.
287 // Setting floatFmt forces an integer value to be formatted in
288 // normalized floating-point format.
289 // TODO(gri) Move this code into package constant.
290 func valString(v constant.Value, floatFmt bool) string {
294 return floatString(v)
297 return floatString(v)
298 case constant.Complex:
299 re := constant.Real(v)
300 im := constant.Imag(v)
302 if constant.Sign(re) != 0 {
304 if constant.Sign(im) >= 0 {
308 im = constant.UnaryOp(token.SUB, im, 0) // negate im
311 // im != 0, otherwise v would be constant.Int or constant.Float
312 return s + floatString(im) + "i"
317 func (p *printer) printObj(obj types.Object) {
320 typ, basic := obj.Type().Underlying().(*types.Basic)
321 if basic && typ.Info()&types.IsUntyped != 0 {
322 // don't write untyped types
325 p.writeType(p.pkg, obj.Type())
328 if obj, ok := obj.(*types.Const); ok {
329 floatFmt := basic && typ.Info()&(types.IsFloat|types.IsComplex) != 0
331 p.print(valString(obj.Val(), floatFmt))
335 func (p *printer) printFunc(recvType types.Type, obj *types.Func) {
337 sig := obj.Type().(*types.Signature)
340 p.writeType(p.pkg, recvType)
344 p.writeSignature(p.pkg, sig)
347 // combinedMethodSet returns the method set for a named type T
348 // merged with all the methods of *T that have different names than
351 // combinedMethodSet is analogous to types/typeutil.IntuitiveMethodSet
352 // but doesn't require a MethodSetCache.
353 // TODO(gri) If this functionality doesn't change over time, consider
354 // just calling IntuitiveMethodSet eventually.
355 func combinedMethodSet(T *types.Named) []*types.Selection {
357 mset := types.NewMethodSet(T)
358 var res []*types.Selection
359 for i, n := 0, mset.Len(); i < n; i++ {
360 res = append(res, mset.At(i))
363 // add all *T methods with names different from T methods
364 pmset := types.NewMethodSet(types.NewPointer(T))
365 for i, n := 0, pmset.Len(); i < n; i++ {
367 if obj := pm.Obj(); mset.Lookup(obj.Pkg(), obj.Name()) == nil {
368 res = append(res, pm)