diff options
| author | Joseph Richey <joerichey@google.com> | 2018-02-11 21:43:56 -0800 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2018-02-11 21:43:56 -0800 |
| commit | 8b6cbfcca9d1f3fb5b05a91b4ac0bca66f75f19e (patch) | |
| tree | 5f6fdc40c7518bc23a63fdac9a92b516dd0c6d36 /vendor/honnef.co/go/tools/internal | |
| parent | aebae1aae2fc61185a8bbc96313d8462727ad202 (diff) | |
| parent | b330463662825a7d7b22efabb2b7a40640d2b18e (diff) | |
Merge pull request #85 from google/depfix
Complete the new Build System
Diffstat (limited to 'vendor/honnef.co/go/tools/internal')
| -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) + } +} |