// visitableType extracts the type information that we care about
// from typ. This handles named and anonymous types that are visitable.
visitableType extracts the type information that we care about
from typ. This handles named and anonymous types that are visitable.
// visitableType extracts the type information that we care about // from typ . This handles named and anonymous types that are visitable .
func (v *visitation) visitableType(typ types.Type, isReachable bool) (visitableType, bool) {
	switch t := typ.(type) {
	case *types.Named:
		if !t.Obj().Exported() || t.Obj().Pkg().Path() != v.packagePath {
			return nil, false
		}
		sourceName := SourceName(t.Obj().Name())
		if ret, ok := v.SourceTypes[sourceName]; ok {
			return ret, true
		}
		switch u := t.Underlying().(type) {
		case *types.Struct:
			ok := v.includeReachable && isReachable
			if !ok {
			outer:
				for _, filter := range v.filters {
					switch tFilter := filter.(type) {
					case namedStruct:
						if types.Identical(u, tFilter.Struct) {
							ok = true
							break outer
						}
					case namedInterfaceType:
						if types.Implements(t, tFilter.Interface) ||
							types.Implements(types.NewPointer(t), tFilter.Interface) {
							ok = true
							break outer
						}
					}
				}
			}
			if ok {
				ret := namedStruct{
					Named:  t,
					Struct: u,
					v:      v,
				}
				v.SourceTypes[sourceName] = ret
				v.ensureTypeID(ret)
				ret.Fields()
				return ret, true
			}
		case *types.Interface:
			ok := v.includeReachable && isReachable
			if !ok {
				for _, filter := range v.filters {
					if filterIntf, isIntf := filter.(namedInterfaceType); isIntf {
						if types.Implements(u, filterIntf.Interface) {
							ok = true
							break
						}
					}
				}
			}
			if ok {
				ret := namedInterfaceType{
					Named:     t,
					Interface: u,
					v:         v,
				}
				v.SourceTypes[sourceName] = ret
				v.ensureTypeID(ret)
				if isReachable && v.includeReachable {
					v.filters = append(v.filters, ret)
					v.populateGeneratedTypes([]*types.Scope{t.Obj().Parent()})
				}
				return ret, true
			}
		default:
			if under, ok := v.visitableType(u, isReachable); ok {
				ret := namedVisitableType{Named: t, Underlying: under}
				v.SourceTypes[sourceName] = ret
				return ret, true
			}
		}
	case *types.Pointer:
		if elem, ok := v.visitableType(t.Elem(), isReachable); ok {
			return pointerType{Elem: elem}, true
		}
	case *types.Slice:
		if elem, ok := v.visitableType(t.Elem(), isReachable); ok {
			return namedSliceType{Elem: elem}, true
		}
	}
	return nil, false
}
func ( v * visitation ) visitableType ( typ types . Type , isReachable bool ) ( visitableType , bool ) { switch t := typ . ( type ) { case * types . Named : if ! t . Obj ( ) . Exported ( ) || t . Obj ( ) . Pkg ( ) . Path ( ) != v . packagePath { return nil , false } sourceName := SourceName ( t . Obj ( ) . Name ( ) ) if ret , ok := v . SourceTypes [ sourceName ] ; ok { return ret , true } switch u := t . Underlying ( ) . ( type ) { case * types . Struct : ok := v . includeReachable && isReachable if ! ok { outer : for _ , filter := range v . filters { switch tFilter := filter . ( type ) { case namedStruct : if types . Identical ( u , tFilter . Struct ) { ok = true break outer } case namedInterfaceType : if types . Implements ( t , tFilter . Interface ) || types . Implements ( types . NewPointer ( t ) , tFilter . Interface ) { ok = true break outer } } } } if ok { ret := namedStruct { Named : t , Struct : u , v : v , } v . SourceTypes [ sourceName ] = ret v . ensureTypeID ( ret ) ret . Fields ( ) return ret , true } case * types . Interface : ok := v . includeReachable && isReachable if ! ok { for _ , filter := range v . filters { if filterIntf , isIntf := filter . ( namedInterfaceType ) ; isIntf { if types . Implements ( u , filterIntf . Interface ) { ok = true break } } } } if ok { ret := namedInterfaceType { Named : t , Interface : u , v : v , } v . SourceTypes [ sourceName ] = ret v . ensureTypeID ( ret ) if isReachable && v . includeReachable { v . filters = append ( v . filters , ret ) v . populateGeneratedTypes ( [ ] * types . Scope { t . Obj ( ) . Parent ( ) } ) } return ret , true } default : if under , ok := v . visitableType ( u , isReachable ) ; ok { ret := namedVisitableType { Named : t , Underlying : under } v . SourceTypes [ sourceName ] = ret return ret , true } } case * types . Pointer : if elem , ok := v . visitableType ( t . Elem ( ) , isReachable ) ; ok { return pointerType { Elem : elem } , true } case * types . Slice : if elem , ok := v . visitableType ( t . Elem ( ) , isReachable ) ; ok { return namedSliceType { Elem : elem } , true } } return nil , false }
visitableType extracts the type information that we care about
from typ.
visitableType extracts the type information that we care about from typ .
// Ignore un-exported types or those from other packages. // If we've added an interface because it's reachable, we need // to also go back and look for any structs that may be implied // by the interface. // Any other named visitable type: type Foos []Foo