package main import ( "fmt" "go/ast" "go/parser" "go/token" "os" "path/filepath" "strings" ) // ControllerCommentChecker Controller注释检查器 type ControllerCommentChecker struct { errors []string } // NewControllerCommentChecker 创建检查器实例 func NewControllerCommentChecker() *ControllerCommentChecker { return &ControllerCommentChecker{ errors: make([]string, 0), } } // CheckFile 检查单个文件 func (c *ControllerCommentChecker) CheckFile(filePath string) error { fset := token.NewFileSet() node, err := parser.ParseFile(fset, filePath, nil, parser.ParseComments) if err != nil { return fmt.Errorf("解析文件失败: %v", err) } // 检查是否是Controller文件 if !strings.Contains(filePath, "controller") { return nil } // 遍历AST节点 ast.Inspect(node, func(n ast.Node) bool { switch x := n.(type) { case *ast.FuncDecl: // 检查Controller方法 if c.isControllerMethod(x) { c.checkMethodComments(x, filePath) } } return true }) return nil } // isControllerMethod 判断是否是Controller方法 func (c *ControllerCommentChecker) isControllerMethod(fn *ast.FuncDecl) bool { // 检查方法接收者 if fn.Recv == nil || len(fn.Recv.List) == 0 { return false } // 检查接收者类型是否包含Controller recvType := fn.Recv.List[0].Type if starExpr, ok := recvType.(*ast.StarExpr); ok { if ident, ok := starExpr.X.(*ast.Ident); ok { return strings.Contains(ident.Name, "Controller") } } return false } // checkMethodComments 检查方法注释 func (c *ControllerCommentChecker) checkMethodComments(fn *ast.FuncDecl, filePath string) { if fn.Doc == nil { c.errors = append(c.errors, fmt.Sprintf("%s:%d 方法 %s 缺少注释", filePath, fn.Pos(), fn.Name.Name)) return } commentText := fn.Doc.Text() requiredTags := []string{"@Summary", "@Description", "@Tags", "@Router"} for _, tag := range requiredTags { if !strings.Contains(commentText, tag) { c.errors = append(c.errors, fmt.Sprintf("%s:%d 方法 %s 缺少 %s 注释", filePath, fn.Pos(), fn.Name.Name, tag)) } } // 检查中文描述 if !c.containsChinese(commentText) { c.errors = append(c.errors, fmt.Sprintf("%s:%d 方法 %s 注释应包含中文描述", filePath, fn.Pos(), fn.Name.Name)) } } // containsChinese 检查是否包含中文字符 func (c *ControllerCommentChecker) containsChinese(text string) bool { for _, r := range text { if r >= 0x4e00 && r <= 0x9fff { return true } } return false } // CheckDirectory 检查目录下的所有Controller文件 func (c *ControllerCommentChecker) CheckDirectory(dir string) error { return filepath.Walk(dir, func(path string, info os.FileInfo, err error) error { if err != nil { return err } if !info.IsDir() && strings.HasSuffix(path, ".go") { return c.CheckFile(path) } return nil }) } // GetErrors 获取检查错误 func (c *ControllerCommentChecker) GetErrors() []string { return c.errors } // PrintReport 打印检查报告 func (c *ControllerCommentChecker) PrintReport() { if len(c.errors) == 0 { fmt.Println("✅ 所有Controller方法注释检查通过") return } fmt.Printf("❌ 发现 %d 个注释问题:\n", len(c.errors)) for i, err := range c.errors { fmt.Printf("%d. %s\n", i+1, err) } } func main() { if len(os.Args) < 2 { fmt.Println("用法: go run check_controller_comments.go ") fmt.Println("示例: go run check_controller_comments.go ./internal/auth/controller") os.Exit(1) } dir := os.Args[1] checker := NewControllerCommentChecker() fmt.Printf("🔍 检查目录: %s\n", dir) if err := checker.CheckDirectory(dir); err != nil { fmt.Printf("❌ 检查失败: %v\n", err) os.Exit(1) } checker.PrintReport() if len(checker.GetErrors()) > 0 { os.Exit(1) } }