func (f *File) validParams(params *ast.FieldList) *Error { if params == nil { panic("ERROR: params fieldlist should never be nil") } if params.List == nil { return nil } for i := 0; i < params.NumFields(); i++ { field := params.List[i] if field == nil { return &Error{errors.New(fmt.Sprint("ERROR nil field, anonymous fields not allowed!!")), params.Pos()} } if len(field.Names) != 1 { panic("ERROR len(field.Names) != 1!!") } name := field.Names[0] if name == nil { panic("ERROR name == nil, this shouldn't occur") } typ := f.Info.TypeOf(field.Type) if e := f.validParamType(typ); e != nil { e.Pos = field.Pos() return e } } return nil }
// storeParams handles parameters // // If the parameters include an ellipsis we need to copy parameters into // an interface{} array as follows. // // params := []interface{}{} // params[0] = p1 // params[1] = p2 // for i, p := range ellipsisParam { // params[2+i] = p // } // // If not it is better to add the params to the call directly for performance // reasons func storeParams(params *ast.FieldList) ([]ast.Stmt, bool, error) { // Is there an ellipsis parameter? listlen := len(params.List) if listlen > 0 { last := params.List[len(params.List)-1] if _, ok := last.Type.(*ast.Ellipsis); ok { code := fmt.Sprintf("\tut__params := make([]interface{}, %d + len(%s))\n", params.NumFields()-1, last.Names[0].Name) i := 0 for _, f := range params.List { for _, n := range f.Names { if _, ok := f.Type.(*ast.Ellipsis); ok { // Ellipsis expression code += fmt.Sprintf(` for j, p := range %s { ut__params[%d+j] = p } `, n.Name, i) } else { code += fmt.Sprintf("\tut__params[%d] = %s\n", i, n.Name) } i++ } } stmts, err := parseCodeBlock(code) return stmts, true, err } } return nil, false, nil }
func (a *typeCompiler) compileFields(fields *ast.FieldList, allowRec bool) ([]Type, []*ast.Ident, []token.Pos, bool) { n := fields.NumFields() ts := make([]Type, n) ns := make([]*ast.Ident, n) ps := make([]token.Pos, n) bad := false if fields != nil { i := 0 for _, f := range fields.List { t := a.compileType(f.Type, allowRec) if t == nil { bad = true } if f.Names == nil { ns[i] = nil ts[i] = t ps[i] = f.Type.Pos() i++ continue } for _, n := range f.Names { ns[i] = n ts[i] = t ps[i] = n.Pos() i++ } } } return ts, ns, ps, bad }
func (check *Checker) collectParams(scope *Scope, list *ast.FieldList, variadicOk bool) (params []*Var, variadic bool) { if list == nil { return } var named, anonymous bool for i, field := range list.List { ftype := field.Type if t, _ := ftype.(*ast.Ellipsis); t != nil { ftype = t.Elt if variadicOk && i == len(list.List)-1 { variadic = true } else { check.invalidAST(field.Pos(), "... not permitted") // ignore ... and continue } } typ := check.typ(ftype) // The parser ensures that f.Tag is nil and we don't // care if a constructed AST contains a non-nil tag. if len(field.Names) > 0 { // named parameter for _, name := range field.Names { if name.Name == "" { check.invalidAST(name.Pos(), "anonymous parameter") // ok to continue } par := NewParam(name.Pos(), check.pkg, name.Name, typ) check.declare(scope, name, par, scope.pos) params = append(params, par) } named = true } else { // anonymous parameter par := NewParam(ftype.Pos(), check.pkg, "", typ) check.recordImplicit(field, par) params = append(params, par) anonymous = true } } if named && anonymous { check.invalidAST(list.Pos(), "list contains both named and anonymous parameters") // ok to continue } // For a variadic function, change the last parameter's type from T to []T. if variadic && len(params) > 0 { last := params[len(params)-1] last.typ = &Slice{elem: last.typ} } return }
func (p *parser) parseParams(n *parse.Node, scope *ast.Scope) *ast.FieldList { fieldList := ast.FieldList{ Opening: token.Pos(n.Child(0).Pos()), Closing: token.Pos(n.LastChild().Pos()), } if n.Child(1).Is(parameterList) { eachListItem(parameterDecl, n.Child(1), func(item *parse.Node) { fieldList.List = append(fieldList.List, p.parseParamDecl(item, scope)) }) } return &fieldList }
// Sets multiLine to true if the signature spans multiple lines. func (p *printer) signature(params, result *ast.FieldList, multiLine *bool) { p.parameters(params, multiLine) n := result.NumFields() if n > 0 { p.print(blank) if n == 1 && result.List[0].Names == nil { // single anonymous result; no ()'s p.expr(result.List[0].Type, multiLine) return } p.parameters(result, multiLine) } }
func (p *printer) funcreturn(result *ast.FieldList) { n := result.NumFields() if n > 0 { p.print(blank) if n == 1 && result.List[0].Names == nil { // single anonymous result; no ()'s p.expr(result.List[0].Type) return } p.parameters(result) } else { p.print("void ") } }
func (fs *FileSet) parseFieldList(fl *ast.FieldList) []gen.StructField { if fl == nil || fl.NumFields() == 0 { return nil } out := make([]gen.StructField, 0, fl.NumFields()) for i, field := range fl.List { fds := fs.getField(field) if len(fds) > 0 { out = append(out, fds...) } else { warnf(" \u26a0 ignored struct field %d\n", i) } } return out }
// filterFieldList removes unexported fields (field names) from the field list // in place and returns true if fields were removed. Anonymous fields are // recorded with the parent type. filterType is called with the types of // all remaining fields. // func (r *reader) filterFieldList(parent *namedType, fields *ast.FieldList) (removedFields bool) { if fields == nil { return } list := fields.List j := 0 for _, field := range list { keepField := false if n := len(field.Names); n == 0 { // anonymous field name := r.recordAnonymousField(parent, field.Type) if ast.IsExported(name) { keepField = true } } else { field.Names = filterIdentList(field.Names) if len(field.Names) < n { removedFields = true } if len(field.Names) > 0 { keepField = true } } if keepField { r.filterType(nil, field.Type) list[j] = field j++ } } if j < len(list) { removedFields = true } fields.List = list[0:j] return }
func (check *checker) collectMethods(list *ast.FieldList) (methods []*Method) { if list == nil { return } for _, f := range list.List { typ := check.typ(f.Type, len(f.Names) > 0) // cycles are not ok for embedded interfaces // the parser ensures that f.Tag is nil and we don't // care if a constructed AST contains a non-nil tag if len(f.Names) > 0 { // methods (the parser ensures that there's only one // and we don't care if a constructed AST has more) sig, ok := typ.(*Signature) if !ok { check.invalidAST(f.Type.Pos(), "%s is not a method signature", typ) continue } for _, name := range f.Names { methods = append(methods, &Method{QualifiedName{check.pkg, name.Name}, sig}) } } else { // embedded interface utyp := underlying(typ) if ityp, ok := utyp.(*Interface); ok { methods = append(methods, ityp.Methods...) } else if utyp != Typ[Invalid] { // if utyp is invalid, don't complain (the root cause was reported before) check.errorf(f.Type.Pos(), "%s is not an interface type", typ) } } } // Check for double declarations. // The parser inserts methods into an interface-local scope, so local // double declarations are reported by the parser already. We need to // check again for conflicts due to embedded interfaces. This will lead // to a 2nd error message if the double declaration was reported before // by the parser. // TODO(gri) clean this up a bit seen := make(map[string]bool) for _, m := range methods { if seen[m.Name] { check.errorf(list.Pos(), "multiple methods named %s", m.Name) return // keep multiple entries, lookup will only return the first entry } seen[m.Name] = true } return }
func (fs *FileSet) parseFieldList(fl *ast.FieldList) []gen.StructField { if fl == nil || fl.NumFields() == 0 { return nil } out := make([]gen.StructField, 0, fl.NumFields()) for _, field := range fl.List { pushstate(fieldName(field)) fds := fs.getField(field) if len(fds) > 0 { out = append(out, fds...) } else { warnln("ignored.") } popstate() } return out }
func (p *parser) parseInterfaceType(n *parse.Node) ast.Expr { keywordPos := token.Pos(n.Child(0).Pos()) n = n.Child(1) specs := ast.FieldList{ Opening: token.Pos(n.Child(0).Pos()), Closing: token.Pos(n.LastChild().Pos()), } if n.ChildCount() > 2 { eachListItem(methodSpec, n.Child(1), func(item *parse.Node) { specs.List = append(specs.List, p.parseMethodSpec(item)) }) } return &ast.InterfaceType{ Interface: keywordPos, Methods: &specs, } }
func (p *printer) signature(params, result *ast.FieldList) { if params != nil { p.parameters(params) } else { p.print(token.LPAREN, token.RPAREN) } n := result.NumFields() if n > 0 { // result != nil p.print(blank) if n == 1 && result.List[0].Names == nil { // single anonymous result; no ()'s p.expr(stripParensAlways(result.List[0].Type)) return } p.parameters(result) } }
func (check *checker) collectMethods(list *ast.FieldList) (methods ObjList) { if list == nil { return } for _, f := range list.List { typ := check.typ(f.Type, len(f.Names) > 0) // cycles are not ok for embedded interfaces // the parser ensures that f.Tag is nil and we don't // care if a constructed AST contains a non-nil tag if len(f.Names) > 0 { // methods (the parser ensures that there's only one // and we don't care if a constructed AST has more) if _, ok := typ.(*Signature); !ok { check.invalidAST(f.Type.Pos(), "%s is not a method signature", typ) continue } for _, name := range f.Names { obj := name.Obj obj.Type = typ methods = append(methods, obj) } } else { // embedded interface utyp := underlying(typ) if ityp, ok := utyp.(*Interface); ok { methods = append(methods, ityp.Methods...) } else if utyp != Typ[Invalid] { // if utyp is invalid, don't complain (the root cause was reported before) check.errorf(f.Type.Pos(), "%s is not an interface type", typ) } } } // check for double declarations methods.Sort() prev := "" for _, obj := range methods { if obj.Name == prev { check.errorf(list.Pos(), "multiple methods named %s", prev) return // keep multiple entries, lookup will only return the first entry } } return }
func (check *checker) collectMethods(list *ast.FieldList) (methods ObjSet) { if list == nil { return } for _, f := range list.List { typ := check.typ(f.Type, len(f.Names) > 0) // cycles are not ok for embedded interfaces // the parser ensures that f.Tag is nil and we don't // care if a constructed AST contains a non-nil tag if len(f.Names) > 0 { // methods (the parser ensures that there's only one // and we don't care if a constructed AST has more) sig, ok := typ.(*Signature) if !ok { check.invalidAST(f.Type.Pos(), "%s is not a method signature", typ) continue } for _, name := range f.Names { // TODO(gri) provide correct declaration info obj := &Func{check.pkg, name.Name, sig, nil} if alt := methods.Insert(obj); alt != nil { check.errorf(list.Pos(), "multiple methods named %s", name.Name) } check.register(name, obj) } } else { // embedded interface utyp := typ.Underlying() if ityp, ok := utyp.(*Interface); ok { for _, obj := range ityp.methods.entries { if alt := methods.Insert(obj); alt != nil { check.errorf(list.Pos(), "multiple methods named %s", obj.Name()) } } } else if utyp != Typ[Invalid] { // if utyp is invalid, don't complain (the root cause was reported before) check.errorf(f.Type.Pos(), "%s is not an interface type", typ) } } } return }
// Struct creates a struct{} expression. The arguments are a series // of name/type/tag tuples. Name must be of type *ast.Ident, type // must be of type ast.Expr, and tag must be of type *ast.BasicLit, // The number of arguments must be a multiple of 3, or a run-time // panic will occur. func Struct(args ...ast.Expr) *ast.StructType { fields := new(ast.FieldList) if len(args)%3 != 0 { panic("Number of args to FieldList must be a multiple of 3, got " + strconv.Itoa(len(args))) } for i := 0; i < len(args); i += 3 { var field ast.Field name, typ, tag := args[i], args[i+1], args[i+2] if name != nil { field.Names = []*ast.Ident{name.(*ast.Ident)} } if typ != nil { field.Type = typ } if tag != nil { field.Tag = tag.(*ast.BasicLit) } fields.List = append(fields.List, &field) } return &ast.StructType{Fields: fields} }
func (f *File) validResults(results *ast.FieldList) *Error { if results == nil || results.List == nil { return nil } if results.NumFields() != 1 { err := fmt.Sprint("ERROR: can only return at most one result, not:", results.NumFields()) return &Error{errors.New(err), results.Pos()} } result := results.List[0] if result == nil { return nil } if result.Names != nil { return &Error{errors.New(fmt.Sprint("ERROR: can only return nonnamed result, not:", result.Names)), result.Pos()} } typ := f.Info.TypeOf(result.Type) if err := f.validResultType(typ); err != nil { err.Pos = result.Pos() if f.validVarDeclType(typ) == nil { err.Err = errors.New(fmt.Sprint(err.Err) + ", type only valid as a var decl, or param") } else if f.validParamType(typ) == nil { err.Err = errors.New(fmt.Sprint(err.Err) + ", type only valid as func param type") } return err } return nil }
// belongsToReceiver checks if a function with these return types belongs to // a receiver. If it belongs to a receiver, the name of that receiver will be // returned with ok set to true. Otherwise ok will be false. // Behavior should be similar to how go doc decides when a function belongs to // a receiver (gosrc/pkg/go/doc/reader.go). func (p *tagParser) belongsToReceiver(types *ast.FieldList) (name string, ok bool) { if types == nil || types.NumFields() == 0 { return "", false } // If the first return type has more than 1 result associated with // it, it should not belong to that receiver. // Similar behavior as go doc (go source/. if len(types.List[0].Names) > 1 { return "", false } // get name of the first return type t := getType(types.List[0].Type, false) // check if it exists in the current list of known types for _, knownType := range p.types { if t == knownType { return knownType, true } } return "", false }
// removeFieldNames removes names from the FieldList in place. // This is used to remove names from return values func removeFieldNames(fl *ast.FieldList) { l := []*ast.Field{} for _, f := range fl.List { if f.Names == nil { l = append(l, f) } else { for range f.Names { nf := *f nf.Names = nil l = append(l, &nf) } } } fl.List = l }
// filterFieldList removes unexported fields (field names) from the field list // in place and returns true if fields were removed. Removed fields that are // anonymous (embedded) fields are added as embedded types to base. filterType // is called with the types of all remaining fields. // func (r *reader) filterFieldList(base *baseType, fields *ast.FieldList) (removedFields bool) { if fields == nil { return } list := fields.List j := 0 for _, field := range list { keepField := false if n := len(field.Names); n == 0 { // anonymous field name, imp := baseTypeName(field.Type) if ast.IsExported(name) { // we keep the field - in this case r.readDecl // will take care of adding the embedded type keepField = true } else if base != nil && !imp { // we don't keep the field - add it as an embedded // type so we won't loose its methods, if any if embedded := r.lookupType(name); embedded != nil { _, ptr := field.Type.(*ast.StarExpr) base.addEmbeddedType(embedded, ptr) } } } else { field.Names = filterIdentList(field.Names) if len(field.Names) < n { removedFields = true } if len(field.Names) > 0 { keepField = true } } if keepField { r.filterType(nil, field.Type) list[j] = field j++ } } if j < len(list) { removedFields = true } fields.List = list[0:j] return }
// filterFieldList removes unexported fields (field names) from the field list // in place and returns true if fields were removed. Anonymous fields are // recorded with the parent type. filterType is called with the types of // all remaining fields. // func (r *reader) filterFieldList(parent *namedType, fields *ast.FieldList, ityp *ast.InterfaceType) (removedFields bool) { if fields == nil { return } list := fields.List j := 0 for _, field := range list { keepField := false if n := len(field.Names); n == 0 { // anonymous field fname := r.recordAnonymousField(parent, field.Type) if ast.IsExported(fname) { keepField = true } else if ityp != nil && fname == "error" { // possibly the predeclared error interface; keep // it for now but remember this interface so that // it can be fixed if error is also defined locally keepField = true r.remember(ityp) } } else { field.Names = filterIdentList(field.Names, false) if len(field.Names) < n { removedFields = true } if len(field.Names) > 0 { keepField = true } } if keepField { r.filterType(nil, field.Type) list[j] = field j++ } } if j < len(list) { removedFields = true } fields.List = list[0:j] return }
// funcType type-checks a function or method type. func (check *Checker) funcType(sig *Signature, recvPar *ast.FieldList, ftyp *ast.FuncType) { scope := NewScope(check.scope, token.NoPos, token.NoPos, "function") check.recordScope(ftyp, scope) recvList, _ := check.collectParams(scope, recvPar, false) params, variadic := check.collectParams(scope, ftyp.Params, true) results, _ := check.collectParams(scope, ftyp.Results, false) if recvPar != nil { // recv parameter list present (may be empty) // spec: "The receiver is specified via an extra parameter section preceding the // method name. That parameter section must declare a single parameter, the receiver." var recv *Var switch len(recvList) { case 0: check.error(recvPar.Pos(), "method is missing receiver") recv = NewParam(0, nil, "", Typ[Invalid]) // ignore recv below default: // more than one receiver check.error(recvList[len(recvList)-1].Pos(), "method must have exactly one receiver") fallthrough // continue with first receiver case 1: recv = recvList[0] } // spec: "The receiver type must be of the form T or *T where T is a type name." // (ignore invalid types - error was reported before) if t, _ := deref(recv.typ); t != Typ[Invalid] { var err string if T, _ := t.(*Named); T != nil { // spec: "The type denoted by T is called the receiver base type; it must not // be a pointer or interface type and it must be declared in the same package // as the method." if T.obj.pkg != check.pkg { err = "type not defined in this package" } else { // TODO(gri) This is not correct if the underlying type is unknown yet. switch u := T.underlying.(type) { case *Basic: // unsafe.Pointer is treated like a regular pointer if u.kind == UnsafePointer { err = "unsafe.Pointer" } case *Pointer, *Interface: err = "pointer or interface type" } } } else { err = "basic or unnamed type" } if err != "" { check.errorf(recv.pos, "invalid receiver %s (%s)", recv.typ, err) // ok to continue } } sig.recv = recv } sig.scope = scope sig.params = NewTuple(params...) sig.results = NewTuple(results...) sig.variadic = variadic }
// declReturnValues builds the return part of the call // func declReturnValues(results *ast.FieldList) ([]ast.Stmt, error) { if results.NumFields() == 0 { return nil, nil } stmts := []ast.Stmt{} for i, f := range results.List { // var r_X type stmts = append(stmts, &ast.DeclStmt{ Decl: &ast.GenDecl{ Tok: token.VAR, Specs: []ast.Spec{ &ast.ValueSpec{ Names: []*ast.Ident{ ast.NewIdent(fmt.Sprintf("r_%d", i)), }, Type: f.Type, }, }, }, }) // if r[X] != nil { // r_X = r[X].(type) // } stmts = append(stmts, &ast.IfStmt{ Cond: &ast.BinaryExpr{ X: &ast.IndexExpr{ X: ast.NewIdent("r"), Index: &ast.BasicLit{ Kind: token.INT, Value: fmt.Sprintf("%d", i), }, }, Op: token.NEQ, Y: ast.NewIdent("nil"), }, Body: &ast.BlockStmt{ List: []ast.Stmt{ &ast.AssignStmt{ Lhs: []ast.Expr{ ast.NewIdent(fmt.Sprintf("r_%d", i)), }, Tok: token.ASSIGN, Rhs: []ast.Expr{ &ast.TypeAssertExpr{ X: &ast.IndexExpr{ X: ast.NewIdent("r"), Index: &ast.BasicLit{ Kind: token.INT, Value: fmt.Sprintf("%d", i), }, }, Type: f.Type, }, }, }, }, }, }) } return stmts, nil }