mirror of
https://github.com/zeromicro/go-zero.git
synced 2026-05-07 15:10:01 +08:00
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:
@@ -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
|
||||
}
|
||||
|
||||
17
tools/goctl/api/gogen/testdata/another_import_api.api
vendored
Normal file
17
tools/goctl/api/gogen/testdata/another_import_api.api
vendored
Normal 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)
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
type ImportData struct {
|
||||
type ImportData {
|
||||
Name string `path:"name,options=you|me"`
|
||||
}
|
||||
}
|
||||
|
||||
2
tools/goctl/api/gogen/testdata/import_twice.api
vendored
Normal file
2
tools/goctl/api/gogen/testdata/import_twice.api
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
import "hasImportApi.api"
|
||||
import "anotherImportApi.api"
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user