Skip to content

Commit

Permalink
fix issue #1346 about generics
Browse files Browse the repository at this point in the history
Signed-off-by: sdghchj <[email protected]>
  • Loading branch information
sdghchj committed Oct 14, 2022
1 parent f8d59d6 commit 424bbbf
Show file tree
Hide file tree
Showing 6 changed files with 59 additions and 38 deletions.
63 changes: 34 additions & 29 deletions generics.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ func typeSpecFullName(typeSpecDef *TypeSpecDef) string {
return fullName
}

func (pkgDefs *PackagesDefinitions) parametrizeStruct(file *ast.File, original *TypeSpecDef, fullGenericForm string, parseDependency bool) *TypeSpecDef {
func (pkgDefs *PackagesDefinitions) parametrizeGenericType(file *ast.File, original *TypeSpecDef, fullGenericForm string, parseDependency bool) *TypeSpecDef {
genericDefinitionsMutex.RLock()
tSpec, ok := genericsDefinitions[original][fullGenericForm]
genericDefinitionsMutex.RUnlock()
Expand Down Expand Up @@ -92,6 +92,7 @@ func (pkgDefs *PackagesDefinitions) parametrizeStruct(file *ast.File, original *
if tdef != nil && !strings.Contains(genericParam, ".") {
genericParam = fullTypeName(file.Name.Name, genericParam)
}

genericParamTypeDefs[original.TypeSpec.TypeParams.List[i].Names[0].Name] = &genericTypeSpec{
ArrayDepth: arrayDepth,
TypeSpec: tdef,
Expand Down Expand Up @@ -142,33 +143,12 @@ func (pkgDefs *PackagesDefinitions) parametrizeStruct(file *ast.File, original *
ident.Name = string(IgnoreNameOverridePrefix) + ident.Name

parametrizedTypeSpec.TypeSpec.Name = ident
origStructType := original.TypeSpec.Type.(*ast.StructType)

newStructTypeDef := &ast.StructType{
Struct: origStructType.Struct,
Incomplete: origStructType.Incomplete,
Fields: &ast.FieldList{
Opening: origStructType.Fields.Opening,
Closing: origStructType.Fields.Closing,
},
}

for _, field := range origStructType.Fields.List {
newField := &ast.Field{
Doc: field.Doc,
Names: field.Names,
Tag: field.Tag,
Comment: field.Comment,
}

newField.Type = resolveType(field.Type, field, genericParamTypeDefs)

newStructTypeDef.Fields.List = append(newStructTypeDef.Fields.List, newField)
}
newType := resolveGenericType(original.TypeSpec.Type, genericParamTypeDefs)

genericDefinitionsMutex.Lock()
defer genericDefinitionsMutex.Unlock()
parametrizedTypeSpec.TypeSpec.Type = newStructTypeDef
parametrizedTypeSpec.TypeSpec.Type = newType
if genericsDefinitions[original] == nil {
genericsDefinitions[original] = map[string]*TypeSpecDef{}
}
Expand Down Expand Up @@ -217,25 +197,50 @@ func splitStructName(fullGenericForm string) (string, []string) {
return genericTypeName, genericParams
}

func resolveType(expr ast.Expr, field *ast.Field, genericParamTypeDefs map[string]*genericTypeSpec) ast.Expr {
func resolveGenericType(expr ast.Expr, genericParamTypeDefs map[string]*genericTypeSpec) ast.Expr {
switch astExpr := expr.(type) {
case *ast.Ident:
if genTypeSpec, ok := genericParamTypeDefs[astExpr.Name]; ok {
if genTypeSpec.ArrayDepth > 0 {
genTypeSpec.ArrayDepth--
return &ast.ArrayType{Elt: resolveType(expr, field, genericParamTypeDefs)}
return &ast.ArrayType{Elt: resolveGenericType(expr, genericParamTypeDefs)}
}
return genTypeSpec.Type()
}
case *ast.ArrayType:
return &ast.ArrayType{
Elt: resolveType(astExpr.Elt, field, genericParamTypeDefs),
Elt: resolveGenericType(astExpr.Elt, genericParamTypeDefs),
Len: astExpr.Len,
Lbrack: astExpr.Lbrack,
}
}
case *ast.StructType:
newStructTypeDef := &ast.StructType{
Struct: astExpr.Struct,
Incomplete: astExpr.Incomplete,
Fields: &ast.FieldList{
Opening: astExpr.Fields.Opening,
Closing: astExpr.Fields.Closing,
},
}

for _, field := range astExpr.Fields.List {
newField := &ast.Field{
Doc: field.Doc,
Names: field.Names,
Tag: field.Tag,
Comment: field.Comment,
}

return field.Type
newField.Type = resolveGenericType(field.Type, genericParamTypeDefs)
if newField.Type == nil {
newField.Type = field.Type
}

newStructTypeDef.Fields.List = append(newStructTypeDef.Fields.List, newField)
}
return newStructTypeDef
}
return nil
}

func getExtendedGenericFieldType(file *ast.File, field ast.Expr) (string, error) {
Expand Down
4 changes: 2 additions & 2 deletions generics_other_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,10 @@ func TestParametrizeStruct(t *testing.T) {
},
}

tr := pd.parametrizeStruct(&ast.File{}, tSpec, "", false)
tr := pd.parametrizeGenericType(&ast.File{}, tSpec, "", false)
assert.Equal(t, tr, tSpec)

tr = pd.parametrizeStruct(&ast.File{}, tSpec, "", true)
tr = pd.parametrizeGenericType(&ast.File{}, tSpec, "", true)
assert.Equal(t, tr, tSpec)
}

Expand Down
12 changes: 6 additions & 6 deletions generics_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ func TestParametrizeStruct(t *testing.T) {
packages: make(map[string]*PackageDefinitions),
}
// valid
typeSpec := pd.parametrizeStruct(
typeSpec := pd.parametrizeGenericType(
&ast.File{Name: &ast.Ident{Name: "test2"}},
&TypeSpecDef{
TypeSpec: &ast.TypeSpec{
Expand All @@ -119,7 +119,7 @@ func TestParametrizeStruct(t *testing.T) {
assert.Equal(t, "$test.Field-string-array_string", typeSpec.Name())

// definition contains one type params, but two type params are provided
typeSpec = pd.parametrizeStruct(
typeSpec = pd.parametrizeGenericType(
&ast.File{Name: &ast.Ident{Name: "test2"}},
&TypeSpecDef{
TypeSpec: &ast.TypeSpec{
Expand All @@ -130,7 +130,7 @@ func TestParametrizeStruct(t *testing.T) {
assert.Nil(t, typeSpec)

// definition contains two type params, but only one is used
typeSpec = pd.parametrizeStruct(
typeSpec = pd.parametrizeGenericType(
&ast.File{Name: &ast.Ident{Name: "test2"}},
&TypeSpecDef{
TypeSpec: &ast.TypeSpec{
Expand All @@ -141,7 +141,7 @@ func TestParametrizeStruct(t *testing.T) {
assert.Nil(t, typeSpec)

// name is not a valid type name
typeSpec = pd.parametrizeStruct(
typeSpec = pd.parametrizeGenericType(
&ast.File{Name: &ast.Ident{Name: "test2"}},
&TypeSpecDef{
TypeSpec: &ast.TypeSpec{
Expand All @@ -151,7 +151,7 @@ func TestParametrizeStruct(t *testing.T) {
}}, "test.Field[string", false)
assert.Nil(t, typeSpec)

typeSpec = pd.parametrizeStruct(
typeSpec = pd.parametrizeGenericType(
&ast.File{Name: &ast.Ident{Name: "test2"}},
&TypeSpecDef{
TypeSpec: &ast.TypeSpec{
Expand All @@ -161,7 +161,7 @@ func TestParametrizeStruct(t *testing.T) {
}}, "test.Field[string, [string]", false)
assert.Nil(t, typeSpec)

typeSpec = pd.parametrizeStruct(
typeSpec = pd.parametrizeGenericType(
&ast.File{Name: &ast.Ident{Name: "test2"}},
&TypeSpecDef{
TypeSpec: &ast.TypeSpec{
Expand Down
2 changes: 1 addition & 1 deletion packages.go
Original file line number Diff line number Diff line change
Expand Up @@ -432,7 +432,7 @@ func (pkgDefs *PackagesDefinitions) findGenericTypeSpec(typeName string, file *a
}

if strings.Contains(tName, genericName) {
if parametrized := pkgDefs.parametrizeStruct(file, tSpec, typeName, parseDependency); parametrized != nil {
if parametrized := pkgDefs.parametrizeGenericType(file, tSpec, typeName, parseDependency); parametrized != nil {
return parametrized
}
}
Expand Down
4 changes: 4 additions & 0 deletions testdata/generics_property/api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,17 @@ type NestedResponse struct {
Post types.Field[[]types.Post]
}

type Audience[T any] []T

type CreateMovie struct {
Name string
MainActor types.Field[Person]
SupportingCast types.Field[[]Person]
Directors types.Field[*[]Person]
CameraPeople types.Field[[]*Person]
Producer types.Field[*Person]
Audience Audience[Person]
AudienceNames Audience[string]
}

type Person struct {
Expand Down
12 changes: 12 additions & 0 deletions testdata/generics_property/expected.json
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,18 @@
"api.CreateMovie": {
"type": "object",
"properties": {
"audience": {
"type": "array",
"items": {
"$ref": "#/definitions/api.Person"
}
},
"audienceNames": {
"type": "array",
"items": {
"type": "string"
}
},
"cameraPeople": {
"$ref": "#/definitions/types.Field-array_api_Person"
},
Expand Down

0 comments on commit 424bbbf

Please sign in to comment.