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  }