|
@@ -0,0 +1,72 @@
|
|
|
|
|
+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)
|
|
|
|
|
+ }
|
|
|
|
|
+}
|