// Copyright 2022 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // See the License for the specific language governing permissions and // limitations under the License. //go:build go1.18 // +build go1.18 package main import ( "errors" "fmt" "go/ast" "go/token" "strings" "go.uber.org/mock/mockgen/model" ) func getTypeSpecTypeParams(ts *ast.TypeSpec) []*ast.Field { if ts == nil || ts.TypeParams == nil { return nil } return ts.TypeParams.List } 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) if err != nil { return nil, err } nm, ok := m.(*model.NamedType) if !ok { return m, nil } t, err := p.parseType(pkg, v.Index, tps) if err != nil { return nil, err } nm.TypeParams = &model.TypeParametersType{TypeParameters: []model.Type{t}} return m, nil case *ast.IndexListExpr: m, err := p.parseType(pkg, v.X, tps) if err != nil { return nil, err } nm, ok := m.(*model.NamedType) if !ok { return m, nil } var ts []model.Type for _, expr := range v.Indices { t, err := p.parseType(pkg, expr, tps) if err != nil { return nil, err } ts = append(ts, t) } nm.TypeParams = &model.TypeParametersType{TypeParameters: ts} return m, nil } return nil, nil } func getIdentTypeParams(decl any) string { if decl == nil { return "" } ts, ok := decl.(*ast.TypeSpec) if !ok { return "" } if ts.TypeParams == nil || len(ts.TypeParams.List) == 0 { return "" } var sb strings.Builder sb.WriteString("[") for i, v := range ts.TypeParams.List { if i != 0 { sb.WriteString(", ") } sb.WriteString(v.Names[0].Name) } 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 case *ast.UnaryExpr: if v.Op == token.TILDE { return nil, errConstraintInterface } return nil, fmt.Errorf("~T may only appear as constraint for %T", field.Type) case *ast.BinaryExpr: if v.Op == token.OR { return nil, errConstraintInterface } return nil, fmt.Errorf("A|B may only appear as constraint for %T", field.Type) 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) } var errConstraintInterface = errors.New("interface contains constraints")