Repository: mgechev/revive (go)

Issue:
range-val-in-closure: incorrectly flags struct key if the key has the same name as a range variable
```go
package main

type t struct {
	key string
}

func main() {
	m := map[string]string{
		"a": "b",
	}

	for key := range m {
		myKey := key
		go func() {
			println(t{key: myKey})
		}()
	}
}
```

```
junk.go:15:14: range-val-in-closure: loop variable key captured by func literal (revive)
			println(t{key: myKey})
```

Pull request:
fix issue #637
Closes #637


Patch:
diff --git a/rule/range-val-in-closure.go b/rule/range-val-in-closure.go
index 857787b..0547b8d 100644
--- a/rule/range-val-in-closure.go
+++ b/rule/range-val-in-closure.go
@@ -87,15 +87,25 @@ func (w rangeValInClosure) Visit(node ast.Node) ast.Visitor {
 	if !ok {
 		return w
 	}
+
 	if lit.Type == nil {
 		// Not referring to a variable (e.g. struct field name)
 		return w
 	}
-	ast.Inspect(lit.Body, func(n ast.Node) bool {
+
+	var inspector func(n ast.Node) bool
+	inspector = func(n ast.Node) bool {
+		kv, ok := n.(*ast.KeyValueExpr)
+		if ok {
+			// do not check identifiers acting as key in key-value expressions (see issue #637)
+			ast.Inspect(kv.Value, inspector)
+			return false
+		}
 		id, ok := n.(*ast.Ident)
 		if !ok || id.Obj == nil {
 			return true
 		}
+
 		for _, v := range vars {
 			if v.Obj == id.Obj {
 				w.onFailure(lint.Failure{
@@ -106,6 +116,7 @@ func (w rangeValInClosure) Visit(node ast.Node) ast.Visitor {
 			}
 		}
 		return true
-	})
+	}
+	ast.Inspect(lit.Body, inspector)
 	return w
 }


Test patch:
diff --git a/testdata/range-val-in-closure.go b/testdata/range-val-in-closure.go
index cdda5d0..3d02972 100644
--- a/testdata/range-val-in-closure.go
+++ b/testdata/range-val-in-closure.go
@@ -24,14 +24,26 @@ func foo() {
 
 	for i, newg := range groups {
 		go func(newg int) {
-			newg.run(m.opts.Context,i) // MATCH /loop variable i captured by func literal/
+			newg.run(m.opts.Context, i) // MATCH /loop variable i captured by func literal/
 		}(newg)
 	}
 
 	for i, newg := range groups {
 		newg := newg
 		go func() {
-			newg.run(m.opts.Context,i) // MATCH /loop variable i captured by func literal/
+			newg.run(m.opts.Context, i) // MATCH /loop variable i captured by func literal/
+		}()
+	}
+}
+
+func issue637() {
+	for key := range m {
+		myKey := key
+		go func() {
+			println(t{
+				key:        myKey,
+				otherField: (10 + key), // MATCH /loop variable key captured by func literal/
+			})
 		}()
 	}
 }