...

Source file src/github.com/google/go-cmp/cmp/internal/value/name.go

Documentation: github.com/google/go-cmp/cmp/internal/value

     1  // Copyright 2020, 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  package value
     6  
     7  import (
     8  	"reflect"
     9  	"strconv"
    10  )
    11  
    12  var anyType = reflect.TypeOf((*interface{})(nil)).Elem()
    13  
    14  // TypeString is nearly identical to reflect.Type.String,
    15  // but has an additional option to specify that full type names be used.
    16  func TypeString(t reflect.Type, qualified bool) string {
    17  	return string(appendTypeName(nil, t, qualified, false))
    18  }
    19  
    20  func appendTypeName(b []byte, t reflect.Type, qualified, elideFunc bool) []byte {
    21  	// BUG: Go reflection provides no way to disambiguate two named types
    22  	// of the same name and within the same package,
    23  	// but declared within the namespace of different functions.
    24  
    25  	// Use the "any" alias instead of "interface{}" for better readability.
    26  	if t == anyType {
    27  		return append(b, "any"...)
    28  	}
    29  
    30  	// Named type.
    31  	if t.Name() != "" {
    32  		if qualified && t.PkgPath() != "" {
    33  			b = append(b, '"')
    34  			b = append(b, t.PkgPath()...)
    35  			b = append(b, '"')
    36  			b = append(b, '.')
    37  			b = append(b, t.Name()...)
    38  		} else {
    39  			b = append(b, t.String()...)
    40  		}
    41  		return b
    42  	}
    43  
    44  	// Unnamed type.
    45  	switch k := t.Kind(); k {
    46  	case reflect.Bool, reflect.String, reflect.UnsafePointer,
    47  		reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
    48  		reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr,
    49  		reflect.Float32, reflect.Float64, reflect.Complex64, reflect.Complex128:
    50  		b = append(b, k.String()...)
    51  	case reflect.Chan:
    52  		if t.ChanDir() == reflect.RecvDir {
    53  			b = append(b, "<-"...)
    54  		}
    55  		b = append(b, "chan"...)
    56  		if t.ChanDir() == reflect.SendDir {
    57  			b = append(b, "<-"...)
    58  		}
    59  		b = append(b, ' ')
    60  		b = appendTypeName(b, t.Elem(), qualified, false)
    61  	case reflect.Func:
    62  		if !elideFunc {
    63  			b = append(b, "func"...)
    64  		}
    65  		b = append(b, '(')
    66  		for i := 0; i < t.NumIn(); i++ {
    67  			if i > 0 {
    68  				b = append(b, ", "...)
    69  			}
    70  			if i == t.NumIn()-1 && t.IsVariadic() {
    71  				b = append(b, "..."...)
    72  				b = appendTypeName(b, t.In(i).Elem(), qualified, false)
    73  			} else {
    74  				b = appendTypeName(b, t.In(i), qualified, false)
    75  			}
    76  		}
    77  		b = append(b, ')')
    78  		switch t.NumOut() {
    79  		case 0:
    80  			// Do nothing
    81  		case 1:
    82  			b = append(b, ' ')
    83  			b = appendTypeName(b, t.Out(0), qualified, false)
    84  		default:
    85  			b = append(b, " ("...)
    86  			for i := 0; i < t.NumOut(); i++ {
    87  				if i > 0 {
    88  					b = append(b, ", "...)
    89  				}
    90  				b = appendTypeName(b, t.Out(i), qualified, false)
    91  			}
    92  			b = append(b, ')')
    93  		}
    94  	case reflect.Struct:
    95  		b = append(b, "struct{ "...)
    96  		for i := 0; i < t.NumField(); i++ {
    97  			if i > 0 {
    98  				b = append(b, "; "...)
    99  			}
   100  			sf := t.Field(i)
   101  			if !sf.Anonymous {
   102  				if qualified && sf.PkgPath != "" {
   103  					b = append(b, '"')
   104  					b = append(b, sf.PkgPath...)
   105  					b = append(b, '"')
   106  					b = append(b, '.')
   107  				}
   108  				b = append(b, sf.Name...)
   109  				b = append(b, ' ')
   110  			}
   111  			b = appendTypeName(b, sf.Type, qualified, false)
   112  			if sf.Tag != "" {
   113  				b = append(b, ' ')
   114  				b = strconv.AppendQuote(b, string(sf.Tag))
   115  			}
   116  		}
   117  		if b[len(b)-1] == ' ' {
   118  			b = b[:len(b)-1]
   119  		} else {
   120  			b = append(b, ' ')
   121  		}
   122  		b = append(b, '}')
   123  	case reflect.Slice, reflect.Array:
   124  		b = append(b, '[')
   125  		if k == reflect.Array {
   126  			b = strconv.AppendUint(b, uint64(t.Len()), 10)
   127  		}
   128  		b = append(b, ']')
   129  		b = appendTypeName(b, t.Elem(), qualified, false)
   130  	case reflect.Map:
   131  		b = append(b, "map["...)
   132  		b = appendTypeName(b, t.Key(), qualified, false)
   133  		b = append(b, ']')
   134  		b = appendTypeName(b, t.Elem(), qualified, false)
   135  	case reflect.Ptr:
   136  		b = append(b, '*')
   137  		b = appendTypeName(b, t.Elem(), qualified, false)
   138  	case reflect.Interface:
   139  		b = append(b, "interface{ "...)
   140  		for i := 0; i < t.NumMethod(); i++ {
   141  			if i > 0 {
   142  				b = append(b, "; "...)
   143  			}
   144  			m := t.Method(i)
   145  			if qualified && m.PkgPath != "" {
   146  				b = append(b, '"')
   147  				b = append(b, m.PkgPath...)
   148  				b = append(b, '"')
   149  				b = append(b, '.')
   150  			}
   151  			b = append(b, m.Name...)
   152  			b = appendTypeName(b, m.Type, qualified, true)
   153  		}
   154  		if b[len(b)-1] == ' ' {
   155  			b = b[:len(b)-1]
   156  		} else {
   157  			b = append(b, ' ')
   158  		}
   159  		b = append(b, '}')
   160  	default:
   161  		panic("invalid kind: " + k.String())
   162  	}
   163  	return b
   164  }
   165  

View as plain text