gitee.com/wgliang/goreporter@v0.0.0-20180902115603-df1b20f7c5d0/linters/simpler/ssa/const.go (about)

     1  // Copyright 2013 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.6
     6  
     7  package ssa
     8  
     9  // This file defines the Const SSA value type.
    10  
    11  import (
    12  	"fmt"
    13  	exact "go/constant"
    14  	"go/token"
    15  	"go/types"
    16  	"strconv"
    17  )
    18  
    19  // NewConst returns a new constant of the specified value and type.
    20  // val must be valid according to the specification of Const.Value.
    21  //
    22  func NewConst(val exact.Value, typ types.Type) *Const {
    23  	return &Const{typ, val}
    24  }
    25  
    26  // intConst returns an 'int' constant that evaluates to i.
    27  // (i is an int64 in case the host is narrower than the target.)
    28  func intConst(i int64) *Const {
    29  	return NewConst(exact.MakeInt64(i), tInt)
    30  }
    31  
    32  // nilConst returns a nil constant of the specified type, which may
    33  // be any reference type, including interfaces.
    34  //
    35  func nilConst(typ types.Type) *Const {
    36  	return NewConst(nil, typ)
    37  }
    38  
    39  // stringConst returns a 'string' constant that evaluates to s.
    40  func stringConst(s string) *Const {
    41  	return NewConst(exact.MakeString(s), tString)
    42  }
    43  
    44  // zeroConst returns a new "zero" constant of the specified type,
    45  // which must not be an array or struct type: the zero values of
    46  // aggregates are well-defined but cannot be represented by Const.
    47  //
    48  func zeroConst(t types.Type) *Const {
    49  	switch t := t.(type) {
    50  	case *types.Basic:
    51  		switch {
    52  		case t.Info()&types.IsBoolean != 0:
    53  			return NewConst(exact.MakeBool(false), t)
    54  		case t.Info()&types.IsNumeric != 0:
    55  			return NewConst(exact.MakeInt64(0), t)
    56  		case t.Info()&types.IsString != 0:
    57  			return NewConst(exact.MakeString(""), t)
    58  		case t.Kind() == types.UnsafePointer:
    59  			fallthrough
    60  		case t.Kind() == types.UntypedNil:
    61  			return nilConst(t)
    62  		default:
    63  			panic(fmt.Sprint("zeroConst for unexpected type:", t))
    64  		}
    65  	case *types.Pointer, *types.Slice, *types.Interface, *types.Chan, *types.Map, *types.Signature:
    66  		return nilConst(t)
    67  	case *types.Named:
    68  		return NewConst(zeroConst(t.Underlying()).Value, t)
    69  	case *types.Array, *types.Struct, *types.Tuple:
    70  		panic(fmt.Sprint("zeroConst applied to aggregate:", t))
    71  	}
    72  	panic(fmt.Sprint("zeroConst: unexpected ", t))
    73  }
    74  
    75  func (c *Const) RelString(from *types.Package) string {
    76  	var s string
    77  	if c.Value == nil {
    78  		s = "nil"
    79  	} else if c.Value.Kind() == exact.String {
    80  		s = exact.StringVal(c.Value)
    81  		const max = 20
    82  		// TODO(adonovan): don't cut a rune in half.
    83  		if len(s) > max {
    84  			s = s[:max-3] + "..." // abbreviate
    85  		}
    86  		s = strconv.Quote(s)
    87  	} else {
    88  		s = c.Value.String()
    89  	}
    90  	return s + ":" + relType(c.Type(), from)
    91  }
    92  
    93  func (c *Const) Name() string {
    94  	return c.RelString(nil)
    95  }
    96  
    97  func (c *Const) String() string {
    98  	return c.Name()
    99  }
   100  
   101  func (c *Const) Type() types.Type {
   102  	return c.typ
   103  }
   104  
   105  func (c *Const) Referrers() *[]Instruction {
   106  	return nil
   107  }
   108  
   109  func (c *Const) Parent() *Function { return nil }
   110  
   111  func (c *Const) Pos() token.Pos {
   112  	return token.NoPos
   113  }
   114  
   115  // IsNil returns true if this constant represents a typed or untyped nil value.
   116  func (c *Const) IsNil() bool {
   117  	return c.Value == nil
   118  }
   119  
   120  // TODO(adonovan): move everything below into github.com/360EntSecGroup-Skylar/goreporter/linters/simpler/ssa/interp.
   121  
   122  // Int64 returns the numeric value of this constant truncated to fit
   123  // a signed 64-bit integer.
   124  //
   125  func (c *Const) Int64() int64 {
   126  	switch x := exact.ToInt(c.Value); x.Kind() {
   127  	case exact.Int:
   128  		if i, ok := exact.Int64Val(x); ok {
   129  			return i
   130  		}
   131  		return 0
   132  	case exact.Float:
   133  		f, _ := exact.Float64Val(x)
   134  		return int64(f)
   135  	}
   136  	panic(fmt.Sprintf("unexpected constant value: %T", c.Value))
   137  }
   138  
   139  // Uint64 returns the numeric value of this constant truncated to fit
   140  // an unsigned 64-bit integer.
   141  //
   142  func (c *Const) Uint64() uint64 {
   143  	switch x := exact.ToInt(c.Value); x.Kind() {
   144  	case exact.Int:
   145  		if u, ok := exact.Uint64Val(x); ok {
   146  			return u
   147  		}
   148  		return 0
   149  	case exact.Float:
   150  		f, _ := exact.Float64Val(x)
   151  		return uint64(f)
   152  	}
   153  	panic(fmt.Sprintf("unexpected constant value: %T", c.Value))
   154  }
   155  
   156  // Float64 returns the numeric value of this constant truncated to fit
   157  // a float64.
   158  //
   159  func (c *Const) Float64() float64 {
   160  	f, _ := exact.Float64Val(c.Value)
   161  	return f
   162  }
   163  
   164  // Complex128 returns the complex value of this constant truncated to
   165  // fit a complex128.
   166  //
   167  func (c *Const) Complex128() complex128 {
   168  	re, _ := exact.Float64Val(exact.Real(c.Value))
   169  	im, _ := exact.Float64Val(exact.Imag(c.Value))
   170  	return complex(re, im)
   171  }