Skip to content

Commit f16791f

Browse files
adonovangopherbot
authored andcommitted
internal/refactor/inline: make soleUse asymptotically faster
Fixes golang/go#75773 Change-Id: Ie1e562ef5a9ba01b5d54cd7e69fffcda36f9a2e9 Reviewed-on: https://go-review.googlesource.com/c/tools/+/717540 Auto-Submit: Alan Donovan <adonovan@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Robert Findley <rfindley@google.com>
1 parent 61c1b28 commit f16791f

File tree

1 file changed

+28
-19
lines changed

1 file changed

+28
-19
lines changed

internal/refactor/inline/inline.go

Lines changed: 28 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -426,12 +426,35 @@ func newImportState(logf func(string, ...any), caller *Caller, callee *gobCallee
426426
// For simplicity we ignore existing dot imports, so that a qualified
427427
// identifier (QI) in the callee is always represented by a QI in the caller,
428428
// allowing us to treat a QI like a selection on a package name.
429-
is := &importState{
429+
ist := &importState{
430430
logf: logf,
431431
caller: caller,
432432
importMap: make(map[string][]string),
433433
}
434434

435+
// Build an index of used-once PkgNames.
436+
type pkgNameUse struct {
437+
count int
438+
id *ast.Ident // an arbitrary use
439+
}
440+
pkgNameUses := make(map[*types.PkgName]pkgNameUse)
441+
for id, obj := range caller.Info.Uses {
442+
if pkgname, ok := obj.(*types.PkgName); ok {
443+
u := pkgNameUses[pkgname]
444+
u.id = id
445+
u.count++
446+
pkgNameUses[pkgname] = u
447+
}
448+
}
449+
// soleUse returns the ident that refers to pkgname, if there is exactly one.
450+
soleUse := func(pkgname *types.PkgName) *ast.Ident {
451+
u := pkgNameUses[pkgname]
452+
if u.count == 1 {
453+
return u.id
454+
}
455+
return nil
456+
}
457+
435458
for _, imp := range caller.File.Imports {
436459
if pkgName, ok := importedPkgName(caller.Info, imp); ok &&
437460
pkgName.Name() != "." &&
@@ -450,7 +473,7 @@ func newImportState(logf func(string, ...any), caller *Caller, callee *gobCallee
450473
// need this import. Doing so eagerly simplifies the resulting logic.
451474
needed := true
452475
sel, ok := ast.Unparen(caller.Call.Fun).(*ast.SelectorExpr)
453-
if ok && soleUse(caller.Info, pkgName) == sel.X {
476+
if ok && soleUse(pkgName) == sel.X {
454477
needed = false // no longer needed by caller
455478
// Check to see if any of the inlined free objects need this package.
456479
for _, obj := range callee.FreeObjs {
@@ -465,13 +488,13 @@ func newImportState(logf func(string, ...any), caller *Caller, callee *gobCallee
465488
// return value holds these.
466489
if needed {
467490
path := pkgName.Imported().Path()
468-
is.importMap[path] = append(is.importMap[path], pkgName.Name())
491+
ist.importMap[path] = append(ist.importMap[path], pkgName.Name())
469492
} else {
470-
is.oldImports = append(is.oldImports, oldImport{pkgName: pkgName, spec: imp})
493+
ist.oldImports = append(ist.oldImports, oldImport{pkgName: pkgName, spec: imp})
471494
}
472495
}
473496
}
474-
return is
497+
return ist
475498
}
476499

477500
// importName finds an existing import name to use in a particular shadowing
@@ -3736,18 +3759,4 @@ func hasNonTrivialReturn(returnInfo [][]returnOperandFlags) bool {
37363759
return false
37373760
}
37383761

3739-
// soleUse returns the ident that refers to obj, if there is exactly one.
3740-
func soleUse(info *types.Info, obj types.Object) (sole *ast.Ident) {
3741-
// This is not efficient, but it is called infrequently.
3742-
for id, obj2 := range info.Uses {
3743-
if obj2 == obj {
3744-
if sole != nil {
3745-
return nil // not unique
3746-
}
3747-
sole = id
3748-
}
3749-
}
3750-
return sole
3751-
}
3752-
37533762
type unit struct{} // for representing sets as maps

0 commit comments

Comments
 (0)