func grindFunc(ctxt *grinder.Context, pkg *grinder.Package, edit *grinder.EditBuffer, fn *ast.FuncDecl) { vars := analyzeFunc(pkg, edit, fn.Body) // fmt.Printf("%s", vardecl.PrintVars(conf.Fset, vars)) for _, v := range vars { spec := v.Decl.Decl.(*ast.GenDecl).Specs[0].(*ast.ValueSpec) if len(spec.Names) > 1 { // TODO: Handle decls with multiple variables continue } if pkg.FileSet.Position(v.Decl.Pos()).Line != pkg.FileSet.Position(v.Decl.End()).Line { // Declaration spans line. Maybe not great to move or duplicate? continue } keepDecl := false for _, d := range v.Defs { if d.Init == v.Decl { keepDecl = true continue } switch x := d.Init.(type) { default: panic("unexpected init") case *ast.EmptyStmt: edit.CopyLine(v.Decl.Pos(), v.Decl.End(), x.Semicolon) case *ast.AssignStmt: edit.Insert(x.TokPos, ":") if !hasType(pkg, fn, edit, x.Rhs[0], x.Lhs[0]) { typ := edit.TextAt(spec.Type.Pos(), spec.Type.End()) if strings.Contains(typ, " ") || typ == "interface{}" || typ == "struct{}" || strings.HasPrefix(typ, "*") { typ = "(" + typ + ")" } edit.Insert(x.Rhs[0].Pos(), typ+"(") edit.Insert(x.Rhs[0].End(), ")") } } } if !keepDecl { edit.DeleteLine(v.Decl.Pos(), v.Decl.End()) } } if edit.NumEdits() == 0 { initToDecl(ctxt, pkg, edit, fn) } }