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
 | 
						|
}
 |