コード例 #1
0
ファイル: rename.go プロジェクト: vpavkin/GoRefactor
func Rename(filename string, line int, column int, newName string) (ok bool, err *errors.GoRefactorError) {

	if ok, err = CheckRenameParameters(filename, line, column, newName); !ok {
		return
	}

	programTree := parseProgram(filename)

	var sym st.Symbol
	if sym, err = programTree.FindSymbolByPosition(filename, line, column); err == nil {

		if _, ok := sym.(*st.PointerTypeSymbol); ok {
			panic("find by position returned pointer type!!!")
		}
		if st.IsPredeclaredIdentifier(sym.Name()) {
			return false, errors.UnrenamableIdentifierError(sym.Name(), " It's a basic language symbol")
		}
		if sym.PackageFrom().IsGoPackage {
			return false, errors.UnrenamableIdentifierError(sym.Name(), " It's a symbol,imported from go library")
		}
		if unicode.IsUpper(int(sym.Name()[0])) && !unicode.IsUpper(int(newName[0])) ||
			unicode.IsLower(int(sym.Name()[0])) && !unicode.IsLower(int(newName[0])) {
			return false, &errors.GoRefactorError{ErrorType: "Can't rename identifier", Message: "can't change access modifier. Changing first letter's case can cause errors."}
		}
		if _, ok := sym.Scope().LookUp(newName, filename); ok {
			return false, errors.IdentifierAlreadyExistsError(newName)
		}

		if meth, ok := sym.(*st.FunctionSymbol); ok {
			if meth.IsInterfaceMethod {
				return false, errors.UnrenamableIdentifierError(sym.Name(), " It's an interface method")
			}
		}
		if ps, ok := sym.(*st.PackageSymbol); ok {
			pack, file := programTree.FindPackageAndFileByFilename(filename)
			impDecl := findImportDecl(pack, file, ps)
			if impDecl == nil {
				panic("couldn't find import decl")
			}
			if impDecl.Name == nil || impDecl.Name.Name == "" {
				impDecl.Name = ast.NewIdent(newName)
			}
		}
		fnames, fsets, files, err := renameSymbol(sym, newName, programTree)
		if err == nil {
			for i, f := range fnames {
				programTree.SaveFileExplicit(f, fsets[i], files[i])
			}
		}
		return err == nil, err
	} else {
		return false, err
	}
	panic("unreachable code")
}
コード例 #2
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

}