github.com/jd-ly/tools@v0.5.7/internal/apidiff/messageset.go (about)

     1  // TODO: show that two-non-empty dotjoin can happen, by using an anon struct as a field type
     2  // TODO: don't report removed/changed methods for both value and pointer method sets?
     3  
     4  package apidiff
     5  
     6  import (
     7  	"fmt"
     8  	"go/types"
     9  	"sort"
    10  	"strings"
    11  )
    12  
    13  // There can be at most one message for each object or part thereof.
    14  // Parts include interface methods and struct fields.
    15  //
    16  // The part thing is necessary. Method (Func) objects have sufficient info, but field
    17  // Vars do not: they just have a field name and a type, without the enclosing struct.
    18  type messageSet map[types.Object]map[string]string
    19  
    20  // Add a message for obj and part, overwriting a previous message
    21  // (shouldn't happen).
    22  // obj is required but part can be empty.
    23  func (m messageSet) add(obj types.Object, part, msg string) {
    24  	s := m[obj]
    25  	if s == nil {
    26  		s = map[string]string{}
    27  		m[obj] = s
    28  	}
    29  	if f, ok := s[part]; ok && f != msg {
    30  		fmt.Printf("! second, different message for obj %s, part %q\n", obj, part)
    31  		fmt.Printf("  first:  %s\n", f)
    32  		fmt.Printf("  second: %s\n", msg)
    33  	}
    34  	s[part] = msg
    35  }
    36  
    37  func (m messageSet) collect() []string {
    38  	var s []string
    39  	for obj, parts := range m {
    40  		// Format each object name relative to its own package.
    41  		objstring := objectString(obj)
    42  		for part, msg := range parts {
    43  			var p string
    44  
    45  			if strings.HasPrefix(part, ",") {
    46  				p = objstring + part
    47  			} else {
    48  				p = dotjoin(objstring, part)
    49  			}
    50  			s = append(s, p+": "+msg)
    51  		}
    52  	}
    53  	sort.Strings(s)
    54  	return s
    55  }
    56  
    57  func objectString(obj types.Object) string {
    58  	if f, ok := obj.(*types.Func); ok {
    59  		sig := f.Type().(*types.Signature)
    60  		if recv := sig.Recv(); recv != nil {
    61  			tn := types.TypeString(recv.Type(), types.RelativeTo(obj.Pkg()))
    62  			if tn[0] == '*' {
    63  				tn = "(" + tn + ")"
    64  			}
    65  			return fmt.Sprintf("%s.%s", tn, obj.Name())
    66  		}
    67  	}
    68  	return obj.Name()
    69  }
    70  
    71  func dotjoin(s1, s2 string) string {
    72  	if s1 == "" {
    73  		return s2
    74  	}
    75  	if s2 == "" {
    76  		return s1
    77  	}
    78  	return s1 + "." + s2
    79  }