func makeCallExpr(name string, params *st.SymbolTable, pointerSymbols map[st.Symbol]int, pos token.Pos, recvSym *st.VariableSymbol, pack *st.Package, filename string) (*ast.CallExpr, int) { var Fun ast.Expr if recvSym != nil { x := ast.NewIdent(recvSym.Name()) x.NamePos = pos Fun = &ast.SelectorExpr{x, ast.NewIdent(name)} } else { x := ast.NewIdent(name) x.NamePos = pos Fun = x } l, _ := utils.GetNodeLength(Fun) l += 2 args, i := make([]ast.Expr, params.Count()), 0 params.ForEachNoLock(func(sym st.Symbol) { args[i] = sym.ToAstExpr(pack, filename) if depth, ok := pointerSymbols[sym]; ok { for depth > 0 { args[i] = &ast.UnaryExpr{token.NoPos, token.AND, args[i]} depth-- } } ll, _ := utils.GetNodeLength(args[i]) l += ll + 2 i++ }) l -= 2 return &ast.CallExpr{Fun, token.NoPos, args, token.NoPos, pos + token.Pos(l-1)}, l }
func (vis *destinationVisitor) Visit(node ast.Node) ast.Visitor { if node == nil { return nil } switch t := node.(type) { case *ast.SelectorExpr: ast.Walk(vis, t.X) return nil case *ast.Ident: newExpr := <-vis.Chan if newExpr != nil { printerUtil.FixPositions(0, int(t.Pos()-newExpr.Pos()), newExpr, true) replaceExpr(vis.FileSet.Position(t.Pos()), vis.FileSet.Position(t.End()), newExpr, vis.FileSet, vis.rootNode) le, _ := utils.GetNodeLength(newExpr) mod := le - int(t.End()-t.Pos()) for _, stmt := range vis.destList { printerUtil.FixPositionsExcept(t.Pos(), mod, stmt, true, map[ast.Node]bool{newExpr: true}) } for i, _ := range vis.nodeLines { if vis.nodeLines[i] > vis.TokFile.Offset(t.Pos()) { vis.nodeLines[i] += mod } } } return nil } return vis }
func extractInterface(programTree *program.Program, filename string, line int, column int, interfaceName string) (bool, *errors.GoRefactorError) { if ok, err := CheckExtractInterfaceParameters(filename, line, column, interfaceName); !ok { return false, err } pack, file := programTree.FindPackageAndFileByFilename(filename) if pack == nil { return false, errors.ArgumentError("filename", "Program packages don't contain file '"+filename+"'") } fset := pack.FileSet mod := 20000 fset, file = printerUtil.ReparseFile(file, filename, mod, programTree.IdentMap) tokFile := printerUtil.GetFileFromFileSet(fset, filename) lines := printerUtil.GetLines(tokFile) tokFile.SetLines(lines[:len(lines)-(mod)]) if _, ok := pack.Symbols.LookUp(interfaceName, filename); ok { return false, errors.IdentifierAlreadyExistsError(interfaceName) } field, nameNum, fdecl, ok := getSelectedArgument(file, token.Position{filename, 0, line, column}, fset) if !ok { return false, &errors.GoRefactorError{ErrorType: "extract interface error", Message: "couldn't find function argument to extract interface"} } if field.Names == nil { return false, &errors.GoRefactorError{ErrorType: "extract interface error", Message: "argument has no name, so empty interface"} } varS, ok := programTree.IdentMap.GetSymbol(field.Names[nameNum]).(*st.VariableSymbol) if !ok { panic("symbol supposed to be a variable, but it's not") } meths, errs := getUsedMethods(programTree, fset, fdecl, varS) if len(errs) > 0 { println("some errors don't allow to extract interface:") for e, _ := range errs { println(e.String()) } return false, &errors.GoRefactorError{ErrorType: "extract interface error", Message: "some errors occured, stopped extracting"} } methList, i := make([]*ast.Field, len(meths)), 0 for m, _ := range meths { methList[i] = &ast.Field{nil, []*ast.Ident{ast.NewIdent(m.Name())}, m.FunctionType.ToAstExpr(pack, filename), nil, nil} i++ } interfaceMethods := &ast.FieldList{token.NoPos, methList, token.NoPos} interfaceType := &ast.InterfaceType{token.NoPos, interfaceMethods, false} interfaceDecl := &ast.TypeSpec{nil, ast.NewIdent(interfaceName), interfaceType, nil} genDecl := &ast.GenDecl{nil, token.NoPos, token.TYPE, token.NoPos, []ast.Spec{interfaceDecl}, token.NoPos} fieldNum := 0 for i := 0; i < len(fdecl.Type.Params.List); i++ { if field == fdecl.Type.Params.List[i] { fieldNum = i break } } oldFTypeLen := int(fdecl.Type.End() - fdecl.Type.Pos()) var lField, mField, rField *ast.Field mField = &ast.Field{nil, []*ast.Ident{field.Names[nameNum]}, ast.NewIdent(interfaceName), nil, nil} if nameNum > 0 { lField = &ast.Field{nil, field.Names[:nameNum], field.Type, nil, nil} } if nameNum < len(field.Names)-1 { rField = &ast.Field{nil, field.Names[(nameNum + 1):], field.Type, nil, nil} } newList := make([]*ast.Field, fieldNum) copy(newList, fdecl.Type.Params.List[:fieldNum]) if lField != nil { newList = append(newList, lField) } newList = append(newList, mField) if rField != nil { newList = append(newList, rField) } newList = append(newList, fdecl.Type.Params.List[(fieldNum+1):]...) fdecl.Type.Params.List = newList newFTypeLen, _ := utils.GetNodeLength(fdecl.Type) newFTypeLen += len(fdecl.Name.Name) + 1 fmt.Printf("old %d new %d\n", oldFTypeLen, newFTypeLen) allMod := newFTypeLen - oldFTypeLen if allMod != 0 { printerUtil.FixPositions(fdecl.Type.End(), allMod, file, true) lines = printerUtil.GetLines(tokFile) fmt.Printf("before last (mod = %d) : %v\n", allMod, lines) for i, offset := range lines { if offset > tokFile.Offset(fdecl.Type.Pos()) { for j := i; j < len(lines); j++ { lines[j] += allMod } break } } fmt.Printf("after last (mod = %d) : %v\n", allMod, lines) if !tokFile.SetLines(lines) { panic("couldn't set lines for file " + tokFile.Name()) } } file.Decls = append(file.Decls, genDecl) programTree.SaveFileExplicit(filename, fset, file) return true, nil }