Repository: goadesign/goa
Pull request #3608 (2024-11-06 21:50:41)

Remove bases from attributes once they are finalized.
This improves performance and also fixes potential bugs where codegen algorithms make modifications to base types that are not reflected in dups created for example when projecting views.

Fixes https://github.com/goadesign/goa/issues/3598


Patch:
diff --git a/expr/attribute.go b/expr/attribute.go
index c4a6f0e0..0742c85f 100644
--- a/expr/attribute.go
+++ b/expr/attribute.go
@@ -320,6 +320,12 @@ func (a *AttributeExpr) Finalize() {
 			}
 			a.Merge(ru.Attribute())
 		}
+
+		// Now that we've merged the bases, we can clear them.  This
+		// avoids issues where the bases are dupped and modifications
+		// made to the originals are not reflected in the dups.
+		a.Bases = nil
+
 		for _, nat := range *AsObject(a.Type) {
 			if pkgPath != "" {
 				if u := AsUnion(nat.Attribute.Type); u != nil {


Test patch:
diff --git a/http/codegen/server_decode_test.go b/http/codegen/server_decode_test.go
index bd16aa86..dc3065ae 100644
--- a/http/codegen/server_decode_test.go
+++ b/http/codegen/server_decode_test.go
@@ -165,6 +165,7 @@ func TestDecode(t *testing.T) {
 		{"decode-body-map-string-validate", testdata.PayloadBodyMapStringValidateDSL, testdata.PayloadBodyMapStringValidateDecodeCode},
 		{"decode-body-map-user", testdata.PayloadBodyMapUserDSL, testdata.PayloadBodyMapUserDecodeCode},
 		{"decode-body-map-user-validate", testdata.PayloadBodyMapUserValidateDSL, testdata.PayloadBodyMapUserValidateDecodeCode},
+		{"decode-deep-user", testdata.PayloadDeepUserDSL, testdata.PayloadDeepUserDecodeCode},
 
 		{"decode-body-primitive-string-validate", testdata.PayloadBodyPrimitiveStringValidateDSL, testdata.PayloadBodyPrimitiveStringValidateDecodeCode},
 		{"decode-body-primitive-bool-validate", testdata.PayloadBodyPrimitiveBoolValidateDSL, testdata.PayloadBodyPrimitiveBoolValidateDecodeCode},
diff --git a/http/codegen/testdata/payload_decode_functions.go b/http/codegen/testdata/payload_decode_functions.go
index ef650720..cc97eddc 100644
--- a/http/codegen/testdata/payload_decode_functions.go
+++ b/http/codegen/testdata/payload_decode_functions.go
@@ -4338,6 +4338,22 @@ func DecodeMethodBodyMapUserValidateRequest(mux goahttp.Muxer, decoder func(*htt
 }
 `
 
+var PayloadDeepUserDecodeCode = `// marshalServicedeepuserviewsImmediatechildextenderViewToImmediatechildextenderResponseBody
+// builds a value of type *ImmediatechildextenderResponseBody from a value of
+// type *servicedeepuserviews.ImmediatechildextenderView.
+func marshalServicedeepuserviewsImmediatechildextenderViewToImmediatechildextenderResponseBody(v *servicedeepuserviews.ImmediatechildextenderView) *ImmediatechildextenderResponseBody {
+	if v == nil {
+		return nil
+	}
+	res := &ImmediatechildextenderResponseBody{}
+	if v.DeepChild != nil {
+		res.DeepChild = marshalServicedeepuserviewsDeepchildViewToDeepchildResponseBody(v.DeepChild)
+	}
+
+	return res
+}
+`
+
 var PayloadBodyPrimitiveStringValidateDecodeCode = `// DecodeMethodBodyPrimitiveStringValidateRequest returns a decoder for
 // requests sent to the ServiceBodyPrimitiveStringValidate
 // MethodBodyPrimitiveStringValidate endpoint.
diff --git a/http/codegen/testdata/payload_dsls.go b/http/codegen/testdata/payload_dsls.go
index 561ed6f8..f22df95a 100644
--- a/http/codegen/testdata/payload_dsls.go
+++ b/http/codegen/testdata/payload_dsls.go
@@ -2301,6 +2301,40 @@ var PayloadBodyMapUserValidateDSL = func() {
 	})
 }
 
+var PayloadDeepUserDSL = func() {
+	var DeepChild = ResultType("DeepChild", func() {
+		Attribute("name", String)
+	})
+	var ImmediateChild = ResultType("ImmediateChild", func() {
+		Attributes(func() {
+			Attribute("deep_child", DeepChild)
+		})
+		View("other", func() {
+			Attribute("deep_child")
+		})
+	})
+	var ImmediateChildExtender = ResultType("ImmediateChildExtender", func() {
+		Extend(ImmediateChild)
+		Attributes(func() {
+			Attribute("deep_child", DeepChild)
+		})
+		View("other", func() {
+			Attribute("deep_child")
+		})
+	})
+	var TopLevel = ResultType("TopLevel", func() {
+		Attributes(func() {
+			Attribute("immediate_child", ImmediateChildExtender)
+		})
+	})
+	Service("ServiceDeepUser", func() {
+		Method("MethodDeepUser", func() {
+			Result(TopLevel)
+			HTTP(func() { GET("/") })
+		})
+	})
+}
+
 var PayloadBodyPrimitiveStringValidateDSL = func() {
 	Service("ServiceBodyPrimitiveStringValidate", func() {
 		Method("MethodBodyPrimitiveStringValidate", func() {