func (v *fileVisitor) method(n *ast.FuncDecl) *Method { method := &Method{Name: n.Name.Name} method.Lines = []*Line{} start := v.fset.Position(n.Pos()) end := v.fset.Position(n.End()) startLine := start.Line startCol := start.Column endLine := end.Line endCol := end.Column // The blocks are sorted, so we can stop counting as soon as we reach the end of the relevant block. for _, b := range v.profile.Blocks { if b.StartLine > endLine || (b.StartLine == endLine && b.StartCol >= endCol) { // Past the end of the function. break } if b.EndLine < startLine || (b.EndLine == startLine && b.EndCol <= startCol) { // Before the beginning of the function continue } for i := b.StartLine; i <= b.EndLine; i++ { method.Lines = append(method.Lines, &Line{Number: i, Hits: int64(b.Count)}) } } return method }
func (p *Parser) checkFuncLength(x *ast.FuncDecl) { numStatements := statementCount(x) if numStatements <= *statementThreshold { return } p.summary.addStatement(p.offender(x.Name.String(), numStatements, x.Pos())) }
func (f *file) checkFunctionBody(funcDecl *ast.FuncDecl) { if funcDecl.Body != nil { return } start := f.fset.Position(funcDecl.Pos()) problem := genFuncBodyProblem(funcDecl.Name.Name, start) f.problems = append(f.problems, problem) }
func (p *Parser) checkResultCount(x *ast.FuncDecl) { numResults := x.Type.Results.NumFields() if numResults <= *resultThreshold { return } p.summary.addResult(p.offender(x.Name.String(), numResults, x.Pos())) }
func checkTestFunc(fn *ast.FuncDecl, arg string) error { if !isTestFunc(fn, arg) { name := fn.Name.String() pos := testFileSet.Position(fn.Pos()) return fmt.Errorf("%s: wrong signature for %s, must be: func %s(%s *testing.%s)", pos, name, name, strings.ToLower(arg), arg) } return nil }
func (p *Parser) checkParamCount(x *ast.FuncDecl) { numFields := x.Type.Params.NumFields() if numFields <= *paramThreshold { return } p.summary.addParam(p.offender(x.Name.String(), numFields, x.Pos())) }
func parseFunction(funcDecl *ast.FuncDecl, fileInBytes []byte) (string, bool) { if ast.IsExported(funcDecl.Name.Name) { fmt.Printf("Function exported: %s\n", funcDecl.Name.Name) return string(fileInBytes[funcDecl.Pos()-1 : funcDecl.Body.Lbrace-1]), true } else { fmt.Printf("Function not exported: %s\n", funcDecl.Name.Name) } return "", false }
func processFunction(funcDecl *ast.FuncDecl) { m := function{} m.bodyStart = fset.Position(funcDecl.Pos()).Line m.bodyEnd = fset.Position(funcDecl.End()).Line m.variables = getFunctionVariables(funcDecl) addFoundFunctions(m) }
// Functions // // http://golang.org/doc/go_spec.html#Function_declarations // https://developer.mozilla.org/en/JavaScript/Reference/Statements/function func (tr *transform) getFunc(decl *ast.FuncDecl) { // godoc go/ast FuncDecl // Doc *CommentGroup // associated documentation; or nil // Recv *FieldList // receiver (methods); or nil (functions) // Name *Ident // function/method name // Type *FuncType // position of Func keyword, parameters and results // Body *BlockStmt // function body; or nil (forward declaration) // Check empty functions if len(decl.Body.List) == 0 { return } isFuncInit := false // function init() // == Initialization to save variables created on this function if decl.Name != nil { // discard literal functions tr.funcTotal++ tr.funcId = tr.funcTotal tr.blockId = 0 tr.vars[tr.funcId] = make(map[int]map[string]bool) tr.addr[tr.funcId] = make(map[int]map[string]bool) tr.maps[tr.funcId] = make(map[int]map[string]struct{}) tr.slices[tr.funcId] = make(map[int]map[string]struct{}) tr.zeroType[tr.funcId] = make(map[int]map[string]string) } // == tr.addLine(decl.Pos()) tr.addIfExported(decl.Name) if decl.Name.Name != "init" { tr.writeFunc(decl.Recv, decl.Name, decl.Type) } else { isFuncInit = true tr.WriteString("(function()" + SP) } tr.getStatement(decl.Body) if isFuncInit { tr.WriteString("());") } // At exiting of the function, it returns at the global scope. if decl.Name != nil { tr.funcId = 0 tr.blockId = 0 } if decl.Recv != nil { tr.recvVar = "" } }
// Sets multiLine to true if the declaration spans multiple lines. func (p *printer) funcDecl(d *ast.FuncDecl, multiLine *bool) { p.setComment(d.Doc) p.print(d.Pos(), token.FUNC, blank) if d.Recv != nil { p.parameters(d.Recv, multiLine) // method: print receiver p.print(blank) } p.expr(d.Name, multiLine) p.signature(d.Type.Params, d.Type.Results, multiLine) p.funcBody(d.Body, distance(d.Pos(), p.pos), false, multiLine) }
// Handle a function declaration. func funcDecl(fset *token.FileSet, decl *ast.FuncDecl) { var recvType string if decl.Recv != nil { // Method definition. There's always only one receiver. recvType = "class:" + typeName(decl.Recv.List[0].Type) } else { // Normal function recvType = "" } emitTag(decl.Name.Name, decl.Pos(), fset, FUNC, recvType) }
func (p *printer) funcDecl(d *ast.FuncDecl) { p.setComment(d.Doc) p.print(d.Pos(), token.FUNC, blank) if d.Recv != nil { p.parameters(d.Recv) // method: print receiver p.print(blank) } p.expr(d.Name) p.signature(d.Type.Params, d.Type.Results) p.adjBlock(p.distanceFrom(d.Pos()), vtab, d.Body) }
func (p *Parser) checkBoolParams(x *ast.FuncDecl) { if *skipBoolParamCheck { return } for _, f := range x.Type.Params.List { // this is ugly, but: if fmt.Sprintf("%s", f.Type) != "bool" { continue } p.summary.addBoolParam(p.offender(x.Name.String(), 0, x.Pos())) } }
func (c *compiler) createFunctionMetadata(f *ast.FuncDecl, fn *LLVMValue) llvm.DebugDescriptor { if len(c.debug_context) == 0 { return nil } file := c.fileset.File(f.Pos()) fnptr := fn.value fun := fnptr.IsAFunction() if fun.IsNil() { fnptr = llvm.ConstExtractValue(fn.value, []uint32{0}) } meta := &llvm.SubprogramDescriptor{ Name: fnptr.Name(), DisplayName: f.Name.Name, Path: llvm.FileDescriptor(file.Name()), Line: uint32(file.Line(f.Pos())), ScopeLine: uint32(file.Line(f.Body.Pos())), Context: &llvm.ContextDescriptor{llvm.FileDescriptor(file.Name())}, Function: fnptr} var result types.Type var metaparams []llvm.DebugDescriptor if ftyp, ok := fn.Type().(*types.Signature); ok { if recv := ftyp.Recv(); recv != nil { metaparams = append(metaparams, c.tollvmDebugDescriptor(recv.Type())) } if ftyp.Params() != nil { for i := 0; i < ftyp.Params().Len(); i++ { p := ftyp.Params().At(i) metaparams = append(metaparams, c.tollvmDebugDescriptor(p.Type())) } } if ftyp.Results() != nil { result = ftyp.Results().At(0).Type() // TODO: what to do with multiple returns? for i := 1; i < ftyp.Results().Len(); i++ { p := ftyp.Results().At(i) metaparams = append(metaparams, c.tollvmDebugDescriptor(p.Type())) } } } meta.Type = llvm.NewSubroutineCompositeType( c.tollvmDebugDescriptor(result), metaparams, ) // compile unit is the first context object pushed compileUnit := c.debug_context[0].(*llvm.CompileUnitDescriptor) compileUnit.Subprograms = append(compileUnit.Subprograms, meta) return meta }
func (p *parser) parseFuncDecl(n *parse.Node) ast.Decl { scope := ast.NewScope(p.topScope) funcDecl := ast.FuncDecl{ Name: p.parseIdent(n.Child(1)), } funcOrSig := n.Child(2).Child(0) if funcOrSig.Rule() == signature { funcDecl.Type = p.parseSignature(funcOrSig, scope) } else { funcDecl.Type, funcDecl.Body = p.parseFunc(funcOrSig, scope) } funcDecl.Type.Func = token.Pos(n.Child(0).Pos()) return &funcDecl }
// topLevelNodeToDecl converts an AST node to Go ast.Decl func topLevelNodeToDecl(node *parser.CallNode) ast.Decl { if node.Callee.(*parser.IdentNode).Ident != "defn" { panic("Top level node has to be defn") } switch node.Callee.(*parser.IdentNode).Ident { case "defn": decl := ast.FuncDecl{ Name: &ast.Ident{ NamePos: 2, Name: node.Args[0].(*parser.IdentNode).Ident, }, } fmt.Printf("SHOW ARGS: %+v\n", node.Args[1:]) // @TODO Fix this to support signature properly params := &ast.FieldList{ Opening: 1, Closing: 3, } params.List = make([]*ast.Field, 1) params.List[0] = &ast.Field{ Names: []*ast.Ident{ &ast.Ident{ Name: "lol", }, }, Type: &ast.Ident{ Name: "interface{}", }, } decl.Type = &ast.FuncType{ Func: 1, Params: params, Results: nil, } //decl.Body = nodeFnBody(node.Args[1:]) // TODO: Check argument lengths decl.Body = nodeFnBody(node.Args[1]) return &decl default: // The rest is normal function call probably //return nodeFnCall(node) fmt.Println("got nil %+v", node) return nil } }
func (check *checker) funcDecl(obj *Func, fdecl *ast.FuncDecl) { // func declarations cannot use iota assert(check.iota == nil) obj.typ = Typ[Invalid] // guard against cycles sig := check.funcType(fdecl.Recv, fdecl.Type, nil) if sig.recv == nil && obj.name == "init" && (sig.params.Len() > 0 || sig.results.Len() > 0) { check.errorf(fdecl.Pos(), "func init must have no arguments and no return values") // ok to continue } obj.typ = sig check.later(obj, sig, fdecl.Body) }
func (f *file) checkFunctionLine(funcDecl *ast.FuncDecl) { lineLimit := f.config.FunctionLine if lineLimit <= 0 { return } start := f.fset.Position(funcDecl.Pos()) startLine := start.Line endLine := f.fset.Position(funcDecl.End()).Line lineCount := endLine - startLine if lineCount > lineLimit { problem := genFuncLineProblem(funcDecl.Name.Name, lineCount, lineLimit, start) f.problems = append(f.problems, problem) } }
// set creates the corresponding Func for f and adds it to mset. // If there are multiple f's with the same name, set keeps the first // one with documentation; conflicts are ignored. // func (mset methodSet) set(f *ast.FuncDecl) { name := f.Name.Name if g := mset[name]; g != nil && g.Doc != "" { // A function with the same name has already been registered; // since it has documentation, assume f is simply another // implementation and ignore it. This does not happen if the // caller is using go/build.ScanDir to determine the list of // files implementing a package. return } // function doesn't exist or has no documentation; use f recv := "" if f.Recv != nil { var typ ast.Expr // be careful in case of incorrect ASTs if list := f.Recv.List; len(list) == 1 { typ = list[0].Type } recv = recvString(typ) } mset[name] = &Func{ Doc: f.Doc.Text(), Name: name, Decl: f, Recv: recv, Orig: recv, } f.Doc = nil // doc consumed - remove from AST }
// writeFunc writes a syscall wrapper for f to w. // It modifies f's data, so be warned! func (m *module) writeFunc(w io.Writer, f *ast.FuncDecl) error { f.Recv = nil // Remove the bogus receiver (really the DLL name). err := m.printConfig.Fprint(w, m.fileSet, f) if err != nil { return err } fmt.Fprintln(w, " {") params, setupCode, resultCode, err := m.analyzeParameterList(f.Type) if err != nil { return err } prefix := "" if m.packageName != "com" { prefix = "com." } if setupCode != "" { fmt.Fprintln(w, setupCode) } fmt.Fprintf(w, "\t_res, _, _ := %sSyscall(proc%s.Addr(),\n\t\t%s)\n", prefix, f.Name.Name, strings.Join(params, ",\n\t\t")) fmt.Fprint(w, resultCode) fmt.Fprintln(w, "\treturn") fmt.Fprintln(w, "}") fmt.Fprintln(w) return nil }
// readFunc processes a func or method declaration. // func (r *reader) readFunc(fun *ast.FuncDecl) { // strip function body fun.Body = nil // determine if it should be associated with a type if fun.Recv != nil { // method recvTypeName, imp := baseTypeName(fun.Recv.List[0].Type) if imp { // should not happen (incorrect AST); // don't show this method return } var typ *baseType if r.isVisible(recvTypeName) { // visible recv type: if not found, add it to r.types typ = r.lookupType(recvTypeName) } else { // invisible recv type: if not found, do not add it // (invisible embedded types are added before this // phase, so if the type doesn't exist yet, we don't // care about this method) typ = r.types[recvTypeName] } if typ != nil { // associate method with the type // (if the type is not exported, it may be embedded // somewhere so we need to collect the method anyway) typ.methods.set(fun) } // otherwise don't show the method // TODO(gri): There may be exported methods of non-exported types // that can be called because of exported values (consts, vars, or // function results) of that type. Could determine if that is the // case and then show those methods in an appropriate section. return } // perhaps a factory function // determine result type, if any if fun.Type.Results.NumFields() >= 1 { res := fun.Type.Results.List[0] if len(res.Names) <= 1 { // exactly one (named or anonymous) result associated // with the first type in result signature (there may // be more than one result) if n, imp := baseTypeName(res.Type); !imp && r.isVisible(n) { if typ := r.lookupType(n); typ != nil { // associate Func with typ typ.funcs.set(fun) return } } } } // just an ordinary function r.funcs.set(fun) }
// Sets multiLine to true if the declaration spans multiple lines. func (p *printer) funcDecl(d *ast.FuncDecl, multiLine *bool) { p.leadComment(d.Doc) p.print(d.Pos(), token.FUNC, blank) if recv := d.Recv; recv != nil { // method: print receiver p.print(token.LPAREN) if len(recv.Names) > 0 { p.expr(recv.Names[0], multiLine) p.print(blank) } p.expr(recv.Type, multiLine) p.print(token.RPAREN, blank) } p.expr(d.Name, multiLine) p.signature(d.Type.Params, d.Type.Results, multiLine) p.funcBody(d.Body, false, multiLine) }
func funcDeclToString(decl *ast.FuncDecl) string { var buffer bytes.Buffer var body *ast.BlockStmt body, decl.Body = decl.Body, nil printer.Fprint(&buffer, token.NewFileSet(), decl) decl.Body = body return buffer.String() }
func newFunc(decl *ast.FuncDecl) *Func { if !ast.IsExported(decl.Name.Name) { return nil } f := new(Func) f.Doc = doc.CommentText(decl.Doc) decl.Doc = nil f.Name = decl.Name.Name if decl.Recv != nil { f.Recv = recvAsString(decl.Recv.List[0].Type) } f.Decl = decl decl.Body = nil // remove body return f }
func (p *printer) funcDecl(d *ast.FuncDecl) { p.setComment(d.Doc) if d.Recv != nil { p.parameters(d.Recv) // method: print receiver p.print(blank) } if d.Name.Name == "main" { p.print("int ") } else { p.funcreturn(d.Type.Results) } p.expr(d.Name) p.signature(d.Type.Params) if d.Name.Name == "main" { zero := &ast.BasicLit{Kind: token.INT, Value: "0"} d.Body.List = append(d.Body.List, &ast.ReturnStmt{Results: []ast.Expr{zero}}) } p.funcBody(d.Body, p.distance(d.Pos(), p.pos), false) }
// parseFunction creates a tag for function declaration f. func (p *tagParser) parseFunction(f *ast.FuncDecl) { tag := p.createTag(f.Name.Name, f.Pos(), Function) tag.Fields[Access] = getAccess(tag.Name) tag.Fields[Signature] = fmt.Sprintf("(%s)", getTypes(f.Type.Params, true)) tag.Fields[TypeField] = getTypes(f.Type.Results, false) if f.Recv != nil && len(f.Recv.List) > 0 { // this function has a receiver, set the type to Method tag.Fields[ReceiverType] = getType(f.Recv.List[0].Type, false) tag.Type = Method } else if name, ok := p.belongsToReceiver(f.Type.Results); ok { // this function does not have a receiver, but it belongs to one based // on its return values; its type will be Function instead of Method. tag.Fields[ReceiverType] = name tag.Type = Function } p.tags = append(p.tags, tag) }
func exampleOutput(fun *ast.FuncDecl, comments []*ast.CommentGroup) string { // find the last comment in the function var last *ast.CommentGroup for _, cg := range comments { if cg.Pos() < fun.Pos() { continue } if cg.End() > fun.End() { break } last = cg } if last != nil { // test that it begins with the correct prefix text := last.Text() if loc := outputPrefix.FindStringIndex(text); loc != nil { return strings.TrimSpace(text[loc[1]:]) } } return "" // no suitable comment found }
func (p *printer) funcDecl(d *ast.FuncDecl) { p.setComment(d.Doc) p.print(d.Pos(), token.FUNC, blank) if d.Recv != nil { p.expr(d.Recv.List[0].Type) // method: print receiver p.print(d.Pos(), ".") if names := d.Recv.List[0].Names; len(names) > 0 { if name := names[0]; name != nil && name.Name != "_" { p.rcvName = name defer func() { p.rcvName = nil }() } } } p.expr(d.Name) p.signature(d.Type.Params, d.Type.Results) p.inFunc = true p.adjBlock(d.Body) p.inFunc = false p.print(unindent) }
// readFunc processes a func or method declaration. // func (r *reader) readFunc(fun *ast.FuncDecl) { // strip function body fun.Body = nil // associate methods with the receiver type, if any if fun.Recv != nil { // method if len(fun.Recv.List) == 0 { // should not happen (incorrect AST); (See issue 17788) // don't show this method return } recvTypeName, imp := baseTypeName(fun.Recv.List[0].Type) if imp { // should not happen (incorrect AST); // don't show this method return } if typ := r.lookupType(recvTypeName); typ != nil { typ.methods.set(fun) } // otherwise ignore the method // TODO(gri): There may be exported methods of non-exported types // that can be called because of exported values (consts, vars, or // function results) of that type. Could determine if that is the // case and then show those methods in an appropriate section. return } // associate factory functions with the first visible result type, if any if fun.Type.Results.NumFields() >= 1 { res := fun.Type.Results.List[0] if len(res.Names) <= 1 { // exactly one (named or anonymous) result associated // with the first type in result signature (there may // be more than one result) if n, imp := baseTypeName(res.Type); !imp && r.isVisible(n) { if typ := r.lookupType(n); typ != nil { // associate function with typ typ.funcs.set(fun) return } } } } // just an ordinary function r.funcs.set(fun) }
func (c *compiler) VisitFuncDecl(f *ast.FuncDecl) Value { fn := c.Resolve(f.Name).(*LLVMValue) attributes := parseAttributes(f.Doc) for _, attr := range attributes { attr.Apply(fn) } if f.Body == nil { return fn } var paramVars []*types.Var ftyp := fn.Type().(*types.Signature) if recv := ftyp.Recv(); recv != nil { paramVars = append(paramVars, recv) } if ftyp.Params() != nil { for i := 0; i < ftyp.Params().Len(); i++ { p := ftyp.Params().At(i) paramVars = append(paramVars, p) } } c.pushDebugContext(c.createFunctionMetadata(f, fn)) defer c.popDebugContext() c.setDebugLine(f.Pos()) paramVarsTuple := types.NewTuple(paramVars...) c.buildFunction(fn, nil, paramVarsTuple, ftyp.Results(), f.Body) if f.Recv == nil && f.Name.Name == "init" { // Is it an 'init' function? Then record it. fnptr := llvm.ConstExtractValue(fn.value, []uint32{0}) c.initfuncs = append(c.initfuncs, fnptr) } return fn }