Skip to content

Commit 784703f

Browse files
committed
Fix endless recursion when traversing recursive types.
Simply keep a slice of already visited types and exit early. Fixes #47 Signed-off-by: Jakub Ciolek <[email protected]>
1 parent 806c0b0 commit 784703f

File tree

2 files changed

+11
-6
lines changed

2 files changed

+11
-6
lines changed

internal/method/resolver.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ func NewResolveReferences(traverser *xptypes.Traverser, receiver, clientPath, re
4343
Field: refProcessor,
4444
Named: xptypes.NamedProcessorChain{},
4545
}
46-
if err := traverser.Traverse(n, cfg); err != nil {
46+
if err := traverser.Traverse(n, cfg, []*types.Named{}); err != nil {
4747
panic(errors.Wrapf(err, "cannot traverse the type tree of %s", n.Obj().Name()))
4848
}
4949
refs := refProcessor.GetReferences()

internal/types/types.go

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -86,8 +86,13 @@ type Traverser struct {
8686
// constructing an error. But we keep that for future type and field processors.
8787

8888
// Traverse traverser given type recursively and runs given processors.
89-
func (t *Traverser) Traverse(n *types.Named, cfg *ProcessorConfig, parentFields ...string) error { // nolint:gocyclo
89+
func (t *Traverser) Traverse(n *types.Named, cfg *ProcessorConfig, visited []*types.Named, parentFields ...string) error { // nolint:gocyclo
9090
// NOTE(muvaf): gocyclo is disabled due to repeated type checks.
91+
for _, v := range visited {
92+
if n == v {
93+
return nil
94+
}
95+
}
9196
if err := cfg.Named.Process(n, t.comments.For(n.Obj())); err != nil {
9297
return errors.Wrapf(err, "type processors failed to run for type %s", n.Obj().Name())
9398
}
@@ -103,24 +108,24 @@ func (t *Traverser) Traverse(n *types.Named, cfg *ProcessorConfig, parentFields
103108
}
104109
switch ft := field.Type().(type) {
105110
case *types.Named:
106-
if err := t.Traverse(ft, cfg, append(parentFields, field.Name())...); err != nil {
111+
if err := t.Traverse(ft, cfg, visited, append(parentFields, field.Name())...); err != nil {
107112
return errors.Wrapf(err, "failed to traverse type of field %s", field.Name())
108113
}
109114
case *types.Pointer:
110115
if elemType, ok := ft.Elem().(*types.Named); ok {
111-
if err := t.Traverse(elemType, cfg, append(parentFields, "*"+field.Name())...); err != nil {
116+
if err := t.Traverse(elemType, cfg, visited, append(parentFields, "*"+field.Name())...); err != nil {
112117
return errors.Wrapf(err, "failed to traverse type of field %s", field.Name())
113118
}
114119
}
115120
case *types.Slice:
116121
switch elemType := ft.Elem().(type) {
117122
case *types.Named:
118-
if err := t.Traverse(elemType, cfg, append(parentFields, "[]"+field.Name())...); err != nil {
123+
if err := t.Traverse(elemType, cfg, visited, append(parentFields, "[]"+field.Name())...); err != nil {
119124
return errors.Wrapf(err, "failed to traverse type of field %s", field.Name())
120125
}
121126
case *types.Pointer:
122127
if elemElemType, ok := elemType.Elem().(*types.Named); ok {
123-
if err := t.Traverse(elemElemType, cfg, append(parentFields, "[]"+"*"+field.Name())...); err != nil {
128+
if err := t.Traverse(elemElemType, cfg, visited, append(parentFields, "[]"+"*"+field.Name())...); err != nil {
124129
return errors.Wrapf(err, "failed to traverse type of field %s", field.Name())
125130
}
126131
}

0 commit comments

Comments
 (0)