Esempio n. 1
0
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
}
Esempio n. 2
0
func inlineMethod(programTree *program.Program, filename string, lineStart int, colStart int, lineEnd int, colEnd int) (bool, *errors.GoRefactorError) {
	if ok, err := CheckInlineMethodParameters(filename, lineStart, colStart, lineEnd, colEnd); !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
	callNode, nodeFrom := getCall(fset, file, filename, lineStart, colStart, lineEnd, colEnd)
	if callNode == nil {
		return false, &errors.GoRefactorError{ErrorType: "inline method error", Message: "couldn't find call expression"}
	}
	_, CallAsExpression := callNode.(*ast.CallExpr)
	callExpr, err := getCallExpr(callNode)
	if err != nil {
		return false, err
	}

	funSym, err := getMethodSymbol(programTree, callExpr)
	if err != nil {
		return false, err
	}
	if funSym.PackageFrom() != pack {
		return false, &errors.GoRefactorError{ErrorType: "inline method error", Message: "can't inline method from other package"}
	}
	decl, sourceFile, err := getDeclarationInFile(programTree, pack, funSym)
	if err != nil {
		return false, err
	}

	if len(decl.Body.List) == 0 {
		ok, err := printerUtil.DeleteNode(fset, filename, file, fset.Position(callExpr.Pos()), fset.Position(callExpr.End()))
		if !ok {
			return false, err
		}
		programTree.SaveFileExplicit(filename, fset, file)
		return true, nil
	}

	destScope := getDestScope(programTree, pack, nodeFrom)
	newNames := getNewNames(callExpr, funSym, destScope)

	for sym, expr := range newNames {
		fmt.Printf("%s -> ", sym.Name())
		printer.Fprint(os.Stdout, token.NewFileSet(), expr)
		print("; ")
	}

	tokFile := printerUtil.GetFileFromFileSet(fset, filename)
	sourceTokFile := printerUtil.GetFileFromFileSet(fset, sourceFile)

	lines := printerUtil.GetLines(tokFile)
	for i, offset := range lines {
		fmt.Printf("%d -> %s(%d)\n", i+1, fset.Position(tokFile.Pos(offset)), offset)
	}

	oldListLines, fline := getRangeLinesAtLeastOne(sourceTokFile, decl.Body.List[0].Pos(), decl.Body.List[len(decl.Body.List)-1].End(), sourceTokFile.Size())
	fmt.Printf("fline = %d\n", fline)

	fmt.Printf("CONVERTER before: %v\n", oldListLines)
	fmt.Printf("CONVERTER pos,end: %d,%d\n", decl.Body.List[0].Pos(), decl.Body.List[len(decl.Body.List)-1].End())

	resList, newListLines, importsToAdd := getResultStmtList(programTree.IdentMap, pack, funSym, newNames, sourceFile, filename, decl.Body.List, pack.FileSet, callExpr.Pos())

	sourceLines := printerUtil.GetLines(sourceTokFile)
	zeroSourceLine := newListLines[0] - sourceLines[fline-2]
	fmt.Printf("zeroSourceLine = %d\n", zeroSourceLine)

	fmt.Printf("CONVERTER after: %v\n", newListLines)
	fmt.Printf("CONVERTER pos,end: %d,%d\n", resList[0].Pos(), resList[len(resList)-1].End())

	callExprLen := int(callExpr.End() - callExpr.Pos())
	listLen := newListLines[len(newListLines)-1] - sourceLines[fline-2]
	importsLen := 0
	for ps, _ := range importsToAdd {
		fmt.Printf("import \"%s\"\n", ps.ShortPath)
		importsLen += len("import \"\"\n") + len(ps.ShortPath)
	}
	mod := listLen + importsLen - callExprLen
	fmt.Printf("mod = %d\n", mod)
	if mod > 0 {
		println("REPARSING *****************************************")
		oldSourceTokFileSize := sourceTokFile.Size()

		fset, file = printerUtil.ReparseFile(file, filename, mod, programTree.IdentMap)
		tokFile = printerUtil.GetFileFromFileSet(fset, filename)
		sourceTokFile = printerUtil.GetFileFromFileSet(pack.FileSet, sourceFile)
		lines = printerUtil.GetLines(tokFile)
		tokFile.SetLines(lines[:len(lines)-(mod)])

		callNode, nodeFrom = getCall(fset, file, filename, lineStart, colStart, lineEnd, colEnd)
		callExpr, _ = getCallExpr(callNode)
		funSym, _ = getMethodSymbol(programTree, callExpr)
		decl, sourceFile, _ = getDeclarationInFile(programTree, pack, funSym)
		destScope = getDestScope(programTree, pack, nodeFrom)
		newNames = getNewNames(callExpr, funSym, destScope)

		lines = printerUtil.GetLines(tokFile)
		for i, offset := range lines {
			fmt.Printf("%d -> %s(%d)\n", i+1, fset.Position(tokFile.Pos(offset)), offset)
		}

		oldListLines, fline = getRangeLinesAtLeastOne(sourceTokFile, decl.Body.List[0].Pos(), decl.Body.List[len(decl.Body.List)-1].End(), oldSourceTokFileSize)
		fmt.Printf("fline = %d\n", fline)

		fmt.Printf("CONVERTER before: %v\n", oldListLines)
		fmt.Printf("CONVERTER pos,end: %d,%d\n", decl.Body.List[0].Pos(), decl.Body.List[len(decl.Body.List)-1].End())

		resList, newListLines, importsToAdd = getResultStmtList(programTree.IdentMap, pack, funSym, newNames, sourceFile, filename, decl.Body.List, pack.FileSet, callExpr.Pos())

		sourceLines := printerUtil.GetLines(sourceTokFile)
		zeroSourceLine = newListLines[0] - sourceLines[fline-2]
		fmt.Printf("lines[fline - 1] = %d, zeroSourceLine = %d\n", sourceLines[fline-2], zeroSourceLine)

		fmt.Printf("CONVERTER after: %v\n", newListLines)
		fmt.Printf("CONVERTER pos,end: %d,%d\n", resList[0].Pos(), resList[len(resList)-1].End())
	}

	impPos := file.Decls[0].Pos()
	nextLineInd := 0
	for i, offs := range lines {
		if offs > tokFile.Offset(impPos) {
			nextLineInd = i
			break
		}
	}

	for ps, _ := range importsToAdd {
		printDecls(tokFile, file)

		file.Decls = append([]ast.Decl{makeImportDecl(impPos, ps.ShortPath)}, file.Decls...)
		mod := len("import \"\"\n") + len(ps.ShortPath)
		//positions
		printerUtil.FixPositionsExcept(impPos-token.Pos(1), mod, file, true, map[ast.Node]bool{file.Decls[0]: true})
		//lines
		lines = printerUtil.GetLines(tokFile)
		fmt.Printf("before import %s (%d): %v\n", ps.ShortPath, impPos, lines)
		newLines := make([]int, 0, len(lines)+1)
		newLines = append(newLines, lines[:nextLineInd]...)
		newLines = append(newLines, tokFile.Offset(impPos))
		newLines = append(newLines, lines[nextLineInd:]...)
		for i := nextLineInd; i < len(newLines); i++ {
			newLines[i] += mod
		}
		fmt.Printf("after import %s (nextLine = %d): %v\n", ps.ShortPath, nextLineInd, newLines)
		if !tokFile.SetLines(newLines) {
			panic("couldn't set lines for file " + tokFile.Name())
		}

		printDecls(tokFile, file)
	}

	resMod := int(callExpr.Pos() - resList[0].Pos())
	for _, stmt := range resList {
		printerUtil.FixPositions(0, resMod, stmt, true)
	}
	lines = printerUtil.GetLines(tokFile)

	resLinesMod := lines[tokFile.Line(callExpr.Pos())-1] - newListLines[0] + zeroSourceLine
	fmt.Printf("resLinesMod: %d\n", resLinesMod)

	for i, _ := range newListLines {
		newListLines[i] += resLinesMod
	}
	fmt.Printf("call pos: %d,%d; list pos: %d,%d\n", callExpr.Pos(), callExpr.End(), resList[0].Pos(), resList[len(resList)-1].End())
	fmt.Printf("newLines %v\n", newListLines)

	lines = printerUtil.GetLines(tokFile)
	for i, offset := range lines {
		fmt.Printf("%d -> %s(%d)\n", i+1, fset.Position(tokFile.Pos(offset)), offset)
	}

	if CallAsExpression {
		rs, ok := resList[0].(*ast.ReturnStmt)
		if !ok {
			return false, &errors.GoRefactorError{ErrorType: "inline method error", Message: "method, inlined as expression, must have only one statement - return statement"}
		}
		switch len(rs.Results) {
		case 0:
			panic("methods, inlined as expression, doesn't return anything")
		default:

			elist := rs.Results
			for _, e := range elist {
				printerUtil.FixPositions(0, -len("return "), e, true)
			}
			mod := int(elist[len(elist)-1].End()-elist[0].Pos()) - callExprLen
			lines = printerUtil.GetLines(tokFile)

			fmt.Printf("before last (mod = %d) : %v\n", mod, lines)
			for i, offset := range lines {
				if offset > tokFile.Offset(callExpr.Pos()) {
					for j := i; j < len(lines); j++ {
						lines[j] += mod
					}
					break
				}
			}
			fmt.Printf("after last (mod = %d) : %v\n", mod, lines)
			fmt.Printf("posits: %s,%s\n", fset.Position(callExpr.Pos()), fset.Position(callExpr.End()))
			if !tokFile.SetLines(lines) {
				panic("couldn't set lines for file " + tokFile.Name())
			}

			printerUtil.FixPositionsExcept(callExpr.Pos(), mod, file, true, map[ast.Node]bool{callExpr: true})

			errs := replaceExprList(fset.Position(callExpr.Pos()), fset.Position(callExpr.End()), elist, fset, file)
			if err, ok := errs[INLINE_METHOD]; ok {
				return false, err
			}
			programTree.SaveFileExplicit(filename, fset, file)
		}

	} else {

		list := getStmtList(nodeFrom)
		i, ok := getIndexOfStmt(callNode.(ast.Stmt), list)
		if !ok {
			panic("couldn't find call statement during inline")
		}

		callExprLine := tokFile.Line(callExpr.Pos()) - 1
		mod := int(resList[len(resList)-1].End()-resList[0].Pos()) - callExprLen

		printerUtil.FixPositions(callExpr.Pos(), mod, file, true)

		lines = printerUtil.GetLines(tokFile)
		fmt.Printf("before last (mod = %d) : %v\n", mod, lines)
		newLines := make([]int, 0, len(lines)+len(newListLines)-1)
		newLines = append(newLines, lines[:callExprLine+1]...)
		newLines = append(newLines, newListLines...)
		newLines = append(newLines, lines[callExprLine+2:]...)
		fmt.Printf("after last (lines[callExprLine] = %d): %v\n", lines[callExprLine], newLines)
		for i := callExprLine + 1 + len(newListLines); i < len(newLines); i++ {
			newLines[i] += mod
		}
		fmt.Printf("after last: %v\n", newLines)
		if !tokFile.SetLines(newLines) {
			panic("couldn't set lines for file " + tokFile.Name())
		}

		if len(resList) == 1 {
			list[i] = resList[0]
			programTree.SaveFileExplicit(filename, fset, file)
			return true, nil
		}
		fmt.Printf("len = %d\n", len(list)-1+len(resList))
		fmt.Printf("%v\n", list)
		newList := make([]ast.Stmt, len(list)-1+len(resList))
		for j := 0; j < i; j++ {
			newList[j] = list[j]
		}
		fmt.Printf("%v\n", newList)
		for j := 0; j < len(resList); j++ {
			newList[j+i] = resList[j]
		}
		fmt.Printf("%v\n", newList)
		for j := i + 1; j < len(list); j++ {
			newList[j+len(resList)-1] = list[j]
		}
		fmt.Printf("%v\n", newList)

		setStmtList(nodeFrom, newList)

		programTree.SaveFileExplicit(filename, fset, file)
	}

	return true, nil
}
Esempio n. 3
0
func extractMethod(programTree *program.Program, filename string, lineStart int, colStart int, lineEnd int, colEnd int, methodName string, recieverVarLine int, recieverVarCol int) (bool, *errors.GoRefactorError) {

	if ok, err := CheckExtractMethodParameters(filename, lineStart, colStart, lineEnd, colEnd, methodName, recieverVarLine, recieverVarCol); !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

	recvSym, err := getRecieverSymbol(programTree, pack, filename, recieverVarLine, recieverVarCol)
	if err != nil {
		return false, err
	}

	if recvSym != nil {
		if recvSym.VariableType.Methods() != nil {
			if _, ok := recvSym.VariableType.Methods().LookUp(methodName, ""); ok {
				return false, errors.ArgumentError("methodName", "reciever already contains a method with name "+methodName)
			}
		}
		switch t := recvSym.VariableType.(type) {
		case *st.StructTypeSymbol:
			if _, ok := t.Fields.LookUp(methodName, ""); ok {
				return false, errors.ArgumentError("methodName", "reciever already contains a field with name "+methodName)
			}
		case *st.PointerTypeSymbol:
			if _, ok := t.Fields.LookUp(methodName, ""); ok {
				return false, errors.ArgumentError("methodName", "reciever already contains a field with name "+methodName)
			}
		}
	} else {
		if _, ok := pack.Symbols.LookUp(methodName, ""); ok {
			return false, errors.ArgumentError("methodName", "package already contains a symbol with name "+methodName)
		}
	}

	stmtList, nodeFrom, err := getExtractedStatementList(pack, file, filename, lineStart, colStart, lineEnd, colEnd)
	if err != nil {
		return false, err
	}
	fmt.Printf("list pos,end = %d,%d\n", stmtList[0].Pos(), stmtList[len(stmtList)-1].End())

	params, declared := getParametersAndDeclaredIn(pack, stmtList, programTree)
	fmt.Printf("list pos,end = %d,%d\n", stmtList[0].Pos(), stmtList[len(stmtList)-1].End())
	if recvSym != nil {
		if _, found := params.LookUp(recvSym.Name(), ""); !found {
			return false, &errors.GoRefactorError{ErrorType: "extract method error", Message: "symbol, desired to be reciever, is not a parameter to extracted code"}
		}
		params.RemoveSymbol(recvSym.Name())
	}

	resultList := getResultList(programTree, pack, filename, stmtList)
	results := st.NewSymbolTable(pack)
	for _, r := range resultList {
		results.AddSymbol(st.MakeVariable(st.NO_NAME, results, r))
	}
	fmt.Printf("list pos,end = %d,%d\n", stmtList[0].Pos(), stmtList[len(stmtList)-1].End())
	pointerSymbols := getPointerPassedSymbols(stmtList, params, programTree.IdentMap)
	fmt.Printf("list pos,end = %d,%d\n", stmtList[0].Pos(), stmtList[len(stmtList)-1].End())
	for s, depth := range pointerSymbols {
		println(s.Name(), depth)
	}

	applyPointerTransform(fset, file, stmtList, pointerSymbols, programTree.IdentMap)
	fmt.Printf("list pos,end = %d,%d\n", stmtList[0].Pos(), stmtList[len(stmtList)-1].End())
	fdecl := makeFuncDecl(methodName, stmtList, params, pointerSymbols, results, recvSym, pack, filename)

	if nodeFrom != nil {

		callExpr, callExprLen := makeCallExpr(methodName, params, pointerSymbols, stmtList[0].Pos(), recvSym, pack, filename)

		if ok, errs := checkScoping(nodeFrom, stmtList, declared, programTree.IdentMap); !ok {
			s := ""
			errs.ForEach(func(sym st.Symbol) {
				s += sym.Name() + " "
			})
			return false, &errors.GoRefactorError{ErrorType: "extract method error", Message: "extracted code declares symbols that are used in not-extracted code: " + s}
		}

		app := callExprLen - int(stmtList[len(stmtList)-1].End()-stmtList[0].Pos())
		if app > 0 {

			S, E := fset.Position(nodeFrom.Pos()), fset.Position(nodeFrom.End())
			poses, ends := make([]token.Position, len(stmtList)), make([]token.Position, len(stmtList))
			for i, stmt := range stmtList {
				poses[i], ends[i] = fset.Position(stmt.Pos()), fset.Position(stmt.End())
			}

			tfile := printerUtil.GetFileFromFileSet(fset, filename)
			baseMod := tfile.Base()
			fmt.Printf("app = %d,baseMod = %d\n", app, baseMod)
			fset, file = printerUtil.ReparseFile(file, filename, app, programTree.IdentMap)
			tfile = printerUtil.GetFileFromFileSet(fset, filename)
			lines := printerUtil.GetLines(tfile)
			tfile.SetLines(lines[:len(lines)-(app)])

			nodeFrom = printerUtil.FindNode(fset, file, S, E)
			if baseMod != 1 {
				for _, stmt := range stmtList {
					printerUtil.FixPositions(0, 1-baseMod, stmt, true)
				}
				printerUtil.FixPositions(0, 1-baseMod, callExpr, true)
				printerUtil.FixPositions(0, 1-baseMod, fdecl, true)
			}
			stmtList = make([]ast.Stmt, len(stmtList))
			for i, _ := range stmtList {
				stmtList[i] = printerUtil.FindNode(fset, file, poses[i], ends[i]).(ast.Stmt)
			}
		}

		list := getStmtList(nodeFrom)

		ind, found := getIndexOfStmt(stmtList[0], list)
		if !found {
			panic("didn't find replace origin")
		}
		fmt.Printf("stmtList length = %d\n", len(stmtList))
		if ok, err := printerUtil.DeleteNodeList(fset, filename, file, stmtList); !ok {
			return false, err
		}
		list = getStmtList(nodeFrom)
		newList := make([]ast.Stmt, len(list)+1)
		copy(newList, list[0:ind])
		newList[ind] = &ast.ExprStmt{callExpr}
		for i := ind; i < len(list); i++ {
			newList[i+1] = list[i]
		}
		printerUtil.AddLineForRange(fset, filename, callExpr.Pos(), callExpr.End())
		setStmtList(nodeFrom, newList)
		printerUtil.FixPositionsExcept(callExpr.Pos(), callExprLen, file, true, map[ast.Node]bool{callExpr: true})

	} else {

		//stmtList[0] = utils.CopyAstNode(stmtList[0]).(ast.Stmt)
		rs := stmtList[0].(*ast.ReturnStmt)

		callExpr, callExprLen := makeCallExpr(methodName, params, pointerSymbols, rs.Results[0].Pos(), recvSym, pack, filename)
		mod, baseMod := callExprLen-int(rs.Results[len(rs.Results)-1].End()-rs.Results[0].Pos()), 0
		fset, file, baseMod = printerUtil.ModifyLine(pack.FileSet, file, filename, programTree.IdentMap, callExpr.Pos(), mod)

		if baseMod != 1 {
			fmt.Printf("baseMod = %d\n", baseMod)
			printerUtil.FixPositions(0, 1-baseMod, callExpr, true)
			printerUtil.FixPositions(0, 1-baseMod, rs, true)
			printerUtil.FixPositions(0, 1-baseMod, fdecl, true)
		}
		fmt.Printf("results st,end = %d,%d, callExpr pos,end = %d,%d\n", rs.Results[0].Pos(), rs.Results[len(rs.Results)-1].End(), callExpr.Pos(), callExpr.End())
		errs := replaceExprList(fset.Position(rs.Results[0].Pos()), fset.Position(rs.Results[len(rs.Results)-1].End()), []ast.Expr{callExpr}, fset, file)
		if err, ok := errs[EXTRACT_METHOD]; ok {
			return false, err
		}

		fmt.Printf("mod = %d\n", mod)
		printerUtil.FixPositionsExcept(callExpr.Pos(), mod, file, true, map[ast.Node]bool{callExpr: true})
	}
	programTree.SaveFileExplicit(filename, fset, file)
	print("AAAAAA")
	if ok, fset, newF, err := printerUtil.AddDeclExplicit(fset, filename, file, fset, filename, file, fdecl, programTree.IdentMap); !ok {
		return false, err
	} else {
		print("BBBBBB")
		programTree.SaveFileExplicit(filename, fset, newF)
	}
	return true, nil

}