• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

99designs / gqlgen / 12320669056

13 Dec 2024 06:01PM UTC coverage: 73.884% (-0.04%) from 73.919%
12320669056

push

github

web-flow
enable testifylint.encoded-compare and fix lint issues (#3434)

8575 of 11606 relevant lines covered (73.88%)

641.17 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

74.95
/codegen/config/binder.go
1
package config
2

3
import (
4
        "errors"
5
        "fmt"
6
        "go/token"
7
        "go/types"
8
        "strings"
9

10
        "github.com/vektah/gqlparser/v2/ast"
11
        "golang.org/x/tools/go/packages"
12

13
        "github.com/99designs/gqlgen/codegen/templates"
14
        "github.com/99designs/gqlgen/internal/code"
15
)
16

17
var ErrTypeNotFound = errors.New("unable to find type")
18

19
// Binder connects graphql types to golang types using static analysis
20
type Binder struct {
21
        pkgs        *code.Packages
22
        schema      *ast.Schema
23
        cfg         *Config
24
        tctx        *types.Context
25
        References  []*TypeReference
26
        SawInvalid  bool
27
        objectCache map[string]map[string]types.Object
28
}
29

30
func (c *Config) NewBinder() *Binder {
218✔
31
        return &Binder{
218✔
32
                pkgs:   c.Packages,
218✔
33
                schema: c.Schema,
218✔
34
                cfg:    c,
218✔
35
        }
218✔
36
}
218✔
37

38
func (b *Binder) TypePosition(typ types.Type) token.Position {
18✔
39
        named, isNamed := code.Unalias(typ).(*types.Named)
18✔
40
        if !isNamed {
18✔
41
                return token.Position{
×
42
                        Filename: "unknown",
×
43
                }
×
44
        }
×
45

46
        return b.ObjectPosition(named.Obj())
18✔
47
}
48

49
func (b *Binder) ObjectPosition(typ types.Object) token.Position {
525✔
50
        if typ == nil {
543✔
51
                return token.Position{
18✔
52
                        Filename: "unknown",
18✔
53
                }
18✔
54
        }
18✔
55
        pkg := b.pkgs.Load(typ.Pkg().Path())
507✔
56
        return pkg.Fset.Position(typ.Pos())
507✔
57
}
58

59
func (b *Binder) FindTypeFromName(name string) (types.Type, error) {
329✔
60
        pkgName, typeName := code.PkgAndType(name)
329✔
61
        return b.FindType(pkgName, typeName)
329✔
62
}
329✔
63

64
func (b *Binder) FindType(pkgName, typeName string) (types.Type, error) {
339✔
65
        if pkgName == "" {
339✔
66
                if typeName == "map[string]interface{}" {
×
67
                        return MapType, nil
×
68
                }
×
69

70
                if typeName == "interface{}" {
×
71
                        return InterfaceType, nil
×
72
                }
×
73
        }
74

75
        obj, err := b.FindObject(pkgName, typeName)
339✔
76
        if err != nil {
339✔
77
                return nil, err
×
78
        }
×
79

80
        t := code.Unalias(obj.Type())
339✔
81
        if _, isFunc := obj.(*types.Func); isFunc {
618✔
82
                return code.Unalias(t.(*types.Signature).Params().At(0).Type()), nil
279✔
83
        }
279✔
84
        return t, nil
60✔
85
}
86

87
func (b *Binder) InstantiateType(orig types.Type, targs []types.Type) (types.Type, error) {
29✔
88
        if b.tctx == nil {
42✔
89
                b.tctx = types.NewContext()
13✔
90
        }
13✔
91

92
        return types.Instantiate(b.tctx, orig, targs, false)
29✔
93
}
94

95
var (
96
        MapType       = types.NewMap(types.Typ[types.String], types.NewInterfaceType(nil, nil).Complete())
97
        InterfaceType = types.NewInterfaceType(nil, nil)
98
)
99

100
func (b *Binder) DefaultUserObject(name string) (types.Type, error) {
122✔
101
        models := b.cfg.Models[name].Model
122✔
102
        if len(models) == 0 {
122✔
103
                return nil, fmt.Errorf("%s not found in typemap", name)
×
104
        }
×
105

106
        if models[0] == "map[string]interface{}" {
122✔
107
                return MapType, nil
×
108
        }
×
109

110
        if models[0] == "interface{}" {
122✔
111
                return InterfaceType, nil
×
112
        }
×
113

114
        pkgName, typeName := code.PkgAndType(models[0])
122✔
115
        if pkgName == "" {
122✔
116
                return nil, fmt.Errorf("missing package name for %s", name)
×
117
        }
×
118

119
        obj, err := b.FindObject(pkgName, typeName)
122✔
120
        if err != nil {
123✔
121
                return nil, err
1✔
122
        }
1✔
123

124
        return code.Unalias(obj.Type()), nil
121✔
125
}
126

127
func (b *Binder) FindObject(pkgName, typeName string) (types.Object, error) {
1,224✔
128
        if pkgName == "" {
1,224✔
129
                return nil, errors.New("package cannot be nil")
×
130
        }
×
131

132
        pkg := b.pkgs.LoadWithTypes(pkgName)
1,224✔
133
        if pkg == nil {
1,224✔
134
                err := b.pkgs.Errors()
×
135
                if err != nil {
×
136
                        return nil, fmt.Errorf("package could not be loaded: %s.%s: %w", pkgName, typeName, err)
×
137
                }
×
138
                return nil, fmt.Errorf("required package was not loaded: %s.%s", pkgName, typeName)
×
139
        }
140

141
        if b.objectCache == nil {
1,416✔
142
                b.objectCache = make(map[string]map[string]types.Object, b.pkgs.Count())
192✔
143
        }
192✔
144

145
        defsIndex, ok := b.objectCache[pkgName]
1,224✔
146
        if !ok {
1,476✔
147
                defsIndex = indexDefs(pkg)
252✔
148
                b.objectCache[pkgName] = defsIndex
252✔
149
        }
252✔
150

151
        // function based marshalers take precedence
152
        if val, ok := defsIndex["Marshal"+typeName]; ok {
1,988✔
153
                return val, nil
764✔
154
        }
764✔
155

156
        if val, ok := defsIndex[typeName]; ok {
919✔
157
                return val, nil
459✔
158
        }
459✔
159

160
        return nil, fmt.Errorf("%w: %s.%s", ErrTypeNotFound, pkgName, typeName)
1✔
161
}
162

163
func indexDefs(pkg *packages.Package) map[string]types.Object {
252✔
164
        res := make(map[string]types.Object)
252✔
165

252✔
166
        scope := pkg.Types.Scope()
252✔
167
        for astNode, def := range pkg.TypesInfo.Defs {
186,937✔
168
                // only look at defs in the top scope
186,685✔
169
                if def == nil {
197,669✔
170
                        continue
10,984✔
171
                }
172
                parent := def.Parent()
175,701✔
173
                if parent == nil || parent != scope {
315,792✔
174
                        continue
140,091✔
175
                }
176

177
                if _, ok := res[astNode.Name]; !ok {
71,220✔
178
                        // The above check may not be really needed, it is only here to have a consistent behavior with
35,610✔
179
                        // previous implementation of FindObject() function which only honored the first inclusion of a def.
35,610✔
180
                        // If this is still needed, we can consider something like sync.Map.LoadOrStore() to avoid two lookups.
35,610✔
181
                        res[astNode.Name] = def
35,610✔
182
                }
35,610✔
183
        }
184

185
        return res
252✔
186
}
187

188
func (b *Binder) PointerTo(ref *TypeReference) *TypeReference {
20✔
189
        newRef := *ref
20✔
190
        newRef.GO = types.NewPointer(ref.GO)
20✔
191
        b.References = append(b.References, &newRef)
20✔
192
        return &newRef
20✔
193
}
20✔
194

195
// TypeReference is used by args and field types. The Definition can refer to both input and output types.
196
type TypeReference struct {
197
        Definition               *ast.Definition
198
        GQL                      *ast.Type
199
        GO                       types.Type  // Type of the field being bound. Could be a pointer or a value type of Target.
200
        Target                   types.Type  // The actual type that we know how to bind to. May require pointer juggling when traversing to fields.
201
        CastType                 types.Type  // Before calling marshalling functions cast from/to this base type
202
        Marshaler                *types.Func // When using external marshalling functions this will point to the Marshal function
203
        Unmarshaler              *types.Func // When using external marshalling functions this will point to the Unmarshal function
204
        IsMarshaler              bool        // Does the type implement graphql.Marshaler and graphql.Unmarshaler
205
        IsOmittable              bool        // Is the type wrapped with Omittable
206
        IsContext                bool        // Is the Marshaler/Unmarshaller the context version; applies to either the method or interface variety.
207
        PointersInUnmarshalInput bool        // Inverse values and pointers in return.
208
        IsRoot                   bool        // Is the type a root level definition such as Query, Mutation or Subscription
209
        EnumValues               []EnumValueReference
210
}
211

212
func (ref *TypeReference) Elem() *TypeReference {
287✔
213
        if p, isPtr := ref.GO.(*types.Pointer); isPtr {
287✔
214
                newRef := *ref
×
215
                newRef.GO = p.Elem()
×
216
                return &newRef
×
217
        }
×
218

219
        if ref.IsSlice() {
574✔
220
                newRef := *ref
287✔
221
                newRef.GO = ref.GO.(*types.Slice).Elem()
287✔
222
                newRef.GQL = ref.GQL.Elem
287✔
223
                return &newRef
287✔
224
        }
287✔
225
        return nil
×
226
}
227

228
func (ref *TypeReference) IsPtr() bool {
2,042✔
229
        _, isPtr := ref.GO.(*types.Pointer)
2,042✔
230
        return isPtr
2,042✔
231
}
2,042✔
232

233
// fix for https://github.com/golang/go/issues/31103 may make it possible to remove this (may still be useful)
234
func (ref *TypeReference) IsPtrToPtr() bool {
937✔
235
        if p, isPtr := ref.GO.(*types.Pointer); isPtr {
1,340✔
236
                _, isPtr := p.Elem().(*types.Pointer)
403✔
237
                return isPtr
403✔
238
        }
403✔
239
        return false
534✔
240
}
241

242
func (ref *TypeReference) IsNilable() bool {
394✔
243
        return IsNilable(ref.GO)
394✔
244
}
394✔
245

246
func (ref *TypeReference) IsSlice() bool {
1,433✔
247
        _, isSlice := ref.GO.(*types.Slice)
1,433✔
248
        return ref.GQL.Elem != nil && isSlice
1,433✔
249
}
1,433✔
250

251
func (ref *TypeReference) IsPtrToSlice() bool {
1,003✔
252
        if ref.IsPtr() {
1,394✔
253
                _, isPointerToSlice := ref.GO.(*types.Pointer).Elem().(*types.Slice)
391✔
254
                return isPointerToSlice
391✔
255
        }
391✔
256
        return false
612✔
257
}
258

259
func (ref *TypeReference) IsPtrToIntf() bool {
1,003✔
260
        if ref.IsPtr() {
1,394✔
261
                _, isPointerToInterface := ref.GO.(*types.Pointer).Elem().(*types.Interface)
391✔
262
                return isPointerToInterface
391✔
263
        }
391✔
264
        return false
612✔
265
}
266

267
func (ref *TypeReference) IsNamed() bool {
×
268
        _, ok := ref.GO.(*types.Named)
×
269
        return ok
×
270
}
×
271

272
func (ref *TypeReference) IsStruct() bool {
36✔
273
        _, ok := ref.GO.Underlying().(*types.Struct)
36✔
274
        return ok
36✔
275
}
36✔
276

277
func (ref *TypeReference) IsScalar() bool {
192✔
278
        return ref.Definition.Kind == ast.Scalar
192✔
279
}
192✔
280

281
func (ref *TypeReference) IsMap() bool {
×
282
        return ref.GO == MapType
×
283
}
×
284

285
func (ref *TypeReference) UniquenessKey() string {
1,552✔
286
        nullability := "O"
1,552✔
287
        if ref.GQL.NonNull {
2,515✔
288
                nullability = "N"
963✔
289
        }
963✔
290

291
        elemNullability := ""
1,552✔
292
        if ref.GQL.Elem != nil && ref.GQL.Elem.NonNull {
1,841✔
293
                // Fix for #896
289✔
294
                elemNullability = "áš„"
289✔
295
        }
289✔
296
        return nullability + ref.Definition.Name + "2" + templates.TypeIdentifier(ref.GO) + elemNullability
1,552✔
297
}
298

299
func (ref *TypeReference) MarshalFunc() string {
532✔
300
        if ref.Definition == nil {
532✔
301
                panic(errors.New("Definition missing for " + ref.GQL.Name()))
×
302
        }
303

304
        if ref.Definition.Kind == ast.InputObject {
538✔
305
                return ""
6✔
306
        }
6✔
307

308
        return "marshal" + ref.UniquenessKey()
526✔
309
}
310

311
func (ref *TypeReference) UnmarshalFunc() string {
262✔
312
        if ref.Definition == nil {
262✔
313
                panic(errors.New("Definition missing for " + ref.GQL.Name()))
×
314
        }
315

316
        if !ref.Definition.IsInputType() {
378✔
317
                return ""
116✔
318
        }
116✔
319

320
        return "unmarshal" + ref.UniquenessKey()
146✔
321
}
322

323
func (ref *TypeReference) IsTargetNilable() bool {
224✔
324
        return IsNilable(ref.Target)
224✔
325
}
224✔
326

327
func (ref *TypeReference) HasEnumValues() bool {
308✔
328
        return len(ref.EnumValues) > 0
308✔
329
}
308✔
330

331
func (b *Binder) PushRef(ret *TypeReference) {
753✔
332
        b.References = append(b.References, ret)
753✔
333
}
753✔
334

335
func isMap(t types.Type) bool {
×
336
        if t == nil {
×
337
                return true
×
338
        }
×
339
        _, ok := t.(*types.Map)
×
340
        return ok
×
341
}
342

343
func isIntf(t types.Type) bool {
×
344
        if t == nil {
×
345
                return true
×
346
        }
×
347
        _, ok := t.(*types.Interface)
×
348
        return ok
×
349
}
350

351
func unwrapOmittable(t types.Type) (types.Type, bool) {
762✔
352
        if t == nil {
1,000✔
353
                return nil, false
238✔
354
        }
238✔
355
        named, ok := t.(*types.Named)
524✔
356
        if !ok {
1,041✔
357
                return t, false
517✔
358
        }
517✔
359
        if named.Origin().String() != "github.com/99designs/gqlgen/graphql.Omittable[T any]" {
8✔
360
                return t, false
1✔
361
        }
1✔
362
        return named.TypeArgs().At(0), true
6✔
363
}
364

365
func (b *Binder) TypeReference(schemaType *ast.Type, bindTarget types.Type) (ret *TypeReference, err error) {
762✔
366
        if bindTarget != nil {
1,286✔
367
                bindTarget = code.Unalias(bindTarget)
524✔
368
        }
524✔
369
        if innerType, ok := unwrapOmittable(bindTarget); ok {
768✔
370
                if schemaType.NonNull {
8✔
371
                        return nil, fmt.Errorf("%s is wrapped with Omittable but non-null", schemaType.Name())
2✔
372
                }
2✔
373

374
                ref, err := b.TypeReference(schemaType, innerType)
4✔
375
                if err != nil {
4✔
376
                        return nil, err
×
377
                }
×
378

379
                ref.IsOmittable = true
4✔
380
                return ref, err
4✔
381
        }
382

383
        if !isValid(bindTarget) {
757✔
384
                b.SawInvalid = true
1✔
385
                return nil, fmt.Errorf("%s has an invalid type", schemaType.Name())
1✔
386
        }
1✔
387

388
        var pkgName, typeName string
755✔
389
        def := b.schema.Types[schemaType.Name()]
755✔
390
        defer func() {
1,510✔
391
                if err == nil && ret != nil {
1,508✔
392
                        b.PushRef(ret)
753✔
393
                }
753✔
394
        }()
395

396
        if len(b.cfg.Models[schemaType.Name()].Model) == 0 {
755✔
397
                return nil, fmt.Errorf("%s was not found", schemaType.Name())
×
398
        }
×
399

400
        for _, model := range b.cfg.Models[schemaType.Name()].Model {
1,510✔
401
                if model == "map[string]interface{}" {
755✔
402
                        if !isMap(bindTarget) {
×
403
                                continue
×
404
                        }
405
                        return &TypeReference{
×
406
                                Definition: def,
×
407
                                GQL:        schemaType,
×
408
                                GO:         MapType,
×
409
                                IsRoot:     b.cfg.IsRoot(def),
×
410
                        }, nil
×
411
                }
412

413
                if model == "interface{}" {
755✔
414
                        if !isIntf(bindTarget) {
×
415
                                continue
×
416
                        }
417
                        return &TypeReference{
×
418
                                Definition: def,
×
419
                                GQL:        schemaType,
×
420
                                GO:         InterfaceType,
×
421
                                IsRoot:     b.cfg.IsRoot(def),
×
422
                        }, nil
×
423
                }
424

425
                pkgName, typeName = code.PkgAndType(model)
755✔
426
                if pkgName == "" {
755✔
427
                        return nil, fmt.Errorf("missing package name for %s", schemaType.Name())
×
428
                }
×
429

430
                ref := &TypeReference{
755✔
431
                        Definition: def,
755✔
432
                        GQL:        schemaType,
755✔
433
                        IsRoot:     b.cfg.IsRoot(def),
755✔
434
                }
755✔
435

755✔
436
                obj, err := b.FindObject(pkgName, typeName)
755✔
437
                if err != nil {
755✔
438
                        return nil, err
×
439
                }
×
440
                t := code.Unalias(obj.Type())
755✔
441
                if values := b.enumValues(def); len(values) > 0 {
757✔
442
                        err = b.enumReference(ref, obj, values)
2✔
443
                        if err != nil {
2✔
444
                                return nil, err
×
445
                        }
×
446
                } else if fun, isFunc := obj.(*types.Func); isFunc {
1,237✔
447
                        ref.GO = code.Unalias(t.(*types.Signature).Params().At(0).Type())
484✔
448
                        ref.IsContext = code.Unalias(t.(*types.Signature).Results().At(0).Type()).String() == "github.com/99designs/gqlgen/graphql.ContextMarshaler"
484✔
449
                        ref.Marshaler = fun
484✔
450
                        ref.Unmarshaler = types.NewFunc(0, fun.Pkg(), "Unmarshal"+typeName, nil)
484✔
451
                } else if hasMethod(t, "MarshalGQLContext") && hasMethod(t, "UnmarshalGQLContext") {
753✔
452
                        ref.GO = t
×
453
                        ref.IsContext = true
×
454
                        ref.IsMarshaler = true
×
455
                } else if hasMethod(t, "MarshalGQL") && hasMethod(t, "UnmarshalGQL") {
269✔
456
                        ref.GO = t
×
457
                        ref.IsMarshaler = true
×
458
                } else if underlying := basicUnderlying(t); def.IsLeafType() && underlying != nil && underlying.Kind() == types.String {
275✔
459
                        // TODO delete before v1. Backwards compatibility case for named types wrapping strings (see #595)
6✔
460

6✔
461
                        ref.GO = t
6✔
462
                        ref.CastType = underlying
6✔
463

6✔
464
                        underlyingRef, err := b.TypeReference(&ast.Type{NamedType: "String"}, nil)
6✔
465
                        if err != nil {
6✔
466
                                return nil, err
×
467
                        }
×
468

469
                        ref.Marshaler = underlyingRef.Marshaler
6✔
470
                        ref.Unmarshaler = underlyingRef.Unmarshaler
6✔
471
                } else {
263✔
472
                        ref.GO = t
263✔
473
                }
263✔
474

475
                ref.Target = ref.GO
755✔
476
                ref.GO = b.CopyModifiersFromAst(schemaType, ref.GO)
755✔
477

755✔
478
                if bindTarget != nil {
1,272✔
479
                        if err = code.CompatibleTypes(ref.GO, bindTarget); err != nil {
519✔
480
                                continue
2✔
481
                        }
482
                        ref.GO = bindTarget
515✔
483
                }
484

485
                ref.PointersInUnmarshalInput = b.cfg.ReturnPointersInUnmarshalInput
753✔
486

753✔
487
                return ref, nil
753✔
488
        }
489

490
        return nil, fmt.Errorf("%s is incompatible with %s", schemaType.Name(), bindTarget.String())
2✔
491
}
492

493
func isValid(t types.Type) bool {
756✔
494
        basic, isBasic := t.(*types.Basic)
756✔
495
        if !isBasic {
1,347✔
496
                return true
591✔
497
        }
591✔
498
        return basic.Kind() != types.Invalid
165✔
499
}
500

501
func (b *Binder) CopyModifiersFromAst(t *ast.Type, base types.Type) types.Type {
1,398✔
502
        if t.Elem != nil {
1,573✔
503
                child := b.CopyModifiersFromAst(t.Elem, base)
175✔
504
                if _, isStruct := child.Underlying().(*types.Struct); isStruct && !b.cfg.OmitSliceElementPointers {
297✔
505
                        child = types.NewPointer(child)
122✔
506
                }
122✔
507
                return types.NewSlice(child)
175✔
508
        }
509

510
        var isInterface bool
1,223✔
511
        if named, ok := base.(*types.Named); ok {
1,683✔
512
                _, isInterface = named.Underlying().(*types.Interface)
460✔
513
        }
460✔
514

515
        if !isInterface && !IsNilable(base) && !t.NonNull {
1,730✔
516
                return types.NewPointer(base)
507✔
517
        }
507✔
518

519
        return base
716✔
520
}
521

522
func IsNilable(t types.Type) bool {
2,964✔
523
        // Note that we use types.Unalias rather than code.Unalias here
2,964✔
524
        // because we want to always check the underlying type.
2,964✔
525
        // code.Unalias only unwraps aliases in Go 1.23
2,964✔
526
        t = types.Unalias(t)
2,964✔
527
        if namedType, isNamed := t.(*types.Named); isNamed {
3,795✔
528
                return IsNilable(namedType.Underlying())
831✔
529
        }
831✔
530
        _, isPtr := t.(*types.Pointer)
2,133✔
531
        _, isMap := t.(*types.Map)
2,133✔
532
        _, isInterface := t.(*types.Interface)
2,133✔
533
        _, isSlice := t.(*types.Slice)
2,133✔
534
        _, isChan := t.(*types.Chan)
2,133✔
535
        return isPtr || isMap || isInterface || isSlice || isChan
2,133✔
536
}
537

538
func hasMethod(it types.Type, name string) bool {
538✔
539
        if ptr, isPtr := it.(*types.Pointer); isPtr {
538✔
540
                it = ptr.Elem()
×
541
        }
×
542
        namedType, ok := it.(*types.Named)
538✔
543
        if !ok {
538✔
544
                return false
×
545
        }
×
546

547
        for i := 0; i < namedType.NumMethods(); i++ {
3,512✔
548
                if namedType.Method(i).Name() == name {
2,974✔
549
                        return true
×
550
                }
×
551
        }
552
        return false
538✔
553
}
554

555
func basicUnderlying(it types.Type) *types.Basic {
269✔
556
        if ptr, isPtr := it.(*types.Pointer); isPtr {
269✔
557
                it = ptr.Elem()
×
558
        }
×
559
        namedType, ok := it.(*types.Named)
269✔
560
        if !ok {
269✔
561
                return nil
×
562
        }
×
563

564
        if basic, ok := namedType.Underlying().(*types.Basic); ok {
275✔
565
                return basic
6✔
566
        }
6✔
567

568
        return nil
263✔
569
}
570

571
type EnumValueReference struct {
572
        Definition *ast.EnumValueDefinition
573
        Object     types.Object
574
}
575

576
func (b *Binder) enumValues(def *ast.Definition) map[string]EnumValue {
755✔
577
        if def.Kind != ast.Enum {
1,484✔
578
                return nil
729✔
579
        }
729✔
580

581
        if strings.HasPrefix(def.Name, "__") {
50✔
582
                return nil
24✔
583
        }
24✔
584

585
        model, ok := b.cfg.Models[def.Name]
2✔
586
        if !ok {
2✔
587
                return nil
×
588
        }
×
589

590
        return model.EnumValues
2✔
591
}
592

593
func (b *Binder) enumReference(ref *TypeReference, obj types.Object, values map[string]EnumValue) error {
2✔
594
        if len(ref.Definition.EnumValues) != len(values) {
2✔
595
                return fmt.Errorf("not all enum values are binded for %v", ref.Definition.Name)
×
596
        }
×
597

598
        t := code.Unalias(obj.Type())
2✔
599
        if fn, ok := t.(*types.Signature); ok {
3✔
600
                ref.GO = code.Unalias(fn.Params().At(0).Type())
1✔
601
        } else {
2✔
602
                ref.GO = t
1✔
603
        }
1✔
604

605
        str, err := b.TypeReference(&ast.Type{NamedType: "String"}, nil)
2✔
606
        if err != nil {
2✔
607
                return err
×
608
        }
×
609

610
        ref.Marshaler = str.Marshaler
2✔
611
        ref.Unmarshaler = str.Unmarshaler
2✔
612
        ref.EnumValues = make([]EnumValueReference, 0, len(values))
2✔
613

2✔
614
        for _, value := range ref.Definition.EnumValues {
6✔
615
                v, ok := values[value.Name]
4✔
616
                if !ok {
4✔
617
                        return fmt.Errorf("enum value not found for: %v, of enum: %v", value.Name, ref.Definition.Name)
×
618
                }
×
619

620
                pkgName, typeName := code.PkgAndType(v.Value)
4✔
621
                if pkgName == "" {
4✔
622
                        return fmt.Errorf("missing package name for %v", value.Name)
×
623
                }
×
624

625
                valueObj, err := b.FindObject(pkgName, typeName)
4✔
626
                if err != nil {
4✔
627
                        return err
×
628
                }
×
629

630
                valueTyp := code.Unalias(valueObj.Type())
4✔
631
                if !types.AssignableTo(valueTyp, ref.GO) {
4✔
632
                        return fmt.Errorf("wrong type: %v, for enum value: %v, expected type: %v, of enum: %v",
×
633
                                valueTyp, value.Name, ref.GO, ref.Definition.Name)
×
634
                }
×
635

636
                switch valueObj.(type) {
4✔
637
                case *types.Const, *types.Var:
4✔
638
                        ref.EnumValues = append(ref.EnumValues, EnumValueReference{
4✔
639
                                Definition: value,
4✔
640
                                Object:     valueObj,
4✔
641
                        })
4✔
642
                default:
×
643
                        return fmt.Errorf("unsupported enum value for: %v, of enum: %v, only const and var allowed",
×
644
                                value.Name, ref.Definition.Name)
×
645
                }
646
        }
647

648
        return nil
2✔
649
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc