// TODO: show that two-non-empty dotjoin can happen, by using an anon struct as a field type// TODO: don't report removed/changed methods for both value and pointer method sets?package apidiffimport ()// objectWithSide contains an object, and information on which side (old or new)// of the comparison it relates to. This matters when need to express the object's// package path, relative to the root path of the comparison, as the old and new// sides can have different roots (e.g. comparing somepackage/v2 vs. somepackage/v3).typeobjectWithSidestruct {objecttypes.ObjectisNewbool}// There can be at most one message for each object or part thereof.// Parts include interface methods and struct fields.//// The part thing is necessary. Method (Func) objects have sufficient info, but field// Vars do not: they just have a field name and a type, without the enclosing struct.typemessageSetmap[objectWithSide]map[string]string// Add a message for obj and part, overwriting a previous message// (shouldn't happen).// obj is required but part can be empty.func ( messageSet) ( objectWithSide, , string) { := []if == nil { = map[string]string{} [] = }if , := []; && != {fmt.Printf("! second, different message for obj %s, isNew %v, part %q\n", .object, .isNew, )fmt.Printf(" first: %s\n", )fmt.Printf(" second: %s\n", ) } [] = }func ( messageSet) (, string) []string {var []stringfor , := range { := if .isNew { = }// Format each object name relative to its own package. := objectString(.object, )for , := range {varstringifstrings.HasPrefix(, ",") { = + } else { = dotjoin(, ) } = append(, +": "+) } }sort.Strings()return}func ( types.Object, string) string { := .Pkg().Path()varstringif == {// obj is in same package as the diff operation root - no prefix = "" } elseifstrings.HasPrefix(, +"/") {// obj is in a child package compared to the diff operation root - use a // prefix starting with "./" to emphasise the relative nature = "./" + [len()+1:] + "." } else {// obj is outside the diff operation root - display full path. This can // happen if there is a need to report a change in a type in an unrelated // package, because it has been used as the underlying type in a type // definition in the package being processed, for example. = + "." }if , := .(*types.Func); { := .Type().(*types.Signature)if := .Recv(); != nil { := types.TypeString(.Type(), types.RelativeTo(.Pkg()))if [0] == '*' { = "(" + + ")" }returnfmt.Sprintf("%s%s.%s", , , .Name()) } }returnfmt.Sprintf("%s%s", , .Name())}func (, string) string {if == "" {return }if == "" {return }return + "." + }
The pages are generated with Goldsv0.7.6. (GOOS=linux GOARCH=amd64)