Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
APP_NAME := godedup
OUTPUT := $(APP_NAME)
COV_REPORT := coverage.txt
INSTALL_DIR := /usr/local/bin

ifeq ($(OS),Windows_NT)
Expand Down
18 changes: 9 additions & 9 deletions internal/hash/hash.go
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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),
)
Expand All @@ -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"),
Expand All @@ -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"),
Expand All @@ -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
Expand All @@ -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"),
Expand Down Expand Up @@ -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")
Expand Down
44 changes: 22 additions & 22 deletions internal/report/report.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
)
Expand Down Expand Up @@ -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
}

Expand All @@ -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 {
Expand All @@ -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
Expand All @@ -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 {
Expand All @@ -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
}

Expand Down Expand Up @@ -344,23 +344,23 @@ 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 := ""
total := widths[0] + widths[1] + widths[2] + widths[3] + widths[4] + widths[5] + widths[6] + 12
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
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package wrapx
package convx

type Integer interface {
~int | ~int8 | ~int16 | ~int32 | ~int64
Expand Down
2 changes: 1 addition & 1 deletion internal/wrapx/print.go → internal/x/fmtx/print.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package wrapx
package fmtx

import (
"fmt"
Expand Down
13 changes: 7 additions & 6 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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()

Expand All @@ -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)
}

Expand All @@ -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)
}

Expand Down