From 535464057b5d70ac816c30e5ae88327d5c9ff0ca Mon Sep 17 00:00:00 2001 From: Alex Jurkiewicz Date: Tue, 24 May 2022 10:14:35 +1000 Subject: [PATCH] Detect and warn on duplicate map keys --- gohcl/decode.go | 17 ++++++++++++++--- gohcl/decode_test.go | 29 +++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 3 deletions(-) diff --git a/gohcl/decode.go b/gohcl/decode.go index 2954f4ce..bcc4a281 100644 --- a/gohcl/decode.go +++ b/gohcl/decode.go @@ -240,16 +240,27 @@ func decodeBodyToMap(body hcl.Body, ctx *hcl.EvalContext, v reflect.Value) hcl.D mv := reflect.MakeMap(v.Type()) for k, attr := range attrs { + key := reflect.ValueOf(k) + var value reflect.Value switch { case attrType.AssignableTo(v.Type().Elem()): - mv.SetMapIndex(reflect.ValueOf(k), reflect.ValueOf(attr)) + value = reflect.ValueOf(attr) case exprType.AssignableTo(v.Type().Elem()): - mv.SetMapIndex(reflect.ValueOf(k), reflect.ValueOf(attr.Expr)) + value = reflect.ValueOf(attr.Expr) default: ev := reflect.New(v.Type().Elem()) diags = append(diags, DecodeExpression(attr.Expr, ctx, ev.Interface())...) - mv.SetMapIndex(reflect.ValueOf(k), ev.Elem()) + value = ev.Elem() } + if mv.MapIndex(key).IsValid() { + diags = append(diags, &hcl.Diagnostic{ + Severity: hcl.DiagWarning, + Summary: "Duplicate map key", + Detail: fmt.Sprintf("Key '%s' was defined twice in this map.", key), + // Subject: ??? + }) + } + mv.SetMapIndex(key, value) } v.Set(mv) diff --git a/gohcl/decode_test.go b/gohcl/decode_test.go index 50eaea7f..8beceef6 100644 --- a/gohcl/decode_test.go +++ b/gohcl/decode_test.go @@ -137,6 +137,35 @@ func TestDecodeBody(t *testing.T) { }, 0, }, + // Duplicate key + { + map[string]interface{}{ + "name": "Ermintrude", + }, + makeInstantiateType(withNameExpression{}), + func(v interface{}) bool { + if v == nil { + return false + } + + wne, valid := v.(withNameExpression) + if !valid { + return false + } + + if wne.Name == nil { + return false + } + + nameVal, _ := wne.Name.Value(nil) + if !nameVal.Equals(cty.StringVal("Ermintrude")).True() { + return false + } + + return true + }, + 0, + }, { map[string]interface{}{ "name": "Ermintrude",