From 8445e75d6f3521daeec9d3195faa1916b09c34c6 Mon Sep 17 00:00:00 2001 From: sdghchj Date: Tue, 21 Mar 2023 06:34:11 +0800 Subject: [PATCH] fix generic type that has more than 2 params with only one constraint type (#1506) * fix generic type that has more than 2 params with only one constraint type * modify test unit Signed-off-by: sdghchj --------- Signed-off-by: sdghchj --- generics.go | 26 +++++++++++++++++++++----- testdata/generics_basic/api/api.go | 8 ++++++++ testdata/generics_basic/expected.json | 20 ++++++++++++++++++++ 3 files changed, 49 insertions(+), 5 deletions(-) diff --git a/generics.go b/generics.go index 8a64cd389..c14b3ab01 100644 --- a/generics.go +++ b/generics.go @@ -19,6 +19,11 @@ type genericTypeSpec struct { Name string } +type formalParamType struct { + Name string + Type string +} + func (t *genericTypeSpec) TypeName() string { if t.TypeSpec != nil { return t.TypeSpec.TypeName() @@ -36,10 +41,21 @@ func (pkgDefs *PackagesDefinitions) parametrizeGenericType(file *ast.File, origi return nil } - genericParamTypeDefs := map[string]*genericTypeSpec{} - if len(genericParams) != len(original.TypeSpec.TypeParams.List) { + //generic[x,y any,z any] considered, TODO what if the type is not `any`, but a concrete one, such as `int32|int64` or an certain interface{} + var formals []formalParamType + for _, field := range original.TypeSpec.TypeParams.List { + for _, ident := range field.Names { + formal := formalParamType{Name: ident.Name} + if ident, ok := field.Type.(*ast.Ident); ok { + formal.Type = ident.Name + } + formals = append(formals, formal) + } + } + if len(genericParams) != len(formals) { return nil } + genericParamTypeDefs := map[string]*genericTypeSpec{} for i, genericParam := range genericParams { arrayDepth := 0 @@ -59,7 +75,7 @@ func (pkgDefs *PackagesDefinitions) parametrizeGenericType(file *ast.File, origi } } - genericParamTypeDefs[original.TypeSpec.TypeParams.List[i].Names[0].Name] = &genericTypeSpec{ + genericParamTypeDefs[formals[i].Name] = &genericTypeSpec{ ArrayDepth: arrayDepth, TypeSpec: typeDef, Name: genericParam, @@ -68,8 +84,8 @@ func (pkgDefs *PackagesDefinitions) parametrizeGenericType(file *ast.File, origi name = fmt.Sprintf("%s%s-", string(IgnoreNameOverridePrefix), original.TypeName()) var nameParts []string - for _, def := range original.TypeSpec.TypeParams.List { - if specDef, ok := genericParamTypeDefs[def.Names[0].Name]; ok { + for _, def := range formals { + if specDef, ok := genericParamTypeDefs[def.Name]; ok { var prefix = "" if specDef.ArrayDepth == 1 { prefix = "array_" diff --git a/testdata/generics_basic/api/api.go b/testdata/generics_basic/api/api.go index 629d4ecb6..eecd72f03 100644 --- a/testdata/generics_basic/api/api.go +++ b/testdata/generics_basic/api/api.go @@ -14,6 +14,13 @@ type Response[T any, X any] struct { Status string } +type Response2[T, X any, Y any] struct { + Data T + Meta X + + Status Y +} + type StringStruct struct { Data string } @@ -31,6 +38,7 @@ type Foo = web.GenericResponseMulti[types.Post, types.Post] // @Success 203 {object} web.GenericResponse[types.Field[int]] // @Success 204 {object} Response[string, types.Field[int]] // @Success 205 {object} Response[StringStruct, types.Field[int]] +// @Success 206 {object} Response2[string, types.Field[int],string] // @Success 222 {object} web.GenericResponseMulti[types.Post, types.Post] // @Failure 400 {object} web.APIError "We need ID!!" // @Failure 404 {object} web.APIError "Can not find ID" diff --git a/testdata/generics_basic/expected.json b/testdata/generics_basic/expected.json index 6eca46ed9..ac5ecc222 100644 --- a/testdata/generics_basic/expected.json +++ b/testdata/generics_basic/expected.json @@ -165,6 +165,12 @@ "$ref": "#/definitions/api.Response-api_StringStruct-types_Field-int" } }, + "206": { + "description": "Partial Content", + "schema": { + "$ref": "#/definitions/api.Response2-string-types_Field-int-string" + } + }, "222": { "description": "", "schema": { @@ -230,6 +236,20 @@ } } }, + "api.Response2-string-types_Field-int-string": { + "type": "object", + "properties": { + "data": { + "type": "string" + }, + "meta": { + "$ref": "#/definitions/types.Field-int" + }, + "status": { + "type": "string" + } + } + }, "api.StringStruct": { "type": "object", "properties": {