コード例 #1
0
ファイル: sort.go プロジェクト: vpavkin/GoRefactor
func CheckSortParameters(filename string, order string) (bool, *errors.GoRefactorError) {
	switch {
	case filename == "" || !utils.IsGoFile(filename):
		return false, errors.ArgumentError("filename", "It's not a valid go file name")
	case !isCorrectOrder(order):
		return false, errors.ArgumentError("order", "invalid order string, type \"goref sort\" to see usage")
	}
	return true, nil
}
コード例 #2
0
ファイル: rename.go プロジェクト: vpavkin/GoRefactor
func CheckRenameParameters(filename string, line int, column int, newName string) (bool, *errors.GoRefactorError) {
	switch {
	case filename == "" || !utils.IsGoFile(filename):
		return false, errors.ArgumentError("filename", "It's not a valid go file name")
	case line < 1:
		return false, errors.ArgumentError("line", "Must be > 1")
	case column < 1:
		return false, errors.ArgumentError("column", "Must be > 1")
	case !IsGoIdent(newName):
		return false, errors.ArgumentError("newName", "It's not a valid go identifier")
	}
	return true, nil
}
コード例 #3
0
ファイル: inlineMethod.go プロジェクト: vpavkin/GoRefactor
func CheckInlineMethodParameters(filename string, lineStart int, colStart int, lineEnd int, colEnd int) (bool, *errors.GoRefactorError) {
	switch {
	case filename == "" || !utils.IsGoFile(filename):
		return false, errors.ArgumentError("filename", "It's not a valid go file name")
	case lineStart < 1:
		return false, errors.ArgumentError("lineStart", "Must be > 1")
	case lineEnd < 1 || lineEnd < lineStart:
		return false, errors.ArgumentError("lineEnd", "Must be > 1 and >= lineStart")
	case colStart < 1:
		return false, errors.ArgumentError("colStart", "Must be > 1")
	case colEnd < 1:
		return false, errors.ArgumentError("colEnd", "Must be > 1")
	}
	return true, nil
}
コード例 #4
0
ファイル: sort.go プロジェクト: vpavkin/GoRefactor
func _sort(programTree *program.Program, filename string, _groupMethodsByType bool, _groupMethodsByVisibility bool, _sortImports bool, order string) (bool, *errors.GoRefactorError) {

	if ok, err := CheckSortParameters(filename, order); !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
	tokFile := printerUtil.GetFileFromFileSet(fset, filename)

	groupMethodsByType = _groupMethodsByType
	groupMethodsByVisibility = _groupMethodsByVisibility
	sortImports = _sortImports
	fullOrder = getFullOrder(order)
	decls := &DeclCollection{file.Decls, file, fset, tokFile}
	if sortImports {
		for _, d := range decls.Arr {
			if gd, ok := d.(*ast.GenDecl); ok {
				if gd.Tok == token.IMPORT {
					sort.Sort(SpecCollection(gd.Specs))
				}
			}
		}
	}

	printDecls(tokFile, file)
	//test
	//decls.Swap(2, decls.Len()-1)
	sort.Sort(decls)
	printDecls(tokFile, file)
	//printer.Fprint(os.Stdout, fset, file)
	return true, nil
}
コード例 #5
0
ファイル: printer_test.go プロジェクト: vpavkin/GoRefactor
func Test_Delete(t *testing.T) {
	filename := "/home/rulerr/goRefactor/testSrc/testPack/testPack.go"
	srcDir, sources, specialPackages, _ := utils.GetProjectInfo(filename)
	p := program.ParseProgram(srcDir, sources, specialPackages)
	pack, file := p.FindPackageAndFileByFilename(filename)
	if pack == nil || file == nil {
		t.Fatalf(errors.ArgumentError("filename", "Program packages don't contain file '"+filename+"'").String())
	}
	if ok, err := DeleteNode(pack.FileSet, filename, file, token.Position{filename, 0, 19, 1}, token.Position{filename, 0, 20, 7}); !ok {
		t.Fatalf(err.String())
	}
	p.SaveFile(filename)
}
コード例 #6
0
ファイル: printer_test.go プロジェクト: vpavkin/GoRefactor
func test_AddDecl(t *testing.T) {
	filename := "/home/rulerr/goRefactor/testSrc/testPack/printer.go"
	srcDir, sources, specialPackages, _ := utils.GetProjectInfo(filename)
	p := program.ParseProgram(srcDir, sources, specialPackages)
	pack, file := p.FindPackageAndFileByFilename(filename)
	if pack == nil || file == nil {
		t.Fatalf(errors.ArgumentError("filename", "Program packages don't contain file '"+filename+"'").String())
	}
	if ok, fset, newF, err := AddDecl(pack.FileSet, filename, file, pack.FileSet, filename, file, token.Position{filename, 0, 5, 1}, token.Position{filename, 0, 13, 2}, p.IdentMap); !ok {
		t.Fatalf(err.String())
	} else {
		p.SaveFileExplicit(filename, fset, newF)
	}
}
コード例 #7
0
ファイル: printer_test.go プロジェクト: vpavkin/GoRefactor
func test_reparseFile(t *testing.T) {
	filename := "/home/rulerr/goRefactor/testSrc/testPack/printer.go"
	srcDir, sources, specialPackages, _ := utils.GetProjectInfo(filename)
	p := program.ParseProgram(srcDir, sources, specialPackages)
	pack, file := p.FindPackageAndFileByFilename(filename)
	if pack == nil || file == nil {
		t.Fatalf(errors.ArgumentError("filename", "Program packages don't contain file '"+filename+"'").String())
	}
	N := 1000
	fset, _ := reparseFile(file, filename, N, p.IdentMap)
	oldTF := getFileFromFileSet(pack.FileSet, filename)
	newTF := getFileFromFileSet(fset, filename)
	if newTF.Size()-oldTF.Size() != N {
		t.Fatalf("expected %d, got %d", N, newTF.Size()-oldTF.Size())
	}
}
コード例 #8
0
ファイル: program.go プロジェクト: vpavkin/GoRefactor
func (p *Program) FindSymbolByPosition(filename string, line int, column int) (symbol st.Symbol, error *errors.GoRefactorError) {
	packageIn, fileIn := p.FindPackageAndFileByFilename(filename)
	if packageIn == nil {
		return nil, errors.ArgumentError("filename", "Program packages don't contain file '"+filename+"'")
	}

	ident, found := printerUtil.FindIdentByPos(packageIn.FileSet, fileIn, token.Position{Filename: filename, Line: line, Column: column})
	if !found {
		return nil, errors.IdentifierNotFoundError(filename, line, column)
	}

	if sym, ok := p.IdentMap[ident]; ok {
		return sym, nil
	} else {
		panic("untracked ident " + ident.Name)
	}

	return nil, errors.IdentifierNotFoundError(filename, line, column)
}
コード例 #9
0
func CheckImplementInterfaceParameters(filename string, line int, column int, varFile string, varLine int, varColumn int) (bool, *errors.GoRefactorError) {
	switch {
	case filename == "" || !utils.IsGoFile(filename):
		return false, errors.ArgumentError("filename", "It's not a valid go file name")
	case varFile == "" || !utils.IsGoFile(varFile):
		return false, errors.ArgumentError("varFile", "It's not a valid go file name")
	case line < 1:
		return false, errors.ArgumentError("line", "Must be > 1")
	case varLine < 1:
		return false, errors.ArgumentError("varLine", "Must be > 1")
	case column < 1:
		return false, errors.ArgumentError("column", "Must be > 1")
	case varColumn < 1:
		return false, errors.ArgumentError("varColumn", "Must be > 1")
	}
	return true, nil
}
コード例 #10
0
ファイル: extractMethod.go プロジェクト: vpavkin/GoRefactor
func CheckExtractMethodParameters(filename string, lineStart int, colStart int, lineEnd int, colEnd int, methodName string, recieverVarLine int, recieverVarCol int) (bool, *errors.GoRefactorError) {
	switch {
	case filename == "" || !utils.IsGoFile(filename):
		return false, errors.ArgumentError("filename", "It's not a valid go file name")
	case lineStart < 1:
		return false, errors.ArgumentError("lineStart", "Must be > 1")
	case lineEnd < 1 || lineEnd < lineStart:
		return false, errors.ArgumentError("lineEnd", "Must be > 1 and >= lineStart")
	case colStart < 1:
		return false, errors.ArgumentError("colStart", "Must be > 1")
	case colEnd < 1:
		return false, errors.ArgumentError("colEnd", "Must be > 1")
	case !IsGoIdent(methodName):
		return false, errors.ArgumentError("methodName", "It's not a valid go identifier")
	}
	return true, nil
}
コード例 #11
0
func implementInterface(programTree *program.Program, filename string, line int, column int, varFile string, varLine int, varColumn int, asPointer bool) (bool, *errors.GoRefactorError) {
	if ok, err := CheckImplementInterfaceParameters(filename, line, column, varFile, varLine, varColumn); !ok {
		return false, err
	}
	packInt, _ := programTree.FindPackageAndFileByFilename(filename)
	if packInt == nil {
		return false, errors.ArgumentError("filename", "Program packages don't contain file '"+filename+"'")
	}
	packType, fileType := programTree.FindPackageAndFileByFilename(varFile)
	if packType == nil {
		return false, errors.ArgumentError("filename", "Program packages don't contain file '"+varFile+"'")
	}
	symInt, err := programTree.FindSymbolByPosition(filename, line, column)
	if err != nil {
		return false, err
	}
	symType, err := programTree.FindSymbolByPosition(varFile, varLine, varColumn)
	if err != nil {
		return false, err
	}

	sI, ok := symInt.(*st.InterfaceTypeSymbol)
	if !ok {
		return false, &errors.GoRefactorError{ErrorType: "implement interface error", Message: "symbol, pointed as interface, is actually not a one"}
	}
	if _, ok := symType.(*st.InterfaceTypeSymbol); ok {
		return false, &errors.GoRefactorError{ErrorType: "implement interface error", Message: "interface can't implement methods"}
	}
	sT, ok := symType.(st.ITypeSymbol)
	if !ok {
		return false, &errors.GoRefactorError{ErrorType: "implement interface error", Message: "interface can be implemented only by a type"}
	}
	if asPointer {
		sT = programTree.GetPointerType(sT)
	}

	errors := make([]*errors.GoRefactorError, 0, 10)
	missedMethods := make(map[*st.FunctionSymbol]bool)
	checker := func(sym st.Symbol) {
		f := sym.(*st.FunctionSymbol)
		ok, err := containsMethod(f, sT)
		if err != nil {
			errors = append(errors, err)
		} else if !ok {
			missedMethods[f] = true
		}
	}
	sI.Methods().ForEachNoLock(checker)
	sI.Methods().ForEachOpenedScope(func(table *st.SymbolTable) {
		table.ForEachNoLock(checker)
	})

	println("missedMethods:")
	for s, _ := range missedMethods {
		list := make([]ast.Stmt, 1)
		list[0] = &ast.ExprStmt{&ast.CallExpr{ast.NewIdent("panic"), token.NoPos, []ast.Expr{&ast.BasicLit{token.NoPos, token.STRING, "\"not implemented yet\""}}, token.NoPos, token.NoPos}}
		fdecl := makeFuncDecl(s.Name(), list, s.FunctionType.(*st.FunctionTypeSymbol).Parameters, nil, s.FunctionType.(*st.FunctionTypeSymbol).Results, st.MakeVariable(st.NO_NAME, sT.Scope(), sT), packType, varFile)
		printer.Fprint(os.Stdout, token.NewFileSet(), fdecl)
		println()
		fileType.Decls = append(fileType.Decls, fdecl)
	}
	println()
	println("errors:")
	for _, err := range errors {
		println(err.String())
	}

	return true, nil
}
コード例 #12
0
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

}
コード例 #13
0
ファイル: inlineMethod.go プロジェクト: vpavkin/GoRefactor
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
}
コード例 #14
0
ファイル: extractMethod.go プロジェクト: vpavkin/GoRefactor
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

}