func grindFunc(ctxt *grinder.Context, pkg *grinder.Package, edit *grinder.EditBuffer, fn *ast.FuncDecl) { if fn.Body == nil { return } blocks := block.Build(pkg.FileSet, fn.Body) ast.Inspect(fn.Body, func(x ast.Node) bool { var list []ast.Stmt switch x := x.(type) { default: return true case *ast.BlockStmt: list = x.List case *ast.CommClause: list = x.Body case *ast.CaseClause: list = x.Body } for i := 0; i < len(list); i++ { x := list[i] if grinder.IsTerminatingStmt(blocks, x) { end := i + 1 for end < len(list) && !isGotoTarget(blocks, list[end]) { end++ } if end > i+1 { edit.Delete(edit.End(x), edit.End(list[end-1])) i = end - 1 // after i++, next iteration starts at end } } } return true }) }
func grindFunc(ctxt *grinder.Context, pkg *grinder.Package, edit *grinder.EditBuffer, fn *ast.FuncDecl) { if fn.Name.Name == "evconst" { old := debug debug = true defer func() { debug = old }() } if pkg.TypesError != nil { // Without scoping information, we can't be sure code moves are okay. fmt.Printf("%s: cannot inline gotos without type information\n", fn.Name) return } if fn.Body == nil { return } blocks := block.Build(pkg.FileSet, fn.Body) for labelname, gotos := range blocks.Goto { target, ok := findTargetBlock(pkg, edit, fn, blocks, labelname) if debug { println("TARGET", ok, labelname, len(gotos), target.dead, target.short) } if ok && (len(gotos) == 1 && target.dead || target.short) { numReplaced := 0 for _, g := range gotos { code := edit.TextAt(target.comment, target.start) + target.code if !objsMatch(pkg, fn, g.Pos(), target.objs, target.start, target.end) { if debug { println("OBJS DO NOT MATCH") } // Cannot inline code here; needed identifiers have different meanings. continue } if target.needReturn { // NOTE: Should really check to see if function results are shadowed. // If we screw up, the code won't compile, so we can put it off. code += "; return" } if target.needGoto != "" { code += "; goto " + target.needGoto } edit.Replace(g.Pos(), g.End(), code) numReplaced++ } if numReplaced == len(gotos) { if len(gotos) == 1 && target.dead { edit.Delete(target.comment, target.end) } else { edit.DeleteLine(target.start, target.endLabel) } } // The code we move might itself have gotos to inline, // and we can't make that change until we get new line // number position, so return after each label change. if numReplaced > 0 { return } } } }