package main import ( "go/ast" "go/parser" "go/token" "path/filepath" "strings" "testing" ) // TestNoDeadFunctions 用 AST 精确检查包内是否存在"定义了但从未被引用"的函数/方法。 // 相比文本 grep:AST 只统计标识符,不会把字符串或注释里的同名文字误判为引用。 // main / init 豁免(由运行时调用)。发现问题即测试失败,作为长期质量门禁。 // // 注意:本文件刻意不用任何带反斜杠的字符串字面量(逐条 Errorf 代替拼接换行), // 以免"转义序列"在生成/复制过程中被破坏。 func TestNoDeadFunctions(t *testing.T) { fset := token.NewFileSet() files, err := filepath.Glob("*.go") if err != nil { t.Fatalf("扫描源文件失败: %v", err) } defs := map[string]string{} // 函数名 -> 定义位置 counts := map[string]int{} // 标识符出现次数(含测试文件) for _, path := range files { if strings.HasSuffix(path, "_test.go") { continue } file, err := parser.ParseFile(fset, path, nil, 0) if err != nil { t.Fatalf("解析 %s 失败: %v", path, err) } for _, decl := range file.Decls { fn, ok := decl.(*ast.FuncDecl) if !ok { continue } name := fn.Name.Name if name == "main" || name == "init" { continue } defs[name] = fset.Position(fn.Pos()).String() } } for _, path := range files { file, err := parser.ParseFile(fset, path, nil, 0) if err != nil { continue } ast.Inspect(file, func(n ast.Node) bool { if id, ok := n.(*ast.Ident); ok { counts[id.Name]++ } return true }) } deadCount := 0 for name, where := range defs { if counts[name] <= 1 { // 仅定义处出现 => 从未被引用 deadCount++ t.Errorf("未被引用的函数: %s (%s)", name, where) } } if deadCount > 0 { t.Errorf("共 %d 个函数未被引用(建议删除,保持最小)", deadCount) } }