diff options
Diffstat (limited to 'vendor/honnef.co/go/tools/internal/sharedcheck')
| -rw-r--r-- | vendor/honnef.co/go/tools/internal/sharedcheck/lint.go | 70 |
1 files changed, 70 insertions, 0 deletions
diff --git a/vendor/honnef.co/go/tools/internal/sharedcheck/lint.go b/vendor/honnef.co/go/tools/internal/sharedcheck/lint.go new file mode 100644 index 0000000..5f62fc2 --- /dev/null +++ b/vendor/honnef.co/go/tools/internal/sharedcheck/lint.go @@ -0,0 +1,70 @@ +package sharedcheck + +import ( + "go/ast" + "go/types" + + "honnef.co/go/tools/lint" + "honnef.co/go/tools/ssa" +) + +func CheckRangeStringRunes(nodeFns map[ast.Node]*ssa.Function, j *lint.Job) { + fn := func(node ast.Node) bool { + rng, ok := node.(*ast.RangeStmt) + if !ok || !lint.IsBlank(rng.Key) { + return true + } + ssafn := nodeFns[rng] + if ssafn == nil { + return true + } + v, _ := ssafn.ValueForExpr(rng.X) + + // Check that we're converting from string to []rune + val, _ := v.(*ssa.Convert) + if val == nil { + return true + } + Tsrc, ok := val.X.Type().(*types.Basic) + if !ok || Tsrc.Kind() != types.String { + return true + } + Tdst, ok := val.Type().(*types.Slice) + if !ok { + return true + } + TdstElem, ok := Tdst.Elem().(*types.Basic) + if !ok || TdstElem.Kind() != types.Int32 { + return true + } + + // Check that the result of the conversion is only used to + // range over + refs := val.Referrers() + if refs == nil { + return true + } + + // Expect two refs: one for obtaining the length of the slice, + // one for accessing the elements + if len(lint.FilterDebug(*refs)) != 2 { + // TODO(dh): right now, we check that only one place + // refers to our slice. This will miss cases such as + // ranging over the slice twice. Ideally, we'd ensure that + // the slice is only used for ranging over (without + // accessing the key), but that is harder to do because in + // SSA form, ranging over a slice looks like an ordinary + // loop with index increments and slice accesses. We'd + // have to look at the associated AST node to check that + // it's a range statement. + return true + } + + j.Errorf(rng, "should range over string, not []rune(string)") + + return true + } + for _, f := range j.Program.Files { + ast.Inspect(f, fn) + } +} |