Commit e7bd71c8 authored by Gary Burd's avatar Gary Burd Committed by Robert Griesemer

go/doc: Handle recursive embedded types.

R=golang-dev, gri
CC=golang-dev
https://golang.org/cl/5645053
parent 025c9a94
...@@ -543,7 +543,8 @@ func customizeRecv(f *Func, recvTypeName string, embeddedIsPtr bool, level int) ...@@ -543,7 +543,8 @@ func customizeRecv(f *Func, recvTypeName string, embeddedIsPtr bool, level int)
// collectEmbeddedMethods collects the embedded methods of typ in mset. // collectEmbeddedMethods collects the embedded methods of typ in mset.
// //
func (r *reader) collectEmbeddedMethods(mset methodSet, typ *namedType, recvTypeName string, embeddedIsPtr bool, level int) { func (r *reader) collectEmbeddedMethods(mset methodSet, typ *namedType, recvTypeName string, embeddedIsPtr bool, level int, visited map[*namedType]bool) {
visited[typ] = true
for embedded, isPtr := range typ.embedded { for embedded, isPtr := range typ.embedded {
// Once an embedded type is embedded as a pointer type // Once an embedded type is embedded as a pointer type
// all embedded types in those types are treated like // all embedded types in those types are treated like
...@@ -557,8 +558,11 @@ func (r *reader) collectEmbeddedMethods(mset methodSet, typ *namedType, recvType ...@@ -557,8 +558,11 @@ func (r *reader) collectEmbeddedMethods(mset methodSet, typ *namedType, recvType
mset.add(customizeRecv(m, recvTypeName, thisEmbeddedIsPtr, level)) mset.add(customizeRecv(m, recvTypeName, thisEmbeddedIsPtr, level))
} }
} }
r.collectEmbeddedMethods(mset, embedded, recvTypeName, thisEmbeddedIsPtr, level+1) if !visited[embedded] {
r.collectEmbeddedMethods(mset, embedded, recvTypeName, thisEmbeddedIsPtr, level+1, visited)
} }
}
delete(visited, typ)
} }
// computeMethodSets determines the actual method sets for each type encountered. // computeMethodSets determines the actual method sets for each type encountered.
...@@ -568,7 +572,7 @@ func (r *reader) computeMethodSets() { ...@@ -568,7 +572,7 @@ func (r *reader) computeMethodSets() {
// collect embedded methods for t // collect embedded methods for t
if t.isStruct { if t.isStruct {
// struct // struct
r.collectEmbeddedMethods(t.methods, t, t.name, false, 1) r.collectEmbeddedMethods(t.methods, t, t.name, false, 1, make(map[*namedType]bool))
} else { } else {
// interface // interface
// TODO(gri) fix this // TODO(gri) fix this
......
...@@ -40,3 +40,70 @@ TYPES ...@@ -40,3 +40,70 @@ TYPES
T4 T4
} }
//
type U1 struct {
*U1
}
// U1.M should appear as method of U1.
func (*U1) M()
//
type U2 struct {
*U3
}
// U2.M should appear as method of U2 and as method of U3 only if ...
func (*U2) M()
//
type U3 struct {
*U2
}
// U3.N should appear as method of U3 and as method of U2 only if ...
func (*U3) N()
//
type U4 struct {
// contains filtered or unexported fields
}
// U4.M should appear as method of U4.
func (*U4) M()
//
type V1 struct {
*V2
*V5
}
//
type V2 struct {
*V3
}
//
type V3 struct {
*V4
}
//
type V4 struct {
*V5
}
// V4.M should appear as method of V2 and V3 if AllMethods is set.
func (*V4) M()
//
type V5 struct {
*V6
}
//
type V6 struct{}
// V6.M should appear as method of V1 and V5 if AllMethods is set.
func (*V6) M()
...@@ -42,6 +42,73 @@ TYPES ...@@ -42,6 +42,73 @@ TYPES
T4 T4
} }
//
type U1 struct {
*U1
}
// U1.M should appear as method of U1.
func (*U1) M()
//
type U2 struct {
*U3
}
// U2.M should appear as method of U2 and as method of U3 only if ...
func (*U2) M()
//
type U3 struct {
*U2
}
// U3.N should appear as method of U3 and as method of U2 only if ...
func (*U3) N()
//
type U4 struct {
*u5
}
// U4.M should appear as method of U4.
func (*U4) M()
//
type V1 struct {
*V2
*V5
}
//
type V2 struct {
*V3
}
//
type V3 struct {
*V4
}
//
type V4 struct {
*V5
}
// V4.M should appear as method of V2 and V3 if AllMethods is set.
func (*V4) M()
//
type V5 struct {
*V6
}
//
type V6 struct{}
// V6.M should appear as method of V1 and V5 if AllMethods is set.
func (*V6) M()
// //
type t1 struct{} type t1 struct{}
...@@ -70,3 +137,8 @@ TYPES ...@@ -70,3 +137,8 @@ TYPES
// t2.M should not appear as method in a Tx type. // t2.M should not appear as method in a Tx type.
func (t2e) M() func (t2e) M()
//
type u5 struct {
*U4
}
...@@ -43,3 +43,88 @@ TYPES ...@@ -43,3 +43,88 @@ TYPES
// T4.M should appear as method of T5 only if AllMethods is set. // T4.M should appear as method of T5 only if AllMethods is set.
func (*T5) M() func (*T5) M()
//
type U1 struct {
*U1
}
// U1.M should appear as method of U1.
func (*U1) M()
//
type U2 struct {
*U3
}
// U2.M should appear as method of U2 and as method of U3 only if ...
func (*U2) M()
// U3.N should appear as method of U3 and as method of U2 only if ...
func (U2) N()
//
type U3 struct {
*U2
}
// U2.M should appear as method of U2 and as method of U3 only if ...
func (U3) M()
// U3.N should appear as method of U3 and as method of U2 only if ...
func (*U3) N()
//
type U4 struct {
// contains filtered or unexported fields
}
// U4.M should appear as method of U4.
func (*U4) M()
//
type V1 struct {
*V2
*V5
}
// V6.M should appear as method of V1 and V5 if AllMethods is set.
func (V1) M()
//
type V2 struct {
*V3
}
// V4.M should appear as method of V2 and V3 if AllMethods is set.
func (V2) M()
//
type V3 struct {
*V4
}
// V4.M should appear as method of V2 and V3 if AllMethods is set.
func (V3) M()
//
type V4 struct {
*V5
}
// V4.M should appear as method of V2 and V3 if AllMethods is set.
func (*V4) M()
//
type V5 struct {
*V6
}
// V6.M should appear as method of V1 and V5 if AllMethods is set.
func (V5) M()
//
type V6 struct{}
// V6.M should appear as method of V1 and V5 if AllMethods is set.
func (*V6) M()
...@@ -77,3 +77,71 @@ func (*T4) M() {} ...@@ -77,3 +77,71 @@ func (*T4) M() {}
type T5 struct { type T5 struct {
T4 T4
} }
// ----------------------------------------------------------------------------
// Recursive type declarations must not lead to endless recursion.
type U1 struct {
*U1
}
// U1.M should appear as method of U1.
func (*U1) M() {}
type U2 struct {
*U3
}
// U2.M should appear as method of U2 and as method of U3 only if AllMethods is set.
func (*U2) M() {}
type U3 struct {
*U2
}
// U3.N should appear as method of U3 and as method of U2 only if AllMethods is set.
func (*U3) N() {}
type U4 struct {
*u5
}
// U4.M should appear as method of U4.
func (*U4) M() {}
type u5 struct {
*U4
}
// ----------------------------------------------------------------------------
// A higher-level embedded type (and its methods) wins over the same type (and
// its methods) embedded at a lower level.
type V1 struct {
*V2
*V5
}
type V2 struct {
*V3
}
type V3 struct {
*V4
}
type V4 struct {
*V5
}
type V5 struct {
*V6
}
type V6 struct{}
// V4.M should appear as method of V2 and V3 if AllMethods is set.
func (*V4) M() {}
// V6.M should appear as method of V1 and V5 if AllMethods is set.
func (*V6) M() {}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment