fix(gf/gen): Fixed a problem that could cause duplication when generating wit… (#4268)

Fixed #4217

---------

Co-authored-by: hailaz <739476267@qq.com>
This commit is contained in:
DustScribe
2025-12-27 20:48:15 +08:00
committed by GitHub
parent 6334ee1958
commit d091547212

View File

@ -8,6 +8,9 @@ package genctrl
import (
"fmt"
"go/ast"
"go/parser"
"go/token"
"path/filepath"
"strings"
@ -144,8 +147,8 @@ func (c *controllerGenerator) doGenerateCtrlItem(dstModuleFolderPath string, ite
"{MethodName}": item.MethodName,
"{MethodComment}": item.GetComment(),
})
if gstr.Contains(gfile.GetContents(methodFilePath), fmt.Sprintf(`func (c *%v) %v(`, ctrlName, item.MethodName)) {
// Use AST-based checking for more accurate method detection
if methodExists(methodFilePath, ctrlName, item.MethodName) {
return
}
if err = gfile.PutContentsAppend(methodFilePath, gstr.TrimLeft(content)); err != nil {
@ -170,7 +173,6 @@ func (c *controllerGenerator) doGenerateCtrlItem(dstModuleFolderPath string, ite
// use -merge
func (c *controllerGenerator) doGenerateCtrlMergeItem(dstModuleFolderPath string, apiItems []apiItem, doneApiSet *gset.StrSet) (err error) {
type controllerFileItem struct {
module string
version string
@ -193,13 +195,23 @@ func (c *controllerGenerator) doGenerateCtrlMergeItem(dstModuleFolderPath string
ctrlFileItemMap[api.FileName] = ctrlFileItem
}
ctrlName := fmt.Sprintf(`Controller%s`, gstr.UcFirst(api.Version))
ctrl := gstr.TrimLeft(gstr.ReplaceByMap(consts.TemplateGenCtrlControllerMethodFuncMerge, g.MapStrStr{
"{Module}": api.Module,
"{CtrlName}": fmt.Sprintf(`Controller%s`, gstr.UcFirst(api.Version)),
"{CtrlName}": ctrlName,
"{Version}": api.Version,
"{MethodName}": api.MethodName,
"{MethodComment}": api.GetComment(),
}))
ctrlFilePath := gfile.Join(dstModuleFolderPath, fmt.Sprintf(
`%s_%s_%s.go`, ctrlFileItem.module, ctrlFileItem.version, api.FileName,
))
// Use AST-based checking for more accurate method detection
if methodExists(ctrlFilePath, ctrlName, api.MethodName) {
return
}
ctrlFileItem.controllers.WriteString(ctrl)
doneApiSet.Add(api.String())
}
@ -229,3 +241,41 @@ func (c *controllerGenerator) doGenerateCtrlMergeItem(dstModuleFolderPath string
}
return
}
// methodExists checks if a method with the given receiver type and name exists in the file.
// It uses AST parsing to accurately detect method definitions regardless of formatting.
// This handles various code formatting styles including multi-line method signatures.
func methodExists(filePath, ctrlName, methodName string) bool {
fset := token.NewFileSet()
node, err := parser.ParseFile(fset, filePath, nil, parser.ParseComments)
if err != nil {
// If parsing fails (e.g., file doesn't exist or invalid syntax), return false
return false
}
for _, decl := range node.Decls {
funcDecl, ok := decl.(*ast.FuncDecl)
if !ok {
continue
}
// Check if it's a method (has receiver)
if funcDecl.Recv != nil && len(funcDecl.Recv.List) > 0 {
// Extract receiver type name
// Handle both *T and T patterns
recvType := ""
switch t := funcDecl.Recv.List[0].Type.(type) {
case *ast.StarExpr:
if ident, ok := t.X.(*ast.Ident); ok {
recvType = ident.Name
}
case *ast.Ident:
recvType = t.Name
}
// Check if both receiver type and method name match
if recvType == ctrlName && funcDecl.Name.Name == methodName {
return true
}
}
}
return false
}