diff --git a/mockgen/generic_go118.go b/mockgen/generic_go118.go index b29db9a8..26f5dffc 100644 --- a/mockgen/generic_go118.go +++ b/mockgen/generic_go118.go @@ -11,6 +11,7 @@ package main import ( + "fmt" "go/ast" "strings" @@ -24,7 +25,7 @@ func getTypeSpecTypeParams(ts *ast.TypeSpec) []*ast.Field { return ts.TypeParams.List } -func (p *fileParser) parseGenericType(pkg string, typ ast.Expr, tps map[string]bool) (model.Type, error) { +func (p *fileParser) parseGenericType(pkg string, typ ast.Expr, tps map[string]model.Type) (model.Type, error) { switch v := typ.(type) { case *ast.IndexExpr: m, err := p.parseType(pkg, v.X, tps) @@ -86,3 +87,30 @@ func getIdentTypeParams(decl interface{}) string { sb.WriteString("]") return sb.String() } + +func (p *fileParser) parseGenericMethod(field *ast.Field, it *namedInterface, iface *model.Interface, pkg string, tps map[string]model.Type) ([]*model.Method, error) { + var indices []ast.Expr + var typ ast.Expr + switch v := field.Type.(type) { + case *ast.IndexExpr: + indices = []ast.Expr{v.Index} + typ = v.X + case *ast.IndexListExpr: + indices = v.Indices + typ = v.X + default: + return nil, fmt.Errorf("don't know how to mock method of type %T", field.Type) + } + + nf := &ast.Field{ + Doc: field.Comment, + Names: field.Names, + Type: typ, + Tag: field.Tag, + Comment: field.Comment, + } + + it.embeddedInstTypeParams = indices + + return p.parseMethod(nf, it, iface, pkg, tps) +} diff --git a/mockgen/generic_notgo118.go b/mockgen/generic_notgo118.go index 8fe48c17..56304795 100644 --- a/mockgen/generic_notgo118.go +++ b/mockgen/generic_notgo118.go @@ -18,6 +18,7 @@ package main import ( + "fmt" "go/ast" "github.com/golang/mock/mockgen/model" @@ -27,10 +28,14 @@ func getTypeSpecTypeParams(ts *ast.TypeSpec) []*ast.Field { return nil } -func (p *fileParser) parseGenericType(pkg string, typ ast.Expr, tps map[string]bool) (model.Type, error) { +func (p *fileParser) parseGenericType(pkg string, typ ast.Expr, tps map[string]model.Type) (model.Type, error) { return nil, nil } func getIdentTypeParams(decl interface{}) string { return "" } + +func (p *fileParser) parseGenericMethod(field *ast.Field, it *namedInterface, iface *model.Interface, pkg string, tps map[string]model.Type) ([]*model.Method, error) { + return nil, fmt.Errorf("don't know how to mock method of type %T", field.Type) +} diff --git a/mockgen/internal/tests/generics/external.go b/mockgen/internal/tests/generics/external.go index ec5032aa..ecb355e0 100644 --- a/mockgen/internal/tests/generics/external.go +++ b/mockgen/internal/tests/generics/external.go @@ -1,6 +1,8 @@ package generics import ( + "context" + "github.com/golang/mock/mockgen/internal/tests/generics/other" "golang.org/x/exp/constraints" ) @@ -19,3 +21,50 @@ type ExternalConstraint[I constraints.Integer, F constraints.Float] interface { Nine(Iface[I]) Ten(*I) } + +type EmbeddingIface[T constraints.Integer, R constraints.Float] interface { + other.Twenty[T, StructType, R, other.Five] + TwentyTwo[StructType] + other.TwentyThree[TwentyTwo[R], TwentyTwo[T]] + TwentyFour[other.StructType] + Foo() error + ExternalConstraint[T, R] +} + +type TwentyOne[T any] interface { + TwentyOne() T +} + +type TwentyFour[T other.StructType] interface { + TwentyFour() T +} + +type Clonable[T any] interface { + Clone() T +} + +type Finder[T Clonable[T]] interface { + Find(ctx context.Context) ([]T, error) +} + +type UpdateNotifier[T any] interface { + NotifyC(ctx context.Context) <-chan []T + + Refresh(ctx context.Context) +} + +type EmbeddedW[W StructType] interface { + EmbeddedY[W] +} + +type EmbeddedX[X StructType] interface { + EmbeddedY[X] +} + +type EmbeddedY[Y StructType] interface { + EmbeddedZ[Y] +} + +type EmbeddedZ[Z any] interface { + EmbeddedZ(Z) +} diff --git a/mockgen/internal/tests/generics/generics.go b/mockgen/internal/tests/generics/generics.go index 0b389622..d0d02abe 100644 --- a/mockgen/internal/tests/generics/generics.go +++ b/mockgen/internal/tests/generics/generics.go @@ -25,6 +25,7 @@ type Bar[T any, R any] interface { Seventeen() (*Foo[other.Three, other.Four], error) Eighteen() (Iface[*other.Five], error) Nineteen() AliasType + other.Twenty[any, any, any, *other.Four] } type Foo[T any, R any] struct{} @@ -38,3 +39,7 @@ type StructType struct{} type StructType2 struct{} type AliasType Baz[other.Three] + +type TwentyTwo[T any] interface { + TwentyTwo() T +} diff --git a/mockgen/internal/tests/generics/other/other.go b/mockgen/internal/tests/generics/other/other.go index 9265422b..6129131b 100644 --- a/mockgen/internal/tests/generics/other/other.go +++ b/mockgen/internal/tests/generics/other/other.go @@ -9,3 +9,13 @@ type Three struct{} type Four struct{} type Five interface{} + +type Twenty[R, S, T any, Z any] interface { + Twenty(S, R) (T, Z) +} + +type TwentyThree[U, V any] interface { + TwentyThree(U, V) StructType +} + +type StructType struct{} diff --git a/mockgen/internal/tests/generics/source/assert_test.go b/mockgen/internal/tests/generics/source/assert_test.go new file mode 100644 index 00000000..1168a418 --- /dev/null +++ b/mockgen/internal/tests/generics/source/assert_test.go @@ -0,0 +1,12 @@ +package source + +import ( + "testing" + + "github.com/golang/mock/mockgen/internal/tests/generics" +) + +func TestAssert(t *testing.T) { + var x MockEmbeddingIface[int, float64] + var _ generics.EmbeddingIface[int, float64] = &x +} diff --git a/mockgen/internal/tests/generics/source/mock_external_test.go b/mockgen/internal/tests/generics/source/mock_external_test.go index aab22749..ab7f137a 100644 --- a/mockgen/internal/tests/generics/source/mock_external_test.go +++ b/mockgen/internal/tests/generics/source/mock_external_test.go @@ -5,6 +5,7 @@ package source import ( + context "context" reflect "reflect" gomock "github.com/golang/mock/gomock" @@ -171,3 +172,571 @@ func (mr *MockExternalConstraintMockRecorder[I, F]) Two(arg0 interface{}) *gomoc mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Two", reflect.TypeOf((*MockExternalConstraint[I, F])(nil).Two), arg0) } + +// MockEmbeddingIface is a mock of EmbeddingIface interface. +type MockEmbeddingIface[T constraints.Integer, R constraints.Float] struct { + ctrl *gomock.Controller + recorder *MockEmbeddingIfaceMockRecorder[T, R] +} + +// MockEmbeddingIfaceMockRecorder is the mock recorder for MockEmbeddingIface. +type MockEmbeddingIfaceMockRecorder[T constraints.Integer, R constraints.Float] struct { + mock *MockEmbeddingIface[T, R] +} + +// NewMockEmbeddingIface creates a new mock instance. +func NewMockEmbeddingIface[T constraints.Integer, R constraints.Float](ctrl *gomock.Controller) *MockEmbeddingIface[T, R] { + mock := &MockEmbeddingIface[T, R]{ctrl: ctrl} + mock.recorder = &MockEmbeddingIfaceMockRecorder[T, R]{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockEmbeddingIface[T, R]) EXPECT() *MockEmbeddingIfaceMockRecorder[T, R] { + return m.recorder +} + +// Eight mocks base method. +func (m *MockEmbeddingIface[T, R]) Eight(arg0 R) other.Two[T, R] { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Eight", arg0) + ret0, _ := ret[0].(other.Two[T, R]) + return ret0 +} + +// Eight indicates an expected call of Eight. +func (mr *MockEmbeddingIfaceMockRecorder[T, R]) Eight(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Eight", reflect.TypeOf((*MockEmbeddingIface[T, R])(nil).Eight), arg0) +} + +// Five mocks base method. +func (m *MockEmbeddingIface[T, R]) Five(arg0 T) generics.Baz[R] { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Five", arg0) + ret0, _ := ret[0].(generics.Baz[R]) + return ret0 +} + +// Five indicates an expected call of Five. +func (mr *MockEmbeddingIfaceMockRecorder[T, R]) Five(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Five", reflect.TypeOf((*MockEmbeddingIface[T, R])(nil).Five), arg0) +} + +// Foo mocks base method. +func (m *MockEmbeddingIface[T, R]) Foo() error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Foo") + ret0, _ := ret[0].(error) + return ret0 +} + +// Foo indicates an expected call of Foo. +func (mr *MockEmbeddingIfaceMockRecorder[T, R]) Foo() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Foo", reflect.TypeOf((*MockEmbeddingIface[T, R])(nil).Foo)) +} + +// Four mocks base method. +func (m *MockEmbeddingIface[T, R]) Four(arg0 T) generics.Foo[T, R] { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Four", arg0) + ret0, _ := ret[0].(generics.Foo[T, R]) + return ret0 +} + +// Four indicates an expected call of Four. +func (mr *MockEmbeddingIfaceMockRecorder[T, R]) Four(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Four", reflect.TypeOf((*MockEmbeddingIface[T, R])(nil).Four), arg0) +} + +// Nine mocks base method. +func (m *MockEmbeddingIface[T, R]) Nine(arg0 generics.Iface[T]) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "Nine", arg0) +} + +// Nine indicates an expected call of Nine. +func (mr *MockEmbeddingIfaceMockRecorder[T, R]) Nine(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Nine", reflect.TypeOf((*MockEmbeddingIface[T, R])(nil).Nine), arg0) +} + +// One mocks base method. +func (m *MockEmbeddingIface[T, R]) One(arg0 string) string { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "One", arg0) + ret0, _ := ret[0].(string) + return ret0 +} + +// One indicates an expected call of One. +func (mr *MockEmbeddingIfaceMockRecorder[T, R]) One(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "One", reflect.TypeOf((*MockEmbeddingIface[T, R])(nil).One), arg0) +} + +// Seven mocks base method. +func (m *MockEmbeddingIface[T, R]) Seven(arg0 T) other.One[T] { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Seven", arg0) + ret0, _ := ret[0].(other.One[T]) + return ret0 +} + +// Seven indicates an expected call of Seven. +func (mr *MockEmbeddingIfaceMockRecorder[T, R]) Seven(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Seven", reflect.TypeOf((*MockEmbeddingIface[T, R])(nil).Seven), arg0) +} + +// Six mocks base method. +func (m *MockEmbeddingIface[T, R]) Six(arg0 T) *generics.Baz[R] { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Six", arg0) + ret0, _ := ret[0].(*generics.Baz[R]) + return ret0 +} + +// Six indicates an expected call of Six. +func (mr *MockEmbeddingIfaceMockRecorder[T, R]) Six(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Six", reflect.TypeOf((*MockEmbeddingIface[T, R])(nil).Six), arg0) +} + +// Ten mocks base method. +func (m *MockEmbeddingIface[T, R]) Ten(arg0 *T) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "Ten", arg0) +} + +// Ten indicates an expected call of Ten. +func (mr *MockEmbeddingIfaceMockRecorder[T, R]) Ten(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Ten", reflect.TypeOf((*MockEmbeddingIface[T, R])(nil).Ten), arg0) +} + +// Three mocks base method. +func (m *MockEmbeddingIface[T, R]) Three(arg0 T) R { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Three", arg0) + ret0, _ := ret[0].(R) + return ret0 +} + +// Three indicates an expected call of Three. +func (mr *MockEmbeddingIfaceMockRecorder[T, R]) Three(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Three", reflect.TypeOf((*MockEmbeddingIface[T, R])(nil).Three), arg0) +} + +// Twenty mocks base method. +func (m *MockEmbeddingIface[T, R]) Twenty(arg0 generics.StructType, arg1 T) (R, other.Five) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Twenty", arg0, arg1) + ret0, _ := ret[0].(R) + ret1, _ := ret[1].(other.Five) + return ret0, ret1 +} + +// Twenty indicates an expected call of Twenty. +func (mr *MockEmbeddingIfaceMockRecorder[T, R]) Twenty(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Twenty", reflect.TypeOf((*MockEmbeddingIface[T, R])(nil).Twenty), arg0, arg1) +} + +// TwentyFour mocks base method. +func (m *MockEmbeddingIface[T, R]) TwentyFour() other.StructType { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "TwentyFour") + ret0, _ := ret[0].(other.StructType) + return ret0 +} + +// TwentyFour indicates an expected call of TwentyFour. +func (mr *MockEmbeddingIfaceMockRecorder[T, R]) TwentyFour() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TwentyFour", reflect.TypeOf((*MockEmbeddingIface[T, R])(nil).TwentyFour)) +} + +// TwentyThree mocks base method. +func (m *MockEmbeddingIface[T, R]) TwentyThree(arg0 generics.TwentyTwo[R], arg1 generics.TwentyTwo[T]) other.StructType { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "TwentyThree", arg0, arg1) + ret0, _ := ret[0].(other.StructType) + return ret0 +} + +// TwentyThree indicates an expected call of TwentyThree. +func (mr *MockEmbeddingIfaceMockRecorder[T, R]) TwentyThree(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TwentyThree", reflect.TypeOf((*MockEmbeddingIface[T, R])(nil).TwentyThree), arg0, arg1) +} + +// TwentyTwo mocks base method. +func (m *MockEmbeddingIface[T, R]) TwentyTwo() generics.StructType { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "TwentyTwo") + ret0, _ := ret[0].(generics.StructType) + return ret0 +} + +// TwentyTwo indicates an expected call of TwentyTwo. +func (mr *MockEmbeddingIfaceMockRecorder[T, R]) TwentyTwo() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TwentyTwo", reflect.TypeOf((*MockEmbeddingIface[T, R])(nil).TwentyTwo)) +} + +// Two mocks base method. +func (m *MockEmbeddingIface[T, R]) Two(arg0 T) string { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Two", arg0) + ret0, _ := ret[0].(string) + return ret0 +} + +// Two indicates an expected call of Two. +func (mr *MockEmbeddingIfaceMockRecorder[T, R]) Two(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Two", reflect.TypeOf((*MockEmbeddingIface[T, R])(nil).Two), arg0) +} + +// MockTwentyOne is a mock of TwentyOne interface. +type MockTwentyOne[T any] struct { + ctrl *gomock.Controller + recorder *MockTwentyOneMockRecorder[T] +} + +// MockTwentyOneMockRecorder is the mock recorder for MockTwentyOne. +type MockTwentyOneMockRecorder[T any] struct { + mock *MockTwentyOne[T] +} + +// NewMockTwentyOne creates a new mock instance. +func NewMockTwentyOne[T any](ctrl *gomock.Controller) *MockTwentyOne[T] { + mock := &MockTwentyOne[T]{ctrl: ctrl} + mock.recorder = &MockTwentyOneMockRecorder[T]{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockTwentyOne[T]) EXPECT() *MockTwentyOneMockRecorder[T] { + return m.recorder +} + +// TwentyOne mocks base method. +func (m *MockTwentyOne[T]) TwentyOne() T { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "TwentyOne") + ret0, _ := ret[0].(T) + return ret0 +} + +// TwentyOne indicates an expected call of TwentyOne. +func (mr *MockTwentyOneMockRecorder[T]) TwentyOne() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TwentyOne", reflect.TypeOf((*MockTwentyOne[T])(nil).TwentyOne)) +} + +// MockTwentyFour is a mock of TwentyFour interface. +type MockTwentyFour[T other.StructType] struct { + ctrl *gomock.Controller + recorder *MockTwentyFourMockRecorder[T] +} + +// MockTwentyFourMockRecorder is the mock recorder for MockTwentyFour. +type MockTwentyFourMockRecorder[T other.StructType] struct { + mock *MockTwentyFour[T] +} + +// NewMockTwentyFour creates a new mock instance. +func NewMockTwentyFour[T other.StructType](ctrl *gomock.Controller) *MockTwentyFour[T] { + mock := &MockTwentyFour[T]{ctrl: ctrl} + mock.recorder = &MockTwentyFourMockRecorder[T]{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockTwentyFour[T]) EXPECT() *MockTwentyFourMockRecorder[T] { + return m.recorder +} + +// TwentyFour mocks base method. +func (m *MockTwentyFour[T]) TwentyFour() T { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "TwentyFour") + ret0, _ := ret[0].(T) + return ret0 +} + +// TwentyFour indicates an expected call of TwentyFour. +func (mr *MockTwentyFourMockRecorder[T]) TwentyFour() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TwentyFour", reflect.TypeOf((*MockTwentyFour[T])(nil).TwentyFour)) +} + +// MockClonable is a mock of Clonable interface. +type MockClonable[T any] struct { + ctrl *gomock.Controller + recorder *MockClonableMockRecorder[T] +} + +// MockClonableMockRecorder is the mock recorder for MockClonable. +type MockClonableMockRecorder[T any] struct { + mock *MockClonable[T] +} + +// NewMockClonable creates a new mock instance. +func NewMockClonable[T any](ctrl *gomock.Controller) *MockClonable[T] { + mock := &MockClonable[T]{ctrl: ctrl} + mock.recorder = &MockClonableMockRecorder[T]{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockClonable[T]) EXPECT() *MockClonableMockRecorder[T] { + return m.recorder +} + +// Clone mocks base method. +func (m *MockClonable[T]) Clone() T { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Clone") + ret0, _ := ret[0].(T) + return ret0 +} + +// Clone indicates an expected call of Clone. +func (mr *MockClonableMockRecorder[T]) Clone() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Clone", reflect.TypeOf((*MockClonable[T])(nil).Clone)) +} + +// MockFinder is a mock of Finder interface. +type MockFinder[T generics.Clonable[T]] struct { + ctrl *gomock.Controller + recorder *MockFinderMockRecorder[T] +} + +// MockFinderMockRecorder is the mock recorder for MockFinder. +type MockFinderMockRecorder[T generics.Clonable[T]] struct { + mock *MockFinder[T] +} + +// NewMockFinder creates a new mock instance. +func NewMockFinder[T generics.Clonable[T]](ctrl *gomock.Controller) *MockFinder[T] { + mock := &MockFinder[T]{ctrl: ctrl} + mock.recorder = &MockFinderMockRecorder[T]{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockFinder[T]) EXPECT() *MockFinderMockRecorder[T] { + return m.recorder +} + +// Find mocks base method. +func (m *MockFinder[T]) Find(ctx context.Context) ([]T, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Find", ctx) + ret0, _ := ret[0].([]T) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Find indicates an expected call of Find. +func (mr *MockFinderMockRecorder[T]) Find(ctx interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Find", reflect.TypeOf((*MockFinder[T])(nil).Find), ctx) +} + +// MockUpdateNotifier is a mock of UpdateNotifier interface. +type MockUpdateNotifier[T any] struct { + ctrl *gomock.Controller + recorder *MockUpdateNotifierMockRecorder[T] +} + +// MockUpdateNotifierMockRecorder is the mock recorder for MockUpdateNotifier. +type MockUpdateNotifierMockRecorder[T any] struct { + mock *MockUpdateNotifier[T] +} + +// NewMockUpdateNotifier creates a new mock instance. +func NewMockUpdateNotifier[T any](ctrl *gomock.Controller) *MockUpdateNotifier[T] { + mock := &MockUpdateNotifier[T]{ctrl: ctrl} + mock.recorder = &MockUpdateNotifierMockRecorder[T]{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockUpdateNotifier[T]) EXPECT() *MockUpdateNotifierMockRecorder[T] { + return m.recorder +} + +// NotifyC mocks base method. +func (m *MockUpdateNotifier[T]) NotifyC(ctx context.Context) <-chan []T { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "NotifyC", ctx) + ret0, _ := ret[0].(<-chan []T) + return ret0 +} + +// NotifyC indicates an expected call of NotifyC. +func (mr *MockUpdateNotifierMockRecorder[T]) NotifyC(ctx interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NotifyC", reflect.TypeOf((*MockUpdateNotifier[T])(nil).NotifyC), ctx) +} + +// Refresh mocks base method. +func (m *MockUpdateNotifier[T]) Refresh(ctx context.Context) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "Refresh", ctx) +} + +// Refresh indicates an expected call of Refresh. +func (mr *MockUpdateNotifierMockRecorder[T]) Refresh(ctx interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Refresh", reflect.TypeOf((*MockUpdateNotifier[T])(nil).Refresh), ctx) +} + +// MockEmbeddedW is a mock of EmbeddedW interface. +type MockEmbeddedW[W generics.StructType] struct { + ctrl *gomock.Controller + recorder *MockEmbeddedWMockRecorder[W] +} + +// MockEmbeddedWMockRecorder is the mock recorder for MockEmbeddedW. +type MockEmbeddedWMockRecorder[W generics.StructType] struct { + mock *MockEmbeddedW[W] +} + +// NewMockEmbeddedW creates a new mock instance. +func NewMockEmbeddedW[W generics.StructType](ctrl *gomock.Controller) *MockEmbeddedW[W] { + mock := &MockEmbeddedW[W]{ctrl: ctrl} + mock.recorder = &MockEmbeddedWMockRecorder[W]{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockEmbeddedW[W]) EXPECT() *MockEmbeddedWMockRecorder[W] { + return m.recorder +} + +// EmbeddedZ mocks base method. +func (m *MockEmbeddedW[W]) EmbeddedZ(arg0 W) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "EmbeddedZ", arg0) +} + +// EmbeddedZ indicates an expected call of EmbeddedZ. +func (mr *MockEmbeddedWMockRecorder[W]) EmbeddedZ(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EmbeddedZ", reflect.TypeOf((*MockEmbeddedW[W])(nil).EmbeddedZ), arg0) +} + +// MockEmbeddedX is a mock of EmbeddedX interface. +type MockEmbeddedX[X generics.StructType] struct { + ctrl *gomock.Controller + recorder *MockEmbeddedXMockRecorder[X] +} + +// MockEmbeddedXMockRecorder is the mock recorder for MockEmbeddedX. +type MockEmbeddedXMockRecorder[X generics.StructType] struct { + mock *MockEmbeddedX[X] +} + +// NewMockEmbeddedX creates a new mock instance. +func NewMockEmbeddedX[X generics.StructType](ctrl *gomock.Controller) *MockEmbeddedX[X] { + mock := &MockEmbeddedX[X]{ctrl: ctrl} + mock.recorder = &MockEmbeddedXMockRecorder[X]{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockEmbeddedX[X]) EXPECT() *MockEmbeddedXMockRecorder[X] { + return m.recorder +} + +// EmbeddedZ mocks base method. +func (m *MockEmbeddedX[X]) EmbeddedZ(arg0 X) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "EmbeddedZ", arg0) +} + +// EmbeddedZ indicates an expected call of EmbeddedZ. +func (mr *MockEmbeddedXMockRecorder[X]) EmbeddedZ(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EmbeddedZ", reflect.TypeOf((*MockEmbeddedX[X])(nil).EmbeddedZ), arg0) +} + +// MockEmbeddedY is a mock of EmbeddedY interface. +type MockEmbeddedY[Y generics.StructType] struct { + ctrl *gomock.Controller + recorder *MockEmbeddedYMockRecorder[Y] +} + +// MockEmbeddedYMockRecorder is the mock recorder for MockEmbeddedY. +type MockEmbeddedYMockRecorder[Y generics.StructType] struct { + mock *MockEmbeddedY[Y] +} + +// NewMockEmbeddedY creates a new mock instance. +func NewMockEmbeddedY[Y generics.StructType](ctrl *gomock.Controller) *MockEmbeddedY[Y] { + mock := &MockEmbeddedY[Y]{ctrl: ctrl} + mock.recorder = &MockEmbeddedYMockRecorder[Y]{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockEmbeddedY[Y]) EXPECT() *MockEmbeddedYMockRecorder[Y] { + return m.recorder +} + +// EmbeddedZ mocks base method. +func (m *MockEmbeddedY[Y]) EmbeddedZ(arg0 Y) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "EmbeddedZ", arg0) +} + +// EmbeddedZ indicates an expected call of EmbeddedZ. +func (mr *MockEmbeddedYMockRecorder[Y]) EmbeddedZ(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EmbeddedZ", reflect.TypeOf((*MockEmbeddedY[Y])(nil).EmbeddedZ), arg0) +} + +// MockEmbeddedZ is a mock of EmbeddedZ interface. +type MockEmbeddedZ[Z any] struct { + ctrl *gomock.Controller + recorder *MockEmbeddedZMockRecorder[Z] +} + +// MockEmbeddedZMockRecorder is the mock recorder for MockEmbeddedZ. +type MockEmbeddedZMockRecorder[Z any] struct { + mock *MockEmbeddedZ[Z] +} + +// NewMockEmbeddedZ creates a new mock instance. +func NewMockEmbeddedZ[Z any](ctrl *gomock.Controller) *MockEmbeddedZ[Z] { + mock := &MockEmbeddedZ[Z]{ctrl: ctrl} + mock.recorder = &MockEmbeddedZMockRecorder[Z]{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockEmbeddedZ[Z]) EXPECT() *MockEmbeddedZMockRecorder[Z] { + return m.recorder +} + +// EmbeddedZ mocks base method. +func (m *MockEmbeddedZ[Z]) EmbeddedZ(arg0 Z) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "EmbeddedZ", arg0) +} + +// EmbeddedZ indicates an expected call of EmbeddedZ. +func (mr *MockEmbeddedZMockRecorder[Z]) EmbeddedZ(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EmbeddedZ", reflect.TypeOf((*MockEmbeddedZ[Z])(nil).EmbeddedZ), arg0) +} diff --git a/mockgen/internal/tests/generics/source/mock_generics_test.go b/mockgen/internal/tests/generics/source/mock_generics_test.go index 0223e311..5207636f 100644 --- a/mockgen/internal/tests/generics/source/mock_generics_test.go +++ b/mockgen/internal/tests/generics/source/mock_generics_test.go @@ -291,6 +291,21 @@ func (mr *MockBarMockRecorder[T, R]) Twelve() *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Twelve", reflect.TypeOf((*MockBar[T, R])(nil).Twelve)) } +// Twenty mocks base method. +func (m *MockBar[T, R]) Twenty(arg0, arg1 any) (any, *other.Four) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Twenty", arg0, arg1) + ret0, _ := ret[0].(any) + ret1, _ := ret[1].(*other.Four) + return ret0, ret1 +} + +// Twenty indicates an expected call of Twenty. +func (mr *MockBarMockRecorder[T, R]) Twenty(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Twenty", reflect.TypeOf((*MockBar[T, R])(nil).Twenty), arg0, arg1) +} + // Two mocks base method. func (m *MockBar[T, R]) Two(arg0 T) string { m.ctrl.T.Helper() @@ -327,3 +342,40 @@ func NewMockIface[T any](ctrl *gomock.Controller) *MockIface[T] { func (m *MockIface[T]) EXPECT() *MockIfaceMockRecorder[T] { return m.recorder } + +// MockTwentyTwo is a mock of TwentyTwo interface. +type MockTwentyTwo[T any] struct { + ctrl *gomock.Controller + recorder *MockTwentyTwoMockRecorder[T] +} + +// MockTwentyTwoMockRecorder is the mock recorder for MockTwentyTwo. +type MockTwentyTwoMockRecorder[T any] struct { + mock *MockTwentyTwo[T] +} + +// NewMockTwentyTwo creates a new mock instance. +func NewMockTwentyTwo[T any](ctrl *gomock.Controller) *MockTwentyTwo[T] { + mock := &MockTwentyTwo[T]{ctrl: ctrl} + mock.recorder = &MockTwentyTwoMockRecorder[T]{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockTwentyTwo[T]) EXPECT() *MockTwentyTwoMockRecorder[T] { + return m.recorder +} + +// TwentyTwo mocks base method. +func (m *MockTwentyTwo[T]) TwentyTwo() T { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "TwentyTwo") + ret0, _ := ret[0].(T) + return ret0 +} + +// TwentyTwo indicates an expected call of TwentyTwo. +func (mr *MockTwentyTwoMockRecorder[T]) TwentyTwo() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TwentyTwo", reflect.TypeOf((*MockTwentyTwo[T])(nil).TwentyTwo)) +} diff --git a/mockgen/parse.go b/mockgen/parse.go index 21c0d70a..59622d89 100644 --- a/mockgen/parse.go +++ b/mockgen/parse.go @@ -274,20 +274,77 @@ func (p *fileParser) parsePackage(path string) (*fileParser, error) { return newP, nil } +func (p *fileParser) constructInstParams(pkg string, params []*ast.Field, instParams []model.Type, embeddedInstParams []ast.Expr, tps map[string]model.Type) ([]model.Type, error) { + pm := make(map[string]int) + var i int + for _, v := range params { + for _, n := range v.Names { + pm[n.Name] = i + instParams = append(instParams, model.PredeclaredType(n.Name)) + i++ + } + } + + var runtimeInstParams []model.Type + for _, instParam := range embeddedInstParams { + switch t := instParam.(type) { + case *ast.Ident: + if idx, ok := pm[t.Name]; ok { + runtimeInstParams = append(runtimeInstParams, instParams[idx]) + continue + } + } + modelType, err := p.parseType(pkg, instParam, tps) + if err != nil { + return nil, err + } + runtimeInstParams = append(runtimeInstParams, modelType) + } + + return runtimeInstParams, nil +} + +func (p *fileParser) constructTps(it *namedInterface) (tps map[string]model.Type) { + tps = make(map[string]model.Type) + n := 0 + for _, tp := range it.typeParams { + for _, tm := range tp.Names { + tps[tm.Name] = nil + if len(it.instTypes) != 0 { + tps[tm.Name] = it.instTypes[n] + n++ + } + } + } + return tps +} + +// parseInterface loads interface specified by pkg and name, parses it and returns +// a new model with the parsed. func (p *fileParser) parseInterface(name, pkg string, it *namedInterface) (*model.Interface, error) { iface := &model.Interface{Name: name} - tps := make(map[string]bool) - + tps := p.constructTps(it) tp, err := p.parseFieldList(pkg, it.typeParams, tps) if err != nil { return nil, fmt.Errorf("unable to parse interface type parameters: %v", name) } + iface.TypeParams = tp - for _, v := range tp { - tps[v.Name] = true + for _, field := range it.it.Methods.List { + var methods []*model.Method + if methods, err = p.parseMethod(field, it, iface, pkg, tps); err != nil { + return nil, err + } + for _, m := range methods { + iface.AddMethod(m) + } } + return iface, nil +} - for _, field := range it.it.Methods.List { +func (p *fileParser) parseMethod(field *ast.Field, it *namedInterface, iface *model.Interface, pkg string, tps map[string]model.Type) ([]*model.Method, error) { + // {} for git diff + { switch v := field.Type.(type) { case *ast.FuncType: if nn := len(field.Names); nn != 1 { @@ -301,7 +358,7 @@ func (p *fileParser) parseInterface(name, pkg string, it *namedInterface) (*mode if err != nil { return nil, err } - iface.AddMethod(m) + return []*model.Method{m}, nil case *ast.Ident: // Embedded interface in this package. embeddedIfaceType := p.auxInterfaces.Get(pkg, v.String()) @@ -312,10 +369,15 @@ func (p *fileParser) parseInterface(name, pkg string, it *namedInterface) (*mode var embeddedIface *model.Interface if embeddedIfaceType != nil { var err error + embeddedIfaceType.instTypes, err = p.constructInstParams(pkg, it.typeParams, it.instTypes, it.embeddedInstTypeParams, tps) + if err != nil { + return nil, err + } embeddedIface, err = p.parseInterface(v.String(), pkg, embeddedIfaceType) if err != nil { return nil, err } + } else { // This is built-in error interface. if v.String() == model.ErrorInterface.Name { @@ -330,16 +392,17 @@ func (p *fileParser) parseInterface(name, pkg string, it *namedInterface) (*mode return nil, p.errorf(v.Pos(), "unknown embedded interface %s.%s", pkg, v.String()) } + embeddedIfaceType.instTypes, err = p.constructInstParams(pkg, it.typeParams, it.instTypes, it.embeddedInstTypeParams, tps) + if err != nil { + return nil, err + } embeddedIface, err = ip.parseInterface(v.String(), pkg, embeddedIfaceType) if err != nil { return nil, err } } } - // Copy the methods. - for _, m := range embeddedIface.Methods { - iface.AddMethod(m) - } + return embeddedIface.Methods, nil case *ast.SelectorExpr: // Embedded interface in another package. filePkg, sel := v.X.(*ast.Ident).String(), v.Sel.String() @@ -352,6 +415,10 @@ func (p *fileParser) parseInterface(name, pkg string, it *namedInterface) (*mode var err error embeddedIfaceType := p.auxInterfaces.Get(filePkg, sel) if embeddedIfaceType != nil { + embeddedIfaceType.instTypes, err = p.constructInstParams(pkg, it.typeParams, it.instTypes, it.embeddedInstTypeParams, tps) + if err != nil { + return nil, err + } embeddedIface, err = p.parseInterface(sel, filePkg, embeddedIfaceType) if err != nil { return nil, err @@ -373,24 +440,25 @@ func (p *fileParser) parseInterface(name, pkg string, it *namedInterface) (*mode if embeddedIfaceType = parser.importedInterfaces.Get(path, sel); embeddedIfaceType == nil { return nil, p.errorf(v.Pos(), "unknown embedded interface %s.%s", path, sel) } + + embeddedIfaceType.instTypes, err = p.constructInstParams(pkg, it.typeParams, it.instTypes, it.embeddedInstTypeParams, tps) + if err != nil { + return nil, err + } embeddedIface, err = parser.parseInterface(sel, path, embeddedIfaceType) if err != nil { return nil, err } } - // Copy the methods. // TODO: apply shadowing rules. - for _, m := range embeddedIface.Methods { - iface.AddMethod(m) - } + return embeddedIface.Methods, nil default: - return nil, fmt.Errorf("don't know how to mock method of type %T", field.Type) + return p.parseGenericMethod(field, it, iface, pkg, tps) } } - return iface, nil } -func (p *fileParser) parseFunc(pkg string, f *ast.FuncType, tps map[string]bool) (inParam []*model.Parameter, variadic *model.Parameter, outParam []*model.Parameter, err error) { +func (p *fileParser) parseFunc(pkg string, f *ast.FuncType, tps map[string]model.Type) (inParam []*model.Parameter, variadic *model.Parameter, outParam []*model.Parameter, err error) { if f.Params != nil { regParams := f.Params.List if isVariadic(f) { @@ -417,7 +485,7 @@ func (p *fileParser) parseFunc(pkg string, f *ast.FuncType, tps map[string]bool) return } -func (p *fileParser) parseFieldList(pkg string, fields []*ast.Field, tps map[string]bool) ([]*model.Parameter, error) { +func (p *fileParser) parseFieldList(pkg string, fields []*ast.Field, tps map[string]model.Type) ([]*model.Parameter, error) { nf := 0 for _, f := range fields { nn := len(f.Names) @@ -451,7 +519,7 @@ func (p *fileParser) parseFieldList(pkg string, fields []*ast.Field, tps map[str return ps, nil } -func (p *fileParser) parseType(pkg string, typ ast.Expr, tps map[string]bool) (model.Type, error) { +func (p *fileParser) parseType(pkg string, typ ast.Expr, tps map[string]model.Type) (model.Type, error) { switch v := typ.(type) { case *ast.ArrayType: ln := -1 @@ -493,7 +561,8 @@ func (p *fileParser) parseType(pkg string, typ ast.Expr, tps map[string]bool) (m } return &model.FuncType{In: in, Out: out, Variadic: variadic}, nil case *ast.Ident: - if v.IsExported() && !tps[v.Name] { + it, ok := tps[v.Name] + if v.IsExported() && !ok { // `pkg` may be an aliased imported pkg // if so, patch the import w/ the fully qualified import maybeImportedPkg, ok := p.imports[pkg] @@ -503,7 +572,9 @@ func (p *fileParser) parseType(pkg string, typ ast.Expr, tps map[string]bool) (m // assume type in this package return &model.NamedType{Package: pkg, Type: v.Name}, nil } - + if ok && it != nil { + return it, nil + } // assume predeclared type return model.PredeclaredType(v.Name), nil case *ast.InterfaceType: @@ -657,9 +728,11 @@ func importsOfFile(file *ast.File) (normalImports map[string]importedPackage, do } type namedInterface struct { - name *ast.Ident - it *ast.InterfaceType - typeParams []*ast.Field + name *ast.Ident + it *ast.InterfaceType + typeParams []*ast.Field + embeddedInstTypeParams []ast.Expr + instTypes []model.Type } // Create an iterator over all interfaces in file. @@ -681,7 +754,7 @@ func iterInterfaces(file *ast.File) <-chan *namedInterface { continue } - ch <- &namedInterface{ts.Name, it, getTypeSpecTypeParams(ts)} + ch <- &namedInterface{name: ts.Name, it: it, typeParams: getTypeSpecTypeParams(ts)} } } close(ch)