internal/breakings: type strings for functions Remove arg and return value names from function signatures. Change-Id: Ifb3a63f35d0942c69c42ac46eb37e6146a6a6964 Reviewed-on: https://go-review.googlesource.com/c/pkgsite/+/813944 Reviewed-by: Ethan Lee <ethanalee@google.com> TryBot-Bypass: Jonathan Amsterdam <jba@google.com> LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
diff --git a/internal/breakings/api.go b/internal/breakings/api.go index 90169dc..aa285e4 100644 --- a/internal/breakings/api.go +++ b/internal/breakings/api.go
@@ -12,16 +12,65 @@ "go/ast" "go/printer" "go/token" + "strings" ) // typeString returns a string for the given type expression that represents the type. // If two such strings are equal, then the corresponding types are equal. // typeString returns "?" if typeExpr is nil. func typeString(typeExpr ast.Expr) string { - if typeExpr == nil { + switch t := typeExpr.(type) { + case nil: return "?" + case *ast.FuncType: + return "func" + sigString(t) + default: + return nodeString(t) } - return nodeString(typeExpr) +} + +// sigString returns a string representation of a function signature +// without parameter or return names (e.g., "(int, int) bool"). +func sigString(ft *ast.FuncType) string { + if ft == nil { + return "" + } + paramTypes := fieldListTypes(ft.Params) + resTypes := fieldListTypes(ft.Results) + + var buf strings.Builder + buf.WriteString("(") + buf.WriteString(strings.Join(paramTypes, ", ")) + buf.WriteString(")") + + if len(resTypes) == 1 { + buf.WriteString(" ") + buf.WriteString(resTypes[0]) + } else if len(resTypes) > 1 { + buf.WriteString(" (") + buf.WriteString(strings.Join(resTypes, ", ")) + buf.WriteString(")") + } + return buf.String() +} + +// fieldListTypes returns the types of a field list, ignoring the field names. +// Note that "field" here means more than just a struct field: it could be +// the arguments or return values of a function. +func fieldListTypes(fl *ast.FieldList) []string { + if fl == nil { + return nil + } + var typeStrings []string + for _, f := range fl.List { + // convert "x, y, z T", to "T, T, T" + n := max(1, len(f.Names)) + tstr := typeString(f.Type) + for i := 0; i < n; i++ { + typeStrings = append(typeStrings, tstr) + } + } + return typeStrings } // nodeString returns a string for node.
diff --git a/internal/breakings/api_test.go b/internal/breakings/api_test.go index 4a4aa88..049163e 100644 --- a/internal/breakings/api_test.go +++ b/internal/breakings/api_test.go
@@ -24,8 +24,7 @@ {"<-chan int", "<-chan int"}, {"func()", "func()"}, {"func(int, int) bool", "func(int, int) bool"}, - // FIX: remove argument names - // {"func(a, b int) (c bool)", "func(int, int) bool"}, + {"func(a, b int) (c bool, _ int)", "func(int, int) (bool, int)"}, } for _, tc := range testCases {