Skip to content

Commit

Permalink
Fixes rjeczalik#35: Slow to generate interfaces
Browse files Browse the repository at this point in the history
Migrate from using the older `loader` package in golang
tools to the new `packages` package in golang tools.  The
previous `loader` package does not support modules and
after switching from `loader` to `packages` it modified
an execution that took over 10s to under 1s.
  • Loading branch information
Steve Graham committed Jun 21, 2023
1 parent 1752681 commit b679cee
Showing 1 changed file with 21 additions and 30 deletions.
51 changes: 21 additions & 30 deletions interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,11 @@ package interfaces

import (
"errors"
"fmt"
"go/types"
"sort"
"unicode"

"golang.org/x/tools/go/loader"
"golang.org/x/tools/go/packages"
)

// Interface represents a typed interface.
Expand Down Expand Up @@ -65,43 +64,35 @@ func (i Interface) Deps() []string {
}

func buildInterface(opts *Options) (Interface, error) {
cfg := &loader.Config{
AllowErrors: true,
Build: opts.context(),
ImportPkgs: map[string]bool{opts.Query.Package: true},
TypeCheckFuncBodies: func(string) bool { return false },
}
cfg.ImportWithTests(opts.Query.Package)
prog, err := cfg.Load()
var err error

// If a requested type is defined in an external test package try to
// build the interface using it before returning an error. Therefore,
// set the `Tests` flag to true so that any test packages are also
// loaded and checked below.
cfg := &packages.Config{
Mode: packages.NeedTypes | packages.NeedTypesInfo | packages.NeedImports | packages.NeedDeps,
Tests: true,
}

pkgs, err := packages.Load(cfg, opts.Query.Package)
if err != nil {
return nil, err
}
pkg, ok := prog.Imported[opts.Query.Package]
if !ok {
return nil, fmt.Errorf("parsing successful, but package %q not found",
opts.Query.Package)
}
i, err := buildInterfaceForPkg(pkg, opts)
if err == nil {
return i, nil
}
// If a requested type is defined in an external test package try to
// build the interface using it before returning an error.
queryCopy := *opts.Query
queryCopy.Package += "_test"
optsCopy := *opts
optsCopy.Query = &queryCopy
for _, pkg := range prog.Created {
if pkg.Pkg.Path() == optsCopy.Query.Package {
return buildInterfaceForPkg(pkg, &optsCopy)

for _, pkg := range pkgs {
opts.Query.Package = pkg.Types.Path()
i, err := buildInterfaceForPkg(pkg, opts)
if err == nil {
return i, nil
}
}
return nil, err
}

func buildInterfaceForPkg(pkg *loader.PackageInfo, opts *Options) (Interface, error) {
func buildInterfaceForPkg(pkg *packages.Package, opts *Options) (Interface, error) {
var typ *types.Named
for _, obj := range pkg.Defs {
for _, obj := range pkg.TypesInfo.Defs {
if obj == nil {
continue
}
Expand Down

0 comments on commit b679cee

Please sign in to comment.