github.com/powerman/golang-tools@v0.1.11-0.20220410185822-5ad214d8d803/internal/apidiff/messageset.go (about)

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