github.com/april1989/origin-go-tools@v0.0.32/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  package main
     6  
     7  import (
     8  	"bytes"
     9  	"fmt"
    10  	"go/constant"
    11  	"go/token"
    12  	"go/types"
    13  	"io"
    14  	"math/big"
    15  )
    16  
    17  // TODO(gri) use tabwriter for alignment?
    18  
    19  func print(w io.Writer, pkg *types.Package, filter func(types.Object) bool) {
    20  	var p printer
    21  	p.pkg = pkg
    22  	p.printPackage(pkg, filter)
    23  	p.printGccgoExtra(pkg)
    24  	io.Copy(w, &p.buf)
    25  }
    26  
    27  type printer struct {
    28  	pkg    *types.Package
    29  	buf    bytes.Buffer
    30  	indent int  // current indentation level
    31  	last   byte // last byte written
    32  }
    33  
    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++ {
    39  		ch := 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])
    45  		}
    46  		p.buf.WriteByte(ch)
    47  		p.last = ch
    48  	}
    49  }
    50  
    51  func (p *printer) printf(format string, args ...interface{}) {
    52  	p.print(fmt.Sprintf(format, args...))
    53  }
    54  
    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
    57  // the zero value.
    58  func methodsFor(obj *types.TypeName) (*types.Named, []*types.Selection) {
    59  	named, _ := obj.Type().(*types.Named)
    60  	if named == nil {
    61  		// A type name's type can also be the
    62  		// exported basic type unsafe.Pointer.
    63  		return nil, nil
    64  	}
    65  	if _, ok := named.Underlying().(*types.Interface); ok {
    66  		// ignore interfaces
    67  		return nil, nil
    68  	}
    69  	methods := combinedMethodSet(named)
    70  	if len(methods) == 0 {
    71  		return nil, nil
    72  	}
    73  	return named, methods
    74  }
    75  
    76  func (p *printer) printPackage(pkg *types.Package, filter func(types.Object) bool) {
    77  	// collect objects by kind
    78  	var (
    79  		consts   []*types.Const
    80  		typem    []*types.Named    // non-interface types with methods
    81  		typez    []*types.TypeName // interfaces or types without methods
    82  		vars     []*types.Var
    83  		funcs    []*types.Func
    84  		builtins []*types.Builtin
    85  		methods  = make(map[*types.Named][]*types.Selection) // method sets for named types
    86  	)
    87  	scope := pkg.Scope()
    88  	for _, name := range scope.Names() {
    89  		obj := scope.Lookup(name)
    90  		if obj.Exported() {
    91  			// collect top-level exported and possibly filtered objects
    92  			if filter == nil || filter(obj) {
    93  				switch obj := obj.(type) {
    94  				case *types.Const:
    95  					consts = append(consts, obj)
    96  				case *types.TypeName:
    97  					// group into types with methods and types without
    98  					if named, m := methodsFor(obj); named != nil {
    99  						typem = append(typem, named)
   100  						methods[named] = m
   101  					} else {
   102  						typez = append(typez, obj)
   103  					}
   104  				case *types.Var:
   105  					vars = append(vars, obj)
   106  				case *types.Func:
   107  					funcs = append(funcs, obj)
   108  				case *types.Builtin:
   109  					// for unsafe.Sizeof, etc.
   110  					builtins = append(builtins, obj)
   111  				}
   112  			}
   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)
   119  					methods[named] = m
   120  				}
   121  			}
   122  		}
   123  	}
   124  
   125  	p.printf("package %s  // %q\n", pkg.Name(), pkg.Path())
   126  
   127  	p.printDecl("const", len(consts), func() {
   128  		for _, obj := range consts {
   129  			p.printObj(obj)
   130  			p.print("\n")
   131  		}
   132  	})
   133  
   134  	p.printDecl("var", len(vars), func() {
   135  		for _, obj := range vars {
   136  			p.printObj(obj)
   137  			p.print("\n")
   138  		}
   139  	})
   140  
   141  	p.printDecl("type", len(typez), func() {
   142  		for _, obj := range typez {
   143  			p.printf("%s ", obj.Name())
   144  			typ := obj.Type()
   145  			if isAlias(obj) {
   146  				p.print("= ")
   147  				p.writeType(p.pkg, typ)
   148  			} else {
   149  				p.writeType(p.pkg, typ.Underlying())
   150  			}
   151  			p.print("\n")
   152  		}
   153  	})
   154  
   155  	// non-interface types with methods
   156  	for _, named := range typem {
   157  		first := true
   158  		if obj := named.Obj(); obj.Exported() {
   159  			if first {
   160  				p.print("\n")
   161  				first = false
   162  			}
   163  			p.printf("type %s ", obj.Name())
   164  			p.writeType(p.pkg, named.Underlying())
   165  			p.print("\n")
   166  		}
   167  		for _, m := range methods[named] {
   168  			if obj := m.Obj(); obj.Exported() {
   169  				if first {
   170  					p.print("\n")
   171  					first = false
   172  				}
   173  				p.printFunc(m.Recv(), obj.(*types.Func))
   174  				p.print("\n")
   175  			}
   176  		}
   177  	}
   178  
   179  	if len(funcs) > 0 {
   180  		p.print("\n")
   181  		for _, obj := range funcs {
   182  			p.printFunc(nil, obj)
   183  			p.print("\n")
   184  		}
   185  	}
   186  
   187  	// TODO(gri) better handling of builtins (package unsafe only)
   188  	if len(builtins) > 0 {
   189  		p.print("\n")
   190  		for _, obj := range builtins {
   191  			p.printf("func %s() // builtin\n", obj.Name())
   192  		}
   193  	}
   194  
   195  	p.print("\n")
   196  }
   197  
   198  func (p *printer) printDecl(keyword string, n int, printGroup func()) {
   199  	switch n {
   200  	case 0:
   201  		// nothing to do
   202  	case 1:
   203  		p.printf("\n%s ", keyword)
   204  		printGroup()
   205  	default:
   206  		p.printf("\n%s (\n", keyword)
   207  		p.indent++
   208  		printGroup()
   209  		p.indent--
   210  		p.print(")\n")
   211  	}
   212  }
   213  
   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]
   221  	}
   222  	return new(big.Int).SetBytes(b)
   223  }
   224  
   225  var (
   226  	one = big.NewRat(1, 1)
   227  	ten = big.NewRat(10, 1)
   228  )
   229  
   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 {
   234  		return "0.0"
   235  	}
   236  	// x != 0
   237  
   238  	// convert |v| into a big.Rat x
   239  	x := new(big.Rat).SetFrac(absInt(constant.Num(v)), absInt(constant.Denom(v)))
   240  
   241  	// normalize x and determine exponent e
   242  	// (This is not very efficient, but also not speed-critical.)
   243  	var e int
   244  	for x.Cmp(ten) >= 0 {
   245  		x.Quo(x, ten)
   246  		e++
   247  	}
   248  	for x.Cmp(one) < 0 {
   249  		x.Mul(x, ten)
   250  		e--
   251  	}
   252  
   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.
   256  
   257  	s := x.FloatString(100) // good-enough precision
   258  
   259  	// trim trailing 0's
   260  	i := len(s)
   261  	for i > 0 && s[i-1] == '0' {
   262  		i--
   263  	}
   264  	s = s[:i]
   265  
   266  	// add a 0 if the number ends in decimal point
   267  	if len(s) > 0 && s[len(s)-1] == '.' {
   268  		s += "0"
   269  	}
   270  
   271  	// add exponent and sign
   272  	if e != 0 {
   273  		s += fmt.Sprintf("e%+d", e)
   274  	}
   275  	if constant.Sign(v) < 0 {
   276  		s = "-" + s
   277  	}
   278  
   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 */
   282  
   283  	return s
   284  }
   285  
   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 {
   291  	switch v.Kind() {
   292  	case constant.Int:
   293  		if floatFmt {
   294  			return floatString(v)
   295  		}
   296  	case constant.Float:
   297  		return floatString(v)
   298  	case constant.Complex:
   299  		re := constant.Real(v)
   300  		im := constant.Imag(v)
   301  		var s string
   302  		if constant.Sign(re) != 0 {
   303  			s = floatString(re)
   304  			if constant.Sign(im) >= 0 {
   305  				s += " + "
   306  			} else {
   307  				s += " - "
   308  				im = constant.UnaryOp(token.SUB, im, 0) // negate im
   309  			}
   310  		}
   311  		// im != 0, otherwise v would be constant.Int or constant.Float
   312  		return s + floatString(im) + "i"
   313  	}
   314  	return v.String()
   315  }
   316  
   317  func (p *printer) printObj(obj types.Object) {
   318  	p.print(obj.Name())
   319  
   320  	typ, basic := obj.Type().Underlying().(*types.Basic)
   321  	if basic && typ.Info()&types.IsUntyped != 0 {
   322  		// don't write untyped types
   323  	} else {
   324  		p.print(" ")
   325  		p.writeType(p.pkg, obj.Type())
   326  	}
   327  
   328  	if obj, ok := obj.(*types.Const); ok {
   329  		floatFmt := basic && typ.Info()&(types.IsFloat|types.IsComplex) != 0
   330  		p.print(" = ")
   331  		p.print(valString(obj.Val(), floatFmt))
   332  	}
   333  }
   334  
   335  func (p *printer) printFunc(recvType types.Type, obj *types.Func) {
   336  	p.print("func ")
   337  	sig := obj.Type().(*types.Signature)
   338  	if recvType != nil {
   339  		p.print("(")
   340  		p.writeType(p.pkg, recvType)
   341  		p.print(") ")
   342  	}
   343  	p.print(obj.Name())
   344  	p.writeSignature(p.pkg, sig)
   345  }
   346  
   347  // combinedMethodSet returns the method set for a named type T
   348  // merged with all the methods of *T that have different names than
   349  // the methods of T.
   350  //
   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 {
   356  	// method set for T
   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))
   361  	}
   362  
   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++ {
   366  		pm := pmset.At(i)
   367  		if obj := pm.Obj(); mset.Lookup(obj.Pkg(), obj.Name()) == nil {
   368  			res = append(res, pm)
   369  		}
   370  	}
   371  
   372  	return res
   373  }