Skip to content

Commit ee45598

Browse files
committed
imports: create named imports for name/path mismatches (again)
For clarity and performance reasons, we want the fast path of goimports to be purely syntactic. Packages whose import paths don't match their package names make this harder. Before this CL, we parsed each imported package to get its real package name. Now, we make named imports for such packages, and on subsequent runs we don't have to do the extra work. A package name matches its import path if the name is the last segment of the path, or the next-to-last before a version suffix vNN. gopkg.in style .vNN suffixes are considered mismatching. The previous attempt (CL 145699) failed because I assumed we'd be able to find all packages from scratch. That's not true if the import path is completely unrelated to the package name. To avoid that problem, rather than removing and re-adding mismatched imports, we just literally add names to them. Fixes golang/go#28428 Change-Id: I93bd820f5956162ae9c99afa73bdcfc570a2e7b4 Reviewed-on: https://go-review.googlesource.com/c/152000 Reviewed-by: Brad Fitzpatrick <[email protected]>
1 parent 5bbcdc1 commit ee45598

File tree

2 files changed

+82
-19
lines changed

2 files changed

+82
-19
lines changed

imports/fix.go

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -238,9 +238,10 @@ type pass struct {
238238
used map[*importInfo]bool
239239

240240
// Inputs to fix. These can be augmented between successive fix calls.
241-
lastTry bool // indicates that this is the last call and fix should clean up as best it can.
242-
candidates []*importInfo // candidate imports in priority order.
243-
knownPackages map[string]*packageInfo // information about all known packages.
241+
lastTry bool // indicates that this is the last call and fix should clean up as best it can.
242+
addImportNames bool // add names to mismatched imports.
243+
candidates []*importInfo // candidate imports in priority order.
244+
knownPackages map[string]*packageInfo // information about all known packages.
244245
}
245246

246247
// loadPackageNames saves the package names for everything referenced by imports.
@@ -334,6 +335,23 @@ func (p *pass) fix() bool {
334335
astutil.DeleteNamedImport(p.fset, p.f, imp.name, imp.importPath)
335336
}
336337
}
338+
339+
if p.addImportNames {
340+
for _, imp := range p.f.Imports {
341+
if imp.Name != nil {
342+
continue
343+
}
344+
path := strings.Trim(imp.Path.Value, `""`)
345+
pkg, ok := p.knownPackages[path]
346+
if !ok {
347+
continue
348+
}
349+
if pkg.name != importPathToNameBasic(path, p.srcDir) {
350+
imp.Name = &ast.Ident{Name: pkg.name, NamePos: imp.Pos()}
351+
}
352+
}
353+
}
354+
337355
for _, imp := range selected {
338356
astutil.AddNamedImport(p.fset, p.f, imp.name, imp.importPath)
339357
}
@@ -421,6 +439,7 @@ func fixImports(fset *token.FileSet, f *ast.File, filename string) error {
421439
// the naive algorithm.
422440
p = &pass{fset: fset, f: f, srcDir: srcDir}
423441
p.pathToName = importPathToName
442+
p.addImportNames = true
424443
p.otherFiles = otherFiles
425444
if p.load() {
426445
return nil
@@ -506,7 +525,7 @@ func addGoPathCandidates(pass *pass, refs map[string]map[string]bool, filename s
506525
}
507526
// If the package name isn't what you'd expect looking
508527
// at the import path, add an explicit name.
509-
if path.Base(ipath) != pkgName {
528+
if importPathToNameBasic(ipath, pass.srcDir) != pkgName {
510529
imp.name = pkgName
511530
}
512531

imports/fix_test.go

Lines changed: 59 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1350,9 +1350,15 @@ var (
13501350
`
13511351

13521352
testConfig{
1353-
module: packagestest.Module{
1354-
Name: "mypkg.com/outpkg",
1355-
Files: fm{"toformat.go": input},
1353+
modules: []packagestest.Module{
1354+
{
1355+
Name: "mypkg.com/outpkg",
1356+
Files: fm{"toformat.go": input},
1357+
},
1358+
{
1359+
Name: "github.com/foo/v2",
1360+
Files: fm{"x.go": "package foo\n func Foo(){}\n"},
1361+
},
13561362
},
13571363
}.processTest(t, "mypkg.com/outpkg", "toformat.go", nil, nil, input)
13581364
}
@@ -1363,18 +1369,24 @@ var (
13631369
// that the package name is "mypkg".
13641370
func TestVendorPackage(t *testing.T) {
13651371
const input = `package p
1366-
13671372
import (
13681373
"fmt"
1369-
13701374
"mypkg.com/mypkg.v1"
13711375
)
1376+
var _, _ = fmt.Print, mypkg.Foo
1377+
`
13721378

1373-
var (
1374-
_ = fmt.Print
1375-
_ = mypkg.Foo
1379+
const want = `package p
1380+
1381+
import (
1382+
"fmt"
1383+
1384+
mypkg "mypkg.com/mypkg.v1"
13761385
)
1386+
1387+
var _, _ = fmt.Print, mypkg.Foo
13771388
`
1389+
13781390
testConfig{
13791391
gopathOnly: true,
13801392
module: packagestest.Module{
@@ -1384,7 +1396,7 @@ var (
13841396
"toformat.go": input,
13851397
},
13861398
},
1387-
}.processTest(t, "mypkg.com/outpkg", "toformat.go", nil, nil, input)
1399+
}.processTest(t, "mypkg.com/outpkg", "toformat.go", nil, nil, want)
13881400
}
13891401

13901402
func TestInternal(t *testing.T) {
@@ -1562,25 +1574,57 @@ func (t *goimportTest) process(module, file string, contents []byte, opts *Optio
15621574
}
15631575

15641576
// Tests that added imports are renamed when the import path's base doesn't
1565-
// match its package name. For example, we want to generate:
1566-
//
1567-
// import cloudbilling "google.golang.org/api/cloudbilling/v1"
1577+
// match its package name.
15681578
func TestRenameWhenPackageNameMismatch(t *testing.T) {
15691579
const input = `package main
15701580
const Y = bar.X`
15711581

15721582
const want = `package main
15731583
1574-
import bar "foo.com/foo/bar/v1"
1584+
import bar "foo.com/foo/bar/baz"
15751585
15761586
const Y = bar.X
15771587
`
15781588
testConfig{
15791589
module: packagestest.Module{
15801590
Name: "foo.com",
15811591
Files: fm{
1582-
"foo/bar/v1/x.go": "package bar \n const X = 1",
1583-
"test/t.go": input,
1592+
"foo/bar/baz/x.go": "package bar \n const X = 1",
1593+
"test/t.go": input,
1594+
},
1595+
},
1596+
}.processTest(t, "foo.com", "test/t.go", nil, nil, want)
1597+
}
1598+
1599+
// Tests that an existing import with badly mismatched path/name has its name
1600+
// correctly added. See #28645 and #29041.
1601+
func TestAddNameToMismatchedImport(t *testing.T) {
1602+
const input = `package main
1603+
1604+
import (
1605+
"foo.com/surprise"
1606+
"foo.com/v1"
1607+
)
1608+
1609+
var _, _ = bar.X, v1.Y`
1610+
1611+
const want = `package main
1612+
1613+
import (
1614+
bar "foo.com/surprise"
1615+
v1 "foo.com/v1"
1616+
)
1617+
1618+
var _, _ = bar.X, v1.Y
1619+
`
1620+
1621+
testConfig{
1622+
module: packagestest.Module{
1623+
Name: "foo.com",
1624+
Files: fm{
1625+
"surprise/x.go": "package bar \n const X = 1",
1626+
"v1/x.go": "package v1 \n const Y = 1",
1627+
"test/t.go": input,
15841628
},
15851629
},
15861630
}.processTest(t, "foo.com", "test/t.go", nil, nil, want)

0 commit comments

Comments
 (0)