interface_build.go

 1package codegen
 2
 3import (
 4	"fmt"
 5	"go/types"
 6	"os"
 7	"sort"
 8
 9	"github.com/vektah/gqlparser/ast"
10	"golang.org/x/tools/go/loader"
11)
12
13func (cfg *Config) buildInterfaces(types NamedTypes, prog *loader.Program) []*Interface {
14	var interfaces []*Interface
15	for _, typ := range cfg.schema.Types {
16		if typ.Kind == ast.Union || typ.Kind == ast.Interface {
17			interfaces = append(interfaces, cfg.buildInterface(types, typ, prog))
18		}
19	}
20
21	sort.Slice(interfaces, func(i, j int) bool {
22		return interfaces[i].GQLType < interfaces[j].GQLType
23	})
24
25	return interfaces
26}
27
28func (cfg *Config) buildInterface(types NamedTypes, typ *ast.Definition, prog *loader.Program) *Interface {
29	i := &Interface{NamedType: types[typ.Name]}
30
31	for _, implementor := range cfg.schema.GetPossibleTypes(typ) {
32		t := types[implementor.Name]
33
34		i.Implementors = append(i.Implementors, InterfaceImplementor{
35			NamedType:     t,
36			ValueReceiver: cfg.isValueReceiver(types[typ.Name], t, prog),
37		})
38	}
39
40	return i
41}
42
43func (cfg *Config) isValueReceiver(intf *NamedType, implementor *NamedType, prog *loader.Program) bool {
44	interfaceType, err := findGoInterface(prog, intf.Package, intf.GoType)
45	if interfaceType == nil || err != nil {
46		return true
47	}
48
49	implementorType, err := findGoNamedType(prog, implementor.Package, implementor.GoType)
50	if implementorType == nil || err != nil {
51		return true
52	}
53
54	for i := 0; i < interfaceType.NumMethods(); i++ {
55		intfMethod := interfaceType.Method(i)
56
57		implMethod := findMethod(implementorType, intfMethod.Name())
58		if implMethod == nil {
59			fmt.Fprintf(os.Stderr, "missing method %s on %s\n", intfMethod.Name(), implementor.GoType)
60			return false
61		}
62
63		sig := implMethod.Type().(*types.Signature)
64		if _, isPtr := sig.Recv().Type().(*types.Pointer); isPtr {
65			return false
66		}
67	}
68
69	return true
70}