@@ -117,7 +117,7 @@ func (c *cache) get(t reflect.Type) *structInfo {
117117 info := c .m [t ]
118118 c .l .RUnlock ()
119119 if info == nil {
120- info = c .create (t , nil )
120+ info = c .create (t , "" )
121121 c .l .Lock ()
122122 c .m [t ] = info
123123 c .l .Unlock ()
@@ -126,37 +126,40 @@ func (c *cache) get(t reflect.Type) *structInfo {
126126}
127127
128128// create creates a structInfo with meta-data about a struct.
129- func (c * cache ) create (t reflect.Type , info * structInfo ) * structInfo {
130- if info == nil {
131- info = & structInfo {fields : []* fieldInfo {}}
132- }
129+ func (c * cache ) create (t reflect.Type , parentAlias string ) * structInfo {
130+ info := & structInfo {}
131+ var anonymousInfos []* structInfo
133132 for i := 0 ; i < t .NumField (); i ++ {
134- field := t .Field (i )
135- if field .Anonymous {
136- ft := field .Type
137- if ft .Kind () == reflect .Ptr {
138- ft = ft .Elem ()
133+ if f := c .createField (t .Field (i ), parentAlias ); f != nil {
134+ info .fields = append (info .fields , f )
135+ if ft := indirectType (f .typ ); ft .Kind () == reflect .Struct && f .isAnonymous {
136+ anonymousInfos = append (anonymousInfos , c .create (ft , f .canonicalAlias ))
139137 }
140- if ft .Kind () == reflect .Struct {
141- bef := len (info .fields )
142- c .create (ft , info )
143- for _ , fi := range info .fields [bef :len (info .fields )] {
144- // exclude required check because duplicated to embedded field
145- fi .isRequired = false
146- }
138+ }
139+ }
140+ for i , a := range anonymousInfos {
141+ others := []* structInfo {info }
142+ others = append (others , anonymousInfos [:i ]... )
143+ others = append (others , anonymousInfos [i + 1 :]... )
144+ for _ , f := range a .fields {
145+ if ! containsAlias (others , f .alias ) {
146+ info .fields = append (info .fields , f )
147147 }
148148 }
149- c .createField (field , info )
150149 }
151150 return info
152151}
153152
154153// createField creates a fieldInfo for the given field.
155- func (c * cache ) createField (field reflect.StructField , info * structInfo ) {
154+ func (c * cache ) createField (field reflect.StructField , parentAlias string ) * fieldInfo {
156155 alias , options := fieldAlias (field , c .tag )
157156 if alias == "-" {
158157 // Ignore this field.
159- return
158+ return nil
159+ }
160+ canonicalAlias := alias
161+ if parentAlias != "" {
162+ canonicalAlias = parentAlias + "." + alias
160163 }
161164 // Check if the type is supported and don't cache it if not.
162165 // First let's get the basic type.
@@ -181,19 +184,20 @@ func (c *cache) createField(field reflect.StructField, info *structInfo) {
181184 if isStruct = ft .Kind () == reflect .Struct ; ! isStruct {
182185 if c .converter (ft ) == nil && builtinConverters [ft .Kind ()] == nil {
183186 // Type is not supported.
184- return
187+ return nil
185188 }
186189 }
187190
188- info . fields = append ( info . fields , & fieldInfo {
191+ return & fieldInfo {
189192 typ : field .Type ,
190193 name : field .Name ,
191194 alias : alias ,
195+ canonicalAlias : canonicalAlias ,
192196 unmarshalerInfo : m ,
193197 isSliceOfStructs : isSlice && isStruct ,
194198 isAnonymous : field .Anonymous ,
195199 isRequired : options .Contains ("required" ),
196- })
200+ }
197201}
198202
199203// converter returns the converter for a type.
@@ -216,11 +220,26 @@ func (i *structInfo) get(alias string) *fieldInfo {
216220 return nil
217221}
218222
223+ func containsAlias (infos []* structInfo , alias string ) bool {
224+ for _ , info := range infos {
225+ if info .get (alias ) != nil {
226+ return true
227+ }
228+ }
229+ return false
230+ }
231+
219232type fieldInfo struct {
220233 typ reflect.Type
221234 // name is the field name in the struct.
222235 name string
223236 alias string
237+ // canonicalAlias is almost the same as the alias, but is prefixed with
238+ // an embedded struct field alias in dotted notation if this field is
239+ // promoted from the struct.
240+ // For instance, if the alias is "N" and this field is an embedded field
241+ // in a struct "X", canonicalAlias will be "X.N".
242+ canonicalAlias string
224243 // unmarshalerInfo contains information regarding the
225244 // encoding.TextUnmarshaler implementation of the field type.
226245 unmarshalerInfo unmarshaler
@@ -231,6 +250,13 @@ type fieldInfo struct {
231250 isRequired bool
232251}
233252
253+ func (f * fieldInfo ) paths (prefix string ) []string {
254+ if f .alias == f .canonicalAlias {
255+ return []string {prefix + f .alias }
256+ }
257+ return []string {prefix + f .alias , prefix + f .canonicalAlias }
258+ }
259+
234260type pathPart struct {
235261 field * fieldInfo
236262 path []string // path to the field: walks structs using field names.
@@ -239,6 +265,13 @@ type pathPart struct {
239265
240266// ----------------------------------------------------------------------------
241267
268+ func indirectType (typ reflect.Type ) reflect.Type {
269+ if typ .Kind () == reflect .Ptr {
270+ return typ .Elem ()
271+ }
272+ return typ
273+ }
274+
242275// fieldAlias parses a field tag to get a field alias.
243276func fieldAlias (field reflect.StructField , tagName string ) (alias string , options tagOptions ) {
244277 if tag := field .Tag .Get (tagName ); tag != "" {
0 commit comments