fix(goctl): multi imports the api cause redeclared error in types.go (#3988)

Co-authored-by: Kevin Wan <wanjunfeng@gmail.com>
This commit is contained in:
Jayson Wang
2024-04-04 19:39:24 +08:00
committed by GitHub
parent b20ec8aedb
commit f138cc792e
6 changed files with 98 additions and 12 deletions

View File

@@ -2,7 +2,12 @@ package gogen
import (
_ "embed"
"go/ast"
goformat "go/format"
"go/importer"
goparser "go/parser"
"go/token"
"go/types"
"os"
"path/filepath"
"strings"
@@ -48,6 +53,10 @@ var (
noStructTagApi string
//go:embed testdata/nest_type_api.api
nestTypeApi string
//go:embed testdata/import_twice.api
importTwiceApi string
//go:embed testdata/another_import_api.api
anotherImportApi string
)
func TestParser(t *testing.T) {
@@ -232,6 +241,46 @@ func TestHasImportApi(t *testing.T) {
validate(t, filename)
}
func TestImportTwiceOnExperimental(t *testing.T) {
defaultExperimental := env.Get(env.GoctlExperimental)
env.Set(t, env.GoctlExperimental, "on")
defer env.Set(t, env.GoctlExperimental, defaultExperimental)
filename := "greet.api"
err := os.WriteFile(filename, []byte(importTwiceApi), os.ModePerm)
assert.Nil(t, err)
defer os.Remove(filename)
importApiName := "importApi.api"
err = os.WriteFile(importApiName, []byte(importApi), os.ModePerm)
assert.Nil(t, err)
defer os.Remove(importApiName)
hasImportApiName := "hasImportApi.api"
err = os.WriteFile(hasImportApiName, []byte(hasImportApi), os.ModePerm)
assert.Nil(t, err)
defer os.Remove(hasImportApiName)
anotherImportApiName := "anotherImportApi.api"
err = os.WriteFile(anotherImportApiName, []byte(anotherImportApi), os.ModePerm)
assert.Nil(t, err)
defer os.Remove(anotherImportApiName)
api, err := parser.Parse(filename)
assert.Nil(t, err)
var hasInline bool
for _, ty := range api.Types {
if ty.Name() == "ImportData" {
hasInline = true
break
}
}
assert.True(t, hasInline)
validate(t, filename)
}
func TestNoStructApi(t *testing.T) {
filename := "greet.api"
err := os.WriteFile(filename, []byte(noStructTagApi), os.ModePerm)
@@ -287,6 +336,9 @@ func validateWithCamel(t *testing.T, api, camel string) {
code, err := os.ReadFile(path)
assert.Nil(t, err)
assert.Nil(t, validateCode(string(code)))
if strings.HasSuffix(path, "types.go") {
assert.Nil(t, checkRedeclaredType(string(code)))
}
}
return nil
})
@@ -301,3 +353,20 @@ func validateCode(code string) error {
_, err := goformat.Source([]byte(code))
return err
}
func checkRedeclaredType(code string) error {
fset := token.NewFileSet()
f, err := goparser.ParseFile(fset, "", code, goparser.ParseComments)
if err != nil {
return err
}
conf := types.Config{
Error: func(err error) {},
Importer: importer.Default(),
}
info := types.Info{Types: make(map[ast.Expr]types.TypeAndValue)}
_, err = conf.Check(f.Name.Name, fset, []*ast.File{f}, &info)
return err
}

View File

@@ -0,0 +1,17 @@
import "importApi.api"
type AnotherRequest {
Name string `path:"name,options=you|me"`
}
type AnotherResponse {
Message string `json:"message"` // message
}
@server(
group: greet
)
service A-api {
@handler AnotherImportHandler
get /greet/from/another/:name(AnotherRequest) returns (AnotherResponse)
}

View File

@@ -1,16 +1,17 @@
import "importApi.api"
type Request struct {
type Request {
Name string `path:"name,options=you|me"`
}
type Response struct {
type Response {
Message string `json:"message"` // message
}
@server(
group: greet
)
service A-api {
@server(
handler: GreetHandler
)
@handler GreetHandler
get /greet/from/:name(Request) returns (Response)
}
}

View File

@@ -1,3 +1,3 @@
type ImportData struct {
type ImportData {
Name string `path:"name,options=you|me"`
}
}

View File

@@ -0,0 +1,2 @@
import "hasImportApi.api"
import "anotherImportApi.api"

View File

@@ -32,11 +32,8 @@ type API struct {
func convert2API(a *ast.AST, importSet map[string]lang.PlaceholderType, is *importstack.ImportStack) (*API, error) {
var api = new(API)
api.importManager = is
api.importSet = make(map[string]lang.PlaceholderType)
api.importSet = importSet
api.Filename = a.Filename
for k, v := range importSet {
api.importSet[k] = v
}
one := a.Stmts[0]
syntax, ok := one.(*ast.SyntaxStmt)
if !ok {