code: func assertAllBlocksHaveNames(name string, list *ast.ObjectList) error {
  	if elem := list.Elem(); len(elem.Items) != 0 {
  		switch et := elem.Items[0].Val.(type) {
  		case *ast.ObjectType:
  			pos := et.Lbrace
  			return fmt.Errorf("%s: %q must be followed by a name", pos, name)
  		default:
  			pos := elem.Items[0].Val.Pos()
  			return fmt.Errorf("%s: %q must be a configuration block", pos, name)
  		}
  	}
  	return nil
  }
docs: /*
  func hclObjectMap(os *hclobj.Object) map[string]ast.ListNode {
  	objects := make(map[string][]*hclobj.Object)
  
  	for _, o := range os.Elem(false) {
  		for _, elem := range o.Elem(true) {
  			val, ok := objects[elem.Key]
  			if !ok {
  				val = make([]*hclobj.Object, 0, 1)
  			}
  
  			val = append(val, elem)
  			objects[elem.Key] = val
  		}
  	}
  
  	return objects
  }
  */
  // assertAllBlocksHaveNames returns an error if any of the items in
  // the given object list are blocks without keys (like "module {}")
  // or simple assignments (like "module = 1"). It returns nil if
  // neither of these things are true.
  //
  // The given name is used in any generated error messages, and should
  // be the name of the block we're dealing with. The given list should
  // be the result of calling .Filter on an object list with that same
  // name.