mirror of
https://github.com/golang/go
synced 2024-11-05 17:46:16 -07:00
c6ec5ea66d
Previously, gorename rejected all method renamings if it would change the assignability relation. Now, so long as the renaming was initiated at an abstract method, the renaming proceeds, changing concrete methods (and possibly other abstract methods) as needed. The user intention is clear. The intention of a renaming initiated at a concrete method is less clear, so we still reject it if it would change the assignability relation. The diagnostic advises the user to rename the abstract method if that was the intention. Additional safety checks are required: for each satisfy.Constraint that couples a concrete type C and an interface type I, we must treat it just like a set of implicit selections C.f, one per abstract method f of I, and ensure the selections' meanings are unchanged. The satisfy package no longer canonicalizes types, since this substitutes one interface for another (equivalent) one, which is sound, but makes the type names random and the error messages confusing. Also, fixed a bug in 'satisfy' relating to map keys. + Lots more tests. LGTM=sameer R=sameer CC=golang-codereviews https://golang.org/cl/173430043
141 lines
4.5 KiB
Go
141 lines
4.5 KiB
Go
// The gorename command performs precise type-safe renaming of
|
|
// identifiers in Go source code. See the -help message or Usage
|
|
// constant for details.
|
|
package main
|
|
|
|
import (
|
|
"flag"
|
|
"fmt"
|
|
"go/build"
|
|
"os"
|
|
"runtime"
|
|
|
|
"golang.org/x/tools/refactor/rename"
|
|
)
|
|
|
|
var (
|
|
offsetFlag = flag.String("offset", "", "file and byte offset of identifier to be renamed, e.g. 'file.go:#123'. For use by editors.")
|
|
fromFlag = flag.String("from", "", "identifier to be renamed; see -help for formats")
|
|
toFlag = flag.String("to", "", "new name for identifier")
|
|
helpFlag = flag.Bool("help", false, "show usage message")
|
|
)
|
|
|
|
func init() {
|
|
flag.BoolVar(&rename.Force, "force", false, "proceed, even if conflicts were reported")
|
|
flag.BoolVar(&rename.DryRun, "dryrun", false, "show the change, but do not apply it")
|
|
flag.BoolVar(&rename.Verbose, "v", false, "print verbose information")
|
|
|
|
// If $GOMAXPROCS isn't set, use the full capacity of the machine.
|
|
// For small machines, use at least 4 threads.
|
|
if os.Getenv("GOMAXPROCS") == "" {
|
|
n := runtime.NumCPU()
|
|
if n < 4 {
|
|
n = 4
|
|
}
|
|
runtime.GOMAXPROCS(n)
|
|
}
|
|
}
|
|
|
|
const Usage = `gorename: precise type-safe renaming of identifiers in Go source code.
|
|
|
|
Usage:
|
|
|
|
gorename (-from <spec> | -offset <file>:#<byte-offset>) -to <name> [-force]
|
|
|
|
You must specify the object (named entity) to rename using the -offset
|
|
or -from flag. Exactly one must be specified.
|
|
|
|
Flags:
|
|
|
|
-offset specifies the filename and byte offset of an identifier to rename.
|
|
This form is intended for use by text editors.
|
|
|
|
-from specifies the object to rename using a query notation;
|
|
This form is intended for interactive use at the command line.
|
|
` + rename.FromFlagUsage + `
|
|
|
|
-to the new name.
|
|
|
|
-force causes the renaming to proceed even if conflicts were reported.
|
|
The resulting program may be ill-formed, or experience a change
|
|
in behaviour.
|
|
|
|
WARNING: this flag may even cause the renaming tool to crash.
|
|
(In due course this bug will be fixed by moving certain
|
|
analyses into the type-checker.)
|
|
|
|
-dryrun causes the tool to report conflicts but not update any files.
|
|
|
|
-v enables verbose logging.
|
|
|
|
gorename automatically computes the set of packages that might be
|
|
affected. For a local renaming, this is just the package specified by
|
|
-from or -offset, but for a potentially exported name, gorename scans
|
|
the workspace ($GOROOT and $GOPATH).
|
|
|
|
gorename rejects renamings of concrete methods that would change the
|
|
assignability relation between types and interfaces. If the interface
|
|
change was intentional, initiate the renaming at the interface method.
|
|
|
|
gorename rejects any renaming that would create a conflict at the point
|
|
of declaration, or a reference conflict (ambiguity or shadowing), or
|
|
anything else that could cause the resulting program not to compile.
|
|
|
|
|
|
Examples:
|
|
|
|
% gorename -offset file.go:#123 -to foo
|
|
|
|
Rename the object whose identifier is at byte offset 123 within file file.go.
|
|
|
|
% gorename -from '"bytes".Buffer.Len' -to Size
|
|
|
|
Rename the "Len" method of the *bytes.Buffer type to "Size".
|
|
|
|
---- TODO ----
|
|
|
|
Correctness:
|
|
- handle dot imports correctly
|
|
- document limitations (reflection, 'implements' guesswork).
|
|
- sketch a proof of exhaustiveness.
|
|
|
|
Features:
|
|
- support running on packages specified as *.go files on the command line
|
|
- support running on programs containing errors (loader.Config.AllowErrors)
|
|
- allow users to specify a scope other than "global" (to avoid being
|
|
stuck by neglected packages in $GOPATH that don't build).
|
|
- support renaming the package clause (no object)
|
|
- support renaming an import path (no ident or object)
|
|
(requires filesystem + SCM updates).
|
|
- detect and reject edits to autogenerated files (cgo, protobufs)
|
|
and optionally $GOROOT packages.
|
|
- report all conflicts, or at least all qualitatively distinct ones.
|
|
Sometimes we stop to avoid redundancy, but
|
|
it may give a disproportionate sense of safety in -force mode.
|
|
- support renaming all instances of a pattern, e.g.
|
|
all receiver vars of a given type,
|
|
all local variables of a given type,
|
|
all PkgNames for a given package.
|
|
- emit JSON output for other editors and tools.
|
|
`
|
|
|
|
func main() {
|
|
flag.Parse()
|
|
if len(flag.Args()) > 0 {
|
|
fmt.Fprintln(os.Stderr, "gorename: surplus arguments.")
|
|
os.Exit(1)
|
|
}
|
|
|
|
if *helpFlag || (*offsetFlag == "" && *fromFlag == "" && *toFlag == "") {
|
|
fmt.Println(Usage)
|
|
return
|
|
}
|
|
|
|
if err := rename.Main(&build.Default, *offsetFlag, *fromFlag, *toFlag); err != nil {
|
|
if err != rename.ConflictError {
|
|
fmt.Fprintf(os.Stderr, "gorename: %s\n", err)
|
|
}
|
|
os.Exit(1)
|
|
}
|
|
}
|