(c *Cache, parentEmbed *structData, name string)
| 38 | } |
| 39 | |
| 40 | func (s *structData) structField(c *Cache, parentEmbed *structData, name string) *structField { |
| 41 | if s.fields == nil { |
| 42 | if s.numField > 0 { |
| 43 | s.fields = make(map[string]*structField, s.numField) |
| 44 | } |
| 45 | } else if f := s.fields[name]; f != nil { |
| 46 | return f |
| 47 | } |
| 48 | if s.finished() { |
| 49 | return nil |
| 50 | } |
| 51 | |
| 52 | // Lookup own fields first. |
| 53 | for ; s.ownIdx < s.numField; s.ownIdx++ { |
| 54 | field := s.rType.Field(s.ownIdx) |
| 55 | if field.Anonymous && s.anonIdx < 0 { |
| 56 | // start iterating anon fields on the first instead of zero |
| 57 | s.anonIdx = s.ownIdx |
| 58 | } |
| 59 | if !field.IsExported() { |
| 60 | continue |
| 61 | } |
| 62 | fName, ok := fieldName(field.Name, field.Tag) |
| 63 | if !ok || fName == "" { |
| 64 | // name can still be empty for a type created at runtime with |
| 65 | // reflect |
| 66 | continue |
| 67 | } |
| 68 | nt := c.FromType(field.Type) |
| 69 | sf := &structField{ |
| 70 | Nature: nt, |
| 71 | Index: field.Index, |
| 72 | } |
| 73 | s.fields[fName] = sf |
| 74 | if parentEmbed != nil { |
| 75 | parentEmbed.trySet(fName, sf) |
| 76 | } |
| 77 | if fName == name { |
| 78 | return sf |
| 79 | } |
| 80 | } |
| 81 | |
| 82 | if s.curChild != nil { |
| 83 | sf := s.findInEmbedded(c, parentEmbed, s.curChild, s.curChildIndex, name) |
| 84 | if sf != nil { |
| 85 | return sf |
| 86 | } |
| 87 | } |
| 88 | |
| 89 | // Lookup embedded fields through anon own fields |
| 90 | for ; s.anonIdx >= 0 && s.anonIdx < s.numField; s.anonIdx++ { |
| 91 | field := s.rType.Field(s.anonIdx) |
| 92 | // we do enter embedded non-exported types because they could contain |
| 93 | // exported fields |
| 94 | if !field.Anonymous { |
| 95 | continue |
| 96 | } |
| 97 | t, k, _ := deref.TypeKind(field.Type, field.Type.Kind()) |
no test coverage detected