summaryrefslogtreecommitdiffstats
path: root/vendor/github.com/mgechev/revive/rule/range.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/mgechev/revive/rule/range.go')
-rw-r--r--vendor/github.com/mgechev/revive/rule/range.go82
1 files changed, 82 insertions, 0 deletions
diff --git a/vendor/github.com/mgechev/revive/rule/range.go b/vendor/github.com/mgechev/revive/rule/range.go
new file mode 100644
index 0000000000..d18492c71a
--- /dev/null
+++ b/vendor/github.com/mgechev/revive/rule/range.go
@@ -0,0 +1,82 @@
+package rule
+
+import (
+ "fmt"
+ "go/ast"
+ "strings"
+
+ "github.com/mgechev/revive/lint"
+)
+
+// RangeRule lints given else constructs.
+type RangeRule struct{}
+
+// Apply applies the rule to given file.
+func (r *RangeRule) Apply(file *lint.File, _ lint.Arguments) []lint.Failure {
+ var failures []lint.Failure
+
+ onFailure := func(failure lint.Failure) {
+ failures = append(failures, failure)
+ }
+
+ w := &lintRanges{file, onFailure}
+ ast.Walk(w, file.AST)
+ return failures
+}
+
+// Name returns the rule name.
+func (r *RangeRule) Name() string {
+ return "range"
+}
+
+type lintRanges struct {
+ file *lint.File
+ onFailure func(lint.Failure)
+}
+
+func (w *lintRanges) Visit(node ast.Node) ast.Visitor {
+ rs, ok := node.(*ast.RangeStmt)
+ if !ok {
+ return w
+ }
+ if rs.Value == nil {
+ // for x = range m { ... }
+ return w // single var form
+ }
+ if !isIdent(rs.Value, "_") {
+ // for ?, y = range m { ... }
+ return w
+ }
+
+ newRS := *rs // shallow copy
+ newRS.Value = nil
+
+ w.onFailure(lint.Failure{
+ Failure: fmt.Sprintf("should omit 2nd value from range; this loop is equivalent to `for %s %s range ...`", w.file.Render(rs.Key), rs.Tok),
+ Confidence: 1,
+ Node: rs.Value,
+ ReplacementLine: firstLineOf(w.file, &newRS, rs),
+ })
+
+ return w
+}
+
+func firstLineOf(f *lint.File, node, match ast.Node) string {
+ line := f.Render(node)
+ if i := strings.Index(line, "\n"); i >= 0 {
+ line = line[:i]
+ }
+ return indentOf(f, match) + line
+}
+
+func indentOf(f *lint.File, node ast.Node) string {
+ line := srcLine(f.Content(), f.ToPosition(node.Pos()))
+ for i, r := range line {
+ switch r {
+ case ' ', '\t':
+ default:
+ return line[:i]
+ }
+ }
+ return line // unusual or empty line
+}