in gotype/fold_reflect.go [339:415]
func makeResolveNonEmptyValue(st reflect.Type) func(reflect.Value) (reflect.Value, bool) {
type resolver func(reflect.Value) (reflect.Value, bool)
resolveBySize := func(v reflect.Value) (reflect.Value, bool) {
return v, v.Len() > 0
}
resolveIsZeroer := func(v reflect.Value) (reflect.Value, bool) {
empty := v.Interface().(IsZeroer).IsZero()
return v, !empty
}
resolveIsZeroerPtr := func(v reflect.Value) (reflect.Value, bool) {
if v.CanAddr() {
return resolveIsZeroer(v.Addr())
}
tmp := reflect.New(v.Type())
tmp.Elem().Set(v)
return resolveIsZeroer(tmp)
}
resolveInterfaceLazy := func(v reflect.Value) (reflect.Value, bool) {
if v.IsNil() {
return v, false
}
// Find potential resolver based on interface element type.
// If no resolver is found, the value seems to be ok and should be reported.
elem := v.Elem()
resolver := makeResolveNonEmptyValue(elem.Type())
if resolver == nil {
return v, true // report, as v does not seem special
}
return resolver(v.Elem())
}
var resolvers []resolver
for {
switch st.Kind() {
case reflect.Ptr:
var r resolver
st, r = makeResolvePointers(st)
resolvers = append(resolvers, r)
continue
case reflect.Interface:
resolvers = append(resolvers, resolveInterfaceLazy)
case reflect.Map, reflect.String, reflect.Slice, reflect.Array:
resolvers = append(resolvers, resolveBySize)
default:
if implementsIsZeroer(st) {
resolvers = append(resolvers, resolveIsZeroer)
} else if implementsPtrIsZeroer(st) {
resolvers = append(resolvers, resolveIsZeroerPtr)
}
}
break
}
if len(resolvers) == 0 {
return nil
}
if len(resolvers) == 1 {
return resolvers[0]
}
return func(v reflect.Value) (reflect.Value, bool) {
for _, r := range resolvers {
var ok bool
if v, ok = r(v); !ok {
return v, ok
}
}
return v, true
}
}