<commit_before>// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// This file defines a refactoring to rename variables, functions, methods,
// structs, interfaces, and packages.

package refactoring

import (
	"go/ast"
	"regexp"
	"runtime"
	//"fmt"
	"go/parser"
	"go/token"
	"io/ioutil"
	"path/filepath"
	"strings"

	"code.google.com/p/go.tools/go/types"
	"golang-refactoring.org/go-doctor/analysis/names"
	"golang-refactoring.org/go-doctor/filesystem"
	"golang-refactoring.org/go-doctor/text"
)

// A Rename refactoring is used to rename identifiers in Go programs.
type Rename struct {
	refactoringBase
	newName   string
	signature *types.Signature
}

func (r *Rename) Description() *Description {
	return &Description{
		Name:      "Rename",
		Synopsis:  "Changes the name of an identifier",
		Usage:     "<new_name>",
		Multifile: true,
		Params: []Parameter{Parameter{
			Label:        "New Name:",
			Prompt:       "What to rename this identifier to.",
			DefaultValue: "",
		}},
		Quality: Testing,
	}
}

func (r *Rename) Run(config *Config) *Result {
	r.refactoringBase.Run(config)
	if !validateArgs(config, r.Description(), r.Log) {
		return &r.Result
	}
	r.Log.ChangeInitialErrorsToWarnings()
	if r.Log.ContainsErrors() {
		return &r.Result
	}

	r.newName = config.Args[0].(string)
	if !r.isIdentifierValid(r.newName) {
		r.Log.Errorf("The new name %s is not a valid Go identifier", r.newName)
		return &r.Result
	}

	if r.selectedNode == nil {
		r.Log.Error("Please select an identifier to rename.")
		r.Log.AssociatePos(r.selectionStart, r.selectionEnd)
		return &r.Result
	}

	if r.newName == "" {
		r.Log.Error("newName cannot be empty")
		return &r.Result
	}

	switch ident := r.selectedNode.(type) {
	case *ast.Ident:
		if ast.IsExported(ident.Name) && !ast.IsExported(r.newName) {
			r.Log.Error("newName cannot be non Exportable if selected identifier name is Exportable")
			return &r.Result
		}
		if ident.Name == "main" && r.pkgInfo(r.fileContaining(ident)).Pkg.Name() == "main" {
			r.Log.Error("cannot rename main function inside main package ,it eliminates the program entry 							point")
			r.Log.AssociateNode(ident)
			return &r.Result
		}

		r.rename(ident)
		r.updateLog(config, false)
	case *ast.BasicLit:
		for pkg, _ := range r.program.AllPackages {
			if pkg.Name() == strings.Replace(ident.Value, "\"", "", 2) {
				search := names.NewSearchEngine(r.program)
				searchResult := search.PackageRename(pkg.Name())
				r.addOccurrences(searchResult)
				r.addFileSystemChanges(searchResult, pkg.Name())
			}
		}
		r.updateLog(config, false)
	default:
		r.Log.Error("Please select an identifier to rename.")
		r.Log.AssociatePos(r.selectionStart, r.selectionEnd)
	}
	return &r.Result
}

func (r *Rename) isIdentifierValid(newName string) bool {
	matched, err := regexp.MatchString("^\\p{L}[\\p{L}\\p{N}]*$", newName)
	if matched && err == nil {
		keyword, err := regexp.MatchString("^(break|case|chan|const|continue|default|defer|else|fallthrough|for|func|go|goto|if|import|interface|map|package|range|return|select|struct|switch|type|var)$", newName)
		return !keyword && err == nil
	}
	return false
}

func (r *Rename) rename(ident *ast.Ident) {
	if !r.identExists(ident) {
		search := names.NewSearchEngine(r.program)
		searchResult, err := search.FindOccurrences(ident)
		if err != nil {
			r.Log.Error(err)
			return
		}

		r.addOccurrences(searchResult)
		if search.IsPackageName(ident) {
			r.addFileSystemChanges(searchResult, ident.Name)
		}
		//TODO: r.checkForErrors()
		return
	}

}

//IdentifierExists checks if there already exists an Identifier with the newName,with in the scope of the oldname.
func (r *Rename) identExists(ident *ast.Ident) bool {

	obj := r.pkgInfo(r.fileContaining(ident)).ObjectOf(ident)
	search := names.NewSearchEngine(r.program)

	if obj == nil && !search.IsPackageName(ident) {

		r.Log.Error("unable to find declaration of selected identifier")
		r.Log.AssociateNode(ident)
		return true
	}

	if search.IsPackageName(ident) {
		return false
	}
	identscope := obj.Parent()

	if names.IsMethod(obj) {
		objfound, _, pointerindirections := types.LookupFieldOrMethod(names.MethodReceiver(obj).Type(), obj.Pkg(), r.newName)
		if names.IsMethod(objfound) && pointerindirections {
			r.Log.Error("newname already exists in scope,please select other value for the newname")
			r.Log.AssociateNode(ident)
			return true
		} else {
			return false<commit_msg>Updates for latest go.tools, see below<commit_after>// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// This file defines a refactoring to rename variables, functions, methods,
// structs, interfaces, and packages.

package refactoring

import (
	"go/ast"
	"regexp"
	"runtime"
	//"fmt"
	"go/parser"
	"go/token"
	"io/ioutil"
	"path/filepath"
	"strings"

	"code.google.com/p/go.tools/go/types"
	"golang-refactoring.org/go-doctor/analysis/names"
	"golang-refactoring.org/go-doctor/filesystem"
	"golang-refactoring.org/go-doctor/text"
)

// A Rename refactoring is used to rename identifiers in Go programs.
type Rename struct {
	refactoringBase
	newName   string
	signature *types.Signature
}

func (r *Rename) Description() *Description {
	return &Description{
		Name:      "Rename",
		Synopsis:  "Changes the name of an identifier",
		Usage:     "<new_name>",
		Multifile: true,
		Params: []Parameter{Parameter{
			Label:        "New Name:",
			Prompt:       "What to rename this identifier to.",
			DefaultValue: "",
		}},
		Quality: Testing,
	}
}

func (r *Rename) Run(config *Config) *Result {
	r.refactoringBase.Run(config)
	if !validateArgs(config, r.Description(), r.Log) {
		return &r.Result
	}
	r.Log.ChangeInitialErrorsToWarnings()
	if r.Log.ContainsErrors() {
		return &r.Result
	}

	r.newName = config.Args[0].(string)
	if !r.isIdentifierValid(r.newName) {
		r.Log.Errorf("The new name %s is not a valid Go identifier", r.newName)
		return &r.Result
	}

	if r.selectedNode == nil {
		r.Log.Error("Please select an identifier to rename.")
		r.Log.AssociatePos(r.selectionStart, r.selectionEnd)
		return &r.Result
	}

	if r.newName == "" {
		r.Log.Error("newName cannot be empty")
		return &r.Result
	}

	switch ident := r.selectedNode.(type) {
	case *ast.Ident:
		if ast.IsExported(ident.Name) && !ast.IsExported(r.newName) {
			r.Log.Error("newName cannot be non Exportable if selected identifier name is Exportable")
			return &r.Result
		}
		if ident.Name == "main" && r.pkgInfo(r.fileContaining(ident)).Pkg.Name() == "main" {
			r.Log.Error("cannot rename main function inside main package ,it eliminates the program entry 							point")
			r.Log.AssociateNode(ident)
			return &r.Result
		}

		r.rename(ident)
		r.updateLog(config, false)
	case *ast.BasicLit:
		for pkg, _ := range r.program.AllPackages {
			if pkg.Name() == strings.Replace(ident.Value, "\"", "", 2) {
				search := names.NewSearchEngine(r.program)
				searchResult := search.PackageRename(pkg.Name())
				r.addOccurrences(searchResult)
				r.addFileSystemChanges(searchResult, pkg.Name())
			}
		}
		r.updateLog(config, false)
	default:
		r.Log.Error("Please select an identifier to rename.")
		r.Log.AssociatePos(r.selectionStart, r.selectionEnd)
	}
	return &r.Result
}

func (r *Rename) isIdentifierValid(newName string) bool {
	matched, err := regexp.MatchString("^\\p{L}[\\p{L}\\p{N}]*$", newName)
	if matched && err == nil {
		keyword, err := regexp.MatchString("^(break|case|chan|const|continue|default|defer|else|fallthrough|for|func|go|goto|if|import|interface|map|package|range|return|select|struct|switch|type|var)$", newName)
		return !keyword && err == nil
	}
	return false
}

func (r *Rename) rename(ident *ast.Ident) {
	if !r.identExists(ident) {
		search := names.NewSearchEngine(r.program)
		searchResult, err := search.FindOccurrences(ident)
		if err != nil {
			r.Log.Error(err)
			return
		}

		r.addOccurrences(searchResult)
		if search.IsPackageName(ident) {
			r.addFileSystemChanges(searchResult, ident.Name)
		}
		//TODO: r.checkForErrors()
		return
	}

}

//IdentifierExists checks if there already exists an Identifier with the newName,with in the scope of the oldname.
func (r *Rename) identExists(ident *ast.Ident) bool {
	obj := r.pkgInfo(r.fileContaining(ident)).ObjectOf(ident)
	search := names.NewSearchEngine(r.program)

	if obj == nil && !search.IsPackageName(ident) {

		r.Log.Error("unable to find declaration of selected identifier")
		r.Log.AssociateNode(ident)
		return true
	}

	if search.IsPackageName(ident) {
		return false
	}
	identscope := obj.Parent()

	if names.IsMethod(obj) {
		objfound, _, pointerindirections := types.LookupFieldOrMethod(names.MethodReceiver(obj).Type(), true, obj.Pkg(), r.newName)
		if names.IsMethod(objfound) && pointerindirections {
			r.Log.Error("newname already exists in scope,please select other value for the newname")
			r.Log.AssociateNode(ident)
			return true
		} else {
			return false
{'fraction_non_alphanumeric': 0.1377528583992964, 'fraction_numerical': 0.0013192612137203166, 'mean_word_length': 4.07361963190184, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7620758', 'n_tokens_mistral': 3405, 'n_tokens_neox': 3117, 'n_words': 741}