Skip to content

Commit 5185da1

Browse files
committed
internal/refactor/inline: avoid redundant import names added by inlining
When analyzing callee objects, keep track of their package names so that we don't have to assign explicit names to new imports when there is no conflict with their implicit name. Fixes golang/go#63613 Change-Id: I5b8dc9c514e434fb4262cab321933a28729bbd76 Reviewed-on: https://go-review.googlesource.com/c/tools/+/536755 LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Alan Donovan <adonovan@google.com>
1 parent 6360c0b commit 5185da1

File tree

7 files changed

+84
-42
lines changed

7 files changed

+84
-42
lines changed

gopls/internal/regtest/marker/testdata/codeaction/removeparam_imports.txt

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ package a
8585

8686
import (
8787
"mod.test/b"
88-
c "mod.test/c"
88+
"mod.test/c"
8989
)
9090

9191
func _() {
@@ -97,7 +97,7 @@ package a
9797

9898
import (
9999
"mod.test/b"
100-
c "mod.test/c"
100+
"mod.test/c"
101101
)
102102

103103
func _() {
@@ -111,7 +111,7 @@ package a
111111

112112
import (
113113
"mod.test/b"
114-
c "mod.test/c"
114+
"mod.test/c"
115115
)
116116

117117
func _() {
@@ -129,9 +129,9 @@ package a
129129
// TODO(rfindley/adonovan): inlining here adds an additional import of
130130
// mod.test/b. Can we do better?
131131
import (
132+
"mod.test/b"
132133
. "mod.test/b"
133-
b "mod.test/b"
134-
c "mod.test/c"
134+
"mod.test/c"
135135
)
136136

137137
func _() {

internal/refactor/inline/callee.go

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -59,9 +59,12 @@ type freeRef struct {
5959

6060
// An object abstracts a free types.Object referenced by the callee. Gob-serializable.
6161
type object struct {
62-
Name string // Object.Name()
63-
Kind string // one of {var,func,const,type,pkgname,nil,builtin}
64-
PkgPath string // pkgpath of object (or of imported package if kind="pkgname")
62+
Name string // Object.Name()
63+
Kind string // one of {var,func,const,type,pkgname,nil,builtin}
64+
PkgPath string // path of object's package (or imported package if kind="pkgname")
65+
PkgName string // name of object's package (or imported package if kind="pkgname")
66+
// TODO(rfindley): should we also track LocalPkgName here? Do we want to
67+
// preserve the local package name?
6568
ValidPos bool // Object.Pos().IsValid()
6669
Shadow map[string]bool // names shadowed at one of the object's refs
6770
}
@@ -192,15 +195,18 @@ func AnalyzeCallee(logf func(string, ...any), fset *token.FileSet, pkg *types.Pa
192195
objidx, ok := freeObjIndex[obj]
193196
if !ok {
194197
objidx = len(freeObjIndex)
195-
var pkgpath string
196-
if pkgname, ok := obj.(*types.PkgName); ok {
197-
pkgpath = pkgname.Imported().Path()
198+
var pkgpath, pkgname string
199+
if pn, ok := obj.(*types.PkgName); ok {
200+
pkgpath = pn.Imported().Path()
201+
pkgname = pn.Imported().Name()
198202
} else if obj.Pkg() != nil {
199203
pkgpath = obj.Pkg().Path()
204+
pkgname = obj.Pkg().Name()
200205
}
201206
freeObjs = append(freeObjs, object{
202207
Name: obj.Name(),
203208
Kind: objectKind(obj),
209+
PkgName: pkgname,
204210
PkgPath: pkgpath,
205211
ValidPos: obj.Pos().IsValid(),
206212
})

internal/refactor/inline/inline.go

Lines changed: 34 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -222,13 +222,13 @@ func Inline(logf func(string, ...any), caller *Caller, callee *Callee) ([]byte,
222222
importDecl = &ast.GenDecl{Tok: token.IMPORT}
223223
f.Decls = prepend[ast.Decl](importDecl, f.Decls...)
224224
}
225-
for _, spec := range res.newImports {
225+
for _, imp := range res.newImports {
226226
// Check that the new imports are accessible.
227-
path, _ := strconv.Unquote(spec.Path.Value)
227+
path, _ := strconv.Unquote(imp.spec.Path.Value)
228228
if !canImport(caller.Types.Path(), path) {
229229
return nil, fmt.Errorf("can't inline function %v as its body refers to inaccessible package %q", callee, path)
230230
}
231-
importDecl.Specs = append(importDecl.Specs, spec)
231+
importDecl.Specs = append(importDecl.Specs, imp.spec)
232232
}
233233
}
234234

@@ -300,8 +300,13 @@ func Inline(logf func(string, ...any), caller *Caller, callee *Callee) ([]byte,
300300
return newSrc, nil
301301
}
302302

303+
type newImport struct {
304+
pkgName string
305+
spec *ast.ImportSpec
306+
}
307+
303308
type result struct {
304-
newImports []*ast.ImportSpec
309+
newImports []newImport
305310
old, new ast.Node // e.g. replace call expr by callee function body expression
306311
}
307312

@@ -387,14 +392,14 @@ func inline(logf func(string, ...any), caller *Caller, callee *gobCallee) (*resu
387392
}
388393

389394
// localImportName returns the local name for a given imported package path.
390-
var newImports []*ast.ImportSpec
391-
localImportName := func(path string, shadows map[string]bool) string {
395+
var newImports []newImport
396+
localImportName := func(obj *object) string {
392397
// Does an import exist?
393-
for _, name := range importMap[path] {
398+
for _, name := range importMap[obj.PkgPath] {
394399
// Check that either the import preexisted,
395400
// or that it was newly added (no PkgName) but is not shadowed,
396401
// either in the callee (shadows) or caller (caller.lookup).
397-
if !shadows[name] {
402+
if !obj.Shadow[name] {
398403
found := caller.lookup(name)
399404
if is[*types.PkgName](found) || found == nil {
400405
return name
@@ -404,7 +409,7 @@ func inline(logf func(string, ...any), caller *Caller, callee *gobCallee) (*resu
404409

405410
newlyAdded := func(name string) bool {
406411
for _, new := range newImports {
407-
if new.Name.Name == name {
412+
if new.pkgName == name {
408413
return true
409414
}
410415
}
@@ -419,29 +424,32 @@ func inline(logf func(string, ...any), caller *Caller, callee *gobCallee) (*resu
419424
//
420425
// "init" is not a legal PkgName.
421426
//
422-
// TODO(adonovan): preserve the PkgName used
423-
// in the original source, or, for a dot import,
424-
// use the package's declared name.
425-
base := pathpkg.Base(path)
427+
// TODO(rfindley): is it worth preserving local package names for callee
428+
// imports? Are they likely to be better or worse than the name we choose
429+
// here?
430+
base := obj.PkgName
426431
name := base
427-
for n := 0; shadows[name] || caller.lookup(name) != nil || newlyAdded(name) || name == "init"; n++ {
432+
for n := 0; obj.Shadow[name] || caller.lookup(name) != nil || newlyAdded(name) || name == "init"; n++ {
428433
name = fmt.Sprintf("%s%d", base, n)
429434
}
430435

431-
// TODO(adonovan): don't use a renaming import
432-
// unless the local name differs from either
433-
// the package name or the last segment of path.
434-
// This requires that we tabulate (path, declared name, local name)
435-
// triples for each package referenced by the callee.
436-
logf("adding import %s %q", name, path)
437-
newImports = append(newImports, &ast.ImportSpec{
438-
Name: makeIdent(name),
436+
logf("adding import %s %q", name, obj.PkgPath)
437+
spec := &ast.ImportSpec{
439438
Path: &ast.BasicLit{
440439
Kind: token.STRING,
441-
Value: strconv.Quote(path),
440+
Value: strconv.Quote(obj.PkgPath),
442441
},
442+
}
443+
// Use explicit pkgname (out of necessity) when it differs from the declared name,
444+
// or (for good style) when it differs from base(pkgpath).
445+
if name != obj.PkgName || name != pathpkg.Base(obj.PkgPath) {
446+
spec.Name = makeIdent(name)
447+
}
448+
newImports = append(newImports, newImport{
449+
pkgName: name,
450+
spec: spec,
443451
})
444-
importMap[path] = append(importMap[path], name)
452+
importMap[obj.PkgPath] = append(importMap[obj.PkgPath], name)
445453
return name
446454
}
447455

@@ -471,8 +479,7 @@ func inline(logf func(string, ...any), caller *Caller, callee *gobCallee) (*resu
471479
var newName ast.Expr
472480
if obj.Kind == "pkgname" {
473481
// Use locally appropriate import, creating as needed.
474-
newName = makeIdent(localImportName(obj.PkgPath, obj.Shadow)) // imported package
475-
482+
newName = makeIdent(localImportName(&obj)) // imported package
476483
} else if !obj.ValidPos {
477484
// Built-in function, type, or value (e.g. nil, zero):
478485
// check not shadowed at caller.
@@ -515,7 +522,7 @@ func inline(logf func(string, ...any), caller *Caller, callee *gobCallee) (*resu
515522

516523
// Form a qualified identifier, pkg.Name.
517524
if qualify {
518-
pkgName := localImportName(obj.PkgPath, obj.Shadow)
525+
pkgName := localImportName(&obj)
519526
newName = &ast.SelectorExpr{
520527
X: makeIdent(pkgName),
521528
Sel: makeIdent(obj.Name),

internal/refactor/inline/testdata/crosspkg.txtar

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,22 +22,30 @@ func A() {
2222
fmt.Println()
2323
b.B1() //@ inline(re"B1", b1result)
2424
b.B2() //@ inline(re"B2", b2result)
25+
b.B3() //@ inline(re"B3", b3result)
2526
}
2627

2728
-- b/b.go --
2829
package b
2930

3031
import "testdata/c"
32+
import "testdata/d"
3133
import "fmt"
3234

3335
func B1() { c.C() }
3436
func B2() { fmt.Println() }
37+
func B3() { e.E() } // (note that "testdata/d" points to package e)
3538

3639
-- c/c.go --
3740
package c
3841

3942
func C() {}
4043

44+
-- d/d.go --
45+
package e // <- this package name intentionally mismatches the path
46+
47+
func E() {}
48+
4149
-- b1result --
4250
package a
4351

@@ -46,7 +54,7 @@ package a
4654
import (
4755
"fmt"
4856
"testdata/b"
49-
c "testdata/c"
57+
"testdata/c"
5058
)
5159

5260
// Nor this one.
@@ -55,6 +63,7 @@ func A() {
5563
fmt.Println()
5664
c.C() //@ inline(re"B1", b1result)
5765
b.B2() //@ inline(re"B2", b2result)
66+
b.B3() //@ inline(re"B3", b3result)
5867
}
5968

6069
-- b2result --
@@ -73,4 +82,24 @@ func A() {
7382
fmt.Println()
7483
b.B1() //@ inline(re"B1", b1result)
7584
fmt.Println() //@ inline(re"B2", b2result)
85+
b.B3() //@ inline(re"B3", b3result)
86+
}
87+
-- b3result --
88+
package a
89+
90+
// This comment does not migrate.
91+
92+
import (
93+
"fmt"
94+
"testdata/b"
95+
e "testdata/d"
96+
)
97+
98+
// Nor this one.
99+
100+
func A() {
101+
fmt.Println()
102+
b.B1() //@ inline(re"B1", b1result)
103+
b.B2() //@ inline(re"B2", b2result)
104+
e.E() //@ inline(re"B3", b3result)
76105
}

internal/refactor/inline/testdata/dotimport.txtar

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ func _() {
2929
package c
3030

3131
import (
32-
a "testdata/a"
32+
"testdata/a"
3333
)
3434

3535
func _() {

internal/refactor/inline/testdata/issue63298.txtar

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ func B() {}
3838
package a
3939

4040
import (
41-
b "testdata/b"
41+
"testdata/b"
4242
b0 "testdata/another/b"
4343

4444
//@ inline(re"a2", result)

internal/refactor/inline/testdata/revdotimport.txtar

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,8 @@ func _() {
3232
package c
3333

3434
import (
35+
"testdata/a"
3536
. "testdata/a"
36-
a "testdata/a"
3737
)
3838

3939
func _() {

0 commit comments

Comments
 (0)