github.com/golangci/go-tools@v0.0.0-20190318060251-af6baa5dc196/staticcheck/vrp/slice.go (about)

     1  package vrp
     2  
     3  // TODO(dh): most of the constraints have implementations identical to
     4  // that of strings. Consider reusing them.
     5  
     6  import (
     7  	"fmt"
     8  	"go/types"
     9  
    10  	"github.com/golangci/go-tools/ssa"
    11  )
    12  
    13  type SliceInterval struct {
    14  	Length IntInterval
    15  }
    16  
    17  func (s SliceInterval) Union(other Range) Range {
    18  	i, ok := other.(SliceInterval)
    19  	if !ok {
    20  		i = SliceInterval{EmptyIntInterval}
    21  	}
    22  	if s.Length.Empty() || !s.Length.IsKnown() {
    23  		return i
    24  	}
    25  	if i.Length.Empty() || !i.Length.IsKnown() {
    26  		return s
    27  	}
    28  	return SliceInterval{
    29  		Length: s.Length.Union(i.Length).(IntInterval),
    30  	}
    31  }
    32  func (s SliceInterval) String() string { return s.Length.String() }
    33  func (s SliceInterval) IsKnown() bool  { return s.Length.IsKnown() }
    34  
    35  type SliceAppendConstraint struct {
    36  	aConstraint
    37  	A ssa.Value
    38  	B ssa.Value
    39  }
    40  
    41  type SliceSliceConstraint struct {
    42  	aConstraint
    43  	X     ssa.Value
    44  	Lower ssa.Value
    45  	Upper ssa.Value
    46  }
    47  
    48  type ArraySliceConstraint struct {
    49  	aConstraint
    50  	X     ssa.Value
    51  	Lower ssa.Value
    52  	Upper ssa.Value
    53  }
    54  
    55  type SliceIntersectionConstraint struct {
    56  	aConstraint
    57  	X ssa.Value
    58  	I IntInterval
    59  }
    60  
    61  type SliceLengthConstraint struct {
    62  	aConstraint
    63  	X ssa.Value
    64  }
    65  
    66  type MakeSliceConstraint struct {
    67  	aConstraint
    68  	Size ssa.Value
    69  }
    70  
    71  type SliceIntervalConstraint struct {
    72  	aConstraint
    73  	I IntInterval
    74  }
    75  
    76  func NewSliceAppendConstraint(a, b, y ssa.Value) Constraint {
    77  	return &SliceAppendConstraint{NewConstraint(y), a, b}
    78  }
    79  func NewSliceSliceConstraint(x, lower, upper, y ssa.Value) Constraint {
    80  	return &SliceSliceConstraint{NewConstraint(y), x, lower, upper}
    81  }
    82  func NewArraySliceConstraint(x, lower, upper, y ssa.Value) Constraint {
    83  	return &ArraySliceConstraint{NewConstraint(y), x, lower, upper}
    84  }
    85  func NewSliceIntersectionConstraint(x ssa.Value, i IntInterval, y ssa.Value) Constraint {
    86  	return &SliceIntersectionConstraint{NewConstraint(y), x, i}
    87  }
    88  func NewSliceLengthConstraint(x, y ssa.Value) Constraint {
    89  	return &SliceLengthConstraint{NewConstraint(y), x}
    90  }
    91  func NewMakeSliceConstraint(size, y ssa.Value) Constraint {
    92  	return &MakeSliceConstraint{NewConstraint(y), size}
    93  }
    94  func NewSliceIntervalConstraint(i IntInterval, y ssa.Value) Constraint {
    95  	return &SliceIntervalConstraint{NewConstraint(y), i}
    96  }
    97  
    98  func (c *SliceAppendConstraint) Operands() []ssa.Value { return []ssa.Value{c.A, c.B} }
    99  func (c *SliceSliceConstraint) Operands() []ssa.Value {
   100  	ops := []ssa.Value{c.X}
   101  	if c.Lower != nil {
   102  		ops = append(ops, c.Lower)
   103  	}
   104  	if c.Upper != nil {
   105  		ops = append(ops, c.Upper)
   106  	}
   107  	return ops
   108  }
   109  func (c *ArraySliceConstraint) Operands() []ssa.Value {
   110  	ops := []ssa.Value{c.X}
   111  	if c.Lower != nil {
   112  		ops = append(ops, c.Lower)
   113  	}
   114  	if c.Upper != nil {
   115  		ops = append(ops, c.Upper)
   116  	}
   117  	return ops
   118  }
   119  func (c *SliceIntersectionConstraint) Operands() []ssa.Value { return []ssa.Value{c.X} }
   120  func (c *SliceLengthConstraint) Operands() []ssa.Value       { return []ssa.Value{c.X} }
   121  func (c *MakeSliceConstraint) Operands() []ssa.Value         { return []ssa.Value{c.Size} }
   122  func (s *SliceIntervalConstraint) Operands() []ssa.Value     { return nil }
   123  
   124  func (c *SliceAppendConstraint) String() string {
   125  	return fmt.Sprintf("%s = append(%s, %s)", c.Y().Name(), c.A.Name(), c.B.Name())
   126  }
   127  func (c *SliceSliceConstraint) String() string {
   128  	var lname, uname string
   129  	if c.Lower != nil {
   130  		lname = c.Lower.Name()
   131  	}
   132  	if c.Upper != nil {
   133  		uname = c.Upper.Name()
   134  	}
   135  	return fmt.Sprintf("%s[%s:%s]", c.X.Name(), lname, uname)
   136  }
   137  func (c *ArraySliceConstraint) String() string {
   138  	var lname, uname string
   139  	if c.Lower != nil {
   140  		lname = c.Lower.Name()
   141  	}
   142  	if c.Upper != nil {
   143  		uname = c.Upper.Name()
   144  	}
   145  	return fmt.Sprintf("%s[%s:%s]", c.X.Name(), lname, uname)
   146  }
   147  func (c *SliceIntersectionConstraint) String() string {
   148  	return fmt.Sprintf("%s = %s.%t ⊓ %s", c.Y().Name(), c.X.Name(), c.Y().(*ssa.Sigma).Branch, c.I)
   149  }
   150  func (c *SliceLengthConstraint) String() string {
   151  	return fmt.Sprintf("%s = len(%s)", c.Y().Name(), c.X.Name())
   152  }
   153  func (c *MakeSliceConstraint) String() string {
   154  	return fmt.Sprintf("%s = make(slice, %s)", c.Y().Name(), c.Size.Name())
   155  }
   156  func (c *SliceIntervalConstraint) String() string { return fmt.Sprintf("%s = %s", c.Y().Name(), c.I) }
   157  
   158  func (c *SliceAppendConstraint) Eval(g *Graph) Range {
   159  	l1 := g.Range(c.A).(SliceInterval).Length
   160  	var l2 IntInterval
   161  	switch r := g.Range(c.B).(type) {
   162  	case SliceInterval:
   163  		l2 = r.Length
   164  	case StringInterval:
   165  		l2 = r.Length
   166  	default:
   167  		return SliceInterval{}
   168  	}
   169  	if !l1.IsKnown() || !l2.IsKnown() {
   170  		return SliceInterval{}
   171  	}
   172  	return SliceInterval{
   173  		Length: l1.Add(l2),
   174  	}
   175  }
   176  func (c *SliceSliceConstraint) Eval(g *Graph) Range {
   177  	lr := NewIntInterval(NewZ(0), NewZ(0))
   178  	if c.Lower != nil {
   179  		lr = g.Range(c.Lower).(IntInterval)
   180  	}
   181  	ur := g.Range(c.X).(SliceInterval).Length
   182  	if c.Upper != nil {
   183  		ur = g.Range(c.Upper).(IntInterval)
   184  	}
   185  	if !lr.IsKnown() || !ur.IsKnown() {
   186  		return SliceInterval{}
   187  	}
   188  
   189  	ls := []Z{
   190  		ur.Lower.Sub(lr.Lower),
   191  		ur.Upper.Sub(lr.Lower),
   192  		ur.Lower.Sub(lr.Upper),
   193  		ur.Upper.Sub(lr.Upper),
   194  	}
   195  	// TODO(dh): if we don't truncate lengths to 0 we might be able to
   196  	// easily detect slices with high < low. we'd need to treat -∞
   197  	// specially, though.
   198  	for i, l := range ls {
   199  		if l.Sign() == -1 {
   200  			ls[i] = NewZ(0)
   201  		}
   202  	}
   203  
   204  	return SliceInterval{
   205  		Length: NewIntInterval(MinZ(ls...), MaxZ(ls...)),
   206  	}
   207  }
   208  func (c *ArraySliceConstraint) Eval(g *Graph) Range {
   209  	lr := NewIntInterval(NewZ(0), NewZ(0))
   210  	if c.Lower != nil {
   211  		lr = g.Range(c.Lower).(IntInterval)
   212  	}
   213  	var l int64
   214  	switch typ := c.X.Type().(type) {
   215  	case *types.Array:
   216  		l = typ.Len()
   217  	case *types.Pointer:
   218  		l = typ.Elem().(*types.Array).Len()
   219  	}
   220  	ur := NewIntInterval(NewZ(l), NewZ(l))
   221  	if c.Upper != nil {
   222  		ur = g.Range(c.Upper).(IntInterval)
   223  	}
   224  	if !lr.IsKnown() || !ur.IsKnown() {
   225  		return SliceInterval{}
   226  	}
   227  
   228  	ls := []Z{
   229  		ur.Lower.Sub(lr.Lower),
   230  		ur.Upper.Sub(lr.Lower),
   231  		ur.Lower.Sub(lr.Upper),
   232  		ur.Upper.Sub(lr.Upper),
   233  	}
   234  	// TODO(dh): if we don't truncate lengths to 0 we might be able to
   235  	// easily detect slices with high < low. we'd need to treat -∞
   236  	// specially, though.
   237  	for i, l := range ls {
   238  		if l.Sign() == -1 {
   239  			ls[i] = NewZ(0)
   240  		}
   241  	}
   242  
   243  	return SliceInterval{
   244  		Length: NewIntInterval(MinZ(ls...), MaxZ(ls...)),
   245  	}
   246  }
   247  func (c *SliceIntersectionConstraint) Eval(g *Graph) Range {
   248  	xi := g.Range(c.X).(SliceInterval)
   249  	if !xi.IsKnown() {
   250  		return c.I
   251  	}
   252  	return SliceInterval{
   253  		Length: xi.Length.Intersection(c.I),
   254  	}
   255  }
   256  func (c *SliceLengthConstraint) Eval(g *Graph) Range {
   257  	i := g.Range(c.X).(SliceInterval).Length
   258  	if !i.IsKnown() {
   259  		return NewIntInterval(NewZ(0), PInfinity)
   260  	}
   261  	return i
   262  }
   263  func (c *MakeSliceConstraint) Eval(g *Graph) Range {
   264  	i, ok := g.Range(c.Size).(IntInterval)
   265  	if !ok {
   266  		return SliceInterval{NewIntInterval(NewZ(0), PInfinity)}
   267  	}
   268  	if i.Lower.Sign() == -1 {
   269  		i.Lower = NewZ(0)
   270  	}
   271  	return SliceInterval{i}
   272  }
   273  func (c *SliceIntervalConstraint) Eval(*Graph) Range { return SliceInterval{c.I} }