rules.go 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294
  1. package staticcheck
  2. import (
  3. "fmt"
  4. "go/constant"
  5. "go/types"
  6. "net"
  7. "net/url"
  8. "regexp"
  9. "sort"
  10. "strconv"
  11. "strings"
  12. "time"
  13. "unicode/utf8"
  14. "honnef.co/go/tools/analysis/code"
  15. "honnef.co/go/tools/go/ir"
  16. "honnef.co/go/tools/go/ir/irutil"
  17. "honnef.co/go/tools/go/types/typeutil"
  18. "golang.org/x/tools/go/analysis"
  19. )
  20. const (
  21. MsgInvalidHostPort = "invalid port or service name in host:port pair"
  22. MsgInvalidUTF8 = "argument is not a valid UTF-8 encoded string"
  23. MsgNonUniqueCutset = "cutset contains duplicate characters"
  24. )
  25. type Call struct {
  26. Pass *analysis.Pass
  27. Instr ir.CallInstruction
  28. Args []*Argument
  29. Parent *ir.Function
  30. invalids []string
  31. }
  32. func (c *Call) Invalid(msg string) {
  33. c.invalids = append(c.invalids, msg)
  34. }
  35. type Argument struct {
  36. Value Value
  37. invalids []string
  38. }
  39. type Value struct {
  40. Value ir.Value
  41. }
  42. func (arg *Argument) Invalid(msg string) {
  43. arg.invalids = append(arg.invalids, msg)
  44. }
  45. type CallCheck func(call *Call)
  46. func extractConstExpectKind(v ir.Value, kind constant.Kind) *ir.Const {
  47. k := extractConst(v)
  48. if k == nil || k.Value == nil || k.Value.Kind() != kind {
  49. return nil
  50. }
  51. return k
  52. }
  53. func extractConst(v ir.Value) *ir.Const {
  54. v = irutil.Flatten(v)
  55. switch v := v.(type) {
  56. case *ir.Const:
  57. return v
  58. case *ir.MakeInterface:
  59. return extractConst(v.X)
  60. default:
  61. return nil
  62. }
  63. }
  64. func ValidateRegexp(v Value) error {
  65. if c := extractConstExpectKind(v.Value, constant.String); c != nil {
  66. s := constant.StringVal(c.Value)
  67. if _, err := regexp.Compile(s); err != nil {
  68. return err
  69. }
  70. }
  71. return nil
  72. }
  73. func ValidateTimeLayout(v Value) error {
  74. if c := extractConstExpectKind(v.Value, constant.String); c != nil {
  75. s := constant.StringVal(c.Value)
  76. s = strings.Replace(s, "_", " ", -1)
  77. s = strings.Replace(s, "Z", "-", -1)
  78. _, err := time.Parse(s, s)
  79. if err != nil {
  80. return err
  81. }
  82. }
  83. return nil
  84. }
  85. func ValidateURL(v Value) error {
  86. if c := extractConstExpectKind(v.Value, constant.String); c != nil {
  87. s := constant.StringVal(c.Value)
  88. _, err := url.Parse(s)
  89. if err != nil {
  90. return fmt.Errorf("%q is not a valid URL: %s", s, err)
  91. }
  92. }
  93. return nil
  94. }
  95. func InvalidUTF8(v Value) bool {
  96. if c := extractConstExpectKind(v.Value, constant.String); c != nil {
  97. s := constant.StringVal(c.Value)
  98. if !utf8.ValidString(s) {
  99. return true
  100. }
  101. }
  102. return false
  103. }
  104. func UnbufferedChannel(v Value) bool {
  105. // TODO(dh): this check of course misses many cases of unbuffered
  106. // channels, such as any in phi or sigma nodes. We'll eventually
  107. // replace this function.
  108. val := v.Value
  109. if ct, ok := val.(*ir.ChangeType); ok {
  110. val = ct.X
  111. }
  112. mk, ok := val.(*ir.MakeChan)
  113. if !ok {
  114. return false
  115. }
  116. if k, ok := mk.Size.(*ir.Const); ok && k.Value.Kind() == constant.Int {
  117. if v, ok := constant.Int64Val(k.Value); ok && v == 0 {
  118. return true
  119. }
  120. }
  121. return false
  122. }
  123. func Pointer(v Value) bool {
  124. switch v.Value.Type().Underlying().(type) {
  125. case *types.Pointer, *types.Interface:
  126. return true
  127. }
  128. return false
  129. }
  130. func ConvertedFromInt(v Value) bool {
  131. conv, ok := v.Value.(*ir.Convert)
  132. if !ok {
  133. return false
  134. }
  135. b, ok := conv.X.Type().Underlying().(*types.Basic)
  136. if !ok {
  137. return false
  138. }
  139. if (b.Info() & types.IsInteger) == 0 {
  140. return false
  141. }
  142. return true
  143. }
  144. func validEncodingBinaryType(pass *analysis.Pass, typ types.Type) bool {
  145. typ = typ.Underlying()
  146. switch typ := typ.(type) {
  147. case *types.Basic:
  148. switch typ.Kind() {
  149. case types.Uint8, types.Uint16, types.Uint32, types.Uint64,
  150. types.Int8, types.Int16, types.Int32, types.Int64,
  151. types.Float32, types.Float64, types.Complex64, types.Complex128, types.Invalid:
  152. return true
  153. case types.Bool:
  154. return code.IsGoVersion(pass, 8)
  155. }
  156. return false
  157. case *types.Struct:
  158. n := typ.NumFields()
  159. for i := 0; i < n; i++ {
  160. if !validEncodingBinaryType(pass, typ.Field(i).Type()) {
  161. return false
  162. }
  163. }
  164. return true
  165. case *types.Array:
  166. return validEncodingBinaryType(pass, typ.Elem())
  167. case *types.Interface:
  168. // we can't determine if it's a valid type or not
  169. return true
  170. }
  171. return false
  172. }
  173. func CanBinaryMarshal(pass *analysis.Pass, v Value) bool {
  174. typ := v.Value.Type().Underlying()
  175. if ttyp, ok := typ.(*types.Pointer); ok {
  176. typ = ttyp.Elem().Underlying()
  177. }
  178. if ttyp, ok := typ.(interface {
  179. Elem() types.Type
  180. }); ok {
  181. if _, ok := ttyp.(*types.Pointer); !ok {
  182. typ = ttyp.Elem()
  183. }
  184. }
  185. return validEncodingBinaryType(pass, typ)
  186. }
  187. func RepeatZeroTimes(name string, arg int) CallCheck {
  188. return func(call *Call) {
  189. arg := call.Args[arg]
  190. if k, ok := arg.Value.Value.(*ir.Const); ok && k.Value.Kind() == constant.Int {
  191. if v, ok := constant.Int64Val(k.Value); ok && v == 0 {
  192. arg.Invalid(fmt.Sprintf("calling %s with n == 0 will return no results, did you mean -1?", name))
  193. }
  194. }
  195. }
  196. }
  197. func validateServiceName(s string) bool {
  198. if len(s) < 1 || len(s) > 15 {
  199. return false
  200. }
  201. if s[0] == '-' || s[len(s)-1] == '-' {
  202. return false
  203. }
  204. if strings.Contains(s, "--") {
  205. return false
  206. }
  207. hasLetter := false
  208. for _, r := range s {
  209. if (r >= 'A' && r <= 'Z') || (r >= 'a' && r <= 'z') {
  210. hasLetter = true
  211. continue
  212. }
  213. if r >= '0' && r <= '9' {
  214. continue
  215. }
  216. return false
  217. }
  218. return hasLetter
  219. }
  220. func validatePort(s string) bool {
  221. n, err := strconv.ParseInt(s, 10, 64)
  222. if err != nil {
  223. return validateServiceName(s)
  224. }
  225. return n >= 0 && n <= 65535
  226. }
  227. func ValidHostPort(v Value) bool {
  228. if k := extractConstExpectKind(v.Value, constant.String); k != nil {
  229. s := constant.StringVal(k.Value)
  230. if s == "" {
  231. return true
  232. }
  233. _, port, err := net.SplitHostPort(s)
  234. if err != nil {
  235. return false
  236. }
  237. // TODO(dh): check hostname
  238. if !validatePort(port) {
  239. return false
  240. }
  241. }
  242. return true
  243. }
  244. // ConvertedFrom reports whether value v was converted from type typ.
  245. func ConvertedFrom(v Value, typ string) bool {
  246. change, ok := v.Value.(*ir.ChangeType)
  247. return ok && typeutil.IsType(change.X.Type(), typ)
  248. }
  249. func UniqueStringCutset(v Value) bool {
  250. if c := extractConstExpectKind(v.Value, constant.String); c != nil {
  251. s := constant.StringVal(c.Value)
  252. rs := runeSlice(s)
  253. if len(rs) < 2 {
  254. return true
  255. }
  256. sort.Sort(rs)
  257. for i, r := range rs[1:] {
  258. if rs[i] == r {
  259. return false
  260. }
  261. }
  262. }
  263. return true
  264. }