Repository: goadesign/goa (Go)

Issue:
generated views of shared types are incorrect
Hi there, I'm having an issue with the generated service code. 
I'm with using the Meta function as intended and it seems to be generating the types pkg with each of the type struct defined correctly. However, those types views are being referenced in the generated service code incorrectly.

I have a file structure like **before** generation
```
|- design
     |- serviceA.go       // serviceA design
     |- serviceB.go      // service B design
```
What I would like after generation...
```
|- design
     |- serviceA.go       // serviceA design
     |- serviceB.go      // service B design
|- gen
     |- http
     |- serviceA
          |- views
               |- views.go
          |- client.go
          |- endpoints.go
          |- service.go
     |- serviceB
          |- ..... <same as serviceA>.....
```

A simplified design would look something like...
```
// ServiceA
//GetMethod
func GetMethod() {
	r.Method("Get", func() {
		Description("Gets the entity based on IDr.")
		Payload(func() {
			Attribute("id", String)
		})
		Result(SimpleResponse)
		DefaultHTTP(func() {
			GET("/{id}")
		})
	})
}

// ServiceB
// CreateMethod 
func CreateMethod() {
	r.Method("Create", func() {
		Description("Creates the entity based on IDr.")
		Payload(func() {
			Attribute("id", String)
		})
		Result(SimpleResponse)
		DefaultHTTP(func() {
			POST("/{id}")
		})
	})
}

var SimpleResponse = ResultType("simple_response", func() {
	Description("The response data of the request")
	WrapData(SimpleEntity, true)()
})

// WrapData is a function that we use to wrap our response within a `data` field
func WrapData(resultType expr.UserType, isRequired bool) func() {
	return func() {
		Attribute("data", resultType, func() {
			Description("the data")
		})
		if isRequired {
			Required("data")
		}
	}
}

var SimpleEntity = Type("simple_entity", func() {
	Description("an instance of an entity")
	Attribute("id", String)
	Attribute("version", Version)
	Required("id", "version")
	Meta("struct:pkg:path", "types")
})

var Version = Type("version", func() {
	Description("The version of the entity")
	AttrName(true, func() {
		Description("The name of the version")
		Example("Test Name")
	})
	Required("name")
	Meta("struct:pkg:path", "types")
})
```

The goal is I want to share the `SimpleEntity` across serviceA and serviceB without generating the model twice therefore using the Meta function provided. The issue is the view of the model `SimpleEntityView` is generated under the view.go & the service.go is trying to point the pkg types. e.g

`/gen/types` (in their own go files)
```
type SimpleResponse struct {
	Data *SimpleEntity
}

type SimpleEntity struct {
	ID            string
	Version   *Version
}

type Version struct {
	Name string
}
```

`gen/view/view.go`
```
// VersionView is a type that runs validations on a projected type.
type VersionView struct {
	Name *string
}
```

`/gen/serviceB/service.go`
```
// transformTypesSimpleEntityViewToTypesSimpleEntity builds a value of type
// *types.SimpleEntity from a value of type *types.SimpleEntityView.
func transformTypesSimpleEntityViewToTypesSimpleEntityt(v *types.SimpleEntityView) *types.SimpleEntity
```
`types.SimpleEntityView` does not exist but `SimpleEntityView` exists within the `view/view.go`. I anticipated the views generated in the types but not sure what the intended purpose is here. Basically all the views that reference the "shared" models defined above are erroring. Thanks in advance.


Discussion:
example design 
```
// SERVICE A
var _ = Service("serviceB", func() {
    Description("some description")
    Method("get", func() {
        Payload(func() {
            Attribute("id", String)
        })
        Result(SimpleResponse)

        HTTP(func() {
            GET("/{id}")
            Response(StatusOK)
        })
    })
})

// SERVICE B
var _ = Service("serviceB", func() {
    Description("some description")
    Method("create", func() {
        Payload(func() {
            Attribute("id", String)
        })
        Result(SimpleResponse)

        HTTP(func() {
            POST("/{id}")
            Response(StatusOK)
        })
    })
})

var SimpleResponse = ResultType("simple_response", func() {
	Description("The response data of the request")
	WrapData(SimpleEntity, true)()
})

// WrapData is a function that we use to wrap our response within a `data` field
func WrapData(resultType expr.UserType, isRequired bool) func() {
	return func() {
		Attribute("data", resultType, func() {
			Description("the data")
		})
		if isRequired {
			Required("data")
		}
	}
}

var SimpleEntity = Type("simple_entity", func() {
	Description("an instance of an entity")
	Attribute("id", String)
	Attribute("version", Version)
	Required("id", "version")
	Meta("struct:pkg:path", "types")
})

var Version = Type("version", func() {
	Description("The version of the entity")
	AttrName(true, func() {
		Description("The name of the version")
		Example("Test Name")
	})
	Required("name")
	Meta("struct:pkg:path", "types")
})
```

I believe you can run `goa gen` now.
Thank you for providing all the details. I believe this is fixed by https://github.com/goadesign/goa/pull/3243
Hi @raphael, thank you for fixing this!!! Is there going to be a release soon that includes this change? 
Yes I'll release a new version in the next few days.



Patch:
diff --git a/codegen/service/service_data.go b/codegen/service/service_data.go
index 3e38b16678..e723135c1d 100644
--- a/codegen/service/service_data.go
+++ b/codegen/service/service_data.go
@@ -1251,6 +1251,7 @@ func buildProjectedType(projected, att *expr.AttributeExpr, viewspkg string, sco
 		}
 		validations = buildValidations(projected, viewScope)
 	}
+	removeMeta(projected)
 	return &ProjectedTypeData{
 		UserTypeData: &UserTypeData{
 			Name:        varname,
@@ -1796,6 +1797,16 @@ func walkViewAttrs(obj *expr.Object, view *expr.ViewExpr, walker func(name strin
 	}
 }
 
+// removeMeta removes the meta attributes from the given attribute. This is
+// needed to make sure that any field name overridding is removed when
+// generating protobuf types (as protogen itself won't honor these overrides).
+func removeMeta(att *expr.AttributeExpr) {
+	_ = codegen.Walk(att, func(a *expr.AttributeExpr) error {
+		delete(a.Meta, "struct:pkg:path")
+		return nil
+	})
+}
+
 const (
 	initTypeCodeT = `{{ if or .ToResult .ToViewed }}
 	{{- if eq (len .Views) 1 }}


Test patch:
diff --git a/codegen/service/testdata/views_code.go b/codegen/service/testdata/views_code.go
index 5fe6abe5fd..c452a91da8 100644
--- a/codegen/service/testdata/views_code.go
+++ b/codegen/service/testdata/views_code.go
@@ -808,3 +808,55 @@ func ValidateUserTypeView(result UserTypeView) (err error) {
 	return
 }
 `
+
+const ResultWithPkgPathCode = `// RT is the viewed result type that is projected based on a view.
+type RT struct {
+	// Type to project
+	Projected *RTView
+	// View to render
+	View string
+}
+
+// RTView is a type that runs validations on a projected type.
+type RTView struct {
+	A *UserTypeView
+}
+
+// UserTypeView is a type that runs validations on a projected type.
+type UserTypeView struct {
+	A *string
+}
+
+var (
+	// RTMap is a map indexing the attribute names of RT by view name.
+	RTMap = map[string][]string{
+		"default": {
+			"a",
+		},
+	}
+)
+
+// ValidateRT runs the validations defined on the viewed result type RT.
+func ValidateRT(result *RT) (err error) {
+	switch result.View {
+	case "default", "":
+		err = ValidateRTView(result.Projected)
+	default:
+		err = goa.InvalidEnumValueError("view", result.View, []interface{}{"default"})
+	}
+	return
+}
+
+// ValidateRTView runs the validations defined on RTView using the "default"
+// view.
+func ValidateRTView(result *RTView) (err error) {
+
+	return
+}
+
+// ValidateUserTypeView runs the validations defined on UserTypeView.
+func ValidateUserTypeView(result *UserTypeView) (err error) {
+
+	return
+}
+`
diff --git a/codegen/service/testdata/views_dsls.go b/codegen/service/testdata/views_dsls.go
index ae5627b114..69075db360 100644
--- a/codegen/service/testdata/views_dsls.go
+++ b/codegen/service/testdata/views_dsls.go
@@ -219,7 +219,7 @@ var ResultWithMultipleMethodsDSL = func() {
 }
 
 var ResultWithEnumTypeDSL = func() {
-	var T = Type("UserType", String, func()  {
+	var T = Type("UserType", String, func() {
 		Enum("a", "b")
 	})
 	var RT = ResultType("application/vnd.result", func() {
@@ -234,6 +234,24 @@ var ResultWithEnumTypeDSL = func() {
 	})
 }
 
+var ResultWithPkgPathDSL = func() {
+	var T = Type("UserType", func() {
+		Attribute("a", String)
+		Meta("struct:pkg:path", "types")
+	})
+	var RT = ResultType("application/vnd.result", func() {
+		TypeName("RT")
+		Attributes(func() {
+			Attribute("a", T)
+		})
+	})
+	Service("ResultWithPkgPath", func() {
+		Method("A", func() {
+			Result(RT)
+		})
+	})
+}
+
 var ResultWithCustomFieldsDSL = func() {
 	var RT = ResultType("application/vnd.result", func() {
 		TypeName("RT")
diff --git a/codegen/service/views_test.go b/codegen/service/views_test.go
index 130fdd9d64..3047bfe39e 100644
--- a/codegen/service/views_test.go
+++ b/codegen/service/views_test.go
@@ -26,6 +26,7 @@ func TestViews(t *testing.T) {
 		{"result-with-recursive-collection-of-result-type", testdata.ResultWithRecursiveCollectionOfResultTypeDSL, testdata.ResultWithRecursiveCollectionOfResultTypeCode},
 		{"result-with-multiple-methods", testdata.ResultWithMultipleMethodsDSL, testdata.ResultWithMultipleMethodsCode},
 		{"result-with-enum-type", testdata.ResultWithEnumTypeDSL, testdata.ResultWithEnumType},
+		{"result-with-pkg-path", testdata.ResultWithPkgPathDSL, testdata.ResultWithPkgPathCode},
 	}
 	for _, c := range cases {
 		t.Run(c.Name, func(t *testing.T) {