github.com/nathanstitt/genqlient@v0.3.1-0.20211028004951-a2bda3c41ab8/generate/types.go (about)

     1  package generate
     2  
     3  // This file defines the data structures from which genqlient generates types,
     4  // and the code to write them out as actual Go code.  The main entrypoint is
     5  // goType, which represents such a type, but convert.go also constructs each
     6  // of the implementing types, by traversing the GraphQL operation and schema.
     7  
     8  import (
     9  	"fmt"
    10  	"io"
    11  	"strings"
    12  
    13  	"github.com/vektah/gqlparser/v2/ast"
    14  )
    15  
    16  // goType represents a type for which we'll generate code.
    17  type goType interface {
    18  	// WriteDefinition writes the code for this type into the given io.Writer.
    19  	//
    20  	// TODO(benkraft): Some of the implementations might now benefit from being
    21  	// converted to templates.
    22  	WriteDefinition(io.Writer, *generator) error
    23  
    24  	// Reference returns the Go name of this type, e.g. []*MyStruct, and may be
    25  	// used to refer to it in Go code.
    26  	Reference() string
    27  
    28  	// GraphQLTypeName returns the name of the GraphQL type to which this Go type
    29  	// corresponds.
    30  	GraphQLTypeName() string
    31  
    32  	// SelectionSet returns the selection-set of the GraphQL field from which
    33  	// this type was generated, or nil if none is applicable (for GraphQL
    34  	// scalar, enum, and input types, as well as any opaque
    35  	// (non-genqlient-generated) type since those are validated upon creation).
    36  	SelectionSet() ast.SelectionSet
    37  
    38  	// Remove slice/pointer wrappers, and return the underlying (named (or
    39  	// builtin)) type.  For example, given []*MyStruct, return MyStruct.
    40  	Unwrap() goType
    41  
    42  	// Count the number of times Unwrap() will unwrap a slice type.  For
    43  	// example, given [][][]*MyStruct (or []**[][]*MyStruct, but we never
    44  	// currently generate that), return 3.
    45  	SliceDepth() int
    46  
    47  	// True if Unwrap() will unwrap a pointer at least once.
    48  	IsPointer() bool
    49  }
    50  
    51  var (
    52  	_ goType = (*goOpaqueType)(nil)
    53  	_ goType = (*goSliceType)(nil)
    54  	_ goType = (*goPointerType)(nil)
    55  	_ goType = (*goEnumType)(nil)
    56  	_ goType = (*goStructType)(nil)
    57  	_ goType = (*goInterfaceType)(nil)
    58  )
    59  
    60  type (
    61  	// goOpaqueType represents a user-defined or builtin type, often used to
    62  	// represent a GraphQL scalar.  (See Config.Bindings for more context.)
    63  	goOpaqueType struct {
    64  		GoRef                  string
    65  		GraphQLName            string
    66  		Marshaler, Unmarshaler string
    67  	}
    68  	// goTypenameForBuiltinType represents a builtin type that was
    69  	// given a different name due to a `typename` directive.  We
    70  	// create a type like `type MyString string` for it.
    71  	goTypenameForBuiltinType struct {
    72  		GoTypeName    string
    73  		GoBuiltinName string
    74  		GraphQLName   string
    75  	}
    76  	// goSliceType represents the Go type []Elem, used to represent GraphQL
    77  	// list types.
    78  	goSliceType struct{ Elem goType }
    79  	// goSliceType represents the Go type *Elem, used when requested by the
    80  	// user (perhaps to handle nulls explicitly, or to avoid copying large
    81  	// structures).
    82  	goPointerType struct{ Elem goType }
    83  )
    84  
    85  // Opaque types are defined by the user; pointers and slices need no definition
    86  func (typ *goOpaqueType) WriteDefinition(io.Writer, *generator) error { return nil }
    87  
    88  func (typ *goTypenameForBuiltinType) WriteDefinition(w io.Writer, g *generator) error {
    89  	fmt.Fprintf(w, "type %s %s", typ.GoTypeName, typ.GoBuiltinName)
    90  	return nil
    91  }
    92  func (typ *goSliceType) WriteDefinition(io.Writer, *generator) error   { return nil }
    93  func (typ *goPointerType) WriteDefinition(io.Writer, *generator) error { return nil }
    94  
    95  func (typ *goOpaqueType) Reference() string             { return typ.GoRef }
    96  func (typ *goTypenameForBuiltinType) Reference() string { return typ.GoTypeName }
    97  func (typ *goSliceType) Reference() string              { return "[]" + typ.Elem.Reference() }
    98  func (typ *goPointerType) Reference() string            { return "*" + typ.Elem.Reference() }
    99  
   100  func (typ *goOpaqueType) SelectionSet() ast.SelectionSet             { return nil }
   101  func (typ *goTypenameForBuiltinType) SelectionSet() ast.SelectionSet { return nil }
   102  func (typ *goSliceType) SelectionSet() ast.SelectionSet              { return typ.Elem.SelectionSet() }
   103  func (typ *goPointerType) SelectionSet() ast.SelectionSet            { return typ.Elem.SelectionSet() }
   104  
   105  func (typ *goOpaqueType) GraphQLTypeName() string             { return typ.GraphQLName }
   106  func (typ *goTypenameForBuiltinType) GraphQLTypeName() string { return typ.GraphQLName }
   107  func (typ *goSliceType) GraphQLTypeName() string              { return typ.Elem.GraphQLTypeName() }
   108  func (typ *goPointerType) GraphQLTypeName() string            { return typ.Elem.GraphQLTypeName() }
   109  
   110  // goEnumType represents a Go named-string type used to represent a GraphQL
   111  // enum.  In this case, we generate both the type (`type T string`) and also a
   112  // list of consts representing the values.
   113  type goEnumType struct {
   114  	GoName      string
   115  	GraphQLName string
   116  	Description string
   117  	Values      []goEnumValue
   118  }
   119  
   120  type goEnumValue struct {
   121  	Name        string
   122  	Description string
   123  }
   124  
   125  func (typ *goEnumType) WriteDefinition(w io.Writer, g *generator) error {
   126  	// All GraphQL enums have underlying type string (in the Go sense).
   127  	writeDescription(w, typ.Description)
   128  	fmt.Fprintf(w, "type %s string\n", typ.GoName)
   129  	fmt.Fprintf(w, "const (\n")
   130  	for _, val := range typ.Values {
   131  		writeDescription(w, val.Description)
   132  		fmt.Fprintf(w, "%s %s = \"%s\"\n",
   133  			typ.GoName+goConstName(val.Name),
   134  			typ.GoName, val.Name)
   135  	}
   136  	fmt.Fprintf(w, ")\n")
   137  	return nil
   138  }
   139  
   140  func (typ *goEnumType) Reference() string              { return typ.GoName }
   141  func (typ *goEnumType) SelectionSet() ast.SelectionSet { return nil }
   142  func (typ *goEnumType) GraphQLTypeName() string        { return typ.GraphQLName }
   143  
   144  // goStructType represents a Go struct type used to represent a GraphQL object
   145  // or input-object type.
   146  type goStructType struct {
   147  	GoName    string
   148  	Fields    []*goStructField
   149  	IsInput   bool
   150  	Selection ast.SelectionSet
   151  	descriptionInfo
   152  	Generator *generator // for the convenience of the template
   153  }
   154  
   155  type goStructField struct {
   156  	GoName      string
   157  	GoType      goType
   158  	JSONName    string // i.e. the field's alias in this query
   159  	GraphQLName string // i.e. the field's name in its type-def
   160  	Omitempty   bool   // only used on input types
   161  	Description string
   162  }
   163  
   164  // IsAbstract returns true if this field is of abstract type (i.e. GraphQL
   165  // union or interface; equivalently, represented by an interface in Go).
   166  func (field *goStructField) IsAbstract() bool {
   167  	_, ok := field.GoType.Unwrap().(*goInterfaceType)
   168  	return ok
   169  }
   170  
   171  // IsEmbedded returns true if this field is embedded (a.k.a. anonymous), which
   172  // is in practice true if it corresponds to a named fragment spread in GraphQL.
   173  func (field *goStructField) IsEmbedded() bool {
   174  	return field.GoName == ""
   175  }
   176  
   177  // Selector returns the field's name, which is unqualified type-name if it's
   178  // embedded.
   179  func (field *goStructField) Selector() string {
   180  	if field.GoName != "" {
   181  		return field.GoName
   182  	}
   183  	// TODO(benkraft): This assumes the type is package-local, which is always
   184  	// true for embedded types for us, but isn't the most robust assumption.
   185  	return field.GoType.Unwrap().Reference()
   186  }
   187  
   188  // unmarshaler returns:
   189  // - the name of the function to use to unmarshal this field
   190  // - true if this is a fully-qualified name (false if it is a package-local
   191  //   unqualified name)
   192  // - true if we need to generate an unmarshaler at all, false if the default
   193  //   behavior will suffice
   194  func (field *goStructField) unmarshaler() (qualifiedName string, needsImport bool, needsUnmarshaler bool) {
   195  	switch typ := field.GoType.Unwrap().(type) {
   196  	case *goOpaqueType:
   197  		if typ.Unmarshaler != "" {
   198  			return typ.Unmarshaler, true, true
   199  		}
   200  	case *goInterfaceType:
   201  		return "__unmarshal" + typ.Reference(), false, true
   202  	}
   203  	return "encoding/json.Unmarshal", true, field.IsEmbedded()
   204  }
   205  
   206  // Unmarshaler returns the Go name of the function to use to unmarshal this
   207  // field (which may be "json.Unmarshal" if there's not a special one).
   208  func (field *goStructField) Unmarshaler(g *generator) (string, error) {
   209  	name, needsImport, _ := field.unmarshaler()
   210  	if needsImport {
   211  		return g.ref(name)
   212  	}
   213  	return name, nil
   214  }
   215  
   216  // marshaler returns:
   217  // - the fully-qualified name of the function to use to marshal this field
   218  // - true if we need to generate an marshaler at all, false if the default
   219  //   behavior will suffice
   220  func (field *goStructField) marshaler() (qualifiedName string, needsImport bool, needsMarshaler bool) {
   221  	switch typ := field.GoType.Unwrap().(type) {
   222  	case *goOpaqueType:
   223  		if typ.Marshaler != "" {
   224  			return typ.Marshaler, true, true
   225  		}
   226  	case *goInterfaceType:
   227  		return "__marshal" + typ.Reference(), false, true
   228  	}
   229  	return "encoding/json.Marshal", true, field.IsEmbedded()
   230  }
   231  
   232  // Marshaler returns the Go name of the function to use to marshal this
   233  // field (which may be "json.Marshal" if there's not a special one).
   234  func (field *goStructField) Marshaler(g *generator) (string, error) {
   235  	name, needsImport, _ := field.marshaler()
   236  	if needsImport {
   237  		return g.ref(name)
   238  	}
   239  	return name, nil
   240  }
   241  
   242  // NeedsMarshaling returns true if this field needs special handling when
   243  // marshaling and unmarshaling, e.g. if it has a user-specified custom
   244  // (un)marshaler.  Note if it needs one, it needs the other: even if the user
   245  // only specified an unmarshaler, we need to add `json:"-"` to the field, which
   246  // means we need to specially handling it when marshaling.
   247  func (field *goStructField) NeedsMarshaling() bool {
   248  	_, _, ok1 := field.marshaler()
   249  	_, _, ok2 := field.unmarshaler()
   250  	return ok1 || ok2
   251  }
   252  
   253  // NeedsMarshaler returns true if any fields of this type need special
   254  // handling when (un)marshaling (see goStructField.NeedsMarshaling).
   255  func (typ *goStructType) NeedsMarshaling() bool {
   256  	for _, f := range typ.Fields {
   257  		if f.NeedsMarshaling() {
   258  			return true
   259  		}
   260  	}
   261  	return false
   262  }
   263  
   264  // selector represents a field and the path to get there from the type in
   265  // question, and is used in FlattenedFields, below.
   266  type selector struct {
   267  	*goStructField
   268  	// e.g. "OuterEmbed.InnerEmbed.LeafField"
   269  	Selector string
   270  }
   271  
   272  // FlattenedFields returns the fields of this type and its recursive embeds,
   273  // and the paths to reach them (via those embeds), but with different
   274  // visibility rules for conflicting fields than Go.
   275  //
   276  // (Before you read further, now's a good time to review Go's rules:
   277  // https://golang.org/ref/spec#Selectors. Done? Good.)
   278  //
   279  // To illustrate the need, consider the following query:
   280  //	fragment A on T { id }
   281  //	fragment B on T { id }
   282  //	query Q { t { ...A ...B } }
   283  // We generate types:
   284  //	type A struct { Id string `json:"id"` }
   285  //	type B struct { Id string `json:"id"` }
   286  //	type QT struct { A; B }
   287  // According to Go's embedding rules, QT has no field Id: since QT.A.Id and
   288  // QT.B.Id are at equal depth, neither wins and gets promoted.  (Go's JSON
   289  // library uses similar logic to decide which field to write to JSON, except
   290  // with the additional rule that a field with a JSON tag wins over a field
   291  // without; in our case both have such a field.)
   292  //
   293  // Those rules don't work for us.  When unmarshaling, we want to fill in all
   294  // the potentially-matching fields (QT.A.Id and QT.B.Id in this case), and when
   295  // marshaling, we want to always marshal exactly one potentially-conflicting
   296  // field; we're happy to use the Go visibility rules when they apply but we
   297  // need to always marshal one field, even if there's not a clear best choice.
   298  // For unmarshaling, our QT.UnmarshalJSON ends up unmarshaling the same JSON
   299  // object into QT, QT.A, and QT.B, which gives us the behavior we want.  But
   300  // for marshaling, we need to resolve the conflicts: if we simply marshaled QT,
   301  // QT.A, and QT.B, we'd have to do some JSON-surgery to join them, and we'd
   302  // probably end up with duplicate fields, which leads to unpredictable behavior
   303  // based on the reader.  That's no good.
   304  //
   305  // So: instead, we have our own rules, which work like the Go rules, except
   306  // that if there's a tie we choose the first field (in source order).  (In
   307  // practice, hopefully, they all match, but validating that is even more work
   308  // for a fairly rare case.)  This function returns, for each JSON-name, the Go
   309  // field we want to use.  In the example above, it would return:
   310  //	[]selector{{<goStructField for QT.A.Id>, "A.Id"}}
   311  func (typ *goStructType) FlattenedFields() ([]*selector, error) {
   312  	seenJSONNames := map[string]bool{}
   313  	retval := make([]*selector, 0, len(typ.Fields))
   314  
   315  	queue := make([]*selector, len(typ.Fields))
   316  	for i, field := range typ.Fields {
   317  		queue[i] = &selector{field, field.Selector()}
   318  	}
   319  
   320  	// Since our (non-embedded) fields always have JSON tags, the logic we want
   321  	// is simply: do a breadth-first search through the recursively embedded
   322  	// fields, and take the first one we see with a given JSON tag.
   323  	for len(queue) > 0 {
   324  		field := queue[0]
   325  		queue = queue[1:]
   326  		if field.IsEmbedded() {
   327  			typ, ok := field.GoType.(*goStructType)
   328  			if !ok {
   329  				// Should never happen: embeds correspond to named fragments,
   330  				// and even if the fragment is of interface type in GraphQL,
   331  				// either it's spread into a concrete type, or we are writing
   332  				// one of the implementations of the interface into which it's
   333  				// spread; either way we embed the corresponding implementation
   334  				// of the fragment.
   335  				return nil, errorf(nil,
   336  					"genqlient internal error: embedded field %s.%s was not a struct",
   337  					typ.GoName, field.GoName)
   338  			}
   339  
   340  			// Enqueue the embedded fields for our BFS.
   341  			for _, subField := range typ.Fields {
   342  				queue = append(queue,
   343  					&selector{subField, field.Selector + "." + subField.Selector()})
   344  			}
   345  			continue
   346  		}
   347  
   348  		if seenJSONNames[field.JSONName] {
   349  			// We already chose a selector for this JSON field.  Skip it.
   350  			continue
   351  		}
   352  
   353  		// Else, we are the selector we are looking for.
   354  		seenJSONNames[field.JSONName] = true
   355  		retval = append(retval, field)
   356  	}
   357  	return retval, nil
   358  }
   359  
   360  func (typ *goStructType) WriteDefinition(w io.Writer, g *generator) error {
   361  	writeDescription(w, structDescription(typ))
   362  
   363  	fmt.Fprintf(w, "type %s struct {\n", typ.GoName)
   364  	for _, field := range typ.Fields {
   365  		writeDescription(w, field.Description)
   366  		jsonTag := `"` + field.JSONName
   367  		if field.Omitempty {
   368  			jsonTag += ",omitempty"
   369  		}
   370  		jsonTag += `"`
   371  		if field.NeedsMarshaling() {
   372  			// certain types are handled in our (Un)MarshalJSON (see below)
   373  			jsonTag = `"-"`
   374  		}
   375  		// Note for embedded types field.GoName is "", which produces the code
   376  		// we want!
   377  		fmt.Fprintf(w, "\t%s %s `json:%s`\n",
   378  			field.GoName, field.GoType.Reference(), jsonTag)
   379  	}
   380  	fmt.Fprintf(w, "}\n")
   381  
   382  	// Write out getter methods for each field.  These are most useful for
   383  	// shared fields of an interface -- the methods will be included in the
   384  	// interface.  But they can be useful in other cases, for example where you
   385  	// have a union several of whose members have a shared field (and can
   386  	// thereby be handled together).  For simplicity's sake, we just write the
   387  	// methods always.
   388  	//
   389  	// Note we use the *flattened* fields here, which ensures we avoid
   390  	// conflicts in the case where multiple embedded types include the same
   391  	// field.
   392  	flattened, err := typ.FlattenedFields()
   393  	if err != nil {
   394  		return err
   395  	}
   396  	for _, field := range flattened {
   397  		description := fmt.Sprintf(
   398  			"Get%s returns %s.%s, and is useful for accessing the field via an interface.",
   399  			field.GoName, typ.GoName, field.GoName)
   400  		writeDescription(w, description)
   401  		fmt.Fprintf(w, "func (v *%s) Get%s() %s { return v.%s }\n",
   402  			typ.GoName, field.GoName, field.GoType.Reference(), field.Selector)
   403  	}
   404  
   405  	// Now, if needed, write the marshaler/unmarshaler.  We need one if we have
   406  	// any interface-typed fields, or any embedded fields.
   407  	//
   408  	// For interface-typed fields, ideally we'd write an UnmarshalJSON method
   409  	// on the field, but you can't add a method to an interface.  So we write a
   410  	// per-interface-type helper, but we have to call it (with a little
   411  	// boilerplate) everywhere the type is referenced.
   412  	//
   413  	// For embedded fields (from fragments), mostly the JSON library would just
   414  	// do what we want, but there are two problems.  First, if the embedded
   415  	// type has its own UnmarshalJSON, naively that would be promoted to
   416  	// become our UnmarshalJSON, which is no good.  But we don't want to just
   417  	// hide that method and inline its fields, either; we need to call its
   418  	// UnmarshalJSON (on the same object we unmarshal into this struct).
   419  	// Second, if the embedded type duplicates any fields of the embedding type
   420  	// -- maybe both the fragment and the selection into which it's spread
   421  	// select the same field, or several fragments select the same field -- the
   422  	// JSON library will only fill one of those (the least-nested one); we want
   423  	// to fill them all.
   424  	//
   425  	// For fields with a custom marshaler or unmarshaler, we do basically the
   426  	// same thing as interface-typed fields, except the user has defined the
   427  	// helper.
   428  	//
   429  	// Note that genqlient itself only uses unmarshalers for output types, and
   430  	// marshalers for input types.  But we write both in case you want to write
   431  	// your data to JSON for some reason (say to put it in a cache).  (And we
   432  	// need to write both if we need to write either, because in such cases we
   433  	// write a `json:"-"` tag on the field.)
   434  	//
   435  	// TODO(benkraft): If/when proposal #5901 is implemented (Go 1.18 at the
   436  	// earliest), we may be able to do some of this a simpler way.
   437  	if typ.NeedsMarshaling() {
   438  		err := g.render("unmarshal.go.tmpl", w, typ)
   439  		if err != nil {
   440  			return err
   441  		}
   442  		err = g.render("marshal.go.tmpl", w, typ)
   443  		if err != nil {
   444  			return err
   445  		}
   446  	}
   447  	return nil
   448  }
   449  
   450  func (typ *goStructType) Reference() string              { return typ.GoName }
   451  func (typ *goStructType) SelectionSet() ast.SelectionSet { return typ.Selection }
   452  func (typ *goStructType) GraphQLTypeName() string        { return typ.GraphQLName }
   453  
   454  // goInterfaceType represents a Go interface type, used to represent a GraphQL
   455  // interface or union type.
   456  type goInterfaceType struct {
   457  	GoName string
   458  	// Fields shared by all the interface's implementations;
   459  	// we'll generate getter methods for each.
   460  	SharedFields    []*goStructField
   461  	Implementations []*goStructType
   462  	Selection       ast.SelectionSet
   463  	descriptionInfo
   464  }
   465  
   466  func (typ *goInterfaceType) WriteDefinition(w io.Writer, g *generator) error {
   467  	writeDescription(w, interfaceDescription(typ))
   468  
   469  	// Write the interface.
   470  	fmt.Fprintf(w, "type %s interface {\n", typ.GoName)
   471  	implementsMethodName := fmt.Sprintf("implementsGraphQLInterface%v", typ.GoName)
   472  	fmt.Fprintf(w, "\t%s()\n", implementsMethodName)
   473  	for _, sharedField := range typ.SharedFields {
   474  		if sharedField.GoName == "" { // embedded type
   475  			fmt.Fprintf(w, "\t%s\n", sharedField.GoType.Reference())
   476  			continue
   477  		}
   478  
   479  		methodName := "Get" + sharedField.GoName
   480  		description := ""
   481  		if sharedField.GraphQLName == "__typename" {
   482  			description = fmt.Sprintf(
   483  				"%s returns the receiver's concrete GraphQL type-name "+
   484  					"(see interface doc for possible values).", methodName)
   485  		} else {
   486  			description = fmt.Sprintf(
   487  				`%s returns the interface-field "%s" from its implementation.`,
   488  				methodName, sharedField.GraphQLName)
   489  			if sharedField.Description != "" {
   490  				description = fmt.Sprintf(
   491  					"%s\nThe GraphQL interface field's documentation follows.\n\n%s",
   492  					description, sharedField.Description)
   493  			}
   494  		}
   495  
   496  		writeDescription(w, description)
   497  		fmt.Fprintf(w, "\t%s() %s\n", methodName, sharedField.GoType.Reference())
   498  	}
   499  	fmt.Fprintf(w, "}\n")
   500  
   501  	// Now, write out the implementations.
   502  	for _, impl := range typ.Implementations {
   503  		fmt.Fprintf(w, "func (v *%s) %s() {}\n",
   504  			impl.Reference(), implementsMethodName)
   505  	}
   506  
   507  	// Finally, write the marshal- and unmarshal-helpers, which
   508  	// will be called by struct fields referencing this type (see
   509  	// goStructType.WriteDefinition).
   510  	err := g.render("unmarshal_helper.go.tmpl", w, typ)
   511  	if err != nil {
   512  		return err
   513  	}
   514  	return g.render("marshal_helper.go.tmpl", w, typ)
   515  }
   516  
   517  func (typ *goInterfaceType) Reference() string              { return typ.GoName }
   518  func (typ *goInterfaceType) SelectionSet() ast.SelectionSet { return typ.Selection }
   519  func (typ *goInterfaceType) GraphQLTypeName() string        { return typ.GraphQLName }
   520  
   521  func (typ *goOpaqueType) Unwrap() goType             { return typ }
   522  func (typ *goTypenameForBuiltinType) Unwrap() goType { return typ }
   523  func (typ *goSliceType) Unwrap() goType              { return typ.Elem.Unwrap() }
   524  func (typ *goPointerType) Unwrap() goType            { return typ.Elem.Unwrap() }
   525  func (typ *goEnumType) Unwrap() goType               { return typ }
   526  func (typ *goStructType) Unwrap() goType             { return typ }
   527  func (typ *goInterfaceType) Unwrap() goType          { return typ }
   528  
   529  func (typ *goOpaqueType) SliceDepth() int             { return 0 }
   530  func (typ *goTypenameForBuiltinType) SliceDepth() int { return 0 }
   531  func (typ *goSliceType) SliceDepth() int              { return typ.Elem.SliceDepth() + 1 }
   532  func (typ *goPointerType) SliceDepth() int            { return 0 }
   533  func (typ *goEnumType) SliceDepth() int               { return 0 }
   534  func (typ *goStructType) SliceDepth() int             { return 0 }
   535  func (typ *goInterfaceType) SliceDepth() int          { return 0 }
   536  
   537  func (typ *goOpaqueType) IsPointer() bool             { return false }
   538  func (typ *goTypenameForBuiltinType) IsPointer() bool { return false }
   539  func (typ *goSliceType) IsPointer() bool              { return typ.Elem.IsPointer() }
   540  func (typ *goPointerType) IsPointer() bool            { return true }
   541  func (typ *goEnumType) IsPointer() bool               { return false }
   542  func (typ *goStructType) IsPointer() bool             { return false }
   543  func (typ *goInterfaceType) IsPointer() bool          { return false }
   544  
   545  func writeDescription(w io.Writer, desc string) {
   546  	if desc != "" {
   547  		for _, line := range strings.Split(desc, "\n") {
   548  			fmt.Fprintf(w, "// %s\n", strings.TrimLeft(line, " \t"))
   549  		}
   550  	}
   551  }