...

Source file src/github.com/hashicorp/hcl/decoder.go

Documentation: github.com/hashicorp/hcl

     1  package hcl
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"reflect"
     7  	"sort"
     8  	"strconv"
     9  	"strings"
    10  
    11  	"github.com/hashicorp/hcl/hcl/ast"
    12  	"github.com/hashicorp/hcl/hcl/parser"
    13  	"github.com/hashicorp/hcl/hcl/token"
    14  )
    15  
    16  // This is the tag to use with structures to have settings for HCL
    17  const tagName = "hcl"
    18  
    19  var (
    20  	// nodeType holds a reference to the type of ast.Node
    21  	nodeType reflect.Type = findNodeType()
    22  )
    23  
    24  // Unmarshal accepts a byte slice as input and writes the
    25  // data to the value pointed to by v.
    26  func Unmarshal(bs []byte, v interface{}) error {
    27  	root, err := parse(bs)
    28  	if err != nil {
    29  		return err
    30  	}
    31  
    32  	return DecodeObject(v, root)
    33  }
    34  
    35  // Decode reads the given input and decodes it into the structure
    36  // given by `out`.
    37  func Decode(out interface{}, in string) error {
    38  	obj, err := Parse(in)
    39  	if err != nil {
    40  		return err
    41  	}
    42  
    43  	return DecodeObject(out, obj)
    44  }
    45  
    46  // DecodeObject is a lower-level version of Decode. It decodes a
    47  // raw Object into the given output.
    48  func DecodeObject(out interface{}, n ast.Node) error {
    49  	val := reflect.ValueOf(out)
    50  	if val.Kind() != reflect.Ptr {
    51  		return errors.New("result must be a pointer")
    52  	}
    53  
    54  	// If we have the file, we really decode the root node
    55  	if f, ok := n.(*ast.File); ok {
    56  		n = f.Node
    57  	}
    58  
    59  	var d decoder
    60  	return d.decode("root", n, val.Elem())
    61  }
    62  
    63  type decoder struct {
    64  	stack []reflect.Kind
    65  }
    66  
    67  func (d *decoder) decode(name string, node ast.Node, result reflect.Value) error {
    68  	k := result
    69  
    70  	// If we have an interface with a valid value, we use that
    71  	// for the check.
    72  	if result.Kind() == reflect.Interface {
    73  		elem := result.Elem()
    74  		if elem.IsValid() {
    75  			k = elem
    76  		}
    77  	}
    78  
    79  	// Push current onto stack unless it is an interface.
    80  	if k.Kind() != reflect.Interface {
    81  		d.stack = append(d.stack, k.Kind())
    82  
    83  		// Schedule a pop
    84  		defer func() {
    85  			d.stack = d.stack[:len(d.stack)-1]
    86  		}()
    87  	}
    88  
    89  	switch k.Kind() {
    90  	case reflect.Bool:
    91  		return d.decodeBool(name, node, result)
    92  	case reflect.Float32, reflect.Float64:
    93  		return d.decodeFloat(name, node, result)
    94  	case reflect.Int, reflect.Int32, reflect.Int64:
    95  		return d.decodeInt(name, node, result)
    96  	case reflect.Interface:
    97  		// When we see an interface, we make our own thing
    98  		return d.decodeInterface(name, node, result)
    99  	case reflect.Map:
   100  		return d.decodeMap(name, node, result)
   101  	case reflect.Ptr:
   102  		return d.decodePtr(name, node, result)
   103  	case reflect.Slice:
   104  		return d.decodeSlice(name, node, result)
   105  	case reflect.String:
   106  		return d.decodeString(name, node, result)
   107  	case reflect.Struct:
   108  		return d.decodeStruct(name, node, result)
   109  	default:
   110  		return &parser.PosError{
   111  			Pos: node.Pos(),
   112  			Err: fmt.Errorf("%s: unknown kind to decode into: %s", name, k.Kind()),
   113  		}
   114  	}
   115  }
   116  
   117  func (d *decoder) decodeBool(name string, node ast.Node, result reflect.Value) error {
   118  	switch n := node.(type) {
   119  	case *ast.LiteralType:
   120  		if n.Token.Type == token.BOOL {
   121  			v, err := strconv.ParseBool(n.Token.Text)
   122  			if err != nil {
   123  				return err
   124  			}
   125  
   126  			result.Set(reflect.ValueOf(v))
   127  			return nil
   128  		}
   129  	}
   130  
   131  	return &parser.PosError{
   132  		Pos: node.Pos(),
   133  		Err: fmt.Errorf("%s: unknown type %T", name, node),
   134  	}
   135  }
   136  
   137  func (d *decoder) decodeFloat(name string, node ast.Node, result reflect.Value) error {
   138  	switch n := node.(type) {
   139  	case *ast.LiteralType:
   140  		if n.Token.Type == token.FLOAT || n.Token.Type == token.NUMBER {
   141  			v, err := strconv.ParseFloat(n.Token.Text, 64)
   142  			if err != nil {
   143  				return err
   144  			}
   145  
   146  			result.Set(reflect.ValueOf(v).Convert(result.Type()))
   147  			return nil
   148  		}
   149  	}
   150  
   151  	return &parser.PosError{
   152  		Pos: node.Pos(),
   153  		Err: fmt.Errorf("%s: unknown type %T", name, node),
   154  	}
   155  }
   156  
   157  func (d *decoder) decodeInt(name string, node ast.Node, result reflect.Value) error {
   158  	switch n := node.(type) {
   159  	case *ast.LiteralType:
   160  		switch n.Token.Type {
   161  		case token.NUMBER:
   162  			v, err := strconv.ParseInt(n.Token.Text, 0, 0)
   163  			if err != nil {
   164  				return err
   165  			}
   166  
   167  			if result.Kind() == reflect.Interface {
   168  				result.Set(reflect.ValueOf(int(v)))
   169  			} else {
   170  				result.SetInt(v)
   171  			}
   172  			return nil
   173  		case token.STRING:
   174  			v, err := strconv.ParseInt(n.Token.Value().(string), 0, 0)
   175  			if err != nil {
   176  				return err
   177  			}
   178  
   179  			if result.Kind() == reflect.Interface {
   180  				result.Set(reflect.ValueOf(int(v)))
   181  			} else {
   182  				result.SetInt(v)
   183  			}
   184  			return nil
   185  		}
   186  	}
   187  
   188  	return &parser.PosError{
   189  		Pos: node.Pos(),
   190  		Err: fmt.Errorf("%s: unknown type %T", name, node),
   191  	}
   192  }
   193  
   194  func (d *decoder) decodeInterface(name string, node ast.Node, result reflect.Value) error {
   195  	// When we see an ast.Node, we retain the value to enable deferred decoding.
   196  	// Very useful in situations where we want to preserve ast.Node information
   197  	// like Pos
   198  	if result.Type() == nodeType && result.CanSet() {
   199  		result.Set(reflect.ValueOf(node))
   200  		return nil
   201  	}
   202  
   203  	var set reflect.Value
   204  	redecode := true
   205  
   206  	// For testing types, ObjectType should just be treated as a list. We
   207  	// set this to a temporary var because we want to pass in the real node.
   208  	testNode := node
   209  	if ot, ok := node.(*ast.ObjectType); ok {
   210  		testNode = ot.List
   211  	}
   212  
   213  	switch n := testNode.(type) {
   214  	case *ast.ObjectList:
   215  		// If we're at the root or we're directly within a slice, then we
   216  		// decode objects into map[string]interface{}, otherwise we decode
   217  		// them into lists.
   218  		if len(d.stack) == 0 || d.stack[len(d.stack)-1] == reflect.Slice {
   219  			var temp map[string]interface{}
   220  			tempVal := reflect.ValueOf(temp)
   221  			result := reflect.MakeMap(
   222  				reflect.MapOf(
   223  					reflect.TypeOf(""),
   224  					tempVal.Type().Elem()))
   225  
   226  			set = result
   227  		} else {
   228  			var temp []map[string]interface{}
   229  			tempVal := reflect.ValueOf(temp)
   230  			result := reflect.MakeSlice(
   231  				reflect.SliceOf(tempVal.Type().Elem()), 0, len(n.Items))
   232  			set = result
   233  		}
   234  	case *ast.ObjectType:
   235  		// If we're at the root or we're directly within a slice, then we
   236  		// decode objects into map[string]interface{}, otherwise we decode
   237  		// them into lists.
   238  		if len(d.stack) == 0 || d.stack[len(d.stack)-1] == reflect.Slice {
   239  			var temp map[string]interface{}
   240  			tempVal := reflect.ValueOf(temp)
   241  			result := reflect.MakeMap(
   242  				reflect.MapOf(
   243  					reflect.TypeOf(""),
   244  					tempVal.Type().Elem()))
   245  
   246  			set = result
   247  		} else {
   248  			var temp []map[string]interface{}
   249  			tempVal := reflect.ValueOf(temp)
   250  			result := reflect.MakeSlice(
   251  				reflect.SliceOf(tempVal.Type().Elem()), 0, 1)
   252  			set = result
   253  		}
   254  	case *ast.ListType:
   255  		var temp []interface{}
   256  		tempVal := reflect.ValueOf(temp)
   257  		result := reflect.MakeSlice(
   258  			reflect.SliceOf(tempVal.Type().Elem()), 0, 0)
   259  		set = result
   260  	case *ast.LiteralType:
   261  		switch n.Token.Type {
   262  		case token.BOOL:
   263  			var result bool
   264  			set = reflect.Indirect(reflect.New(reflect.TypeOf(result)))
   265  		case token.FLOAT:
   266  			var result float64
   267  			set = reflect.Indirect(reflect.New(reflect.TypeOf(result)))
   268  		case token.NUMBER:
   269  			var result int
   270  			set = reflect.Indirect(reflect.New(reflect.TypeOf(result)))
   271  		case token.STRING, token.HEREDOC:
   272  			set = reflect.Indirect(reflect.New(reflect.TypeOf("")))
   273  		default:
   274  			return &parser.PosError{
   275  				Pos: node.Pos(),
   276  				Err: fmt.Errorf("%s: cannot decode into interface: %T", name, node),
   277  			}
   278  		}
   279  	default:
   280  		return fmt.Errorf(
   281  			"%s: cannot decode into interface: %T",
   282  			name, node)
   283  	}
   284  
   285  	// Set the result to what its supposed to be, then reset
   286  	// result so we don't reflect into this method anymore.
   287  	result.Set(set)
   288  
   289  	if redecode {
   290  		// Revisit the node so that we can use the newly instantiated
   291  		// thing and populate it.
   292  		if err := d.decode(name, node, result); err != nil {
   293  			return err
   294  		}
   295  	}
   296  
   297  	return nil
   298  }
   299  
   300  func (d *decoder) decodeMap(name string, node ast.Node, result reflect.Value) error {
   301  	if item, ok := node.(*ast.ObjectItem); ok {
   302  		node = &ast.ObjectList{Items: []*ast.ObjectItem{item}}
   303  	}
   304  
   305  	if ot, ok := node.(*ast.ObjectType); ok {
   306  		node = ot.List
   307  	}
   308  
   309  	n, ok := node.(*ast.ObjectList)
   310  	if !ok {
   311  		return &parser.PosError{
   312  			Pos: node.Pos(),
   313  			Err: fmt.Errorf("%s: not an object type for map (%T)", name, node),
   314  		}
   315  	}
   316  
   317  	// If we have an interface, then we can address the interface,
   318  	// but not the slice itself, so get the element but set the interface
   319  	set := result
   320  	if result.Kind() == reflect.Interface {
   321  		result = result.Elem()
   322  	}
   323  
   324  	resultType := result.Type()
   325  	resultElemType := resultType.Elem()
   326  	resultKeyType := resultType.Key()
   327  	if resultKeyType.Kind() != reflect.String {
   328  		return &parser.PosError{
   329  			Pos: node.Pos(),
   330  			Err: fmt.Errorf("%s: map must have string keys", name),
   331  		}
   332  	}
   333  
   334  	// Make a map if it is nil
   335  	resultMap := result
   336  	if result.IsNil() {
   337  		resultMap = reflect.MakeMap(
   338  			reflect.MapOf(resultKeyType, resultElemType))
   339  	}
   340  
   341  	// Go through each element and decode it.
   342  	done := make(map[string]struct{})
   343  	for _, item := range n.Items {
   344  		if item.Val == nil {
   345  			continue
   346  		}
   347  
   348  		// github.com/hashicorp/terraform/issue/5740
   349  		if len(item.Keys) == 0 {
   350  			return &parser.PosError{
   351  				Pos: node.Pos(),
   352  				Err: fmt.Errorf("%s: map must have string keys", name),
   353  			}
   354  		}
   355  
   356  		// Get the key we're dealing with, which is the first item
   357  		keyStr := item.Keys[0].Token.Value().(string)
   358  
   359  		// If we've already processed this key, then ignore it
   360  		if _, ok := done[keyStr]; ok {
   361  			continue
   362  		}
   363  
   364  		// Determine the value. If we have more than one key, then we
   365  		// get the objectlist of only these keys.
   366  		itemVal := item.Val
   367  		if len(item.Keys) > 1 {
   368  			itemVal = n.Filter(keyStr)
   369  			done[keyStr] = struct{}{}
   370  		}
   371  
   372  		// Make the field name
   373  		fieldName := fmt.Sprintf("%s.%s", name, keyStr)
   374  
   375  		// Get the key/value as reflection values
   376  		key := reflect.ValueOf(keyStr)
   377  		val := reflect.Indirect(reflect.New(resultElemType))
   378  
   379  		// If we have a pre-existing value in the map, use that
   380  		oldVal := resultMap.MapIndex(key)
   381  		if oldVal.IsValid() {
   382  			val.Set(oldVal)
   383  		}
   384  
   385  		// Decode!
   386  		if err := d.decode(fieldName, itemVal, val); err != nil {
   387  			return err
   388  		}
   389  
   390  		// Set the value on the map
   391  		resultMap.SetMapIndex(key, val)
   392  	}
   393  
   394  	// Set the final map if we can
   395  	set.Set(resultMap)
   396  	return nil
   397  }
   398  
   399  func (d *decoder) decodePtr(name string, node ast.Node, result reflect.Value) error {
   400  	// Create an element of the concrete (non pointer) type and decode
   401  	// into that. Then set the value of the pointer to this type.
   402  	resultType := result.Type()
   403  	resultElemType := resultType.Elem()
   404  	val := reflect.New(resultElemType)
   405  	if err := d.decode(name, node, reflect.Indirect(val)); err != nil {
   406  		return err
   407  	}
   408  
   409  	result.Set(val)
   410  	return nil
   411  }
   412  
   413  func (d *decoder) decodeSlice(name string, node ast.Node, result reflect.Value) error {
   414  	// If we have an interface, then we can address the interface,
   415  	// but not the slice itself, so get the element but set the interface
   416  	set := result
   417  	if result.Kind() == reflect.Interface {
   418  		result = result.Elem()
   419  	}
   420  	// Create the slice if it isn't nil
   421  	resultType := result.Type()
   422  	resultElemType := resultType.Elem()
   423  	if result.IsNil() {
   424  		resultSliceType := reflect.SliceOf(resultElemType)
   425  		result = reflect.MakeSlice(
   426  			resultSliceType, 0, 0)
   427  	}
   428  
   429  	// Figure out the items we'll be copying into the slice
   430  	var items []ast.Node
   431  	switch n := node.(type) {
   432  	case *ast.ObjectList:
   433  		items = make([]ast.Node, len(n.Items))
   434  		for i, item := range n.Items {
   435  			items[i] = item
   436  		}
   437  	case *ast.ObjectType:
   438  		items = []ast.Node{n}
   439  	case *ast.ListType:
   440  		items = n.List
   441  	default:
   442  		return &parser.PosError{
   443  			Pos: node.Pos(),
   444  			Err: fmt.Errorf("unknown slice type: %T", node),
   445  		}
   446  	}
   447  
   448  	for i, item := range items {
   449  		fieldName := fmt.Sprintf("%s[%d]", name, i)
   450  
   451  		// Decode
   452  		val := reflect.Indirect(reflect.New(resultElemType))
   453  
   454  		// if item is an object that was decoded from ambiguous JSON and
   455  		// flattened, make sure it's expanded if it needs to decode into a
   456  		// defined structure.
   457  		item := expandObject(item, val)
   458  
   459  		if err := d.decode(fieldName, item, val); err != nil {
   460  			return err
   461  		}
   462  
   463  		// Append it onto the slice
   464  		result = reflect.Append(result, val)
   465  	}
   466  
   467  	set.Set(result)
   468  	return nil
   469  }
   470  
   471  // expandObject detects if an ambiguous JSON object was flattened to a List which
   472  // should be decoded into a struct, and expands the ast to properly deocode.
   473  func expandObject(node ast.Node, result reflect.Value) ast.Node {
   474  	item, ok := node.(*ast.ObjectItem)
   475  	if !ok {
   476  		return node
   477  	}
   478  
   479  	elemType := result.Type()
   480  
   481  	// our target type must be a struct
   482  	switch elemType.Kind() {
   483  	case reflect.Ptr:
   484  		switch elemType.Elem().Kind() {
   485  		case reflect.Struct:
   486  			//OK
   487  		default:
   488  			return node
   489  		}
   490  	case reflect.Struct:
   491  		//OK
   492  	default:
   493  		return node
   494  	}
   495  
   496  	// A list value will have a key and field name. If it had more fields,
   497  	// it wouldn't have been flattened.
   498  	if len(item.Keys) != 2 {
   499  		return node
   500  	}
   501  
   502  	keyToken := item.Keys[0].Token
   503  	item.Keys = item.Keys[1:]
   504  
   505  	// we need to un-flatten the ast enough to decode
   506  	newNode := &ast.ObjectItem{
   507  		Keys: []*ast.ObjectKey{
   508  			{
   509  				Token: keyToken,
   510  			},
   511  		},
   512  		Val: &ast.ObjectType{
   513  			List: &ast.ObjectList{
   514  				Items: []*ast.ObjectItem{item},
   515  			},
   516  		},
   517  	}
   518  
   519  	return newNode
   520  }
   521  
   522  func (d *decoder) decodeString(name string, node ast.Node, result reflect.Value) error {
   523  	switch n := node.(type) {
   524  	case *ast.LiteralType:
   525  		switch n.Token.Type {
   526  		case token.NUMBER:
   527  			result.Set(reflect.ValueOf(n.Token.Text).Convert(result.Type()))
   528  			return nil
   529  		case token.STRING, token.HEREDOC:
   530  			result.Set(reflect.ValueOf(n.Token.Value()).Convert(result.Type()))
   531  			return nil
   532  		}
   533  	}
   534  
   535  	return &parser.PosError{
   536  		Pos: node.Pos(),
   537  		Err: fmt.Errorf("%s: unknown type for string %T", name, node),
   538  	}
   539  }
   540  
   541  func (d *decoder) decodeStruct(name string, node ast.Node, result reflect.Value) error {
   542  	var item *ast.ObjectItem
   543  	if it, ok := node.(*ast.ObjectItem); ok {
   544  		item = it
   545  		node = it.Val
   546  	}
   547  
   548  	if ot, ok := node.(*ast.ObjectType); ok {
   549  		node = ot.List
   550  	}
   551  
   552  	// Handle the special case where the object itself is a literal. Previously
   553  	// the yacc parser would always ensure top-level elements were arrays. The new
   554  	// parser does not make the same guarantees, thus we need to convert any
   555  	// top-level literal elements into a list.
   556  	if _, ok := node.(*ast.LiteralType); ok && item != nil {
   557  		node = &ast.ObjectList{Items: []*ast.ObjectItem{item}}
   558  	}
   559  
   560  	list, ok := node.(*ast.ObjectList)
   561  	if !ok {
   562  		return &parser.PosError{
   563  			Pos: node.Pos(),
   564  			Err: fmt.Errorf("%s: not an object type for struct (%T)", name, node),
   565  		}
   566  	}
   567  
   568  	// This slice will keep track of all the structs we'll be decoding.
   569  	// There can be more than one struct if there are embedded structs
   570  	// that are squashed.
   571  	structs := make([]reflect.Value, 1, 5)
   572  	structs[0] = result
   573  
   574  	// Compile the list of all the fields that we're going to be decoding
   575  	// from all the structs.
   576  	type field struct {
   577  		field reflect.StructField
   578  		val   reflect.Value
   579  	}
   580  	fields := []field{}
   581  	for len(structs) > 0 {
   582  		structVal := structs[0]
   583  		structs = structs[1:]
   584  
   585  		structType := structVal.Type()
   586  		for i := 0; i < structType.NumField(); i++ {
   587  			fieldType := structType.Field(i)
   588  			tagParts := strings.Split(fieldType.Tag.Get(tagName), ",")
   589  
   590  			// Ignore fields with tag name "-"
   591  			if tagParts[0] == "-" {
   592  				continue
   593  			}
   594  
   595  			if fieldType.Anonymous {
   596  				fieldKind := fieldType.Type.Kind()
   597  				if fieldKind != reflect.Struct {
   598  					return &parser.PosError{
   599  						Pos: node.Pos(),
   600  						Err: fmt.Errorf("%s: unsupported type to struct: %s",
   601  							fieldType.Name, fieldKind),
   602  					}
   603  				}
   604  
   605  				// We have an embedded field. We "squash" the fields down
   606  				// if specified in the tag.
   607  				squash := false
   608  				for _, tag := range tagParts[1:] {
   609  					if tag == "squash" {
   610  						squash = true
   611  						break
   612  					}
   613  				}
   614  
   615  				if squash {
   616  					structs = append(
   617  						structs, result.FieldByName(fieldType.Name))
   618  					continue
   619  				}
   620  			}
   621  
   622  			// Normal struct field, store it away
   623  			fields = append(fields, field{fieldType, structVal.Field(i)})
   624  		}
   625  	}
   626  
   627  	usedKeys := make(map[string]struct{})
   628  	decodedFields := make([]string, 0, len(fields))
   629  	decodedFieldsVal := make([]reflect.Value, 0)
   630  	unusedKeysVal := make([]reflect.Value, 0)
   631  
   632  	// fill unusedNodeKeys with keys from the AST
   633  	// a slice because we have to do equals case fold to match Filter
   634  	unusedNodeKeys := make(map[string][]token.Pos, 0)
   635  	for i, item := range list.Items {
   636  		for _, k := range item.Keys {
   637  			// isNestedJSON returns true for e.g. bar in
   638  			// { "foo": { "bar": {...} } }
   639  			// This isn't an unused node key, so we want to skip it
   640  			isNestedJSON := i > 0 && len(item.Keys) > 1
   641  			if !isNestedJSON && (k.Token.JSON || k.Token.Type == token.IDENT) {
   642  				fn := k.Token.Value().(string)
   643  				sl := unusedNodeKeys[fn]
   644  				unusedNodeKeys[fn] = append(sl, k.Token.Pos)
   645  			}
   646  		}
   647  	}
   648  
   649  	for _, f := range fields {
   650  		field, fieldValue := f.field, f.val
   651  		if !fieldValue.IsValid() {
   652  			// This should never happen
   653  			panic("field is not valid")
   654  		}
   655  
   656  		// If we can't set the field, then it is unexported or something,
   657  		// and we just continue onwards.
   658  		if !fieldValue.CanSet() {
   659  			continue
   660  		}
   661  
   662  		fieldName := field.Name
   663  
   664  		tagValue := field.Tag.Get(tagName)
   665  		tagParts := strings.SplitN(tagValue, ",", 2)
   666  		if len(tagParts) >= 2 {
   667  			switch tagParts[1] {
   668  			case "decodedFields":
   669  				decodedFieldsVal = append(decodedFieldsVal, fieldValue)
   670  				continue
   671  			case "key":
   672  				if item == nil {
   673  					return &parser.PosError{
   674  						Pos: node.Pos(),
   675  						Err: fmt.Errorf("%s: %s asked for 'key', impossible",
   676  							name, fieldName),
   677  					}
   678  				}
   679  
   680  				fieldValue.SetString(item.Keys[0].Token.Value().(string))
   681  				continue
   682  			case "unusedKeyPositions":
   683  				unusedKeysVal = append(unusedKeysVal, fieldValue)
   684  				continue
   685  			}
   686  		}
   687  
   688  		if tagParts[0] != "" {
   689  			fieldName = tagParts[0]
   690  		}
   691  
   692  		// Determine the element we'll use to decode. If it is a single
   693  		// match (only object with the field), then we decode it exactly.
   694  		// If it is a prefix match, then we decode the matches.
   695  		filter := list.Filter(fieldName)
   696  
   697  		prefixMatches := filter.Children()
   698  		matches := filter.Elem()
   699  		if len(matches.Items) == 0 && len(prefixMatches.Items) == 0 {
   700  			continue
   701  		}
   702  
   703  		// Track the used keys
   704  		usedKeys[fieldName] = struct{}{}
   705  		unusedNodeKeys = removeCaseFold(unusedNodeKeys, fieldName)
   706  
   707  		// Create the field name and decode. We range over the elements
   708  		// because we actually want the value.
   709  		fieldName = fmt.Sprintf("%s.%s", name, fieldName)
   710  		if len(prefixMatches.Items) > 0 {
   711  			if err := d.decode(fieldName, prefixMatches, fieldValue); err != nil {
   712  				return err
   713  			}
   714  		}
   715  		for _, match := range matches.Items {
   716  			var decodeNode ast.Node = match.Val
   717  			if ot, ok := decodeNode.(*ast.ObjectType); ok {
   718  				decodeNode = &ast.ObjectList{Items: ot.List.Items}
   719  			}
   720  
   721  			if err := d.decode(fieldName, decodeNode, fieldValue); err != nil {
   722  				return err
   723  			}
   724  		}
   725  
   726  		decodedFields = append(decodedFields, field.Name)
   727  	}
   728  
   729  	if len(decodedFieldsVal) > 0 {
   730  		// Sort it so that it is deterministic
   731  		sort.Strings(decodedFields)
   732  
   733  		for _, v := range decodedFieldsVal {
   734  			v.Set(reflect.ValueOf(decodedFields))
   735  		}
   736  	}
   737  
   738  	if len(unusedNodeKeys) > 0 {
   739  		// like decodedFields, populated the unusedKeys field(s)
   740  		for _, v := range unusedKeysVal {
   741  			v.Set(reflect.ValueOf(unusedNodeKeys))
   742  		}
   743  	}
   744  
   745  	return nil
   746  }
   747  
   748  // findNodeType returns the type of ast.Node
   749  func findNodeType() reflect.Type {
   750  	var nodeContainer struct {
   751  		Node ast.Node
   752  	}
   753  	value := reflect.ValueOf(nodeContainer).FieldByName("Node")
   754  	return value.Type()
   755  }
   756  
   757  func removeCaseFold(xs map[string][]token.Pos, y string) map[string][]token.Pos {
   758  	var toDel []string
   759  
   760  	for i := range xs {
   761  		if strings.EqualFold(i, y) {
   762  			toDel = append(toDel, i)
   763  		}
   764  	}
   765  	for _, i := range toDel {
   766  		delete(xs, i)
   767  	}
   768  	return xs
   769  }
   770  

View as plain text