// errorOrVoid filters the list of functions to only those that return only an // error or have no return value. func errorOrVoid(fns []*ast.FuncDecl, info types.Info) []*ast.FuncDecl { fds := []*ast.FuncDecl{} for _, fn := range fns { // look for functions with 0 or 1 return values res := fn.Type.Results if res.NumFields() > 1 { continue } // 0 return value is ok if res.NumFields() == 0 { fds = append(fds, fn) continue } // if 1 return value, look for those that return an error ret := res.List[0] // handle (a, b, c int) if len(ret.Names) > 1 { continue } t := info.TypeOf(ret.Type) if t != nil && t.String() == "error" { fds = append(fds, fn) } } return fds }
func functions(f *ast.File, info types.Info, fset *token.FileSet) ([]Function, error) { fns := exportedFuncs(f, fset) fns = errorOrVoid(fns, info) cmtMap := ast.NewCommentMap(fset, f, f.Comments) functions := make([]Function, len(fns)) for i, fn := range fns { fun := Function{Name: fn.Name.Name} fun.Comment = combine(cmtMap[fn]) // we only support null returns or error returns, so if there's a // return, it's an error. if len(fn.Type.Results.List) > 0 { fun.IsError = true } params := fn.Type.Params.List fun.Params = make([]Param, 0, len(params)) for _, field := range params { t := info.TypeOf(field.Type) pointer := false if p, ok := t.(*types.Pointer); ok { t = p.Elem() pointer = true } if b, ok := t.(*types.Basic); ok { if b.Kind() == types.UnsafePointer { log.Printf( "Can't create command for function %q because its parameter %q is an unsafe.Pointer.", fn.Name.Name, field.Names[0]) break } fieldCmt := combine(cmtMap[field]) // handle a, b, c int for _, name := range field.Names { nameCmt := combine(cmtMap[name]) if nameCmt == "" { nameCmt = fieldCmt } param := Param{ Name: name.Name, Type: b.Kind(), IsPointer: pointer, Comment: nameCmt, } fun.Params = append(fun.Params, param) } continue } } functions[i] = fun } return functions, nil }