string.go 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259
  1. package vrp
  2. import (
  3. "fmt"
  4. "go/token"
  5. "go/types"
  6. "honnef.co/go/tools/ssa"
  7. )
  8. type StringInterval struct {
  9. Length IntInterval
  10. }
  11. func (s StringInterval) Union(other Range) Range {
  12. i, ok := other.(StringInterval)
  13. if !ok {
  14. i = StringInterval{EmptyIntInterval}
  15. }
  16. if s.Length.Empty() || !s.Length.IsKnown() {
  17. return i
  18. }
  19. if i.Length.Empty() || !i.Length.IsKnown() {
  20. return s
  21. }
  22. return StringInterval{
  23. Length: s.Length.Union(i.Length).(IntInterval),
  24. }
  25. }
  26. func (s StringInterval) String() string {
  27. return s.Length.String()
  28. }
  29. func (s StringInterval) IsKnown() bool {
  30. return s.Length.IsKnown()
  31. }
  32. type StringSliceConstraint struct {
  33. aConstraint
  34. X ssa.Value
  35. Lower ssa.Value
  36. Upper ssa.Value
  37. }
  38. type StringIntersectionConstraint struct {
  39. aConstraint
  40. ranges Ranges
  41. A ssa.Value
  42. B ssa.Value
  43. Op token.Token
  44. I IntInterval
  45. resolved bool
  46. }
  47. type StringConcatConstraint struct {
  48. aConstraint
  49. A ssa.Value
  50. B ssa.Value
  51. }
  52. type StringLengthConstraint struct {
  53. aConstraint
  54. X ssa.Value
  55. }
  56. type StringIntervalConstraint struct {
  57. aConstraint
  58. I IntInterval
  59. }
  60. func NewStringSliceConstraint(x, lower, upper, y ssa.Value) Constraint {
  61. return &StringSliceConstraint{NewConstraint(y), x, lower, upper}
  62. }
  63. func NewStringIntersectionConstraint(a, b ssa.Value, op token.Token, ranges Ranges, y ssa.Value) Constraint {
  64. return &StringIntersectionConstraint{
  65. aConstraint: NewConstraint(y),
  66. ranges: ranges,
  67. A: a,
  68. B: b,
  69. Op: op,
  70. }
  71. }
  72. func NewStringConcatConstraint(a, b, y ssa.Value) Constraint {
  73. return &StringConcatConstraint{NewConstraint(y), a, b}
  74. }
  75. func NewStringLengthConstraint(x ssa.Value, y ssa.Value) Constraint {
  76. return &StringLengthConstraint{NewConstraint(y), x}
  77. }
  78. func NewStringIntervalConstraint(i IntInterval, y ssa.Value) Constraint {
  79. return &StringIntervalConstraint{NewConstraint(y), i}
  80. }
  81. func (c *StringSliceConstraint) Operands() []ssa.Value {
  82. vs := []ssa.Value{c.X}
  83. if c.Lower != nil {
  84. vs = append(vs, c.Lower)
  85. }
  86. if c.Upper != nil {
  87. vs = append(vs, c.Upper)
  88. }
  89. return vs
  90. }
  91. func (c *StringIntersectionConstraint) Operands() []ssa.Value { return []ssa.Value{c.A} }
  92. func (c StringConcatConstraint) Operands() []ssa.Value { return []ssa.Value{c.A, c.B} }
  93. func (c *StringLengthConstraint) Operands() []ssa.Value { return []ssa.Value{c.X} }
  94. func (s *StringIntervalConstraint) Operands() []ssa.Value { return nil }
  95. func (c *StringSliceConstraint) String() string {
  96. var lname, uname string
  97. if c.Lower != nil {
  98. lname = c.Lower.Name()
  99. }
  100. if c.Upper != nil {
  101. uname = c.Upper.Name()
  102. }
  103. return fmt.Sprintf("%s[%s:%s]", c.X.Name(), lname, uname)
  104. }
  105. func (c *StringIntersectionConstraint) String() string {
  106. return fmt.Sprintf("%s = %s %s %s (%t branch)", c.Y().Name(), c.A.Name(), c.Op, c.B.Name(), c.Y().(*ssa.Sigma).Branch)
  107. }
  108. func (c StringConcatConstraint) String() string {
  109. return fmt.Sprintf("%s = %s + %s", c.Y().Name(), c.A.Name(), c.B.Name())
  110. }
  111. func (c *StringLengthConstraint) String() string {
  112. return fmt.Sprintf("%s = len(%s)", c.Y().Name(), c.X.Name())
  113. }
  114. func (c *StringIntervalConstraint) String() string { return fmt.Sprintf("%s = %s", c.Y().Name(), c.I) }
  115. func (c *StringSliceConstraint) Eval(g *Graph) Range {
  116. lr := NewIntInterval(NewZ(0), NewZ(0))
  117. if c.Lower != nil {
  118. lr = g.Range(c.Lower).(IntInterval)
  119. }
  120. ur := g.Range(c.X).(StringInterval).Length
  121. if c.Upper != nil {
  122. ur = g.Range(c.Upper).(IntInterval)
  123. }
  124. if !lr.IsKnown() || !ur.IsKnown() {
  125. return StringInterval{}
  126. }
  127. ls := []Z{
  128. ur.Lower.Sub(lr.Lower),
  129. ur.Upper.Sub(lr.Lower),
  130. ur.Lower.Sub(lr.Upper),
  131. ur.Upper.Sub(lr.Upper),
  132. }
  133. // TODO(dh): if we don't truncate lengths to 0 we might be able to
  134. // easily detect slices with high < low. we'd need to treat -∞
  135. // specially, though.
  136. for i, l := range ls {
  137. if l.Sign() == -1 {
  138. ls[i] = NewZ(0)
  139. }
  140. }
  141. return StringInterval{
  142. Length: NewIntInterval(MinZ(ls...), MaxZ(ls...)),
  143. }
  144. }
  145. func (c *StringIntersectionConstraint) Eval(g *Graph) Range {
  146. var l IntInterval
  147. switch r := g.Range(c.A).(type) {
  148. case StringInterval:
  149. l = r.Length
  150. case IntInterval:
  151. l = r
  152. }
  153. if !l.IsKnown() {
  154. return StringInterval{c.I}
  155. }
  156. return StringInterval{
  157. Length: l.Intersection(c.I),
  158. }
  159. }
  160. func (c StringConcatConstraint) Eval(g *Graph) Range {
  161. i1, i2 := g.Range(c.A).(StringInterval), g.Range(c.B).(StringInterval)
  162. if !i1.Length.IsKnown() || !i2.Length.IsKnown() {
  163. return StringInterval{}
  164. }
  165. return StringInterval{
  166. Length: i1.Length.Add(i2.Length),
  167. }
  168. }
  169. func (c *StringLengthConstraint) Eval(g *Graph) Range {
  170. i := g.Range(c.X).(StringInterval).Length
  171. if !i.IsKnown() {
  172. return NewIntInterval(NewZ(0), PInfinity)
  173. }
  174. return i
  175. }
  176. func (c *StringIntervalConstraint) Eval(*Graph) Range { return StringInterval{c.I} }
  177. func (c *StringIntersectionConstraint) Futures() []ssa.Value {
  178. return []ssa.Value{c.B}
  179. }
  180. func (c *StringIntersectionConstraint) Resolve() {
  181. if (c.A.Type().Underlying().(*types.Basic).Info() & types.IsString) != 0 {
  182. // comparing two strings
  183. r, ok := c.ranges[c.B].(StringInterval)
  184. if !ok {
  185. c.I = NewIntInterval(NewZ(0), PInfinity)
  186. return
  187. }
  188. switch c.Op {
  189. case token.EQL:
  190. c.I = r.Length
  191. case token.GTR, token.GEQ:
  192. c.I = NewIntInterval(r.Length.Lower, PInfinity)
  193. case token.LSS, token.LEQ:
  194. c.I = NewIntInterval(NewZ(0), r.Length.Upper)
  195. case token.NEQ:
  196. default:
  197. panic("unsupported op " + c.Op.String())
  198. }
  199. } else {
  200. r, ok := c.ranges[c.B].(IntInterval)
  201. if !ok {
  202. c.I = NewIntInterval(NewZ(0), PInfinity)
  203. return
  204. }
  205. // comparing two lengths
  206. switch c.Op {
  207. case token.EQL:
  208. c.I = r
  209. case token.GTR:
  210. c.I = NewIntInterval(r.Lower.Add(NewZ(1)), PInfinity)
  211. case token.GEQ:
  212. c.I = NewIntInterval(r.Lower, PInfinity)
  213. case token.LSS:
  214. c.I = NewIntInterval(NInfinity, r.Upper.Sub(NewZ(1)))
  215. case token.LEQ:
  216. c.I = NewIntInterval(NInfinity, r.Upper)
  217. case token.NEQ:
  218. default:
  219. panic("unsupported op " + c.Op.String())
  220. }
  221. }
  222. }
  223. func (c *StringIntersectionConstraint) IsKnown() bool {
  224. return c.I.IsKnown()
  225. }
  226. func (c *StringIntersectionConstraint) MarkUnresolved() {
  227. c.resolved = false
  228. }
  229. func (c *StringIntersectionConstraint) MarkResolved() {
  230. c.resolved = true
  231. }
  232. func (c *StringIntersectionConstraint) IsResolved() bool {
  233. return c.resolved
  234. }