435c0d9fc8
This PR switches the Nomad repository from using govendor to Go modules for managing dependencies. Aspects of the Nomad workflow remain pretty much the same. The usual Makefile targets should continue to work as they always did. The API submodule simply defers to the parent Nomad version on the repository, keeping the semantics of API versioning that currently exists.
80 lines
1.9 KiB
Go
80 lines
1.9 KiB
Go
// 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 apidiff
|
|
|
|
import (
|
|
"fmt"
|
|
"go/types"
|
|
"sort"
|
|
"strings"
|
|
)
|
|
|
|
// 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.
|
|
type messageSet map[types.Object]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 (m messageSet) add(obj types.Object, part, msg string) {
|
|
s := m[obj]
|
|
if s == nil {
|
|
s = map[string]string{}
|
|
m[obj] = s
|
|
}
|
|
if f, ok := s[part]; ok && f != msg {
|
|
fmt.Printf("! second, different message for obj %s, part %q\n", obj, part)
|
|
fmt.Printf(" first: %s\n", f)
|
|
fmt.Printf(" second: %s\n", msg)
|
|
}
|
|
s[part] = msg
|
|
}
|
|
|
|
func (m messageSet) collect() []string {
|
|
var s []string
|
|
for obj, parts := range m {
|
|
// Format each object name relative to its own package.
|
|
objstring := objectString(obj)
|
|
for part, msg := range parts {
|
|
var p string
|
|
|
|
if strings.HasPrefix(part, ",") {
|
|
p = objstring + part
|
|
} else {
|
|
p = dotjoin(objstring, part)
|
|
}
|
|
s = append(s, p+": "+msg)
|
|
}
|
|
}
|
|
sort.Strings(s)
|
|
return s
|
|
}
|
|
|
|
func objectString(obj types.Object) string {
|
|
if f, ok := obj.(*types.Func); ok {
|
|
sig := f.Type().(*types.Signature)
|
|
if recv := sig.Recv(); recv != nil {
|
|
tn := types.TypeString(recv.Type(), types.RelativeTo(obj.Pkg()))
|
|
if tn[0] == '*' {
|
|
tn = "(" + tn + ")"
|
|
}
|
|
return fmt.Sprintf("%s.%s", tn, obj.Name())
|
|
}
|
|
}
|
|
return obj.Name()
|
|
}
|
|
|
|
func dotjoin(s1, s2 string) string {
|
|
if s1 == "" {
|
|
return s2
|
|
}
|
|
if s2 == "" {
|
|
return s1
|
|
}
|
|
return s1 + "." + s2
|
|
}
|