diff --git a/Makefile b/Makefile index be245c6..2ad10c1 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,5 @@ APP_NAME := godedup OUTPUT := $(APP_NAME) -COV_REPORT := coverage.txt INSTALL_DIR := /usr/local/bin ifeq ($(OS),Windows_NT) diff --git a/internal/hash/hash.go b/internal/hash/hash.go index 9a806e4..f8f21b4 100644 --- a/internal/hash/hash.go +++ b/internal/hash/hash.go @@ -11,7 +11,7 @@ import ( "go/ast" "go/token" - "github.com/hashmap-kz/godedup/internal/wrapx" + "github.com/hashmap-kz/godedup/internal/x/convx" ) // FuncInfo holds the hashing result for a single function. @@ -139,7 +139,7 @@ func (h *Hasher) hashNode(node ast.Node) uint64 { case *ast.AssignStmt: return combine(nodeID("AssignStmt"), - wrapx.ToUint64(n.Tok), // = vs := + convx.ToUint64(n.Tok), // = vs := h.hashExprList(n.Lhs), h.hashExprList(n.Rhs), ) @@ -155,7 +155,7 @@ func (h *Hasher) hashNode(node ast.Node) uint64 { for _, s := range n.Specs { specs = append(specs, h.hashNode(s)) } - return combine(nodeID("GenDecl"), wrapx.ToUint64(n.Tok), hashUint64Slice(specs)) + return combine(nodeID("GenDecl"), convx.ToUint64(n.Tok), hashUint64Slice(specs)) case *ast.ValueSpec: return combine(nodeID("ValueSpec"), @@ -164,7 +164,7 @@ func (h *Hasher) hashNode(node ast.Node) uint64 { ) case *ast.IncDecStmt: - return combine(nodeID("IncDecStmt"), wrapx.ToUint64(n.Tok), h.hashNode(n.X)) + return combine(nodeID("IncDecStmt"), convx.ToUint64(n.Tok), h.hashNode(n.X)) case *ast.SendStmt: return combine(nodeID("SendStmt"), @@ -179,7 +179,7 @@ func (h *Hasher) hashNode(node ast.Node) uint64 { return combine(nodeID("DeferStmt"), h.hashNode(n.Call)) case *ast.BranchStmt: - return combine(nodeID("BranchStmt"), wrapx.ToUint64(n.Tok)) + return combine(nodeID("BranchStmt"), convx.ToUint64(n.Tok)) case *ast.LabeledStmt: // normalize away label name @@ -202,17 +202,17 @@ func (h *Hasher) hashNode(node ast.Node) uint64 { case *ast.BasicLit: // normalize: all literals of the same kind hash the same - return combine(nodeID("BasicLit"), wrapx.ToUint64(n.Kind)) + return combine(nodeID("BasicLit"), convx.ToUint64(n.Kind)) case *ast.BinaryExpr: return combine(nodeID("BinaryExpr"), - wrapx.ToUint64(n.Op), + convx.ToUint64(n.Op), h.hashNode(n.X), h.hashNode(n.Y), ) case *ast.UnaryExpr: - return combine(nodeID("UnaryExpr"), wrapx.ToUint64(n.Op), h.hashNode(n.X)) + return combine(nodeID("UnaryExpr"), convx.ToUint64(n.Op), h.hashNode(n.X)) case *ast.CallExpr: return combine(nodeID("CallExpr"), @@ -277,7 +277,7 @@ func (h *Hasher) hashNode(node ast.Node) uint64 { ) case *ast.ChanType: - return combine(nodeID("ChanType"), wrapx.ToUint64(n.Dir), h.hashNode(n.Value)) + return combine(nodeID("ChanType"), convx.ToUint64(n.Dir), h.hashNode(n.Value)) case *ast.InterfaceType: return nodeID("InterfaceType") diff --git a/internal/report/report.go b/internal/report/report.go index eb7a2ff..8955f00 100644 --- a/internal/report/report.go +++ b/internal/report/report.go @@ -6,7 +6,7 @@ import ( "sort" "strings" - "github.com/hashmap-kz/godedup/internal/wrapx" + "github.com/hashmap-kz/godedup/internal/x/fmtx" "github.com/hashmap-kz/godedup/internal/hash" ) @@ -175,7 +175,7 @@ func sortClones(clones []Clone) { // Print writes a human-readable report to w. func Print(w io.Writer, clones []Clone, cwd string) { if len(clones) == 0 { - wrapx.Fprintln(w, "godedup: no structural duplicates found") + fmtx.Fprintln(w, "godedup: no structural duplicates found") return } @@ -189,7 +189,7 @@ func Print(w io.Writer, clones []Clone, cwd string) { } } - wrapx.Fprintf(w, "godedup: found %d clone group(s) (%d exact, %d near)\n\n", + fmtx.Fprintf(w, "godedup: found %d clone group(s) (%d exact, %d near)\n\n", len(clones), exact, near) for i, clone := range clones { @@ -200,7 +200,7 @@ func Print(w io.Writer, clones []Clone, cwd string) { simStr = fmt.Sprintf("%.0f%%", clone.Similarity*100) } - wrapx.Fprintf(w, "=== clone group %d [%s %s similarity] ===\n", + fmtx.Fprintf(w, "=== clone group %d [%s %s similarity] ===\n", i+1, kind, simStr) // sort functions by file+line for stable output @@ -215,38 +215,38 @@ func Print(w io.Writer, clones []Clone, cwd string) { for _, f := range sorted { relPath := relativePath(f.File, cwd) - wrapx.Fprintf(w, " %s\n", f.Name) - wrapx.Fprintf(w, " %s:%d (%d stmts, %d lines)\n", + fmtx.Fprintf(w, " %s\n", f.Name) + fmtx.Fprintf(w, " %s:%d (%d stmts, %d lines)\n", relPath, f.Line, f.NumStmts, f.NumLines) } - wrapx.Fprintln(w) + fmtx.Fprintln(w) } - wrapx.Fprintf(w, "suggestion: extract shared logic into a common function\n") - wrapx.Fprintf(w, " or use generics if types differ\n") + fmtx.Fprintf(w, "suggestion: extract shared logic into a common function\n") + fmtx.Fprintf(w, " or use generics if types differ\n") } // PrintJSON writes machine-readable JSON output. func PrintJSON(w io.Writer, clones []Clone) { - wrapx.Fprintln(w, "[") + fmtx.Fprintln(w, "[") for i, clone := range clones { - wrapx.Fprintf(w, ` {"exact":%v,"similarity":%.2f,"functions":[`, + fmtx.Fprintf(w, ` {"exact":%v,"similarity":%.2f,"functions":[`, clone.Exact, clone.Similarity) for j, f := range clone.Funcs { if j > 0 { - wrapx.Fprint(w, ",") + fmtx.Fprint(w, ",") } - wrapx.Fprintf(w, `{"name":%q,"file":%q,"line":%d,"stmts":%d}`, + fmtx.Fprintf(w, `{"name":%q,"file":%q,"line":%d,"stmts":%d}`, f.Name, f.File, f.Line, f.NumStmts) } - wrapx.Fprint(w, "]}") + fmtx.Fprint(w, "]}") if i < len(clones)-1 { - wrapx.Fprintln(w, ",") + fmtx.Fprintln(w, ",") } else { - wrapx.Fprintln(w) + fmtx.Fprintln(w) } } - wrapx.Fprintln(w, "]") + fmtx.Fprintln(w, "]") } func relativePath(path, cwd string) string { @@ -264,7 +264,7 @@ func relativePath(path, cwd string) string { // Columns: GROUP TYPE SIM FUNCTION LOCATION STMTS LINES func PrintTable(w io.Writer, clones []Clone, cwd string) { if len(clones) == 0 { - wrapx.Fprintln(w, "godedup: no structural duplicates found") + fmtx.Fprintln(w, "godedup: no structural duplicates found") return } @@ -344,7 +344,7 @@ func PrintTable(w io.Writer, clones []Clone, cwd string) { } // header - wrapx.Fprintln(w, fmtRow(headers)) + fmtx.Fprintln(w, fmtRow(headers)) // separator using only dashes sep := "" @@ -352,15 +352,15 @@ func PrintTable(w io.Writer, clones []Clone, cwd string) { for i := 0; i < total; i++ { sep += "-" } - wrapx.Fprintln(w, sep) + fmtx.Fprintln(w, sep) // rows: emit the separator between groups prevGroup := "" for _, r := range rows { if prevGroup != "" && r.group != prevGroup { - wrapx.Fprintln(w, sep) + fmtx.Fprintln(w, sep) } - wrapx.Fprintln(w, fmtRow(r)) + fmtx.Fprintln(w, fmtRow(r)) prevGroup = r.group } } diff --git a/internal/wrapx/safeconv.go b/internal/x/convx/safeconv.go similarity index 91% rename from internal/wrapx/safeconv.go rename to internal/x/convx/safeconv.go index 3da6cec..750202e 100644 --- a/internal/wrapx/safeconv.go +++ b/internal/x/convx/safeconv.go @@ -1,4 +1,4 @@ -package wrapx +package convx type Integer interface { ~int | ~int8 | ~int16 | ~int32 | ~int64 diff --git a/internal/wrapx/print.go b/internal/x/fmtx/print.go similarity index 94% rename from internal/wrapx/print.go rename to internal/x/fmtx/print.go index 94c09ef..877fc33 100644 --- a/internal/wrapx/print.go +++ b/internal/x/fmtx/print.go @@ -1,4 +1,4 @@ -package wrapx +package fmtx import ( "fmt" diff --git a/main.go b/main.go index aed331f..98c6719 100644 --- a/main.go +++ b/main.go @@ -5,9 +5,10 @@ import ( "fmt" "os" + "github.com/hashmap-kz/godedup/internal/x/fmtx" + "github.com/hashmap-kz/godedup/internal/load" "github.com/hashmap-kz/godedup/internal/report" - "github.com/hashmap-kz/godedup/internal/wrapx" ) var Version = "dev" @@ -40,9 +41,9 @@ func main() { showVer := flag.Bool("version", false, "print version and exit") flag.Usage = func() { - wrapx.Fprint(os.Stderr, usage) + fmtx.Fprint(os.Stderr, usage) flag.PrintDefaults() - wrapx.Fprintln(os.Stderr) + fmtx.Fprintln(os.Stderr) } flag.Parse() @@ -55,7 +56,7 @@ func main() { case "text", "table", "json": // valid default: - wrapx.Fprintf(os.Stderr, "godedup: unknown output format %q (want: text, table, json)\n", *output) + fmtx.Fprintf(os.Stderr, "godedup: unknown output format %q (want: text, table, json)\n", *output) os.Exit(1) } @@ -68,12 +69,12 @@ func main() { result, err := load.Load(paths, *noTests) if err != nil { - wrapx.Fprintf(os.Stderr, "godedup: load error: %v\n", err) + fmtx.Fprintf(os.Stderr, "godedup: load error: %v\n", err) os.Exit(1) } if len(result.Funcs) == 0 { - wrapx.Fprintln(os.Stderr, "godedup: no functions found") + fmtx.Fprintln(os.Stderr, "godedup: no functions found") os.Exit(0) }