mirror of
https://github.com/golang/go
synced 2024-11-18 10:54:40 -07:00
cmd/bundle: Support renaming imports.
Document a risk of generating invalid code due to shadowing between identifiers in code files and the imported package names. This risk was present before for any package with more than 1 .go file, but it's increased when some files have renamed imports (since they're typically used to resolve shadowing conflicts). Resolves TODO(adonovan): support renaming imports. Change-Id: Ie0e702345790fd2059c229623fb99fe645d688a4 Reviewed-on: https://go-review.googlesource.com/23785 Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org> Reviewed-by: Alan Donovan <adonovan@google.com>
This commit is contained in:
parent
6e2a0ce36e
commit
5cb1c80a83
@ -96,6 +96,7 @@ import (
|
||||
"log"
|
||||
"os"
|
||||
"path"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/tools/go/loader"
|
||||
@ -257,46 +258,61 @@ func bundle(src, dst, dstpkg, prefix string) ([]byte, error) {
|
||||
|
||||
fmt.Fprintf(&out, "package %s\n\n", dstpkg)
|
||||
|
||||
// Print a single declaration that imports all necessary packages.
|
||||
// TODO(adonovan):
|
||||
// - support renaming imports.
|
||||
// BUG(adonovan,shurcooL): bundle may generate incorrect code
|
||||
// due to shadowing between identifiers and imported package names.
|
||||
//
|
||||
// The generated code will either fail to compile or
|
||||
// (unlikely) compile successfully but have different behavior
|
||||
// than the original package. The risk of this happening is higher
|
||||
// when the original package has renamed imports (they're typically
|
||||
// renamed in order to resolve a shadow inside that particular .go file).
|
||||
|
||||
// TODO(adonovan,shurcooL):
|
||||
// - detect shadowing issues, and either return error or resolve them
|
||||
// - preserve comments from the original import declarations.
|
||||
|
||||
// pkgStd and pkgExt are sets of printed import specs. This is done
|
||||
// to deduplicate instances of the same import name and path.
|
||||
var pkgStd = make(map[string]bool)
|
||||
var pkgExt = make(map[string]bool)
|
||||
for _, f := range info.Files {
|
||||
for _, imp := range f.Imports {
|
||||
if imp.Name != nil {
|
||||
return nil, fmt.Errorf("%s: renaming imports not supported",
|
||||
lprog.Fset.Position(imp.Pos()))
|
||||
path, err := strconv.Unquote(imp.Path.Value)
|
||||
if err != nil {
|
||||
log.Fatalf("invalid import path string: %v", err) // Shouldn't happen here since conf.Load succeeded.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var pkgStd, pkgExt []string
|
||||
for _, p := range info.Pkg.Imports() {
|
||||
if p.Path() == dst {
|
||||
if path == dst {
|
||||
continue
|
||||
}
|
||||
x, ok := importMap[p.Path()]
|
||||
if !ok {
|
||||
x = p.Path()
|
||||
if newPath, ok := importMap[path]; ok {
|
||||
path = newPath
|
||||
}
|
||||
if isStandardImportPath(x) {
|
||||
pkgStd = append(pkgStd, x)
|
||||
|
||||
var name string
|
||||
if imp.Name != nil {
|
||||
name = imp.Name.Name
|
||||
}
|
||||
spec := fmt.Sprintf("%s %q", name, path)
|
||||
if isStandardImportPath(path) {
|
||||
pkgStd[spec] = true
|
||||
} else {
|
||||
pkgExt = append(pkgExt, x)
|
||||
pkgExt[spec] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Print a single declaration that imports all necessary packages.
|
||||
fmt.Fprintln(&out, "import (")
|
||||
for _, p := range pkgStd {
|
||||
fmt.Fprintf(&out, "\t%q\n", p)
|
||||
for p := range pkgStd {
|
||||
fmt.Fprintf(&out, "\t%s\n", p)
|
||||
}
|
||||
if len(pkgExt) > 0 {
|
||||
fmt.Fprintln(&out)
|
||||
for _, p := range pkgExt {
|
||||
fmt.Fprintf(&out, "\t%q\n", p)
|
||||
}
|
||||
for p := range pkgExt {
|
||||
fmt.Fprintf(&out, "\t%s\n", p)
|
||||
}
|
||||
fmt.Fprintln(&out, ")\n")
|
||||
fmt.Fprint(&out, ")\n\n")
|
||||
|
||||
// Modify and print each file.
|
||||
for _, f := range info.Files {
|
||||
|
@ -28,6 +28,7 @@ func TestBundle(t *testing.T) {
|
||||
"initial": {
|
||||
"a.go": load("testdata/src/initial/a.go"),
|
||||
"b.go": load("testdata/src/initial/b.go"),
|
||||
"c.go": load("testdata/src/initial/c.go"),
|
||||
},
|
||||
"domain.name/importdecl": {
|
||||
"p.go": load("testdata/src/domain.name/importdecl/p.go"),
|
||||
|
10
cmd/bundle/testdata/out.golden
vendored
10
cmd/bundle/testdata/out.golden
vendored
@ -8,6 +8,10 @@ package dest
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
. "fmt"
|
||||
_ "fmt"
|
||||
renamedfmt "fmt"
|
||||
renamedfmt2 "fmt"
|
||||
|
||||
"domain.name/importdecl"
|
||||
)
|
||||
@ -31,3 +35,9 @@ const prefixc = 1
|
||||
func prefixfoo() {
|
||||
fmt.Println(importdecl.F())
|
||||
}
|
||||
|
||||
func prefixbaz() {
|
||||
renamedfmt.Println()
|
||||
renamedfmt2.Println()
|
||||
Println()
|
||||
}
|
||||
|
12
cmd/bundle/testdata/src/initial/c.go
vendored
Normal file
12
cmd/bundle/testdata/src/initial/c.go
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
package initial
|
||||
|
||||
import _ "fmt"
|
||||
import renamedfmt "fmt"
|
||||
import renamedfmt2 "fmt"
|
||||
import . "fmt"
|
||||
|
||||
func baz() {
|
||||
renamedfmt.Println()
|
||||
renamedfmt2.Println()
|
||||
Println()
|
||||
}
|
Loading…
Reference in New Issue
Block a user