// Returns which field index is an embedded storable.Document, or -1 if none. func (p *Processor) processFields(s *types.Struct, done []*types.Struct) (base int, fields []*Field) { c := s.NumFields() base = -1 fields = make([]*Field, 0) for i := 0; i < c; i++ { f := s.Field(i) if !f.Exported() { continue } t := reflect.StructTag(s.Tag(i)) if f.Type().String() == BaseDocument { base = i } field := NewField(f.Name(), f.Type().Underlying().String(), t) field.CheckedNode = f str := p.tryGetStruct(f.Type()) if f.Type().String() != BaseDocument && str != nil { field.Type = getStructType(f.Type()) d := false for _, v := range done { if v == str { d = true break } } if !d { _, subfs := p.processFields(str, append(done, str)) field.SetFields(subfs) } } fields = append(fields, field) } return base, fields }
//iterate over a struct's fields recursively and add its fields to the candidate list func findStructFields(str *types.Struct, prefix string, fset *token.FileSet) []UnexportCandidate { candidates := []UnexportCandidate{} for i := 0; i < str.NumFields(); i++ { field := str.Field(i) if !field.Exported() || field.Anonymous() { continue } // Tags are a likely indicator that this field is used by something // like json or xml that uses reflection. Skip it to be safe. // TODO: override flag? whitelist? if str.Tag(i) != "" { continue } candidate := UnexportCandidate{field.Name(), prefix + "." + field.Name(), fset.Position(field.Pos())} candidates = append(candidates, candidate) if nested, ok := field.Type().(*types.Struct); ok { candidates = append(candidates, findStructFields(nested, candidate.DisplayName, fset)...) } } return candidates }
func Struct(path string, st reflect.StructTag, u *types.Struct, named *types.Named) IObj { rv := IStruct{} rv.name = strings.Split(st.Get("json"), ",")[0] rv.typ = getname(named, u) rv.description = st.Get("description") rv.path = pathAppend(path, rv.name) for i := 0; i < u.NumFields(); i++ { rv2 := dump(rv.path, u.Field(i).Type(), reflect.StructTag(u.Tag(i))) if rv2 == nil { continue } if st, ok := rv2.(IStruct); ok && st.name == "" { for _, j := range st.items { rv.items = append(rv.items, j) } } else { rv.items = append(rv.items, rv2) } } return rv }
func (p *Processor) processFields(s *types.Struct) int { c := s.NumFields() base := -1 fields := make([]*Field, 0) if _, ok := p.fieldsForStr[s]; !ok { p.fieldsForStr[s] = &fields } for i := 0; i < c; i++ { f := s.Field(i) if !f.Exported() { continue } t := reflect.StructTag(s.Tag(i)) if f.Type().String() == BaseDocument { base = i } field := NewField(f.Name(), f.Type().Underlying().String(), t) str := p.tryGetStruct(f.Type()) if f.Type().String() != BaseDocument && str != nil { field.Type = getStructType(f.Type()) field.CheckedNode = f _, ok := p.fieldsForStr[str] if !ok { p.processFields(str) } } fields = append(fields, field) } return base }