From 424bbbfb613646a8b95837bf951b7146f6634b89 Mon Sep 17 00:00:00 2001 From: sdghchj Date: Fri, 14 Oct 2022 18:45:00 +0800 Subject: [PATCH 1/2] fix issue #1346 about generics Signed-off-by: sdghchj --- generics.go | 63 +++++++++++++----------- generics_other_test.go | 4 +- generics_test.go | 12 ++--- packages.go | 2 +- testdata/generics_property/api/api.go | 4 ++ testdata/generics_property/expected.json | 12 +++++ 6 files changed, 59 insertions(+), 38 deletions(-) diff --git a/generics.go b/generics.go index c42518916..45cb426a9 100644 --- a/generics.go +++ b/generics.go @@ -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() @@ -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, @@ -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{} } @@ -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) { diff --git a/generics_other_test.go b/generics_other_test.go index fafe2e2f2..f9c9a3f8c 100644 --- a/generics_other_test.go +++ b/generics_other_test.go @@ -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) } diff --git a/generics_test.go b/generics_test.go index b92fc6bb1..44b7cd24c 100644 --- a/generics_test.go +++ b/generics_test.go @@ -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{ @@ -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{ @@ -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{ @@ -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{ @@ -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{ @@ -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{ diff --git a/packages.go b/packages.go index 402ee7c89..39048ac62 100644 --- a/packages.go +++ b/packages.go @@ -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 } } diff --git a/testdata/generics_property/api/api.go b/testdata/generics_property/api/api.go index 8f45eee8c..4c0ceb80c 100644 --- a/testdata/generics_property/api/api.go +++ b/testdata/generics_property/api/api.go @@ -11,6 +11,8 @@ type NestedResponse struct { Post types.Field[[]types.Post] } +type Audience[T any] []T + type CreateMovie struct { Name string MainActor types.Field[Person] @@ -18,6 +20,8 @@ type CreateMovie struct { Directors types.Field[*[]Person] CameraPeople types.Field[[]*Person] Producer types.Field[*Person] + Audience Audience[Person] + AudienceNames Audience[string] } type Person struct { diff --git a/testdata/generics_property/expected.json b/testdata/generics_property/expected.json index 65b394e5b..237159d82 100644 --- a/testdata/generics_property/expected.json +++ b/testdata/generics_property/expected.json @@ -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" }, From 56c074eac8150b3392f1e5c82f424b012793d195 Mon Sep 17 00:00:00 2001 From: sdghchj Date: Sat, 15 Oct 2022 11:58:29 +0800 Subject: [PATCH 2/2] fix issue #1346 about generics --- generics_other.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/generics_other.go b/generics_other.go index ddfca85b9..43acc9577 100644 --- a/generics_other.go +++ b/generics_other.go @@ -13,7 +13,7 @@ func typeSpecFullName(typeSpecDef *TypeSpecDef) string { return typeSpecDef.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 { return original }