// Copyright 2021 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package reflect

// VisibleFields returns all the visible fields in t, which must be a
// struct type. A field is defined as visible if it's accessible
// directly with a FieldByName call. The returned fields include fields
// inside anonymous struct members and unexported fields. They follow
// the same order found in the struct, with anonymous fields followed
// immediately by their promoted fields.
//
// For each element e of the returned slice, the corresponding field
// can be retrieved from a value v of type t by calling v.FieldByIndex(e.Index).
func ( Type) []StructField {
	if  == nil {
		panic("reflect: VisibleFields(nil)")
	}
	if .Kind() != Struct {
		panic("reflect.VisibleFields of non-struct type")
	}
	 := &visibleFieldsWalker{
		byName:   make(map[string]int),
		visiting: make(map[Type]bool),
		fields:   make([]StructField, 0, .NumField()),
		index:    make([]int, 0, 2),
	}
	.walk()
	// Remove all the fields that have been hidden.
	// Use an in-place removal that avoids copying in
	// the common case that there are no hidden fields.
	 := 0
	for  := range .fields {
		 := &.fields[]
		if .Name == "" {
			continue
		}
		if  !=  {
			// A field has been removed. We need to shuffle
			// all the subsequent elements up.
			.fields[] = *
		}
		++
	}
	return .fields[:]
}

type visibleFieldsWalker struct {
	byName   map[string]int
	visiting map[Type]bool
	fields   []StructField
	index    []int
}

// walk walks all the fields in the struct type t, visiting
// fields in index preorder and appending them to w.fields
// (this maintains the required ordering).
// Fields that have been overridden have their
// Name field cleared.
func ( *visibleFieldsWalker) ( Type) {
	if .visiting[] {
		return
	}
	.visiting[] = true
	for  := 0;  < .NumField(); ++ {
		 := .Field()
		.index = append(.index, )
		 := true
		if ,  := .byName[.Name];  {
			 := &.fields[]
			if len(.index) == len(.Index) {
				// Fields with the same name at the same depth
				// cancel one another out. Set the field name
				// to empty to signify that has happened, and
				// there's no need to add this field.
				.Name = ""
				 = false
			} else if len(.index) < len(.Index) {
				// The old field loses because it's deeper than the new one.
				.Name = ""
			} else {
				// The old field wins because it's shallower than the new one.
				 = false
			}
		}
		if  {
			// Copy the index so that it's not overwritten
			// by the other appends.
			.Index = append([]int(nil), .index...)
			.byName[.Name] = len(.fields)
			.fields = append(.fields, )
		}
		if .Anonymous {
			if .Type.Kind() == Pointer {
				.Type = .Type.Elem()
			}
			if .Type.Kind() == Struct {
				.(.Type)
			}
		}
		.index = .index[:len(.index)-1]
	}
	delete(.visiting, )
}