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 }